📄 rfatsa.cxx
字号:
_ft = INVALID_FATTYPE;
_StartDataLbn = 0;
_ClusterCount = 0;
_sysid = SYSID_NONE;
_data_aligned = FALSE;
_AdditionalReservedSectors = MAXULONG;
}
UFAT_EXPORT
REAL_FAT_SA::~REAL_FAT_SA(
)
/*++
Routine Description:
Destructor for REAL_FAT_SA.
Arguments:
None.
Return Value:
None.
--*/
{
Destroy();
}
UFAT_EXPORT
BOOLEAN
REAL_FAT_SA::Initialize(
IN OUT PLOG_IO_DP_DRIVE Drive,
IN OUT PMESSAGE Message,
IN BOOLEAN Formatted
)
/*++
Routine Description:
This routine initializes the FAT super area to an initial state. It
does so by first reading in the boot sector and verifying it with
the methods of REAL_FAT_SA. Upon computing the super area's actual size,
the underlying SECRUN will be set to the correct size.
If the caller needs to format this volume, then this method should
be called with the Formatted parameter set to FALSE.
Arguments:
Drive - Supplies the drive where the super area resides.
Message - Supplies an outlet for messages
Formatted - Supplies a boolean which indicates whether or not
the volume is formatted.
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
BIG_INT data_offset;
//
// Reset the state of the REAL_FAT_SA object.
//
Destroy();
//
// Make sure that the boot sector(s) is(are) at least 512 bytes
// in size. Note that the boot area for a FAT32 volume is of size at least
// 32 * 512 bytes but that adjustment will be made later. The first
// 512 bytes of a FAT volume should contain the whole Bpb and that is all we
// care for the moment.
//
_sec_per_boot = max(1, BYTES_PER_BOOT_SECTOR/Drive->QuerySectorSize());
if (!Formatted) {
return _mem.Initialize() &&
DosSaInit(&_mem, Drive, _sec_per_boot, Message);
}
//
// Do some quick parameter checking, initialize the underlying
// SUPERAREA and SECRUN structure, and read in the Bpb.
//
if (!Drive ||
!(Drive->QuerySectorSize()) ||
!_mem.Initialize() ||
!DosSaInit(&_mem, Drive, _sec_per_boot, Message) ||
!SECRUN::Read()) {
Message->Set(MSG_CANT_READ_BOOT_SECTOR);
Message->Display("");
Destroy();
return FALSE;
}
//
// Unpack the bpb in the SECRUN buffer into the _sector_zero
// member for easier access to the fields within the bpb.
//
UnpackExtendedBios(&_sector_zero,
(PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
//
// Have a really quick check on the unpacked Bpb.
//
if (!VerifyBootSector() || !_sector_zero.Bpb.Fats) {
Destroy();
return FALSE;
}
//
// Determine the FAT type and the number of clusters on the volume
// depending on the
//
_ClusterCount = DetermineClusterCountAndFatType ( &_StartDataLbn,
&_ft );
//
// figured out if the data clusters are aligned
//
data_offset = QuerySectorsPerFat()*QueryFats()+QueryReservedSectors();
data_offset = data_offset * Drive->QuerySectorSize();
data_offset += QueryRootEntries()*BytesPerDirent;
DebugAssert(FAT_FIRST_DATA_CLUSTER_ALIGNMENT <= MAXULONG);
_data_aligned = ((data_offset.GetLowPart() & (FAT_FIRST_DATA_CLUSTER_ALIGNMENT - 1)) == 0);
//
// Determine the partition id.
//
if (_ft == SMALL) {
_sysid = SYSID_FAT12BIT;
} else if (QueryVirtualSectors() < CSEC_FAT32MEG) {
_sysid = SYSID_FAT16BIT;
} else if (_ft == LARGE32) {
_sysid = SYSID_FAT32BIT;
} else {
_sysid = SYSID_FAT32MEG;
}
//
// Adjust the _sector_per_boot member if the volume
// is a FAT32 volume and also in the case of a FAT32 drive
// only set up the super area to include memory for one FAT.
// On FAT32 drives the FAT can be much larger than on a FAT16 drive
// and we do not want to carry around the second FAT in memory as
// extra baggage.
//
if ( _ft == LARGE32 ) {
//
// FAT32 drives have a variable reserved area size so we do not want this
// number hard wired at 32 unless it is not set yet (BPB value is 0 or 1)
//
if(_sector_zero.Bpb.ReservedSectors > 1) {
_sec_per_boot = _sector_zero.Bpb.ReservedSectors;
} else {
_sec_per_boot = max((32 * 512)/_drive->QuerySectorSize(), 32);
}
if(!_mem.Initialize() || !DosSaInit(&_mem, Drive,
_sector_zero.Bpb.ReservedSectors + _sector_zero.Bpb.BigSectorsPerFat,
Message)) {
Message->Set(MSG_FMT_NO_MEMORY);
Message->Display("");
Destroy();
return FALSE;
}
} else {
//
// The main idea behind the following code segment is to allocate
// memory for the whole super area including the boot area, all copies
// of the FAT, and the root directory for FAT12/16 volume and to initialize
// the underlying SECRUn object to cover the whole superarea on the
// disk.
//
if(!_mem.Initialize() || !DosSaInit(&_mem, Drive, _StartDataLbn, Message)) {
Message->Set(MSG_FMT_NO_MEMORY);
Message->Display("");
Destroy();
return FALSE;
}
}
//
// Initialize the root directory of the volume.
//
if (!(InitializeRootDirectory(Message))) {
return FALSE;
}
return TRUE;
}
UFAT_EXPORT
BOOLEAN
REAL_FAT_SA::InitFATChkDirty(
IN OUT PLOG_IO_DP_DRIVE Drive,
IN OUT PMESSAGE Message
)
/*++
Routine Description:
This routine initializes the _fat pointer in the FAT super area
to point to the first sector of one of the FATs so that the dirty bits in the FAT[1]
entry can be looked at.
Arguments:
Drive - Supplies the drive.
Message - Supplies an outlet for messages
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
UINT StartSec;
UnpackExtendedBios(&_sector_zero,
(PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
if (!VerifyBootSector() || !_sector_zero.Bpb.Fats) {
return FALSE;
}
_ClusterCount = DetermineClusterCountAndFatType ( &_StartDataLbn,
&_ft );
StartSec = _sector_zero.Bpb.ReservedSectors;
if(!_mem2.Initialize()) {
return FALSE;
}
DELETE(_fat);
if (!(_fat = NEW FAT)) {
return FALSE;
}
if (!_fat->Initialize(&_secrun2, &_mem2, Drive, StartSec, _ClusterCount, 1)) {
DELETE(_fat);
return FALSE;
}
if(!_secrun2.Read()) {
if(_sector_zero.Bpb.SectorsPerFat == 0) {
StartSec += _sector_zero.Bpb.BigSectorsPerFat;
} else {
StartSec += (UINT)_sector_zero.Bpb.SectorsPerFat;
}
if (!_fat->Initialize(&_secrun2, &_mem2, Drive, StartSec, _ClusterCount, 1)) {
DELETE(_fat);
return FALSE;
}
if(!_secrun2.Read()) {
DELETE(_fat);
return FALSE;
}
}
return TRUE;
}
ULONG
REAL_FAT_SA::DetermineClusterCountAndFatType (
IN OUT PULONG StartingDataLbn,
IN OUT FATTYPE *FatType
)
/*++
Routine Description:
This routine computes the number of clusters and fat type of a volume
based on the total number of sectors on the volume and data in the Bpb.
Note that this method assumes that the _sector_zero member has beeen
initialized properly.
Arguments:
StartingDataLbn - Supplies the address at which the starting data
Lbn should be returned to the caller.
FatType - Supplies the address at which the Fat type should be
returned to the caller.
Return Values:
Number of clusters on the volume. Note that this number includes the
first two entries.
--*/
{
ULONG cluster_count; // Number of clusters on the volume
ULONG sectors; // Number of sectors on the volume.
ULONG starting_data_lbn; // The first data sector on the FAT volume.
FATTYPE fat_type; // FAT type.
ULONG sector_size; // Sector size.
sectors = QueryVirtualSectors();
starting_data_lbn = ComputeStartDataLbn();
sector_size = _drive->QuerySectorSize();
//
// Use the naive formula to compute a preliminary cluster count
// on the volume.
//
cluster_count = (sectors - starting_data_lbn) / (ULONG)QuerySectorsPerCluster() +
FirstDiskCluster;
//
// We can determine the fat type now, note that we are assuming
// that subsequent adjustment to the cluster count will not affect the
// fat type which is fairly reasonable.
//
fat_type = cluster_count > MAX_CLUS_ENT_SMALL ? LARGE16 : SMALL;
//
// It is possible to have a FAT16 volume that doesn't use up all
// the space on the disk so we should check whether _sector_zero.Bpb
// .SectorsPerfat == 0 in order to make sure that the volume is really
// a FAT32 volume.
//
if (cluster_count > MAX_CLUS_ENT_BIG) {
if ( _sector_zero.Bpb.SectorsPerFat == 0 ) {
fat_type = LARGE32;
} else {
cluster_count = MAX_CLUS_ENT_BIG;
}
}
//
// Check to make sure the FAT size in the BPB is actually big enough to hold this
// many clusters, adjust the cluster_count down if it is not.
//
switch(fat_type) {
case SMALL:
if (RoundUpDiv(cluster_count * 12, sector_size * 8) > _sector_zero.Bpb.SectorsPerFat ) {
cluster_count = (_sector_zero.Bpb.SectorsPerFat * sector_size * 8) / 12;
}
break;
case LARGE16:
if (RoundUpDiv(cluster_count * 2, sector_size) > _sector_zero.Bpb.SectorsPerFat ) {
cluster_count = (_sector_zero.Bpb.SectorsPerFat * sector_size) / 2;
}
break;
case LARGE32:
if (RoundUpDiv(cluster_count * 4, sector_size) > _sector_zero.Bpb.BigSectorsPerFat ) {
cluster_count = (_sector_zero.Bpb.BigSectorsPerFat * sector_size) / 4;
}
break;
default:
DebugPrintTrace(("Bad FAT type.\n"));
}
//
// Make sure that the caller gets what it wants.
//
*FatType = fat_type;
*StartingDataLbn = starting_data_lbn;
return cluster_count;
}
BOOLEAN
REAL_FAT_SA::InitializeRootDirectory (
IN PMESSAGE Message
)
/*++
Routine Description:
This routine initializes the root directory structure in the
FAT super area object after the boot sector has been read from the
disk.
Arguments:
Message - Supplies an outlet for messages.
Return Values:
TRUE - The opreation is completed successfully.
FALSE - This routine fails to complete the intended operation.
--*/
{
//
// Note that the root directory for a FAT32 volume is a cluster
// chain while the FAT16/12 root directory is a fixed size area
// that comes right after the FATs.
//
if ( _ft == LARGE32 ) {
if (!(_dirF32 = NEW FILEDIR)) {
Destroy();
Message->Set(MSG_FMT_NO_MEMORY);
Message->Display("");
return FALSE;
}
//
// Complete initialization of _dirF32 is deffered until
// REAL_FAT_SA::read is called because the FAT
// is needed.
//
} else {
CONT_MEM cmem; // This CONT_MEM object piggybacks onto the
// the root directory section of the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -