我正在编写嵌入式FAT32驱动程序。我有问题。
我用金属填充我的金士顿DTR30G2高达1GB并将其插入Windows 7盒子,并将其格式化为FAT32。然后,在我的Linux机器上,我将1GB的闪存转储到文件并在十六进制编辑器中打开它并获得以下值:
uint16_t BPB_ResvdSecCnt = 32 at offset 0xE
uint8_t BPB_SecPerClus = 8 at offset 0xD
uint8_t BPB_NumFATs = 2 at offset 0x10
接下来,我查看FAT32卷ID中的扇区总数:
uint32_t DskSize = 30734336 at offset 0x20
它与Linux报告相同:
thinkpad :: ~ % cat /sys/block/sdb/sdb1/size
30734336
这完全符合FAT32的规范。现在,让我们看一下偏移量为0x24的驱动器上的FAT表扇区大小。它的29951
部门。这不是FAT32的规格。 Microsoft官方文档声明了以下等式:
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;
对于FAT32,RootDirSectors
始终为0,因为它在FAT32文档中指定:
请注意,在FAT32卷上,BPB_RootEntCnt值始终为0,因此在FAT32卷上 RootDirSectors始终为0.
所以这给了:
TmpVal1 = DskSize – BPB_ResvdSecCnt;
TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
TmpVal2 = TmpVal2 / 2;
FATSz = (TMPVal1 + (TmpVal2 – 1)) / TmpVal2;
现在,我实现了这个:
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);
}
此代码段提供29985
个扇区作为FAT大小。
编辑:
Linux上的 mkfs.fat 3.0.28
,与以下设置一起使用时:
mkfs.fat /dev/sdb1 -S 512 -s 8 -F 32
使FAT表格大小为29956
。现在,我在同一个分区上有 3个不同数量的相同的文件系统。
29985
29951
29956
我现在应该信任谁? 规范或实施。为什么数字会被34
个部门关闭?
答案 0 :(得分:2)
我找到了您似乎询问here(PDF)的规范的副本。
您所指的文档部分(位于第21页的顶部)是 Advisory ,而不是强制性的 - 它描述了一些未指定版本的Windows在计算FAT大小时所执行的操作格式化FAT32卷。唯一的实际要求是FATSz
足够大以包含FAT。该文档明确允许使用对于FAT来说太大的FATSz
,并要求在格式化期间将浪费的扇区归零,否则将被忽略。
根据您的观察,似乎在现代版本的Windows中使用稍微更高效的算法。 (似乎链接文档说明它描述的算法永远不会导致超过8个浪费的扇区。我没有尝试过数学,但也许它与你的卷这个事实有关“重新分析是使用4KB群集而不是文档为14GB磁盘指示的8KB群集 - 请参阅第20页的表格。”
如果要格式化磁盘,则需要使用记录的算法,或者非常仔细地编写自己的算法,确保它永远不会产生太小的结果。 (或者,如果碰巧您已经知道磁盘的大小,则可以使用Windows在格式化相同大小的磁盘时使用的参数。)
如果要安装已格式化的磁盘,当然可以使用存储在磁盘上的值。