windows-nt/Source/XPSP1/NT/base/ntsetup/mpk/imagpart/fat.c

407 lines
10 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "imagpart.h"
//
// FAT boot sector.
//
#pragma pack(1)
typedef struct FAT_BOOT_SECTOR {
BYTE Jump[3]; // offset = 0x00 0
UCHAR Oem[8]; // offset = 0x03 3
USHORT BytesPerSector; // offset = 0x0b 11
BYTE SectorsPerCluster; // offset = 0x0d 13
USHORT ReservedSectors; // offset = 0x0e 14
BYTE Fats; // offset = 0x10 16
USHORT RootEntries; // offset = 0x11 17
USHORT Sectors; // offset = 0x13 19
BYTE Media; // offset = 0x15 21
USHORT SectorsPerFat; // offset = 0x16 22
USHORT SectorsPerTrack; // offset = 0x18 24
USHORT Heads; // offset = 0x1a 26
ULONG HiddenSectors; // offset = 0x1c 28
ULONG LargeSectors; // offset = 0x20 32
BYTE PhysicalDriveNumber; // offset = 0x24 36
BYTE Reserved; // offset = 0x25 37
BYTE Signature; // offset = 0x26 38
ULONG Id; // offset = 0x27 39
UCHAR VolumeLabel[11]; // offset = 0x2B 43
UCHAR SystemId[8]; // offset = 0x36 54
BYTE BootStrap[510-62]; // offset = 0x3e 62
BYTE AA55Signature[2]; // offset = 0x1fe 510
} FAT_BOOT_SECTOR,_far *FPFAT_BOOT_SECTOR;
#pragma pack()
typedef enum {
Fat12,
Fat16,
Fat32
} FatSize;
FatSize
pFatDetermineFatSize(
IN FPFAT_BOOT_SECTOR BootSector
);
ULONG
pFatClusterCount(
IN FPFAT_BOOT_SECTOR BootSector
);
ULONG
pFatFirstClusterSector(
IN FPFAT_BOOT_SECTOR BootSector
);
ULONG
pFatSectorsPerFat(
IN FPFAT_BOOT_SECTOR BootSector
);
BOOL
FatIsFat(
IN HPARTITION PartitionHandle
)
{
FPFAT_BOOT_SECTOR BootSector;
if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
return(FALSE);
}
BootSector = IoBuffer;
if(BootSector->Sectors) {
BootSector->LargeSectors = 0;
}
//
// Check various fields for permissible values.
//
if((BootSector->Jump[0] != 0x49) // Fujitsu FMR
&& (BootSector->Jump[0] != 0xe9)
&& (BootSector->Jump[0] != 0xeb)) {
return(FALSE);
}
if(BootSector->BytesPerSector != 512) {
return(FALSE);
}
if((BootSector->SectorsPerCluster != 1)
&& (BootSector->SectorsPerCluster != 2)
&& (BootSector->SectorsPerCluster != 4)
&& (BootSector->SectorsPerCluster != 8)
&& (BootSector->SectorsPerCluster != 16)
&& (BootSector->SectorsPerCluster != 32)
&& (BootSector->SectorsPerCluster != 64)
&& (BootSector->SectorsPerCluster != 128)) {
return(FALSE);
}
if(!BootSector->ReservedSectors || !BootSector->Fats) {
return(FALSE);
}
if(!BootSector->Sectors && !BootSector->LargeSectors) {
return(FALSE);
}
if((BootSector->Media != 0x00) // FMR (formatted by OS/2)
&& (BootSector->Media != 0x01) // FMR (floppy, formatted by DOS)
&& (BootSector->Media != 0xf0)
&& (BootSector->Media != 0xf8)
&& (BootSector->Media != 0xf9)
&& (BootSector->Media != 0xfa) // FMR
&& (BootSector->Media != 0xfb)
&& (BootSector->Media != 0xfc)
&& (BootSector->Media != 0xfd)
&& (BootSector->Media != 0xfe)
&& (BootSector->Media != 0xff)) {
return(FALSE);
}
if(BootSector->SectorsPerFat && !BootSector->RootEntries) {
return(FALSE);
}
return(TRUE);
}
BOOL
FatInitializeVolumeData(
IN HPARTITION PartitionHandle,
OUT ULONG *TotalSectorCount,
OUT ULONG *NonClusterSectors,
OUT ULONG *ClusterCount,
OUT BYTE *SectorsPerCluster
)
{
FPFAT_BOOT_SECTOR BootSector;
if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
fprintf(stderr,"\n");
fprintf(stderr,textReadFailedAtSector,0L);
fprintf(stderr,"\n");
return(FALSE);
}
BootSector = IoBuffer;
*TotalSectorCount = BootSector->Sectors
? (ULONG)BootSector->Sectors
: BootSector->LargeSectors;
*ClusterCount = pFatClusterCount(BootSector);
*NonClusterSectors = pFatFirstClusterSector(BootSector);
*SectorsPerCluster = BootSector->SectorsPerCluster;
return(TRUE);
}
BOOL
FatBuildClusterBitmap(
IN HPARTITION PartitionHandle,
IN UINT FileHandle,
IN OUT PARTITION_IMAGE *PartitionImage
)
{
FPFAT_BOOT_SECTOR BootSector;
FatSize fatsize;
ULONG CurrentFatSectorBase;
ULONG FatSectorsLeft;
ULONG CurrentCluster;
ULONG SectorsPerFat;
BYTE c;
USHORT ClusterLimit;
USHORT i;
USHORT x1;
ULONG x2;
printf(textScanningFat,0L);
printf("\r");
if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
fprintf(stderr,"\n");
fprintf(stderr,textReadFailedAtSector,0L);
fprintf(stderr,"\n");
return(FALSE);
}
BootSector = IoBuffer;
fatsize = pFatDetermineFatSize(BootSector);
CurrentFatSectorBase = BootSector->ReservedSectors;
SectorsPerFat = pFatSectorsPerFat(BootSector);
FatSectorsLeft = SectorsPerFat;
CurrentCluster = 0;
InitClusterBuffer((FPBYTE)IoBuffer + (3*512),FileHandle);
while(CurrentCluster < PartitionImage->ClusterCount) {
//
// Read next block of fat sectors. Deal with 3 at a time so
// we never get partial 12-bit fat entries.
//
c = 3;
if((ULONG)c > FatSectorsLeft) {
c = (BYTE)FatSectorsLeft;
}
if(!ReadPartition(PartitionHandle,CurrentFatSectorBase,c,IoBuffer)) {
fprintf(stderr,"\n");
fprintf(stderr,textReadFailedAtSector,CurrentFatSectorBase);
fprintf(stderr,"\n");
return(FALSE);
}
//
// Figure out how many clusters are described by the 3 sectors
// of the FAT we just read in
//
switch(fatsize) {
case Fat12:
ClusterLimit = 1024;
break;
case Fat16:
ClusterLimit = 768;
break;
case Fat32:
ClusterLimit = 384;
break;
}
if((CurrentCluster + ClusterLimit) > PartitionImage->ClusterCount) {
ClusterLimit = (USHORT)(PartitionImage->ClusterCount - CurrentCluster);
}
//
// Fat values:
//
// 0 - free cluster
// 1 - (unused)
// [ffff]ff0 - [ffff]ff6 - (reserved)
// [ffff]ff7 - bad cluster
// [ffff]ff8 - [ffff]fff - last cluster of file
//
// All other values - used cluster
//
switch(fatsize) {
case Fat12:
for(i=0; i<ClusterLimit; i++,CurrentCluster++) {
x1 = *(FPUSHORT)((FPBYTE)IoBuffer + (3 * i / 2));
if(i & 1) {
x1 >>= 4;
} else {
x1 &= 0xfffU;
}
if((((x1 > 1) && (x1 <= 0xfefU)) || (x1 >= 0xff8U)) && (CurrentCluster >= 2)) {
PartitionImage->LastUsedCluster = CurrentCluster-2;
PartitionImage->UsedClusterCount++;
if(!MarkClusterUsed(CurrentCluster-2)) {
return(FALSE);
}
}
}
break;
case Fat16:
for(i=0; i<ClusterLimit; i++,CurrentCluster++) {
x1 = ((FPUSHORT)IoBuffer)[i];
if((((x1 > 1) && (x1 <= 0xffefU)) || (x1 >= 0xfff8U)) && (CurrentCluster >= 2)) {
PartitionImage->LastUsedCluster = CurrentCluster-2;
PartitionImage->UsedClusterCount++;
if(!MarkClusterUsed(CurrentCluster-2)) {
return(FALSE);
}
}
}
break;
case Fat32:
for(i=0; i<ClusterLimit; i++,CurrentCluster++) {
x2 = ((FPULONG)IoBuffer)[i] & 0xfffffffU;
if((((x2 > 1) && (x2 <= 0xfffffefUL)) || (x2 >= 0xffffff8UL)) && (CurrentCluster >= 2)) {
PartitionImage->LastUsedCluster = CurrentCluster-2;
PartitionImage->UsedClusterCount++;
if(!MarkClusterUsed(CurrentCluster-2)) {
return(FALSE);
}
}
}
break;
}
CurrentFatSectorBase += c;
FatSectorsLeft -= c;
printf(textScanningFat,100 * (SectorsPerFat - FatSectorsLeft) / SectorsPerFat);
printf("\r");
}
printf("\n");
if(!FlushClusterBuffer()) {
return(FALSE);
}
return(TRUE);
}
FatSize
pFatDetermineFatSize(
IN FPFAT_BOOT_SECTOR BootSector
)
{
//
// For fat32 the # of root dir entries in the bpb is 0.
//
if(!BootSector->SectorsPerFat) {
return(Fat32);
}
//
// See whether we overflow a 12-bit fat and return result.
//
return((pFatClusterCount(BootSector) < 4087L) ? Fat12 : Fat16);
}
ULONG
pFatClusterCount(
IN FPFAT_BOOT_SECTOR BootSector
)
{
ULONG s;
//
// Calculate the number of sectors that are in the data area,
// which is the size of the volume minus the number of sectors
// that are not in the data area.
//
s = BootSector->Sectors ? (ULONG)BootSector->Sectors : BootSector->LargeSectors;
s -= pFatFirstClusterSector(BootSector);
return(s / BootSector->SectorsPerCluster);
}
ULONG
pFatFirstClusterSector(
IN FPFAT_BOOT_SECTOR BootSector
)
{
ULONG s;
//
// Calculate the number of sectors that are not
// part of the data area. This includes reserved sectors,
// sectors used for the fats, and in the non-fat32 case,
// sectors used for the root directory.
//
// Note that for fat32 the # of root dir entries in the bpb is 0.
//
s = BootSector->ReservedSectors;
s += BootSector->Fats * pFatSectorsPerFat(BootSector);
s += BootSector->RootEntries / 16;
return(s);
}
ULONG
pFatSectorsPerFat(
IN FPFAT_BOOT_SECTOR BootSector
)
{
ULONG SectorsPerFat;
SectorsPerFat = BootSector->SectorsPerFat
? (ULONG)BootSector->SectorsPerFat
: *(FPULONG)((FPBYTE)BootSector + 0x24); // large sectors per fat
return(SectorsPerFat);
}