📄 fatsachk.cxx
字号:
// Remove all unused EAs from EA file.
if (!PurgeEaFile(ea_infos, num_eas, &fat_bitmap, FixLevel, Message,
&fmsg)) {
// DELETE( ea_infos );
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
// Rebuild header portion of EA file.
if (!ea_header_mem.Initialize() ||
!RebuildEaHeader(&ea_clus_num, ea_infos, num_eas,
&ea_header_mem, &ea_header, &fat_bitmap,
FixLevel, Message, &fmsg)) {
// DELETE( ea_infos );
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
if (ea_clus_num) {
eadent.SetStartingCluster(ea_clus_num);
eadent.SetFileSize(cluster_size*
_fat->QueryLengthOfChain(ea_clus_num));
} else {
dofmsg(Message, &fmsg);
Message->Set(MSG_CHK_EMPTY_EA_FILE);
Message->Display();
//
// Note that the following two steps cause the EA file chain to get recovered
// as a lost cluster chain since all this does is erase the dirent, not the
// cluster chain.
//
eadent.SetErased();
FreeSpaceInBitmap(eadent.QueryStartingCluster(), _fat,
&fat_bitmap);
}
*ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
}
//
// If WalkDirectoryTree deleted any files, we need to sync the
// FAT_EXTENSIONS up with the FAT again.
//
if (!VerifyFatExtensions(FixLevel, Message, &fmsg)) {
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
if (!RecoverOrphans(&fat_bitmap, FixLevel, Message, &fmsg, &report, &changes)) {
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
//
// RecoverOrphans may have cleared faulty entries from the FAT,
// and now we need to sync the FAT_EXTENSIONS again.
//
if (!VerifyFatExtensions(FixLevel, Message, &fmsg)) {
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
// If requested, validate all of the free space on the volume.
if (RecoverFree && !RecoverFreeSpace(Message)) {
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
total_count = cluster_count - FirstDiskCluster;
if (changes) {
report.ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
}
*ExitStatus = report.ExitStatus;
switch (*ExitStatus) {
case CHKDSK_EXIT_SUCCESS:
Message->DisplayMsg(MSG_CHK_NO_PROBLEM_FOUND);
break;
case CHKDSK_EXIT_ERRS_FIXED:
Message->DisplayMsg((FixLevel != CheckOnly) ? MSG_CHK_ERRORS_FIXED : MSG_CHK_NEED_F_PARAMETER);
break;
case CHKDSK_EXIT_COULD_NOT_CHK:
// case CHKDSK_EXIT_ERRS_NOT_FIXED:
// case CHKDSK_EXIT_COULD_NOT_FIX:
Message->DisplayMsg(MSG_CHK_ERRORS_NOT_FIXED);
break;
}
BIG_INT temp_big_int;
ULONG temp_ulong;
MSGID message_id;
BOOLEAN KSize;
DSTRING wdNum1;
char wdAstr[14];
DSTRING wdNum2;
if (!wdNum1.Initialize(" ") ||
!wdNum2.Initialize(" ") ) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
temp_big_int = cluster_size;
temp_big_int = temp_big_int * total_count;
// NOTE: The magic number 4095MB comes from Win9x's GUI SCANDISK utility
if (temp_big_int.GetHighPart() || (temp_big_int.GetLowPart() > (4095ul*1024ul*1024ul))) {
temp_ulong = (temp_big_int / 1024ul).GetLowPart();
message_id = MSG_TOTAL_KILOBYTES;
KSize = TRUE;
} else {
temp_ulong = temp_big_int.GetLowPart();
message_id = MSG_TOTAL_DISK_SPACE;
KSize = FALSE;
}
Message->Set(message_id);
sprintf(wdAstr, "%u", temp_ulong);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
if (report.HiddenEntriesCount) {
temp_big_int = cluster_size;
temp_big_int = temp_big_int * report.HiddenClusters;
if (KSize) {
temp_ulong = (temp_big_int / 1024ul).GetLowPart();
message_id = MSG_KILOBYTES_IN_HIDDEN_FILES;
} else {
temp_ulong = temp_big_int.GetLowPart();
message_id = MSG_HIDDEN_FILES;
}
Message->Set(message_id);
sprintf(wdAstr, "%u", temp_ulong);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
sprintf(wdAstr, "%d", report.HiddenEntriesCount);
InsertSeparators(wdNum2.GetWSTR(),wdAstr, 0);
Message->Display("%ws%ws", wdNum1.GetWSTR(), wdNum2.GetWSTR());
}
if (report.DirEntriesCount) {
temp_big_int = cluster_size;
temp_big_int = temp_big_int * report.DirClusters;
if (KSize) {
temp_ulong = (temp_big_int / 1024ul).GetLowPart();
message_id = MSG_KILOBYTES_IN_DIRECTORIES;
} else {
temp_ulong = temp_big_int.GetLowPart();
message_id = MSG_DIRECTORIES;
}
Message->Set(message_id);
sprintf(wdAstr, "%u", temp_ulong);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
sprintf(wdAstr, "%d", report.DirEntriesCount);
InsertSeparators(wdNum2.GetWSTR(),wdAstr, 0);
Message->Display("%ws%ws", wdNum1.GetWSTR(), wdNum2.GetWSTR());
}
if (report.FileEntriesCount) {
temp_big_int = cluster_size;
temp_big_int = temp_big_int * report.FileClusters;
if (KSize) {
temp_ulong = (temp_big_int / 1024ul).GetLowPart();
message_id = MSG_KILOBYTES_IN_USER_FILES;
} else {
temp_ulong = temp_big_int.GetLowPart();
message_id = MSG_USER_FILES;
}
Message->Set(message_id);
sprintf(wdAstr, "%u", temp_ulong);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
sprintf(wdAstr, "%d", report.FileEntriesCount);
InsertSeparators(wdNum2.GetWSTR(),wdAstr, 0);
Message->Display("%ws%ws", wdNum1.GetWSTR(), wdNum2.GetWSTR());
}
if (bad_count = _fat->QueryBadClusters()) {
temp_big_int = bad_count;
temp_big_int = temp_big_int * cluster_size;
if (KSize) {
temp_ulong = (temp_big_int / 1024ul).GetLowPart();
message_id = MSG_CHK_NTFS_BAD_SECTORS_REPORT_IN_KB;
} else {
temp_ulong = temp_big_int.GetLowPart();
message_id = MSG_BAD_SECTORS;
}
Message->Set(message_id);
sprintf(wdAstr, "%u", temp_ulong);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
}
if (ea_infos) {
Message->Set(MSG_CHK_EA_SIZE);
sprintf(wdAstr, "%u", cluster_size*_fat->QueryLengthOfChain(ea_clus_num));
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
}
free_count = _fat->QueryFreeClusters();
temp_big_int = free_count;
temp_big_int = temp_big_int * cluster_size;
if (KSize) {
temp_ulong = (temp_big_int / 1024ul).GetLowPart();
message_id = MSG_AVAILABLE_KILOBYTES;
} else {
temp_ulong = temp_big_int.GetLowPart();
message_id = MSG_AVAILABLE_DISK_SPACE;
}
Message->Set(message_id);
sprintf(wdAstr, "%u", temp_ulong);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
Message->Set(MSG_ALLOCATION_UNIT_SIZE);
sprintf(wdAstr, "%u", cluster_size);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
Message->Set(MSG_TOTAL_ALLOCATION_UNITS);
sprintf(wdAstr, "%u", total_count);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
Message->Set(MSG_AVAILABLE_ALLOCATION_UNITS);
sprintf(wdAstr, "%u", free_count);
InsertSeparators(wdNum1.GetWSTR(),wdAstr, 13);
Message->Display("%ws", wdNum1.GetWSTR());
if (FixLevel != CheckOnly && ea_infos && !ea_header.Write()) {
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
// Clear the dirty bit.
//
if( RecoverAlloc ) {
SetVolumeFlags(FAT_BPB_RESERVED_DIRTY | FAT_BPB_RESERVED_TEST_SURFACE,
TRUE);
} else {
SetVolumeFlags(FAT_BPB_RESERVED_DIRTY, TRUE);
}
if (FixLevel != CheckOnly && !Write(Message)) {
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
// DELETE(ea_infos);
delete [] ea_infos; ea_infos = NULL;
_Verbose = FALSE;
_pvfMessage = NULL;
return TRUE;
}
BOOLEAN
FAT_SA::VerifyAndFixFat32RootDir (
IN OUT PBITVECTOR FatBitMap,
IN PMESSAGE Message,
IN OUT PFATCHK_REPORT Report,
IN OUT PBOOLEAN NeedErrorMessage
)
/*++
Routine Description:
This routine verifies the FAT32 root directory which is not an integral
part of the super area buffer. The method employed to verify and fix the
root directory is very similar to the one used to verify and fix regular
directory structure.
Arguments:
BitVector - Supplies a bit map for cross/bad links detection. The whole
map should be zeroed when it is passed in this method.
Message - Supplies an outlet for messages.
Report - Supplies the fat chkdsk report structures for storing the
actions performed by this method.
NeedErrorsMessage - Supplies whether or not an error has occurred
under check only conditions.
Return Values:
TRUE - Success.
FALSE - Failed.
--*/
{
BOOLEAN crosslink_detected = FALSE;
BOOLEAN changes_made = FALSE;
ULONG starting_cluster;
ULONG dummy;
starting_cluster = QueryFat32RootDirStartingCluster();
_fat->ScrubChain( starting_cluster,
FatBitMap,
&changes_made,
&crosslink_detected,
&dummy );
//
// Root dir is the only component marked in the
// bitmap so far.
//
DebugAssert(!crosslink_detected);
if (changes_made) {
dofmsg(Message, NeedErrorMessage);
Message->Set(MSG_BAD_LINK);
Message->Display("%s", "\\");
Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
//
// We have to reinitialized the root directory.
//
if (!_hmem_F32->Initialize() ||
!_dirF32->Initialize( _hmem_F32, _drive, this,
_fat, starting_cluster)) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return FALSE;
}
//
// Force a re-reading of the root directory.
// We don't care if it fails, subsequent code can fix that.
//
_dirF32->Read();
}
//
// Validate the readability of the root chain
//
//
// We don't want replacement clusters becuase the replacement given
// by RecoverChain will be zeroed which, according to the spec., means
// it contains the end of the directory structure and WalkDirectoryTree
// will just go ahead and erase all the 'good' directory entries that comes
// after the replaced cluster. Not a really nice thing to do to the root
// directory IMHO.
//
if(!RecoverChain(&starting_cluster, &changes_made, 0, FALSE)){
dofmsg(Message, NeedErrorMessage);
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return FALSE;
}
if (changes_made) {
if ( starting_cluster ) {
if ( starting_cluster != _dirF32->QueryStartingCluster() ) {
SetFat32RootDirStartingCluster( starting_cluster );
}
//
// Should reinitialize the root directory
//
if (!_hmem_F32->Initialize() ||
!_dirF32->Initialize( _hmem_F32, _drive, this,
_fat, starting_cluster)) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return FALSE;
}
} else {
if(!RelocateNewFat32RootDirectory( Report, FatBitMap, Message )) {
return FALSE;
}
}
//
// Reread the root directory
//
if (!_dirF32->Read()) {
//
// Shouldn't fail.
//
DebugAbort("Failed to read the FAT32 root directory despite all the fixing.\n");
}
dofmsg(Message, NeedErrorMessage);
Message->Set(MSG_CHK_NTFS_CORRECTING_ERROR_IN_DIRECTORY);
Message->Display("%s", "\\");
//
// Erasing the root will totally destroy the disk
// so we just leave it partially corrupted and
// hopefully WalkDirectoryTree will be able to fix it.
//
Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
}
return TRUE;
}
BOOLEAN
FAT_SA::RelocateNewFat32RootDirectory (
IN OUT PFATCHK_REPORT Report,
IN OUT PBITVECTOR FatBitMap,
IN PMESSAGE Message
)
/*++
Routine Description:
This routine relocates a FAT32 root directory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -