📄 fatsachk.cxx
字号:
Arguments:
Report - Supplies the fat chkdsk report structure for storing
the fix status.
FatBitMap - Supplies a pointer to the bit map for cross-link
detection.
Message - Supplies an outlet for messages.
Return Values:
TRUE - Success.
FALSE - Failed.
--*/
{
SECRUN root_secrun; // Allocate one cluster for the
// new root directory.
ULONG root_clus; // New cluster number of the
// root directory
ULONG cluster_size;// Number of sectors in a cluster.
ULONG starting_data_lbn;
ULONG sector_size;
starting_data_lbn = QueryStartDataLbn();
cluster_size = QuerySectorsPerCluster();
sector_size = _drive->QuerySectorSize();
for (;;) {
root_clus = _fat->AllocChain(1, NULL);
if (!root_clus) {
//
// The disk is full, we have no choice but to bail out.
//
Message->Set(MSG_CHK_INSUFFICIENT_DISK_SPACE);
Message->Display();
return FALSE;
}
if ( !_hmem_F32->Initialize() ||
!root_secrun.Initialize( _hmem_F32,
_drive,
QuerySectorFromCluster(root_clus, NULL),
cluster_size)) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return FALSE;
}
memset(root_secrun.GetBuf(), 0, cluster_size * sector_size);
if (root_secrun.Write() && root_secrun.Read()) {
SetFat32RootDirStartingCluster(root_clus);
//
// Set the bit for the new root in the bit map.
//
FatBitMap->SetBit(root_clus);
//
// Reinitialize the FAT32 root directory
//
if ( !_hmem_F32->Initialize() ||
!_dirF32->Initialize( _hmem_F32, _drive, this,
_fat, root_clus)) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return FALSE;
}
Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
return TRUE;
} else {
_fat->SetClusterBad(root_clus);
}
}
DebugPrintTrace(("FAT_SA::RelocateNewFat32RootDirectory: This line should not be reached.\n"));
return FALSE;
}
BOOLEAN
FAT_SA::PerformEaLogOperations(
IN ULONG EaFileCn,
IN FIX_LEVEL FixLevel,
IN OUT PMESSAGE Message,
IN OUT PBOOLEAN NeedErrorsMessage
)
/*++
Routine Description:
This routine reads the EA file log from the disk and then performs
any logged operations specified.
Arguments:
EaFileCn - Supplies the first cluster of the EA file.
FixLevel - Supplies the fix level.
Message - Supplies an outlet for messages.
NeedErrorsMessage - Supplies whether or not an error has occurred
under check only conditions.
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
HMEM hmem;
EA_HEADER ea_header;
PEA_FILE_HEADER pea_header;
ULONG cluster_size;
ULONG num_clus;
cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
num_clus = sizeof(EA_FILE_HEADER) + BaseTableSize*sizeof(USHORT);
if (num_clus%cluster_size) {
num_clus = (num_clus/cluster_size + 1);
} else {
num_clus = (num_clus/cluster_size);
}
if (!hmem.Initialize() ||
!ea_header.Initialize(&hmem, _drive, this, _fat, EaFileCn, num_clus) ||
!(pea_header = ea_header.GetEaFileHeader())) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return FALSE;
}
if (!ea_header.Read()) {
Message->Set(MSG_CHK_CANT_CHECK_EA_LOG);
Message->Display();
return TRUE;
}
if (pea_header->Signature != HeaderSignature ||
pea_header->FormatType ||
pea_header->LogType) {
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_BAD_LOG, NORMAL_MESSAGE, TEXT_MESSAGE);
Message->Display();
if (Message->IsYesResponse(TRUE)) {
pea_header->Signature = HeaderSignature;
pea_header->Cluster1 = 0;
pea_header->Cluster2 = 0;
pea_header->Cluster3 = 0;
if (FixLevel != CheckOnly) {
ea_header.Write();
}
return TRUE;
} else {
return FALSE;
}
}
if (pea_header->Cluster1) {
if (_fat->IsInRange(pea_header->Cluster1) &&
_fat->IsInRange(pea_header->NewCValue1)) {
_fat->SetEntry(pea_header->Cluster1, pea_header->NewCValue1);
} else {
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_ERROR_IN_LOG);
Message->Display();
}
}
if (pea_header->Cluster2) {
if (_fat->IsInRange(pea_header->Cluster2) &&
_fat->IsInRange(pea_header->NewCValue2)) {
_fat->SetEntry(pea_header->Cluster2, pea_header->NewCValue2);
} else {
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_ERROR_IN_LOG);
Message->Display();
}
}
if (pea_header->Cluster3) {
if (_fat->IsInRange(pea_header->Cluster3) &&
_fat->IsInRange(pea_header->NewCValue3)) {
_fat->SetEntry(pea_header->Cluster3, pea_header->NewCValue3);
} else {
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_ERROR_IN_LOG);
Message->Display();
}
}
return TRUE;
}
PEA_INFO
FAT_SA::RecoverEaSets(
IN ULONG EaFileCn,
OUT PUSHORT NumEas,
IN FIX_LEVEL FixLevel,
IN OUT PMESSAGE Message,
IN OUT PBOOLEAN NeedErrorsMessage
)
/*++
Routine Description:
This routine validates and if necessary recovers the EA file.
Arguments:
EaFileCn - Supplies the cluster number for the EA file.
NumEas - Returns the number of EA sets in the EA file.
FixLevel - Supplies the CHKDSK fix level.
Message - Supplies an outlet for messages.
NeedErrorsMessage - Supplies whether or not an error has occurred
under check only conditions.
Return Value:
An allocated array containing 'NumberOfEaSets' entries documenting
important information about the EA sets. If there are no EAs then
'NumberOfEaSets' is returned as 0 and NULL is returned. If there
is an error then NULL will be returned with a non-zero
'NumberOfEaSets'.
--*/
{
PEA_INFO ea_infos;
ULONG clus, prev;
USHORT num_eas;
ULONG i;
ULONG length;
DebugAssert(NumEas);
*NumEas = 1;
length = _fat->QueryLengthOfChain(EaFileCn);
ea_infos = NEW EA_INFO[length];
if (!ea_infos) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return NULL;
}
memset(ea_infos, 0, length*sizeof(EA_INFO));
//
// Scan file for EA sets and validate them while updating the
// array.
//
num_eas = 0;
prev = EaFileCn;
while (!_fat->IsEndOfChain(prev)) {
clus = VerifyAndFixEaSet(prev, &ea_infos[num_eas], FixLevel,
Message, NeedErrorsMessage);
if (clus) {
num_eas++;
} else {
clus = _fat->QueryEntry(prev);
}
prev = clus;
}
if (!num_eas) {
// All the ea sets are unused, the ea file is
// effectively empty.
// Should use array delete instead.
// DELETE( ea_infos );
delete [] ea_infos;
// Free the cluster chain occupied by the ea file
// so subsequent checking and fixing will not
// complain about the lost chain in the ea file.
_fat->FreeChain(EaFileCn);
ea_infos = NULL;
*NumEas = 0;
return NULL;
}
// Go through and remove unused portions of the EA file.
for (i = 0; i < (USHORT)(num_eas - 1); i++) {
if (ea_infos[i].LastCn != ea_infos[i + 1].PreceedingCn) {
_fat->RemoveChain(ea_infos[i].LastCn,
ea_infos[i + 1].PreceedingCn);
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_UNUSED_EA_PORTION);
Message->Display();
ea_infos[i + 1].PreceedingCn = ea_infos[i].LastCn;
}
}
if (!_fat->IsEndOfChain(ea_infos[num_eas - 1].LastCn)) {
_fat->SetEndOfChain(ea_infos[num_eas - 1].LastCn);
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_UNUSED_EA_PORTION);
Message->Display();
}
// Sort the EAs in the EA file.
if (!EaSort(ea_infos, num_eas, Message, NeedErrorsMessage)) {
return NULL;
}
*NumEas = num_eas;
return ea_infos;
}
ULONG
FAT_SA::VerifyAndFixEaSet(
IN ULONG PreceedingCluster,
OUT PEA_INFO EaInfo,
IN FIX_LEVEL FixLevel,
IN OUT PMESSAGE Message,
IN OUT PBOOLEAN NeedErrorsMessage
)
/*++
Routine Description:
This routine attempts to identify the clusters following the
'PreceedingCluster' as an EA set. If this routine does not
recognize these clusters as an EA set then it will return 0.
Otherwise, it will return the last cluster of the validated EA set.
Changes may be made to the clusters if they are recognized as an EA
set with errors.
Arguments:
PreceedingCluster - Supplies the cluster preceeding the EA set cluster.
Info - Returns information about the EA set.
FixLevel - Supplies the CHKDSK fix level.
Message - Supplies an outlet for messages.
NeedErrorsMessage - Supplies whether or not errors have occurred
under check only conditions.
Return Value:
The cluster number of the last cluster in the EA set or 0.
--*/
{
HMEM hmem;
EA_SET easet;
ULONG clus;
PEA_HDR eahdr;
LONG i;
ULONG j;
ULONG need_count;
LONG total_size;
LONG size;
ULONG length;
BOOLEAN need_write;
PEA pea;
BOOLEAN more;
ULONG chain_length;
clus = _fat->QueryEntry(PreceedingCluster);
chain_length = _fat->QueryLengthOfChain(clus);
length = 1;
need_write = FALSE;
if (!hmem.Initialize() ||
!easet.Initialize(&hmem, _drive, this, _fat, clus, length) ||
!(eahdr = easet.GetEaSetHeader())) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return 0;
}
if (!easet.Read()) {
return 0;
}
if (!easet.VerifySignature()) {
return 0;
}
need_count = 0;
total_size = 4;
for (i = 0; ; i++) {
for (j = 0; !(pea = easet.GetEa(i, &size, &more)) && more &&
length + j < chain_length; ) {
j++;
if (!hmem.Initialize() ||
!easet.Initialize(&hmem, _drive, this, _fat, clus, length + j)) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display();
return 0;
}
if (!easet.Read()) {
return 0;
}
}
if (pea) {
length += j;
} else {
break;
}
total_size += size;
if (pea->Flag & NeedFlag) {
need_count++;
}
}
if (!i) {
return 0;
}
if (total_size != eahdr->TotalSize) {
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_EASET_SIZE);
Message->Display("%d", clus);
eahdr->TotalSize = total_size;
need_write = TRUE;
}
if (need_count != eahdr->NeedCount) {
dofmsg(Message, NeedErrorsMessage);
Message->Set(MSG_CHK_EASET_NEED_COUNT);
Message->Display("%d", clus);
eahdr->NeedCount = need_count;
need_write = TRUE;
}
EaInfo->OwnHandle = eahdr->OwnHandle;
EaInfo->PreceedingCn = PreceedingCluster;
EaInfo->LastCn = _fat->QueryNthCluster(PreceedingCluster, length);
memcpy(EaInfo->OwnerFileName, eahdr->OwnerFileName, 14);
EaInfo->UsedCount = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -