Reputation: 2742
I'm writing a embedded FAT32 driver. I have issues.
I fill my Kingston DTR30G2 up to 1GB with zeros and plug it into a Windows 7 box, and format it as FAT32. Then, on my Linux box, I dump 1GB of the flash to file and open it in a hex editor and get the following values:
uint16_t BPB_ResvdSecCnt = 32 at offset 0xE
uint8_t BPB_SecPerClus = 8 at offset 0xD
uint8_t BPB_NumFATs = 2 at offset 0x10
Next, I look at the total number of sectors in the FAT32 volume ID:
uint32_t DskSize = 30734336 at offset 0x20
It's the same as Linux reports:
thinkpad :: ~ % cat /sys/block/sdb/sdb1/size
30734336
This is all within spec of FAT32. Now, let's look at the FAT Table sector size on the drive at offset 0x24. It's 29951
sectors. That is not in spec of FAT32. Official Microsoft documents declare the following equation:
RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec;
TmpVal1 = DskSize – (BPB_ResvdSecCnt + RootDirSectors);
TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
TmpVal2 = TmpVal2 / 2;
FATSz = (TMPVal1 + (TmpVal2 – 1)) / TmpVal2;
Where RootDirSectors
is constantly 0 for FAT32 as it is specified in the FAT32 documents:
Note that on a FAT32 volume the BPB_RootEntCnt value is always 0, so on a FAT32 volume RootDirSectors is always 0.
So this gives:
TmpVal1 = DskSize – BPB_ResvdSecCnt;
TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
TmpVal2 = TmpVal2 / 2;
FATSz = (TMPVal1 + (TmpVal2 – 1)) / TmpVal2;
Now, I implemented this:
int main(void) {
uint32_t DskSize = 30734336;
uint32_t FATSz;
uint16_t BPB_ResvdSecCnt = 32;
uint8_t BPB_SecPerClus = 8;
uint8_t BPB_NumFATs = 2;
uint32_t RootDirSectors = 0;
uint32_t TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
uint32_t TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
TmpVal2 = TmpVal2 / 2;
FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
printf("%d\n", FATSz);
}
This code snippet gives 29985
sectors as the FAT size.
EDIT:
mkfs.fat 3.0.28
on Linux, when used with the following settings:
mkfs.fat /dev/sdb1 -S 512 -s 8 -F 32
Gives a FAT Table size of 29956
. Now, I have 3 different numbers of the same file system on the same partition.
29985
29951
29956
Who should I now trust? The specification or the implementation. Why are the numbers off by 34
sectors?
Upvotes: 4
Views: 948
Reputation: 36328
I found a copy of the specification you appear to be asking about here (PDF).
The part of the document you're referring to (at the top of page 21) is advisory, not mandatory - it is describing what some unspecified version of Windows did to calculate the FAT size when formatting a FAT32 volume. The only actual requirement is that FATSz
be large enough to contain the FAT. The document explicitly permits using a FATSz
that is too large for the FAT, and requires that the wasted sectors be zeroed during formatting and otherwise ignored.
From your observations, it would appear that a slightly more efficient algorithm is used in modern versions of Windows. (It would also appear that the linked document was incorrect in stating that the algorithm it describes never results in more than 8 wasted sectors. I haven't attempted to do the math, but perhaps it has to do with the fact that the volume you're analyzing is using 4KB clusters instead of the 8KB clusters the document indicates for a 14GB disk - see the table on page 20.)
If you are formatting a disk, you either need to use the algorithm as documented, or very carefully write your own algorithm, ensuring that it can never produce a too-small result. (Or, if it so happens that you already know what size the disk will be, you could use the parameters that Windows uses when formatting a disk of the same size.)
If you are mounting a disk that is already formatted, you of course use the value stored on the disk.
Upvotes: 3