mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
674 lines
19 KiB
674 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cvthpfs.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains the main section of the HPFS-to-NTFS conversion
|
|
utility.
|
|
|
|
Author:
|
|
|
|
Bill McJohn (billmc) 01-Dec-1991
|
|
|
|
Environment:
|
|
|
|
ULIB, User Mode
|
|
|
|
--*/
|
|
|
|
#include <pch.cxx>
|
|
|
|
#define _NTAPI_ULIB_
|
|
|
|
#include "ulib.hxx"
|
|
#include "uhpfs.hxx"
|
|
#include "untfs.hxx"
|
|
|
|
#include "bitmap.hxx"
|
|
#include "error.hxx"
|
|
#include "fnode.hxx"
|
|
#include "hpcensus.hxx"
|
|
#include "hpfsvol.hxx"
|
|
#include "hpfssa.hxx"
|
|
#include "smsg.hxx"
|
|
#include "rtmsg.h"
|
|
#include "wstring.hxx"
|
|
#include "intstack.hxx"
|
|
|
|
// #include "system.hxx"
|
|
#include "ifssys.hxx"
|
|
#include "ulibcl.hxx"
|
|
|
|
#include "attrib.hxx"
|
|
#include "bitfrs.hxx"
|
|
#include "logfile.hxx"
|
|
#include "mft.hxx"
|
|
#include "ntfssa.hxx"
|
|
#include "ntfsbit.hxx"
|
|
#include "indxtree.hxx"
|
|
#include "mftfile.hxx"
|
|
#include "upcase.hxx"
|
|
#include "upfile.hxx"
|
|
|
|
#include "cuhpfs.hxx"
|
|
#include "nametab.hxx"
|
|
|
|
// Global buffers used for name conversion.
|
|
|
|
CONST NameBufferLength = 512;
|
|
CHAR NameBuffer[NameBufferLength];
|
|
|
|
CONST EaBufferLength = 0x10000;
|
|
CHAR EaBuffer[EaBufferLength];
|
|
|
|
BOOLEAN
|
|
CheckGeometryMatch(
|
|
IN PHPFS_SA HpfsSuperArea,
|
|
IN PHPFS_VOL HpfsVol
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method checks that the geometry recorded in the
|
|
Bios Parameter Block agrees with the geometry reported
|
|
by the driver.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the geometry in the BPB matches that reported
|
|
by the driver; false if not. The only field that is
|
|
checked is BytesPerSector.
|
|
|
|
--*/
|
|
{
|
|
USHORT SectorSize, SectorsPerTrack, Heads;
|
|
ULONG HiddenSectors;
|
|
|
|
HpfsSuperArea->QueryGeometry( &SectorSize,
|
|
&SectorsPerTrack,
|
|
&Heads,
|
|
&HiddenSectors );
|
|
|
|
if( SectorSize != HpfsVol->QuerySectorSize() ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ConvertToNtfs(
|
|
IN OUT PHPFS_VOL HpfsVol,
|
|
IN PCNAME_LOOKUP_TABLE NameTable,
|
|
IN PNUMBER_SET BadSectors,
|
|
IN OUT PMESSAGE Message,
|
|
IN BOOLEAN Verbose,
|
|
OUT PBOOLEAN Corrupt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function converts the specified HPFS volume into an NTFS
|
|
volume.
|
|
|
|
Arguments:
|
|
|
|
NtDriveName -- supplies the name of the volume to convert.
|
|
BadSectors -- supplies the volume's bad sector list.
|
|
Message -- supplies an outlet for messages.
|
|
Verbose -- supplies a flag which, if TRUE, indicates that
|
|
CONVERT should list every file converted.
|
|
Corrupt -- receives TRUE if conversion fails because the
|
|
volume was found to be corrupt.
|
|
|
|
Return Value:
|
|
|
|
TRUE upon successful completion.
|
|
|
|
--*/
|
|
{
|
|
DIRBLK RootDirblk;
|
|
FNODE RootFnode;
|
|
NTFS_SA NtfsSuperArea;
|
|
HPFS_CENSUS Census;
|
|
HPFS_MAIN_BITMAP HpfsOnlyBitmap;
|
|
NTFS_BITMAP NtfsVolumeBitmap;
|
|
NTFS_UPCASE_TABLE UpcaseTable;
|
|
NTFS_MFT_FILE Mft;
|
|
NTFS_BITMAP_FILE BitmapFile;
|
|
NTFS_LOG_FILE LogFile;
|
|
NTFS_UPCASE_FILE UpcaseFile;
|
|
NTFS_FILE_RECORD_SEGMENT RootIndexFile;
|
|
NTFS_INDEX_TREE RootIndex;
|
|
NTFS_ATTRIBUTE BitmapAttribute;
|
|
NTFS_ATTRIBUTE LogfileData;
|
|
NTFS_ATTRIBUTE UpcaseAttribute;
|
|
DSTRING LabelString, FileNameIndexName;
|
|
FSTRING BootLogFileName, RootName;
|
|
SECRUN NukeSuperblockSecrun;
|
|
HMEM NukeSuperblockMem;
|
|
|
|
PHPFS_SA HpfsSuperArea;
|
|
PHPFS_BITMAP HpfsVolumeBitmap;
|
|
|
|
BIG_INT TotalKilobytes, FreeKilobytes, RequiredKilobytes, BytesInIndices;
|
|
ULONG NumberOfSectors, i, SectorSize, SectorsInBootArea,
|
|
SectorsFree, SectorsRequired;
|
|
|
|
BOOLEAN Error;
|
|
|
|
CONST ULONG ClusterFactor = 1;
|
|
ULONG ClustersPerFrs = NTFS_SA::QueryDefaultClustersPerFrs(
|
|
HpfsVol, ClusterFactor);
|
|
ULONG ClustersPerIndexBuffer = NTFS_SA::QueryDefaultClustersPerIndexBuffer(
|
|
HpfsVol, ClusterFactor);
|
|
|
|
|
|
CONST AverageBytesPerIndexEntry = 128;
|
|
|
|
|
|
|
|
// Attributes associated with indices over $FILE_NAME always
|
|
// have the name $I3.
|
|
//
|
|
if( !FileNameIndexName.Initialize( FileNameIndexNameData ) ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HpfsSuperArea = HpfsVol->GetHPFSSuperArea();
|
|
|
|
// Assume innocent until proven guilty:
|
|
//
|
|
*Corrupt = FALSE;
|
|
|
|
// To protect ourselves from disk drivers that cannot
|
|
// correctly determine the disk geometry, compare the
|
|
// boot-code-critical values from the existing BPB with
|
|
// the drive's values. If they don't match, we can't
|
|
// convert this drive because if it's the system partition,
|
|
// the system won't boot.
|
|
//
|
|
if( !CheckGeometryMatch( HpfsSuperArea, HpfsVol ) ) {
|
|
|
|
Message->Set( MSG_CONV_GEOMETRY_MISMATCH );
|
|
Message->Display( "%s", "NTFS" );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Take the census of the HPFS volume.
|
|
//
|
|
if( !HpfsOnlyBitmap.Initialize( HpfsVol ) ||
|
|
!HpfsOnlyBitmap.SetFree( 0, HpfsVol->QuerySectors().GetLowPart() ) ||
|
|
!Census.Initialize( 1 ) ) {
|
|
|
|
DebugPrint( "Can't initialize census stuff.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Add the must-clear sectors:
|
|
|
|
if( !Census.AddClearSector( HpfsVol->QuerySectors().GetLowPart()/2 ) ) {
|
|
|
|
DebugPrint( "Can't add clear-sector.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
Message->Set( MSG_CONV_CHECKING_SPACE );
|
|
Message->Display();
|
|
|
|
if( !HpfsSuperArea->TakeCensusAndClear( &HpfsOnlyBitmap, &Census ) ) {
|
|
|
|
DebugPrint( "Census failed.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Set up the NTFS bitmap. I start out with it equivalent to the
|
|
// HPFS bitmap, so that new NTFS structures will get put down
|
|
// only in the volume free space. The NTFS volume will have a
|
|
// clusterfactor of 1.
|
|
|
|
if( !NtfsVolumeBitmap.Initialize( HpfsVol->QuerySectors(), FALSE,
|
|
HpfsVol, 1 )) {
|
|
|
|
DebugPrint( "Can't initialize NTFS bitmap.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
NumberOfSectors = HpfsVol->QuerySectors().GetLowPart();
|
|
SectorSize = HpfsVol->QuerySectorSize();
|
|
|
|
HpfsVolumeBitmap = HpfsSuperArea->GetBitmap();
|
|
|
|
for( i = 0; i < NumberOfSectors; i++ ) {
|
|
|
|
if( !HpfsVolumeBitmap->IsFree( i, 1 ) ) {
|
|
|
|
NtfsVolumeBitmap.SetAllocated( i, 1 );
|
|
|
|
}
|
|
}
|
|
|
|
// Compute free space requirement and see if there's enough.
|
|
// The amount of free space required is:
|
|
// The space required by the elementary structures, plus
|
|
// One FRS for each file or directory, plus
|
|
// Enough index blocks to hold the required index entries.
|
|
// (The number of bytes in indices is multiplied by
|
|
// two to reflect that the average index block will
|
|
// be half-full.)
|
|
//
|
|
SectorsRequired =
|
|
NTFS_SA::QuerySectorsInElementaryStructures( HpfsVol,
|
|
ClusterFactor,
|
|
ClustersPerFrs,
|
|
ClustersPerIndexBuffer,
|
|
0 );
|
|
|
|
SectorsRequired += ( Census.QueryNumberOfFiles() +
|
|
Census.QueryNumberOfDirectories() ) *
|
|
ClustersPerFrs *
|
|
ClusterFactor;
|
|
|
|
BytesInIndices = ( Census.QueryNumberOfFiles() +
|
|
Census.QueryNumberOfDirectories() ) *
|
|
AverageBytesPerIndexEntry * 2;
|
|
|
|
SectorsRequired += (BytesInIndices / SectorSize).GetLowPart();
|
|
|
|
|
|
// Note that conversion requires limits us to one
|
|
// sector per cluster.
|
|
//
|
|
SectorsFree = NtfsVolumeBitmap.QueryFreeClusters().GetLowPart();
|
|
|
|
// These calculations are broken up into separate statements to
|
|
// avoid problems with overflow in ULONG arithmetic.
|
|
//
|
|
TotalKilobytes = NumberOfSectors;
|
|
TotalKilobytes = (TotalKilobytes * SectorSize)/1024;
|
|
|
|
FreeKilobytes = SectorsFree;
|
|
FreeKilobytes = (FreeKilobytes * SectorSize)/1024;
|
|
|
|
RequiredKilobytes = SectorsRequired;
|
|
RequiredKilobytes = (RequiredKilobytes * SectorSize)/1024;
|
|
|
|
Message->Set( MSG_CONV_KBYTES_TOTAL );
|
|
Message->Display( "%9d", TotalKilobytes.GetLowPart() );
|
|
|
|
Message->Set( MSG_CONV_KBYTES_FREE );
|
|
Message->Display( "%9d", FreeKilobytes.GetLowPart() );
|
|
|
|
Message->Set( MSG_CONV_KBYTES_NEEDED );
|
|
Message->Display( "%9d", RequiredKilobytes.GetLowPart() );
|
|
|
|
|
|
if( SectorsRequired > SectorsFree ) {
|
|
|
|
Message->Set( MSG_CONV_NO_DISK_SPACE );
|
|
Message->Display();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Clear the clusters that are allowed to conflict with HPFS-only
|
|
// structures in the HPFS-only bitmap.
|
|
//
|
|
SectorsInBootArea = ( BYTES_IN_BOOT_AREA % SectorSize ) ?
|
|
( BYTES_IN_BOOT_AREA / SectorSize + 1 ) :
|
|
( BYTES_IN_BOOT_AREA / SectorSize );
|
|
|
|
HpfsOnlyBitmap.SetFree( 0, SectorsInBootArea );
|
|
HpfsOnlyBitmap.SetFree( NumberOfSectors/2, 1 );
|
|
|
|
|
|
// Now I'm ready to create the NTFS super area. It will have
|
|
// 1 sector per cluster.
|
|
//
|
|
if( !NtfsSuperArea.Initialize( HpfsVol, Message ) ) {
|
|
|
|
DebugPrint( "Can't initialize NTFS Super Area.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the existing volume label:
|
|
//
|
|
if( !HpfsSuperArea->QueryLabel( &LabelString ) ) {
|
|
|
|
DebugPrint( "Can't get existing volume label." );
|
|
return FALSE;
|
|
}
|
|
|
|
Message->Set( MSG_CONV_CONVERTING_FS );
|
|
Message->Display();
|
|
|
|
// Create the file-system elementary structures--ie. all
|
|
// the system files. Pass in a small number for the log
|
|
// file size to prevent it from gobbling up the available
|
|
// contiguous space; patch this up later.
|
|
//
|
|
if( !NtfsSuperArea.CreateElementaryStructures( &NtfsVolumeBitmap,
|
|
ClusterFactor,
|
|
ClustersPerFrs,
|
|
ClustersPerIndexBuffer,
|
|
0x1000,
|
|
BadSectors,
|
|
Message,
|
|
HpfsSuperArea->GetBpb(),
|
|
&LabelString ) ) {
|
|
|
|
DebugPrint( "CreateElementaryStructures failed.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// I now have a valid NTFS volume, except that the boot sectors
|
|
// have not been written to disk. The bitmap has all existing files,
|
|
// all HPFS structures, and all NTFS structures marked as in-use.
|
|
|
|
// Get a Master File Table object. Note that I don't have an
|
|
// upcase table yet, so I pass in NULL.
|
|
//
|
|
if( !Mft.Initialize( HpfsVol,
|
|
NtfsSuperArea.QueryMftStartingLcn(),
|
|
NtfsSuperArea.QueryClusterFactor(),
|
|
NtfsSuperArea.QueryClustersPerFrs(),
|
|
NtfsSuperArea.QueryVolumeSectors(),
|
|
&NtfsVolumeBitmap,
|
|
NULL ) ||
|
|
!Mft.Read() ) {
|
|
|
|
DebugPrint( "Can't get the MFT I just created.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Tell the ntfs volume bitmap about the mft so it can use the
|
|
// bad cluster file to keep track of any bad clusters that are
|
|
// found.
|
|
|
|
NtfsVolumeBitmap.SetMftPointer(Mft.GetMasterFileTable());
|
|
|
|
// Get the upcase table.
|
|
//
|
|
if( !UpcaseFile.Initialize( Mft.GetMasterFileTable() ) ||
|
|
!UpcaseFile.Read() ||
|
|
!UpcaseFile.QueryAttribute( &UpcaseAttribute, &Error, $DATA ) ||
|
|
!UpcaseTable.Initialize( &UpcaseAttribute ) ) {
|
|
|
|
DebugPrint( "Can't get the upcase table.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
Mft.SetUpcaseTable( &UpcaseTable );
|
|
Mft.GetMasterFileTable()->SetUpcaseTable( &UpcaseTable );
|
|
|
|
|
|
// Extend the Master File Table to provide space for all the File
|
|
// Record Segments I know I'll need. Include some slush, to provide
|
|
// for files with external attributes (especially the MFT itself).
|
|
//
|
|
if( !Mft.Extend( Census.QueryNumberOfFiles() +
|
|
Census.QueryNumberOfDirectories() +
|
|
0x10 ) ) {
|
|
|
|
DebugPrint( "CONVERT: Can't create a sufficiently large Master File Table.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Flush the MFT again, so that it claims the first available
|
|
// File Record Segments for its overflow (to prevent bootstrap
|
|
// errors later).
|
|
//
|
|
if( !Mft.Flush() ) {
|
|
|
|
DebugPrint( "Can't flush the Master File Table.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Now patch the log file: initialize it, fetch its data attribute
|
|
// and truncate it to zero, and then create a new data attribute,
|
|
// passing in zero to tell it to choose a reasonable default.
|
|
//
|
|
if( !LogFile.Initialize( Mft.GetMasterFileTable() ) ||
|
|
!LogFile.Read() ||
|
|
!LogFile.QueryAttribute( &LogfileData, &Error, $DATA ) ||
|
|
!LogfileData.Resize( 0, &NtfsVolumeBitmap ) ||
|
|
!LogFile.CreateDataAttribute( 0, &NtfsVolumeBitmap ) ||
|
|
!LogFile.Flush( &NtfsVolumeBitmap ) ) {
|
|
|
|
DebugPrint( "CONVERT: Can't resize log file.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Sanity check: make sure that the log file doesn't have
|
|
// an attribute list. The file system will die horribly
|
|
// if Convert creates a log file with external attributes.
|
|
//
|
|
if( LogFile.IsAttributePresent( $ATTRIBUTE_LIST ) ) {
|
|
|
|
Message->Set( MSG_CONV_VOLUME_TOO_FRAGMENTED );
|
|
Message->Display( "" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Initialize and read the root file name index FRS.
|
|
//
|
|
if( !RootIndexFile.Initialize( ROOT_FILE_NAME_INDEX_NUMBER,
|
|
Mft.GetMasterFileTable() ) ||
|
|
!RootIndexFile.Read() ||
|
|
!RootIndex.Initialize( HpfsVol,
|
|
NtfsSuperArea.QueryClusterFactor(),
|
|
&NtfsVolumeBitmap,
|
|
&UpcaseTable,
|
|
RootIndexFile.
|
|
QueryMaximumAttributeRecordSize()/2,
|
|
&RootIndexFile,
|
|
&FileNameIndexName ) ) {
|
|
|
|
DebugPrint( "Can't read/initialize the root file name index.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Force the HPFS Codepage information into memory:
|
|
|
|
if( !HpfsSuperArea->ReadCodepage() ) {
|
|
|
|
DebugPrint( "Can't read codepages--volume is corrupt." );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// Get the root Dirblk of the HPFS volume. This Dirblk will
|
|
// be the key to the entire directory tree.
|
|
|
|
if( !RootFnode.Initialize( HpfsVol,
|
|
HpfsSuperArea->GetSuper()->
|
|
QueryRootFnodeLbn() ) ) {
|
|
|
|
DebugPrint( "Can't initialize root FNode.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
if( !RootFnode.Read() || !RootFnode.IsFnode() ) {
|
|
|
|
DebugPrint( "Root FNode is not an FNode--volume is corrupt.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
if( !RootDirblk.Initialize( HpfsVol,
|
|
NULL,
|
|
RootFnode.QueryRootDirblkLbn() ) ) {
|
|
|
|
DebugPrint( "Can't initialize root dirblk.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
if( !RootDirblk.Read() || !RootDirblk.IsDirblk() ) {
|
|
|
|
DebugPrint( "Root dirblk is not a dirblk--volume is corrupt.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Convert the root dirblk. This will recursively convert the
|
|
// entire directory tree. Since this is the root directory,
|
|
// I supply zero for the level. Note that this requires two
|
|
// passes; the first pass converts short names, while the
|
|
// second pass converts long names.
|
|
//
|
|
RootName.Initialize( L"" );
|
|
|
|
if( !ConvertDirblkToNtfs( HpfsVol,
|
|
NameTable,
|
|
Message,
|
|
&NtfsVolumeBitmap,
|
|
&HpfsOnlyBitmap,
|
|
HpfsSuperArea->GetCasemap(),
|
|
&Mft,
|
|
ClustersPerIndexBuffer,
|
|
&RootDirblk,
|
|
&RootIndex,
|
|
RootIndexFile.QuerySegmentReference(),
|
|
Corrupt,
|
|
Verbose,
|
|
NameBuffer,
|
|
NameBufferLength,
|
|
EaBuffer,
|
|
EaBufferLength,
|
|
0,
|
|
&RootName,
|
|
FALSE ) ||
|
|
!ConvertDirblkToNtfs( HpfsVol,
|
|
NameTable,
|
|
Message,
|
|
&NtfsVolumeBitmap,
|
|
&HpfsOnlyBitmap,
|
|
HpfsSuperArea->GetCasemap(),
|
|
&Mft,
|
|
ClustersPerIndexBuffer,
|
|
&RootDirblk,
|
|
&RootIndex,
|
|
RootIndexFile.QuerySegmentReference(),
|
|
Corrupt,
|
|
Verbose,
|
|
NameBuffer,
|
|
NameBufferLength,
|
|
EaBuffer,
|
|
EaBufferLength,
|
|
0,
|
|
&RootName,
|
|
TRUE ) ) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Save the root file name index
|
|
|
|
if( !RootIndex.Save( &RootIndexFile ) ||
|
|
!RootIndexFile.Write() ) {
|
|
|
|
DebugPrint( "Can't save root index.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// Free the HPFS-only sectors. Any sector which is marked as
|
|
// in use in the HPFS-only bitmap becomes marked as free in
|
|
// the NTFS bitmap.
|
|
|
|
for( i = 0; i < NumberOfSectors; i++ ) {
|
|
|
|
if( !HpfsOnlyBitmap.IsFree( i ) ) {
|
|
|
|
NtfsVolumeBitmap.SetFree( i, 1 );
|
|
}
|
|
}
|
|
|
|
|
|
// Flush the MFT. Note that this will also update the volume
|
|
// bitmap and the MFT mirror.
|
|
|
|
if( !Mft.Flush() ) {
|
|
|
|
DebugPrint( "Can't flush the Master File Table.\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Flush the cache before we write sector zero, just
|
|
// to be safe.
|
|
//
|
|
HpfsVol->FlushCache();
|
|
|
|
|
|
// Write the super area.
|
|
//
|
|
if( !NtfsSuperArea.Write() ) {
|
|
|
|
DebugPrint( "Failed writing the NTFS superarea!!!\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
// Write the rest of the boot code:
|
|
//
|
|
if( !NtfsSuperArea.WriteRemainingBootCode() ) {
|
|
|
|
DebugPrint( "UNTFS: Unable to write boot code.\n" );
|
|
}
|
|
|
|
// Nuke the signatures in sector 16, to make sure nobody
|
|
// mistakes this for an HPFS volume.
|
|
//
|
|
if( NukeSuperblockMem.Initialize() &&
|
|
NukeSuperblockSecrun.Initialize( &NukeSuperblockMem,
|
|
HpfsVol,
|
|
LBN_SUPERB,
|
|
1 ) &&
|
|
NukeSuperblockSecrun.Read() ) {
|
|
|
|
memset( NukeSuperblockSecrun.GetBuf(), 0, 8 );
|
|
NukeSuperblockSecrun.Write();
|
|
}
|
|
|
|
|
|
#if defined( _AUTOCHECK_ )
|
|
|
|
// Autoconvert needs to reboot at this point, to force
|
|
// the new file system to be recognized.
|
|
//
|
|
Message->Set( MSG_CONVERT_REBOOT );
|
|
Message->Display();
|
|
|
|
BootLogFileName.Initialize( L"bootex.log" );
|
|
if( Message->IsLoggingEnabled() &&
|
|
!NTFS_SA::DumpMessagesToFile( &BootLogFileName, &Mft, Message ) ) {
|
|
|
|
DebugPrintf( "CONVERT: Error writing messages to BOOTEX.LOG\n" );
|
|
}
|
|
|
|
HpfsVol->FlushCache();
|
|
IFS_SYSTEM::Reboot();
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|