struct DSKSZTOSECPERCLUS { |
DWORD DiskSize; |
BYTE SecPerClusVal; |
}; |
/* |
*This is the table for FAT16 drives. NOTE that this table includes |
* entries for disk sizes larger than 512 MB even though typically |
* only the entries for disks < 512 MB in size are used. |
* The way this table is accessed is to look for the first entry |
* in the table for which the disk size is less than or equal |
* to the DiskSize field in that table entry. For this table to |
* work properly BPB_RsvdSecCnt must be 1, BPB_NumFATs |
* must be 2, and BPB_RootEntCnt must be 512. Any of these values |
* being different may require the first table entries DiskSize value |
* to be changed otherwise the cluster count may be to low for FAT16. |
*/ |
DSKSZTOSECPERCLUS DskTableFAT16 [] = { |
{ 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal trips an error */ |
{ 32680, 2}, /* disks up to 16 MB, 1k cluster */ |
{ 262144, 4}, /* disks up to 128 MB, 2k cluster */ |
{ 524288, 8}, /* disks up to 256 MB, 4k cluster */ |
{ 1048576, 16}, /* disks up to 512 MB, 8k cluster */ |
/* The entries after this point are not used unless FAT16 is forced */ |
{ 2097152, 32}, /* disks up to 1 GB, 16k cluster */ |
{ 4194304, 64}, /* disks up to 2 GB, 32k cluster */ |
{ 0xFFFFFFFF, 0} /* any disk greater than 2GB, 0 value for SecPerClusVal trips an error */ |
}; |
/* |
* This is the table for FAT32 drives. NOTE that this table includes |
* entries for disk sizes smaller than 512 MB even though typically |
* only the entries for disks >= 512 MB in size are used. |
* The way this table is accessed is to look for the first entry |
* in the table for which the disk size is less than or equal |
* to the DiskSize field in that table entry. For this table to |
* work properly BPB_RsvdSecCnt must be 32, and BPB_NumFATs |
* must be 2. Any of these values being different may require the first |
* table entries DiskSize value to be changed otherwise the cluster count |
* may be to low for FAT32. |
*/ |
DSKSZTOSECPERCLUS DskTableFAT32 [] = { |
{ 66600, 0}, /* disks up to 32.5 MB, the 0 value for SecPerClusVal trips an error */ |
{ 532480, 1}, /* disks up to 260 MB, .5k cluster */ |
{ 16777216, 8}, /* disks up to 8 GB, 4k cluster */ |
{ 33554432, 16}, /* disks up to 16 GB, 8k cluster */ |
{ 67108864, 32}, /* disks up to 32 GB, 16k cluster */ |
{ 0xFFFFFFFF, 64}/* disks greater than 32GB, 32k cluster */ |
}; |
RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec; TmpVal1 = DskSize – (BPB_ResvdSecCnt + RootDirSectors); TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs; If(FATType == FAT32) TmpVal2 = TmpVal2 / 2; FATSz = (TMPVal1 + (TmpVal2 – 1)) / TmpVal2; If(FATType == FAT32) { BPB_FATSz16 = 0; BPB_FATSz32 = FATSz; } else { BPB_FATSz16 = LOWORD(FATSz); /* there is no BPB_FATSz32 in a FAT16 BPB */ } Do not spend too much time trying to figure out why this math works. The basis for the computation is complicated; the important point is that this is how Microsoft operating systems do it, and it works. Note, however, that this math does not work perfectly. It will occasionally set a FATSz that is up to 2 sectors too large for FAT16, and occasionally up to 8 sectors too large for FAT32. It will never compute a FATSz value that is too small, however. Because it is OK to have a FATSz that is too large, at the expense of wasting a few sectors, the fact that this computation is surprisingly simple more than makes up for it being off in a safe way in some cases. |