FAT32 文件系统
按照自己的学习习惯,第一部分先摘取关键有效信息做笔记,接着再转为有效的合适的数据结构,最后画流程图。
1 FAT32 信息摘要
1.1 FSInfo
| 名称 | Offset(byte) | 大小(Byte) | 描述 |
| FSI_LeadSig | 0 | 4 | 值为0x41615252,这个标记用来表示该扇区为FSInfo扇区。 |
| FSI_Reserved1 | 4 | 480 | 保留为以后扩展使用,FAT32格式化程序应该把此域全部设置为0,当前版本的FAT程序不可以访问该域。 |
| FSI_StrucSig | 484 | 4 | 值为0x61417272,更具体地表明该扇区已经被使用。 |
| FSI_Free_Count | 488 | 4 | 保存最新的剩余簇的数量,如果为0xFFFFFFFF表示剩余簇未知,需要重新计算,除此之外的其他值都可以用,而且不要求十分精确,但必须保证其值≤磁盘所有的簇数。 |
| FSI_Nxt_Free | 492 | 4 | 该域为FAT驱动程序提供一条有利的线索,它告诉驱动程序应该从哪里开始寻找剩余簇,因为FAT32的FAT表可能非常庞大,如果已经分配的簇很多的话要从头开始查找剩余簇,这将耗费大量时间。通常这个值被设定为驱动程序最后分配出去的簇号,如果值为0xFFFFFFFF,那么驱动程序必须从簇2开始查找,除此之外其他的值都可以使用,当然,前提是这个值必须是合法的。 |
| FSI_Reserved2 | 496 | 12 | 保留为以后扩展使用,FAT32格式化程序应该把此域全部设置为0,当前版本的FAT程序不可以访问该域。 |
| FSI_TrailSig | 508 | 4 | 值为0xAA550000,此结束标记用来表示这是一个FSInfo扇区,注意此域的高两位偏移量为510和511,这和启动扇区在相同偏移处的标记是一样的。 |
1.2 FAT表
1.3 目录项
FAT32的根目录由簇链组成,其扇区数是不确定的,这点和普通文件相同,根目录的第一个扇区号存储在BPB_RootClus中。根目录不同于其他的目录,没有日期和时间戳,也没有目录名(“/”并不是其目录名),同时根目录里没有“.”和“..”这两个目录项,根目录另一个特殊的地方在于,根目录中有一个设置了ATTR_VOLUME_ID位(见下表)的文件,这个文件在整个FAT卷中是唯一的。
文件系统刚被创建(可通过格式化你的设备实现),还没有任何存储数据时,文件系统只为根目录分配了一个簇的空间(通常为2号簇),并将结束标记0x0FFFFFFF,表示该簇已经被使用,但根目录下没有任何内容,目录项全部为00。
此时通过新建文件,或者更改卷标,刚才全部为空的根目录就会如以上根目录项的格式填充内容。
DIR_Name域实际由两部分组成:8个字符的主文件名和3个字符的扩展名。两部分如果字符数不够的话用空格(0x20)填充(Trailing Space Padded)。
[注]:根目录项中只有定义了卷标,才会出现 DIR_Attr
=ATTR_VOLUME_ID 的内容。否则没有属性为卷标的目录项。另外卷标所在的目录项不一定会分配到根目录到第一个目录项空间,根目录的空间分配按照创建时间从0号目录项依次分配,所以在当检测到DIR_Name[0]为0x00时,可以认为此后的目录项都没有内容。
目录所在的扇区,都是以32 Bytes划分为一个单位,每个单位称为一个目录项(Directory Entry ),即每个目录项的长度都是32 Bytes 。根目录由若干个目录项组成,一个目录项占用32个字节,可以是长文件名目录项、文件目录项、子目录项等。
| 名称 | Offset (Byte) | 大小(Byte) | 描述 |
| DIR_Name | 0 | 11 |
短文件名 |
| DIR_Attr | 11 | 1 |
文件属性: ATTR_READ_ONLY ATTR_HIDDEN ATTR_SYSTEM ATTR_VOLUME_ID ATTR_DIRECTORY ATTR_ARCHIVE ATTR_LONG_NAME 前两个属性位为保留位,在文件创建时应该把这两位设为0,在以后的使用中不能读写和更改。 |
| DIR_NTRes | 12 | 1 | 保留给Windows NT使用,在文件创建时设置该位为0,在以后的使用中不能读写和更改。 |
| DIR_CrtTimeTeenth | 13 | 1 | 文件创建时间的毫秒级时间戳,由于DIR_CrtTime的精度为2秒,所以此域的有效值在0-199之间。 |
| DIR_CrtTime | 14 | 2 | 文件创建时间。 |
| DIR_CrtData | 16 | 2 | 文件创建日期。 |
| DIR_LastAccDate | 18 | 2 | 最后访问日期,请注意并没有最后访问时间域,而只有日期,这日期是指文件被读写的日期,如果是写,该日期还应该被写到DIR_WrDate中。 |
| DIR_FstClusHI | 20 | 2 | 该目录项起始簇号的高位字(FAT12/16此位为0) |
| DIR_WrtTime | 22 | 2 | 最后写的时间,文件创建被认作写 |
| DIR_WrtDate | 24 | 2 | 最后写的日期,文件创建被认作写 |
| DIR_FstClusL0 | 26 | 2 | 该目录项起始簇号的低位字 |
| DIR_FileSize | 28 | 4 | 文件大小,由32-bit双字组成 |
1.3.1 DIR_Name[0]
此处特别注释目录项的第一个字节 DIR_Name[0]:
- 如果DIR_Name[0] == 0xE5,则此目录为空(目录项不包含文件和目录),或表示该项已被删除
- 如果DIR_Name[0] == 0x00,则此目录为空(同0xE5),并且此后的不再分配有目录项(此后所有的DIR_Name[0]均为0)。不同于0xE5,如果DIR_Name[0]的值为0,那么FAT程序将不会再去检测其后续的磁盘空间,因为这些空间都是空闲的。
- 如果DIR_Name[0] == 0x05,则文件名在该位的实际值为0xE5,但0xE5是日文中合法的字符,当需要用0xE5来作为DIR_Name[0]时使用0x05来代替,避免程序误认为该目录项为空。
- DIR_Name[0]不允许为0x20,主文件名和扩展文件名的间隔“.”并不真实存在于DIR_Name中,小写字母不允许出现在DIR_Name中(这些字符因为不同的国家和地区而异)。
[注]:以下字符不允许出现在DIR_Name中的任何位置:0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D还有0x7C。
1.4 数据区举例
1.5 文件创建
1.5.1 文件分配规则
首先,根据创建文件的不同,FAT32的结构分配也不同,需要知道的是:
- 所有文件大小大于0的文本文件
- 所有文件夹,不论是否为空
- 所有目录文件
- 首先系统将2号簇默认为根目录文件
- 任何类型的文件都有一个目录项用于存储其文件名,文件大小,起始簇地址以及其他属性
- 目录项存储于目录文件中,一个目录文件中可存放多个目录项(目录项大小32Byte)
- 目录文件根据当前文件的数量动态创建,当前目录文件没有足够空间存储一个新建文件(不论大小)的目录项时,在FAT表中新建一个簇作为目录文件
- 同一个目录文件中的所有文件同属于该目录文件的路径下
1.5.2 创建一个文件和一个目录
- 文档在被新建的时候,已经明确其所在的路径,即已经有目录被创建,不存在为每个新建文档分配目录文件的问题,当文档被新建,其起始簇的0地址偏移处即存储文档内容;
- 文件夹作为目录的创建方式,必须分配新簇空间。需要存储该目录下所有的文件信息,所以起始簇的0地址偏移处存储的是当前目录下的所有文件信息,即使是空目录也会存放子目录和父目录信息,用来表示该目录所处的路径。
- 创建文档和目录都需要将文件属性信息存储在目录项中,另外,创建非空文档时需要被分配有效的可用簇存储文档内容;创建目录需要在目录项中明确父目录子目录关系,但不需要再分配空间。
- 获取文件(文档或目录)大小
- 遍历FAT表,按照合适的文件分配策略在FAT表中填写簇的分配信息
- 定位当前所在目录,在其所在目录文件中增加目录项
- 根据FAT表分配在目录项中写入所在簇起始地址以及其他已知信息
- 将文件内容写入给文档分配的起始簇
- 2‘. 当文件大小为0时,查看当前目录大小是否够用(只需要一个目录项的大小),不够用则新增FAT表,否则跳过步骤2到步骤3
- 5'. 新建文件夹或空文档跳过步骤5
以上新建内容是目前所理解做的整理,实际开发之后补充验证结果。
1.5.3 文件创建举例
1.5.3.1 txt文件创建
1.5.3.2 文件夹 目录创建
1万+

被折叠的 条评论
为什么被折叠?



