FAT 文件系统

最后更新: 2025-04-10 18:45:27 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

文件分配表(File Allocation Table,FAT)家族起源于小型 Microsoft 系统,后来成为 DOS 和 IBM PC 介质的交换格式。简单的数据结构使 FAT 适用于启动固件和资源受限的操作系统。相同的设计不包含日志记录、所有权和事务语义,因此它至今仍被使用的原因是互操作性,而不是故障隔离。

卷布局 #

FAT 卷由按逻辑扇区计量的区域组成:

  1. 保留区域以卷引导扇区及其 BIOS 参数块(BPB)开头。FAT32 还可以在此处放置 FSInfo 扇区,并且通常会放置一个备用引导扇区。
  2. 一个或多个 FAT 副本包含固定宽度的分配项。通常使用两个副本,但实际数量由 BPB 指定。
  3. 在 FAT12 和 FAT16 中,根目录区域的位置和项数是固定的。
  4. 数据区域包含编号后的簇。在 FAT32 中,根目录不是固定区域,而是该区域中的普通簇链。

BPB 提供每扇区字节数、每簇扇区数、保留扇区数、FAT 数量、总扇区数和 FAT 大小。读取器根据这些字段推导区域边界,而不是搜索目录签名。必须检查算术运算是否溢出,因为损坏的 BPB 值可能导致读取范围超出卷边界。

簇与 FAT 分类 #

簇是文件系统的分配单位。在 Microsoft 定义的 FAT 格式中,一个簇包含数量为 2 的幂次的扇区。簇编号 0 和 1 为保留编号;数据簇从 2 开始。数据簇数量由 BPB 按以下方式计算:

text
root_dir_sectors =
  ceil(root_entry_count × 32 / bytes_per_sector)

first_data_sector =
  reserved_sectors + fat_count × sectors_per_fat + root_dir_sectors

data_clusters =
  floor((total_sectors - first_data_sector) / sectors_per_cluster)

卷的分类依据是簇数量,而不是标签字符串或分区类型字节:

分类数据簇数量项表示
FAT12少于 4,085打包的 12 位项
FAT164,085 至 65,52416 位项
FAT3265,525 或更多32 位项,其中低 28 位有效

实际可用的上限还取决于簇大小、实现策略以及 BPB 中的字段。更宽的项可以表示更多簇,但会为每个 FAT 副本消耗更多扇区。

分配项与簇链 #

每个 FAT 项描述对应的簇。其值可以表示:

  • 表示空闲簇的零值;
  • 表示链中下一个链接的其他簇编号;
  • 保留簇或坏簇标记;
  • 处于链尾范围内的值。

文件的短目录项存储其首个簇和字节长度。读取文件时从该簇开始,沿 FAT 链接继续读取,直到获得足够的字节或遇到结束标记。最后一个簇可能包含超出逻辑长度的空闲字节。FAT32 中的目录以及所有非根目录都使用相同的簇链机制。

链式分配使文件无需找到一个连续的区段即可增长,但碎片化的链需要额外的 FAT 查找和非顺序 I/O。该表也是一个共享的故障点。循环、超出范围的链接、过早出现的结束标记,或同一个簇被两个文件声明使用,都会使目录元数据与分配状态不一致。

多个 FAT 副本不构成日志。写入操作可能在更新某一个副本、目录项或链的一部分之后失败。修复软件必须在过时的副本和推断出的所有权之间进行选择;两个副本逐字节一致,也不能证明目录项正确。FAT32 的 FSInfo 空闲计数和下一个空闲簇提示也可能过时,因此读取器必须将其视为提示信息。

目录项与时间戳 #

标准目录槽为 32 字节。短文件名项包含一个 8.3 文件名、属性标志、时间戳字段、起始簇和文件大小。FAT32 将起始簇拆分为高位字和低位字。首字节的特殊值表示未使用槽或已删除项,而目录属性用于区分子目录和普通文件。

经典 FAT 时间戳编码的是本地民用时间,而不是 UTC 时刻:

  • 修改时间的分辨率为两秒;
  • 修改日期和创建日期使用打包的年、月、日字段;
  • 创建时间可以包含十分之一秒字段;
  • 最后访问时间仅存储日期,不存储当天时间。

时区和夏令时的解释属于实现责任。因此,在不同系统之间复制卷可能会改变显示的时刻,而不改变磁盘上的位。验证时必须拒绝不可能的日期,不能直接将打包值传递给日历 API。

VFAT 长文件名 #

VFAT 通过将长文件名(LFN)项放置在关联短文件名项之前,来保持与 8.3 读取器的兼容性。LFN 槽具有以下特征:

  • 使用属性值 0x0F,旧版 FAT 读取器不会将其视为普通文件;
  • 在不连续的字段中存储最多 13 个 UTF-16 代码单元;
  • 携带一个序号,用于表示其位置以及是否为最后一个槽;
  • 重复存储由短 8.3 文件名导出的校验和。

槽在磁盘上按序号逆序出现,随后是短文件名项。只有在序号、属性和校验和一致时,读取器才会重构文件名。否则,短文件名仍是安全的身份标识。UTF-16 代码单元可以包含代理对,而 FAT 禁止的字符和尾随空格规则仍属于独立的验证问题。

引导扇区几何信息与分区元数据 #

由于 FAT 是随着 BIOS CHS 引导和分区磁盘发展起来的,BPB 仍保留每磁道扇区数、磁头数、介质描述符和隐藏扇区等字段。现代系统通过 LBA 访问卷,因此几何值可能是合成的。它们描述的是引导时兼容性,而不是物理盘片布局。

卷引导扇区属于 FAT,而 MBR 或 GPT 项位于卷外部,用于定位该卷。分区的起始位置和长度必须与根据 BPB 推导的边界一致,但一种结构不能替代另一种结构。在额外的 UEFI 要求下,UEFI 固件使用 FAT 文件系统作为 EFI System Partition;没有相应的分区元数据和引导路径,任意 FAT 卷都不会成为 EFI System Partition。

运行影响 #

FAT 仍适用于可移动介质、固件可见的卷以及资源受限的设备,因为独立实现可以使用很少的机制对其进行解析。应用程序仍应在移除介质前刷新数据,在读取不可信镜像时验证所有偏移量和簇链长度,并在尝试修复前保留镜像。没有日志,便无法区分已完成的更新和断电留下的中间状态。

参考资料 #

评论

在 GitHub 上阅读或评论(发表评论需要登录)