介绍
exFAT 文件系统(Microsoft 扩展 FAT 文件系统)是作为一系列行业标准 FAT 文件系统而开发的,广泛用于可移动介质和嵌入式系统中的内置存储。因此,它是基于 FAT 文件系统设计的,以便于在现有系统中实现。本文档主要描述这些文件系统之间的差异。exFAT 文件系统具有 FAT 文件系统的一些优点,如下所示。
开头为 0x 的数字为十六进制数字,其他数字为十进制数字。
假设每个单元的前缀K、M、G和T分别为210, 220,230,240.
本文档中包含的程序代码片段是用C语言编写的,但语法并不严格。
32位值和16位值任意混合在程序代码片段中。程序员需要了解由于类型转换而导致的数据丢失以及如何避免它。此外,每种数据类型都假定为unsigned。不要进行有符号计算,否则可能会导致意想不到的结果。
exFAT 卷
exFAT 卷由三个区域组成。每个区域按如下顺序位于卷上:(exFAT 卷映射)

引导区(卷配置参数)
FAT 区域(仅适用于碎片簇链)
数据区(文件、目录和一些系统结构)
引导扇区
引导扇区(扇区 0)
卷配置参数与 FAT 文件系统一样记录在引导扇区中。exFAT引导扇区实际上是在12个连续的扇区块中,并且两组引导扇区(主引导扇区和备份引导扇区)设置在exFAT卷顶部的引导区域中。每个簇的边界、大小和数量都明确记录在引导扇区中,卷识别中没有任何不清楚的地方。

扩展引导扇区(扇区 1-8):

扇区 9 包含 OEM 参数,扇区 10 保留供将来使用。这些扇区的内容取决于系统,不用时用零填充。扇区11包含 从扇区0到扇区10(包括扇区10)的32位校验和值。这 11 个扇区作为简单的字节数组以字节为单位进行计算,但 0号扇区的 卷标志 和卷使用率被排除在计算之外。
/* 计算32位校验和 */
uint32_t sum32 (const void* p, uint32_t n)
{
uint32_t sum = 0;
const uint8_t *dp = (const uint8_t*)p;
do {
sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + *dp++;
} while (--n);
return sum;
}
FAT 和分配位图
exFAT的 FAT 条目的大小与 FAT32 FAT 条目相同,但每个条目中的所有位均被使用。exFAT采用分配位图来管理簇分配状态,无论是否空闲。分配位图的第一位(第一个字节的0号位 )对应于2号簇 。位值 1 表示该集群正在使用中,不能用于新的分配。位值为 0 表示簇空闲,此时的FAT 条目的值没有任何意义。这是 exFAT 文件系统与 FAT 文件系统的显着区别,FAT 文件系统在 FAT 条目中用零表示空闲簇。下表显示了簇的状态和相应的条目。**在特殊情况下,即使簇正在使用,FAT 条目中的值也可能没有任何意义。**这在目录操作中进行了描述。

分配位图被记录在数据区域中,并且其分配信息(起始簇和大小)被记录为根目录上的特殊目录条目(在目录条目中描述)。分配位图的大小变为 (簇数 + 7) / 8 字节。
大写表
在 exFAT 文件系统中,文件名的处理方式与 FAT 文件系统的 LFN 扩展名相同。记录时保留 大小写信息,并在不区分大小写的情况下进行匹配。exFAT 卷在卷上有一个用于大写转换的大写表,而它是通过 FAT 文件系统中的系统转换表完成的。也许,这是为了将来新的角色定义。然而,这些变化与现有系统之间的兼容性如何尚不清楚。大写表至少需要支持 ASCII 字母字符,非 ASCII 字符是可选的。根据对Windows格式化的exFAT卷的研究,它似乎与Windows上的FAT文件系统相同,但未来并不是一成不变。
大写表似乎仅支持 BMP,其中对应于 U+0000 - U+FFFF。它以压缩形式记录在卷上。下面的函数是提取压缩表并创建大小写转换表。
oid load_upcase (
uint16_t dst[], /* Output table for U+0000 - U+FFFF */
uint16_t src[], /* Compressed table to input */
uint16_t n_src /* Size of compressed table [items] */
)
{
uint16_t c, si, di;
/* Fill output table with default values */
c = 0; do dst[c] = c; while (++c);
si = di = 0;
do {
c = src[si++]; /* Get an up-case character */
if (c == 0xFFFF && si < n_src) {
di += src[si++]; /* When U+FFFF appeared, skip the codes indicated by next item */
} else {
dst[di++] = c; /* Store the up-case character */
}
} while (si < n_src);
}
大写表记录在数据区中,其分配信息(起始簇和大小)记录在根目录上的特殊目录项(下面将对此进行描述)中。
目录条目
条目类型
根目录记录在数据区中。 第一个簇号存储在 第一个根目录簇 中。目录项的大小为32字节。这些与 FAT 文件系统相同。目录的最大长度为 256 MB(最多有8 M 个条目),而 FAT 文件系统为 2 MB。每个条目的第一个字节代表该条目的类型。分为四个位域如下图
条目类型 字节中的位字段

因此条目类型 字节提供了有关条目的信息,但实际上重要的是它的值来标识条目类型。下表显示了定义的值和条目类型。表中的最后四种条目类型对于通用用途是可选的,或者未为 exFAT 1.00 定义,因此本文档中未对它们进行描述。
条目类型 是每种类型的条目的唯一公共字段,其他字段是为每种条目类型单独定义的。要删除条目,请清除 EntryType 的使用中(第7位) 位,而不是像 FAT 文件系统那样存储 0xE5。如果 EntryType 为零,则目录中所有后续条目都保证为零。
分配位图条目
包含分配位图的分配信息。该条目独立记录在根目录中。

大写表条目
包含大写表的分配信息。该条目独立记录在根目录中。

卷表条目
包含该卷的卷标签。该条目独立记录在根目录中。如果该条目的大小字段为零或该条目不存在,则该卷没有卷标。文件名允许的任何字符(包括点)都可以用作卷标。

文件和目录条目
这是组成条目集的条目类型之一。它表示条目集的开始并包含文件属性和时间戳。条目集是一组连续的目录条目,用于记录文件或子目录的元数据。它按照该条目(1 个条目)、流扩展条目(1 个条目)和名称扩展条目(1-17 个条目)的顺序在目录上设置,以便条目集跨越 3 到 19 个条目。

流扩展入口
这是组成条目集的条目类型之一。它包含文件分配信息。

文件名条目
这是组成条目集的条目类型之一。它包含文件名字符串。除了控制字符(U+0000 到 U+001F、U+007F)和“ * / : < > ? \ | 之外的任何字符都可以作为 FAT 文件系统的 LFN 扩展名。exFAT 文件系统不支持FAT 文件系统支持的文件别名(SFN, short file name)。

目录操作
创建文件
要创建文件,请在目录中找到一块空闲条目并创建该文件的条目集。条目集具有存档属性并将数据长度字段设置为零作为初始值。AllocationPossible位始终为 1,NoFatChain位最初被清除。
当任何数据写入文件并分配新簇时,簇号将设置为FirstCluster并设置NoFatChain位。此后,只要簇链是连续的,就不会向 FAT 条目写入任何数据。当簇链在簇分配上出现碎片时,在 FAT 上创建有效的簇链并清除NoFatChain位。这仅适用于文件和子目录。任何其他数据(根目录、分配位图和大写表)在 FAT 上始终具有有效的簇链。
创建子目录
要创建子目录,请在目录中找到一块空闲条目,并创建子目录的条目集。条目集具有目录属性。最初为目录分配一个簇,每个条目都用零填充。NoFatChain位如上所述。当子目录满时,簇链每次拉伸一个簇,并且簇被初始化为零。目录的最大长度为 256 MB(8 M 条目)。
与FAT子目录有显着差异。DataLength字段具有有效值。FAT 子目录中的点(“.”、“…”)在 exFAT 子目录中不存在。它可以逻辑地生成并出现在目录列表中。
删除文件
要删除文件,请清除文件条目集中每个条目中的InUse位。如果文件具有簇链,则还需要从 FAT 中删除该链。在这种情况下,不需要更改 FAT 条目,因为通过清除分配位图可以释放簇。
删除子目录
与删除文件相同。删除目录之前,需要扫描目录下的所有节点,并删除目录中的所有文件和目录,否则这些对象的簇会丢失簇。
磁盘分区
与FAT文件系统的描述相同。exFAT卷的分区表中的系统类型值为0x07,与NTFS相同。但MBR格式不支持大于2TB的存储设备,因为分区表中的分配信息记录在32位LBA中。要使用此类存储设备,需要采用 SFD 格式或 GPT 格式。
1568





