407 lines
10 KiB
C
407 lines
10 KiB
C
|
#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);
|
||
|
}
|
||
|
|