📄 fatsa.cxx
字号:
/*++
Copyright (c) 1990-2000 Microsoft Corporation
Module Name:
fatsa.cxx
Environment:
ULIB, User Mode
--*/
#include "pch.cxx"
#define _UFAT_MEMBER_
#include "ufat.hxx"
#include "cmem.hxx"
#include "error.hxx"
#include "rtmsg.h"
#include "drive.hxx"
#if !defined( _EFICHECK_ )
extern "C" {
#include <parttype.h>
}
#endif // _EFICHECK_
#if !defined(_AUTOCHECK_) && !defined(_SETUP_LOADER_) && !defined( _EFICHECK_ )
#include "timeinfo.hxx"
#endif
// Control-C handling is not necessary for autocheck.
#if !defined( _AUTOCHECK_ ) && !defined(_SETUP_LOADER_) && !defined( _EFICHECK_ )
#include "keyboard.hxx"
#endif
#define CSEC_FAT32MEG 65536
#define CSEC_FAT16BIT 32680
#define CSEC_FAT32BIT (1024*1024)
#define MIN_CLUS_BIG 4085 // Minimum clusters for a big FAT.
#define MAX_CLUS_BIG 65525 // Maximum + 1 clusters for big FAT.
#define MIN_CLUS_FAT32 65536
DEFINE_EXPORTED_CONSTRUCTOR( FAT_SA, SUPERAREA, UFAT_EXPORT );
VOID
FAT_SA::Construct (
)
/*++
Routine Description:
Constructor for FAT_SA.
Arguments:
None.
Return Value:
None.
--*/
{
_fat = NULL;
_dir = NULL;
_dirF32 = NULL;
_hmem_F32 = NULL;
}
UFAT_EXPORT
FAT_SA::~FAT_SA(
)
/*++
Routine Description:
Destructor for FAT_SA.
Arguments:
None.
Return Value:
None.
--*/
{
Destroy();
}
BOOLEAN
FAT_SA::RecoverFile(
IN PCWSTRING FullPathFileName,
IN OUT PMESSAGE Message
)
/*++
Routine Description:
This routine runs through the clusters for the file described by
'FileName' and takes out bad sectors.
Arguments:
FullPathFileName - Supplies a full path name of the file to recover.
Message - Supplies an outlet for messages.
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
#if defined( _SETUP_LOADER_ )
return FALSE;
#else // _SETUP_LOADER_
HMEM hmem;
ULONG clus;
BOOLEAN changes;
PFATDIR fatdir;
BOOLEAN need_delete;
FAT_DIRENT dirent;
ULONG old_file_size;
ULONG new_file_size;
if ((clus = QueryFileStartingCluster(FullPathFileName,
&hmem,
&fatdir,
&need_delete,
&dirent)) == 1) {
Message->Set(MSG_FILE_NOT_FOUND);
Message->Display("%W", FullPathFileName);
return FALSE;
}
if (clus == 0xFFFFFFFF) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display("");
return FALSE;
}
if (clus == 0) {
Message->Set(MSG_FILE_NOT_FOUND);
Message->Display("%W", FullPathFileName);
return FALSE;
}
if (dirent.IsDirectory()) {
old_file_size = _drive->QuerySectorSize()*
QuerySectorsPerCluster()*
_fat->QueryLengthOfChain(clus);
} else {
old_file_size = dirent.QueryFileSize();
}
if (!RecoverChain(&clus, &changes)) {
Message->Set(MSG_CHK_NO_MEMORY);
Message->Display("");
return FALSE;
}
if (dirent.IsDirectory() || changes) {
new_file_size = _drive->QuerySectorSize()*
QuerySectorsPerCluster()*
_fat->QueryLengthOfChain(clus);
} else {
new_file_size = old_file_size;
}
if (changes) {
// Autochk doesn't need control C handling.
#if !defined( _AUTOCHECK_ ) && !defined( _EFICHECK_ )
// Disable contol-C handling and
if (!KEYBOARD::EnableBreakHandling()) {
Message->Set(MSG_CANT_LOCK_THE_DRIVE);
Message->Display("");
return FALSE;
}
#endif
// Lock the drive in preparation for writes.
if (!_drive->Lock()) {
Message->Set(MSG_CANT_LOCK_THE_DRIVE);
Message->Display("");
return FALSE;
}
dirent.SetStartingCluster(clus);
dirent.SetFileSize(new_file_size);
if (!fatdir->Write()) {
return FALSE;
}
if (!Write(Message)) {
return FALSE;
}
// Autochk doesn't need control C handling.
#if !defined( _AUTOCHECK_ ) && !defined( _EFICHECK_ )
KEYBOARD::DisableBreakHandling();
#endif
}
Message->Set(MSG_RECOV_BYTES_RECOVERED);
Message->Display("%d%d", new_file_size, old_file_size);
if (need_delete) {
DELETE(fatdir);
}
return TRUE;
#endif // _SETUP_LOADER_
}
SECTORCOUNT
FAT_SA::QueryFreeSectors(
) CONST
/*++
Routine Description:
This routine computes the number of unused sectors on disk.
Arguments:
None.
Return Value:
The number of free sectors on disk.
--*/
{
if (!_fat) {
perrstk->push(ERR_NOT_READ, QueryClassId());
return 0;
}
return _fat->QueryFreeClusters()*QuerySectorsPerCluster();
}
FATTYPE
FAT_SA::QueryFatType(
) CONST
/*++
Routine Description:
This routine computes the FATTYPE of the FAT for this volume.
Arguments:
None.
Return Value:
The FATTYPE for the FAT.
--*/
{
return _ft;
}
#if !defined( _AUTOCHECK_ ) && !defined(_SETUP_LOADER_) && !defined( _EFICHECK_ )
BOOLEAN
FAT_SA::QueryLabel(
OUT PWSTRING Label
) CONST
/*++
Routine Description:
This routine queries the label from the FAT superarea.
If the label is not present then 'Label' will return the null-string.
If the label is invalid then FALSE will be returned.
Arguments:
Label - Returns a volume label.
Return Value:
FALSE - The label is invalid.
TRUE - The label is valid.
--*/
{
return QueryLabel(Label, NULL);
}
BOOLEAN
FAT_SA::QueryLabel(
OUT PWSTRING Label,
OUT PTIMEINFO TimeInfo
) CONST
/*++
Routine Description:
This routine queries the label from the FAT superarea.
If the label is not present then 'Label' will return the null-string.
If the label is invalid then FALSE will be returned.
Arguments:
Label - Returns a volume label.
Return Value:
FALSE - The label is invalid.
TRUE - The label is valid.
--*/
{
INT i;
FAT_DIRENT dirent;
FILETIME TimeStamp;
PFATDIR _fat_dir;
UCHAR FatType;
if (!_dirF32) {
DebugAssert(_dir);
_fat_dir = _dir;
FatType = FAT_TYPE_EAS_OKAY;
} else {
_fat_dir = _dirF32;
FatType = FAT_TYPE_FAT32;
}
for (i = 0; ; i++) {
if (!dirent.Initialize(_fat_dir->GetDirEntry(i), FatType) ||
dirent.IsEndOfDirectory()) {
return Label->Initialize("");
}
if (!dirent.IsErased() && dirent.IsVolumeLabel()) {
break;
}
}
dirent.QueryName(Label);
if ( TimeInfo ) {
return ( dirent.QueryLastWriteTime( (LARGE_INTEGER *)&TimeStamp ) &&
TimeInfo->Initialize( &TimeStamp ) );
}
return TRUE;
}
#else // _AUTOCHECK_ or _SETUP_LOADER_ is defined
BOOLEAN
FAT_SA::QueryLabel(
OUT PWSTRING Label
) CONST
{
INT i;
FAT_DIRENT dirent;
PFATDIR _fat_dir;
if (!_dirF32) {
DebugAssert(_dir);
_fat_dir = _dir;
} else {
_fat_dir = _dirF32;
}
for (i = 0; ; i++) {
if (!dirent.Initialize(_fat_dir->GetDirEntry(i)) ||
dirent.IsEndOfDirectory()) {
return Label->Initialize("");
}
if (!dirent.IsErased() && dirent.IsVolumeLabel()) {
break;
}
}
dirent.QueryName(Label);
return TRUE;
}
#endif // _AUTOCHECK_
BOOLEAN
FAT_SA::SetLabel(
IN PCWSTRING NewLabel
)
/*++
Routine Description:
This routine sets the label for a FAT partition.
Arguments:
NewLabel - Supplies the new volume label.
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
FAT_DIRENT dirent;
INT i;
DSTRING label;
PFATDIR _fat_dir;
UCHAR FatType;
if (!_dir) {
if (!_dirF32) {
return FALSE;
}
_fat_dir = _dirF32;
FatType = FAT_TYPE_FAT32;
} else {
_fat_dir = _dir;
FatType = FAT_TYPE_EAS_OKAY;
}
if (!label.Initialize(NewLabel)) {
return FALSE;
}
if (!label.Strupr()) {
return FALSE;
}
if (!IsValidString(&label)) {
return FALSE;
}
for (i = 0; dirent.Initialize(_fat_dir->GetDirEntry(i), FatType); i++) {
if (dirent.IsEndOfDirectory()) {
break;
}
if (dirent.IsErased()) {
continue;
}
if (dirent.IsVolumeLabel()) {
if (!label.QueryChCount()) {
dirent.SetErased();
return TRUE;
}
return (BOOLEAN) (dirent.SetLastWriteTime() &&
dirent.SetName(&label));
}
}
if (!label.QueryChCount()) {
return TRUE;
}
if (!dirent.Initialize(_fat_dir->GetFreeDirEntry(), FatType)) {
return FALSE;
}
dirent.Clear();
dirent.SetVolumeLabel();
return (BOOLEAN) (dirent.SetLastWriteTime() && dirent.SetName(&label));
}
UFAT_EXPORT
ULONG
FAT_SA::QueryFileStartingCluster(
IN PCWSTRING FullPathFileName,
OUT PHMEM Hmem,
OUT PPFATDIR Directory,
OUT PBOOLEAN DeleteDirectory,
OUT PFAT_DIRENT DirEntry
)
/*++
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -