Windows 7 格式化驱动器上的 FAT32 文件分配 Table 大小不符合 FAT32 规范

FAT32 File Allocation Table size on Windows 7 formatted drive is out of FAT32 specification

我正在编写嵌入式 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 Table 扇区大小。这是 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;

其中 RootDirSectors 对于 FAT32 始终为 0,因为它在 FAT32 文档中指定:

Note that on a FAT32 volume the BPB_RootEntCnt value is always 0, so on a FAT32 volume RootDirSectors is always 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 大小。

编辑:

mkfs.fat 3.0.28 on Linux,当与以下设置一起使用时:

mkfs.fat /dev/sdb1 -S 512 -s 8 -F 32 

给出 Table 大小 29956 的 FAT。现在,我在同一个分区上有 3 个不同编号的同一个文件系统

我现在应该信任谁? 规范实现。为什么数字相差 34 个扇区?

我找到了一份您似乎询问的关于 here (PDF) 的规范副本。

您所指的文档部分(在第 21 页的顶部)是 建议 ,不是强制性的 - 它描述了 [=27] 的某些未指定版本=] 在格式化 FAT32 卷时计算 FAT 大小。唯一实际的 要求 FATSz 足够大以包含 FAT。该文档明确允许使用对于 FAT 而言太大的 FATSz,并要求在格式化期间将浪费的扇区归零,否则将被忽略。

根据您的观察,Windows 的现代版本中似乎使用了稍微更有效的算法。 (看起来链接文档在声明它所描述的算法永远不会导致超过 8 个浪费的扇区时是不正确的。我没有尝试进行数学计算,但也许这与你的体积有关正在分析的是使用 4KB 簇而不是文档指示的 14GB 磁盘的 8KB 簇 - 请参阅第 20 页的 table。)

如果您正在格式化磁盘,您要么需要使用文档中的算法,要么非常小心地编写自己的算法,确保它永远不会产生太小的结果。 (或者,如果碰巧您已经知道磁盘的大小,则可以使用 Windows 在格式化相同大小的磁盘时使用的参数。)

如果你挂载的是已经格式化的磁盘,你当然会使用存储在磁盘上的值。