📄 fatsachk.cxx
字号:
/*++
Copyright (c) 1991-2001 Microsoft Corporation
Module Name:
fatsachk.cxx
--*/
#include <pch.cxx>
#include "bitvect.hxx"
#include "error.hxx"
#include "rtmsg.h"
#include "ifsentry.hxx"
// Timeinfo is full of windows stuff.
#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ ) && !defined( _EFICHECK_ )
#include "timeinfo.hxx"
#endif
#define UCHAR_SP ' '
typedef struct _VISIT_DIR *PVISIT_DIR;
typedef struct _VISIT_DIR {
PVISIT_DIR Next;
PWSTRING Path;
ULONG Cluster;
} VISIT_DIR;
#if !defined( _EFICHECK_ )
extern "C" {
#include <stdio.h>
}
#endif
extern VOID InsertSeparators(
LPCWSTR OutWNumber,
char * InANumber,
ULONG Width
);
VOID
dofmsg(
IN PMESSAGE Message,
IN OUT PBOOLEAN NeedErrorsMessage
)
{
if (*NeedErrorsMessage) {
Message->Set(MSG_CORRECTIONS_WILL_NOT_BE_WRITTEN, NORMAL_MESSAGE, TEXT_MESSAGE);
Message->Display();
*NeedErrorsMessage = FALSE;
}
}
BOOLEAN
CheckAndFixFileName(
PVOID DirEntry,
PBOOLEAN Changes
)
{
PUCHAR p = (PUCHAR)DirEntry;
#if 1
//
// Should not correct case error within file name because
// different language build translates differently. On a
// dual boot machine containing build of two different languages,
// the chkdsk from one build may not like what the second build
// put onto the disk.
//
return TRUE;
#else
memcpy(backup_copy, p, 11);
first_char_replaced = (0x5 == p[0]);
if (first_char_replaced)
p[0] = 0xe5;
ntstatus = RtlOemToUnicodeN(unicode_string,
sizeof(unicode_string),
&unicode_string_length,
(PCHAR)p,
11);
if (!NT_SUCCESS(ntstatus)) {
DebugPrintTrace(("UFAT: Error in RtlOemToUnicodeN, 0x%x\n", ntstatus));
memcpy(p, backup_copy, 11);
return FALSE;
}
ntstatus = RtlUpcaseUnicodeToOemN((PCHAR)p,
11,
NULL,
unicode_string,
unicode_string_length);
if (!NT_SUCCESS(ntstatus)) {
DebugPrintTrace(("UFAT: Error in RtlUpcaseUnicodeToOemN, 0x%x\n", ntstatus));
memcpy(p, backup_copy, 11);
return FALSE;
}
if (first_char_replaced) {
if (0xe5 == p[0]) {
p[0] = 0x5;
} else {
DebugPrintTrace(("UFAT: First byte changed to 0x%x unexpectedly\n", p[0]));
memcpy(p, backup_copy, 11);
return FALSE;
}
}
*Changes = (memcmp(p, backup_copy, 11) != 0);
return TRUE;
#endif
}
BOOLEAN
IsFileNameMatch(
PFATDIR Dir,
UCHAR FatType,
ULONG CurrentIndex,
ULONG MatchingIndexCount,
PULONG MatchingIndexArray
)
{
ULONG j;
for (j = 0; j < MatchingIndexCount; j++) {
FAT_DIRENT fd;
ULONG indx = MatchingIndexArray[j];
if (!fd.Initialize(Dir->GetDirEntry(indx), FatType) ||
fd.IsVolumeLabel()) {
continue;
}
if (!memcmp(Dir->GetDirEntry(indx), Dir->GetDirEntry(CurrentIndex), 11)) {
return TRUE; // there is a match
}
}
return FALSE; // no match
}
BOOLEAN
RenameFileName(
PULONG Positions,
PVOID DirEntry
)
{
PUCHAR p = (PUCHAR)DirEntry;
INT i;
if (*Positions == 0) { // if first rename
// find out the first char in the extension that is real
for (i = 10; i > 7; i--)
if (p[i] != UCHAR_SP)
break;
if (i >= 7 && i < 10) { // fill the unused extension space with dashes
for (i++; i < 10; i++)
p[i] = '-';
}
*Positions = 1;
if (p[10] != '0') {
p[10] = '0'; // the last char of the extension gets a zero
return TRUE;
}
}
// extension chars are all in use now
// check to see if renaming is already in progress
for (i=10; i>=0; i--) {
if (!(*Positions & (1 << (10-i)))) {
*Positions |= (1 << (10-i));
if (p[i] != '0') {
p[i] = '0';
return TRUE;
}
}
if (p[i] >= '0' && p[i] < '9') {
p[i]++;
return TRUE;
} else if (p[i] == '9') {
p[i] = '0';
}
}
// if we get here that means we have exhausted all possible name
// shouldn't be as there are more combination than the max number
// of files that can be in a FAT directory (65536)
return FALSE;
}
BOOLEAN
PushVisitDir(
IN OUT PVISIT_DIR *VisitDirStack,
IN ULONG Cluster,
IN PWSTRING DirectoryPath
)
{
PVISIT_DIR visit_dir;
visit_dir = (PVISIT_DIR)MALLOC( sizeof( VISIT_DIR ) );
if( visit_dir == NULL ){
return FALSE;
}
visit_dir->Path = DirectoryPath;
visit_dir->Cluster = Cluster;
visit_dir->Next = *VisitDirStack;
*VisitDirStack = visit_dir;
return TRUE;
}
BOOLEAN
PopVisitDir(
IN OUT PVISIT_DIR *VisitDirStack,
OUT PULONG Cluster OPTIONAL,
OUT PWSTRING *DirectoryPath OPTIONAL
)
{
PVISIT_DIR visit_dir;
visit_dir = *VisitDirStack;
if( visit_dir == NULL ){
return FALSE;
}
*VisitDirStack = visit_dir->Next;
if( ARGUMENT_PRESENT( Cluster ) ){
*Cluster = visit_dir->Cluster;
}
if( ARGUMENT_PRESENT( DirectoryPath ) ){
*DirectoryPath = visit_dir->Path;
}
FREE( visit_dir );
return TRUE;
}
STATIC VOID
EraseAssociatedLongName(
PFATDIR Dir,
INT FirstLongEntry,
INT ShortEntry
)
{
FAT_DIRENT dirent;
for (int j = FirstLongEntry; j < ShortEntry; ++j) {
dirent.Initialize(Dir->GetDirEntry(j));
dirent.SetErased();
}
}
STATIC BOOLEAN
IsString8Dot3(
PCWSTRING s
)
/*++
Routine Description:
This routine is used to ensure that lfn's legally correspond
to their short names. The given string is examined to see if it
is a legal fat 8.3 name.
Arguments:
s -- lfn to examine.
Return Value:
TRUE - The string is a legal 8.3 name.
FALSE - Not legal.
--*/
{
USHORT i;
BOOLEAN extension_present = FALSE;
WCHAR c;
//
// The name can't be more than 12 characters (including a single dot).
//
if (s->QueryChCount() > 12) {
return FALSE;
}
for (i = 0; i < s->QueryChCount(); ++i) {
c = s->QueryChAt(i);
#if 0
if (!FsRtlIsAnsiCharLegalFat(c, FALSE)) {
return FALSE;
}
#endif
if (c == '.') {
//
// We stepped onto a period. We require the following things:
//
// - it can't be the first character
// - there can be only one
// - there can't be more than 3 characters following it
// - the previous character can't be a space
//
if (i == 0 ||
extension_present ||
s->QueryChCount() - (i + 1) > 3 ||
s->QueryChAt(i - 1) == ' ') {
return FALSE;
}
extension_present = TRUE;
}
//
// The base part of the name can't be more than 8 characters long.
//
if (i >= 8 && !extension_present) {
return FALSE;
}
}
//
// The name cannot end in a space or a period.
//
if (c == ' ' || c == '.') {
return FALSE;
}
return TRUE;
}
STATIC PMESSAGE _pvfMessage = NULL;
STATIC BOOLEAN _Verbose = FALSE;
VOID
FreeSpaceInBitmap(
IN ULONG StartingCluster,
IN PCFAT Fat,
IN OUT PBITVECTOR FatBitMap
);
BOOLEAN
FAT_SA::VerifyAndFix(
IN FIX_LEVEL FixLevel,
IN OUT PMESSAGE Message,
IN ULONG Flags,
IN ULONG LogFileSize,
OUT PULONG ExitStatus,
IN PCWSTRING DriveLetter
)
/*++
Routine Description:
This routine verifies the FAT superarea and if neccessary fixes
it to a correct state.
Arguments:
FixLevel - Supplies the level of fixes that may be performed on
the disk.
Message - Supplies an outlet for messages.
Flags - Supplies flags to control the behavior of chkdsk
(see ulib\inc\ifsserv.hxx for details)
LogFileSize - ignored
ExitStatus - Returns an indication of the result of the check
DriveLetter - For autocheck, supplies the letter of the volume
being checked
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
FAT_DIRENT eadent;
ULONG cluster_size;
ULONG ea_clus_num;
USHORT num_eas, save_num_eas;
PEA_INFO ea_infos;
ULONG cluster_count;
HMEM ea_header_mem;
EA_HEADER ea_header;
BOOLEAN changes = FALSE;
BITVECTOR fat_bitmap;
FATCHK_REPORT report;
PUSHORT p;
VOLID volid;
ULONG free_count, bad_count, total_count;
BOOLEAN fmsg;
DSTRING label;
DSTRING eafilename;
DSTRING eafilepath;
BOOLEAN tmp_bool;
ULONG tmp_ulong;
DSTRING date;
DSTRING time;
UCHAR dirty_byte, media_byte;
BOOLEAN Verbose = (BOOLEAN)(Flags & CHKDSK_VERBOSE);
BOOLEAN OnlyIfDirty = (BOOLEAN)(Flags & CHKDSK_CHECK_IF_DIRTY);
BOOLEAN EnableUpgrade = (BOOLEAN)(Flags & CHKDSK_ENABLE_UPGRADE);
BOOLEAN EnableDowngrade = (BOOLEAN)(Flags & CHKDSK_DOWNGRADE);
BOOLEAN RecoverFree = (BOOLEAN)(Flags & CHKDSK_RECOVER_FREE_SPACE);
BOOLEAN RecoverAlloc = (BOOLEAN)(Flags & CHKDSK_RECOVER_ALLOC_SPACE);
_pvfMessage = Message;
_Verbose = Verbose;
memset(&report, 0, sizeof(FATCHK_REPORT));
fmsg = FALSE;
if (FixLevel != CheckOnly) {
fmsg = TRUE;
}
if (NULL == ExitStatus) {
ExitStatus = &report.ExitStatus;
}
report.ExitStatus = CHKDSK_EXIT_SUCCESS;
*ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
if (EnableUpgrade || EnableDowngrade) {
Message->Set(MSG_CHK_CANNOT_UPGRADE_DOWNGRADE_FAT);
Message->Display();
_Verbose = FALSE;
_pvfMessage = NULL;
return FALSE;
}
//
// Check to see if the dirty bit is set.
//
dirty_byte = QueryVolumeFlags();
if (OnlyIfDirty) {
if ((dirty_byte &
(FAT_BPB_RESERVED_DIRTY | FAT_BPB_RESERVED_TEST_SURFACE)) == 0) {
Message->Set(MSG_CHK_VOLUME_CLEAN);
Message->Display();
Message->SetLoggingEnabled(FALSE);
*ExitStatus = CHKDSK_EXIT_SUCCESS;
_Verbose = FALSE;
_pvfMessage = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -