/*++ Copyright (c) 1990 Microsoft Corporation Module Name: cvthpfs.cxx Abstract: This module contains the declaration of ConvertHPFS, which is the main entry point for this DLL. Author: Bill McJohn (billmc) 09-Jan-1992 Environment: ULIB, User Mode --*/ #include #define _NTAPI_ULIB_ #include "ulib.hxx" #include "message.hxx" #include "rtmsg.h" #include "drive.hxx" #include "rwcache.hxx" #include "intstack.hxx" #include "numset.hxx" #include "uhpfs.hxx" #include "hpfsvol.hxx" #include "hpfssa.hxx" #include "cuhpfs.hxx" #include "nametab.hxx" DECLARE_CLASS( NAME_TABLE ); DECLARE_CLASS( NAME_LOOKUP_TABLE ); extern "C" BOOLEAN InitializeCuhpfs ( PVOID DllHandle, ULONG Reason, PCONTEXT Context ) /*++ Routine Description: This function is the initialization entry point for CUHPFS.DLL. At present, it's a null function, but this is where any initialization goes if it's ever needed. --*/ { if( !DEFINE_CLASS_DESCRIPTOR( NAME_TABLE ) || !DEFINE_CLASS_DESCRIPTOR( NAME_LOOKUP_TABLE ) ) { return FALSE; } return TRUE; } BOOLEAN FAR APIENTRY ConvertHPFSVolume( IN PHPFS_VOL HpfsVolume, IN PCWSTRING TargetFileSystem, IN PCNAME_LOOKUP_TABLE NameTable, IN OUT PMESSAGE Message, IN BOOLEAN Verbose, OUT PCONVERT_STATUS Status ) /*++ Routine Description: This function converts an opened HPFS Volume to a new file system. Arguments: Drive -- Supplies the drive to convert. Note that it the caller must lock the drive (Convert) or open it for exclusive write access (Autoconvert). TargetFileSystem -- Supplies the file system to which the drive will be converted. Note that only "NTFS" is presently supported. Message -- Supplies an outlet for messages. Verbose -- Supplies a flag indicating (if TRUE) that conversion should be carried out in verbose mode. Status -- Receives the status of the conversion. --*/ { PREAD_WRITE_CACHE RwCache; NUMBER_SET BadSectorSet; DSTRING FatString, HpfsString, NtfsString, CdfsString; PHPFS_SA HpfsSuperArea; PLBN BadLbnList; ULONG NumberOfBadLbns, ActualNumberOfBadLbns, i; BOOLEAN Result, Corrupt; // Load in the read write cache. if ((RwCache = NEW READ_WRITE_CACHE) && RwCache->Initialize( HpfsVolume, 75 )) { HpfsVolume->SetCache(RwCache); } else { DELETE(RwCache); } // Check that this volume meets the requirements for conversion. // It must be a clean HPFS volume with no hotfixes. HpfsSuperArea = HpfsVolume->GetHPFSSuperArea(); if( !HpfsSuperArea->CheckSuperBlockSignatures() ) { Message->Set( MSG_CONV_HPFS_NOT_HPFS ); Message->Display( "" ); *Status = CONVERT_STATUS_ERROR; return FALSE; } if( HpfsSuperArea->GetSuper()->QueryVersion() != SUPERB_VERSION || ( HpfsSuperArea->GetSuper()->QueryFuncVersion() != SUPERB_FVERSION_2 && HpfsSuperArea->GetSuper()->QueryFuncVersion() != SUPERB_FVERSION_3 ) ) { Message->Set( MSG_HPFS_CHKDSK_WRONG_VERSION ); Message->Display( "" ); return FALSE; } if( !HpfsSuperArea->IsClean() ) { Message->Set( MSG_CONV_HPFS_DIRTY_VOLUME ); Message->Display( "" ); *Status = CONVERT_STATUS_ERROR; return FALSE; } if( HpfsSuperArea->GetSpare()->QueryHotFixCount() != 0 || HpfsSuperArea->GetSpare()->IsHotFixesUsed() ) { Message->Set( MSG_CONV_HPFS_HOTFIXES_PRESENT ); Message->Display( "" ); *Status = CONVERT_STATUS_ERROR; return FALSE; } // Fetch the list of bad lbns and bundle them up into an intstack. NumberOfBadLbns = HpfsSuperArea->GetSuper()->QueryBadSectors(); if( (BadLbnList = (PLBN)MALLOC( NumberOfBadLbns * sizeof(LBN) )) == NULL ) { Message->Set( MSG_CONV_NO_MEMORY ); Message->Display( "" ); DebugPrint( "Insufficient memory.\n" ); *Status = CONVERT_STATUS_ERROR; return FALSE; } if( !HpfsSuperArea->QueryBadLbns( NumberOfBadLbns, BadLbnList, &ActualNumberOfBadLbns ) ) { Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME ); Message->Display( "" ); FREE( BadLbnList ); *Status = CONVERT_STATUS_ERROR; return FALSE; } if( !BadSectorSet.Initialize() ) { Message->Set( MSG_CONV_NO_MEMORY ); Message->Display( "" ); FREE( BadLbnList ); *Status = CONVERT_STATUS_ERROR; return FALSE; } for( i = 0; i < ActualNumberOfBadLbns; i++ ) { if( !BadSectorSet.Add( BadLbnList[i] ) ) { Message->Set( MSG_CONV_NO_MEMORY ); Message->Display( "" ); FREE( BadLbnList ); *Status = CONVERT_STATUS_ERROR; return FALSE; } } // Tell the HPFS SuperArea to read its codepage information if( !HpfsSuperArea->ReadCodepage() ) { Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME ); Message->Display( "" ); FREE( BadLbnList ); *Status = CONVERT_STATUS_ERROR; return FALSE; } // Determine whether the target file system is supported. Set up // a WSTRING for each recognized target file system. if( !FatString.Initialize( "FAT" ) || !HpfsString.Initialize( "HPFS" ) || !NtfsString.Initialize( "NTFS" ) || !CdfsString.Initialize( "CDFS" ) ) { Message->Set( MSG_CONV_NO_MEMORY ); Message->Display( "" ); FREE( BadLbnList ); *Status = CONVERT_STATUS_ERROR; return FALSE; } if( *TargetFileSystem == NtfsString ) { Result = ConvertToNtfs( HpfsVolume, NameTable, &BadSectorSet, Message, Verbose, &Corrupt ); *Status = (Result) ? CONVERT_STATUS_CONVERTED : CONVERT_STATUS_ERROR; if( !Result && Corrupt ) { Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME ); Message->Display( "" ); } } else if ( *TargetFileSystem == FatString || *TargetFileSystem == HpfsString || *TargetFileSystem == CdfsString ) { // recognized but unsupported target *Status = CONVERT_STATUS_CONVERSION_NOT_AVAILABLE; Result = FALSE; } else { *Status = CONVERT_STATUS_INVALID_FILESYSTEM; Result = FALSE; } FREE( BadLbnList ); return Result; } BOOLEAN FAR APIENTRY ConvertHPFS( IN PCWSTRING NtDriveName, IN PCWSTRING TargetFileSystem, IN OUT PMESSAGE Message, IN BOOLEAN Verbose, OUT PCONVERT_STATUS Status ) /*++ Routine Description: This function converts an HPFS volume to the target file system in-place. This function opens and locks the volume, so it is not suitable for use by autoconvert. Arguments: NtDriveName -- Supplies the name of the drive. TargetFileSystem -- Supplies the file system to which the drive will be converted. Note that only "NTFS" is presently supported. Message -- Supplies an outlet for messages. Verbose -- Supplies a flag indicating (if TRUE) that conversion should be carried out in verbose mode. Status -- Receives the status of the conversion. Return Value: TRUE upon successful completion. --*/ { HPFS_VOL HpfsVolume; DP_DRIVE DpDrive; // Make sure that the volume does not have a queer sector size. if (!DpDrive.Initialize(NtDriveName, Message)) { *Status = CONVERT_STATUS_ERROR; return FALSE; } if (DpDrive.QuerySectorSize() != 512) { Message->Set(MSG_CONVERT_UNSUPPORTED_SECTOR_SIZE); Message->Display("%W", TargetFileSystem); *Status = CONVERT_STATUS_ERROR; return FALSE; } // Initialize and lock the volume. if( !HpfsVolume.Initialize( NtDriveName, Message )) { *Status = CONVERT_STATUS_ERROR; return FALSE; } // Lock the volume for exclusive access. if( !HpfsVolume.Lock() ) { *Status = CONVERT_STATUS_CANNOT_LOCK_DRIVE; return FALSE; } return( ConvertHPFSVolume( &HpfsVolume, TargetFileSystem, NULL, Message, Verbose, Status ) ); }