FAT文件系统的数据结构中有两个重要的结构:文件分配表和目录项。
FAT16整体结构由DBR扇区、FAT表、根目录和数据区组成。下面将详细介绍。
- DBR扇区结构
其也称为引导扇区,由跳转指令JUMP,OEM厂商标志,BPB和扩展BPB,引导代码,结束标志0XAA55构成。下图为winhex下的DBR扇区截图。其具体内容设计可查看FATwiki:https://zh.wikipedia.org/wiki/FAT#%E8%AE%BE%E8%AE%A1。其中,可以看到保留扇区为0x08,FAT表为两个,每簇扇区数为0x80(0x0d),每个FAT占位0x80扇区(0x16-0x17)。
- FAT表(文件分配表)
紧跟在保留分区后面的是FAT区,其由两个完全相同的FAT(File Allocation Table,文件分配表)表单组成,FAT文件系统的名字也是因此而来。FAT 表是一组与数据簇号对应的列表。FAT2紧跟在FAT1之后,它的位置可以通过FAT1的位置加上FAT表的扇区数计算出来。(有时也只有一个FAT,具体多少要看DBR中偏移量为0x10处的值)
它是映射到分区每个簇的条目列表。每个条目记录下面五种信息中的一种。
- 链中下一个簇的地址
- 一个特殊的簇链结束符(EOC,End Of Cluster-chain,或称End Of Chain)符号指示链的结束
- 一个特殊的符号标示坏簇
- 一个特殊的符号标示保留簇
- 0来表示空闲簇
定位:0x8*512 = 0x1000
它是一个表示目录的特殊类型文件(现今通常称为文件夹)。它里面保存的每个文件或目录使用表中的32字节条目表示。每个条目记录名字、扩展名、属性(档案、目录、隐藏、只读、系统和卷)、创建的日期和时间、文件/目录数据第一个簇的地址,最后是文件/目录的大小。FAT16的根目录并不由簇进行管理。FAT16固定为32个扇区。
定位:0x1000 + 0x80*512*2 = 0x21000
115.gif定位:0x21000 + 32*512 + (5-2)*128*512 = 0x55000
FAT32与FAT16类似,它主要是由保留区(DBR,FSINFO信息扇区,其余),文件分配表,数据区(根目录,数据)。整体上看,其区别主要在于保留区,数据区中的根目录由簇进行管理。
具体设计还是参照wiki: https://zh.wikipedia.org/wiki/FAT#%E8%AE%BE%E8%AE%A1。
下面图片是我的磁盘上的DBR信息,可以看到FAT表(0x10)为两个,保留扇区数(0x0e-0x0f)为0x2022=8226。
每个FAT表大小为(0x24-0x27)0x0FEF = 4079扇区。每簇扇区数为0x8(0x0d)。
- FSINFO扇区
FAT32在保留区中增加了一个FSINFO扇区,用以记录文件系统中空闲簇的数量以及下一可用簇的簇号等信息,以供操作系统作为参考。
- FAT表
根据DBR中信息:FAT表位置应该是8226*512 = 0x404400。
0x404400+0xFEF*0x200*2 = 0x800000
可以看到a.txt的目录项从0x8000e0开始,总共32个字节,位于8号簇。由DBR信息可知,每个簇占8个扇区(DBR信息),那么可以定位a.txt的位置为0x806000 = 0x80000 + 6 * 8 * 512。
- FAT16文件定位与FAT32文件定位区别
- 在DBR中表示FAT表的大小偏移量不同。FAT16: 0x16-0x17 FAT32:0x24-0x27
- 文件目录项大小不同,FAT16固定为32个扇区,而FAT32对目录项以簇为单位进行表示。
- (短文件)文件目录项中表示文件所在簇号位置偏移量不同。FAT16:0x1a-0x1b FAT32:0x14-0x15(高字节) 0x1a-0x1b(低字节)
- FAT32 长文件解析
我将a.txt文件改名为a0123456789.txt。
长文件名使用目录登记项格式,占用2个字节。采用Unicode格式(一个字符占两个字节16位)一个长文件名需要若干个这样的不登记项,它们的含义表示为:
偏移量 | 长(字节) | 含义 |
0 | 1 | 顺序字节 |
1~10 | 10 | 长文件名节(5个字符) |
11 | 1 | 文件属性(3F) |
12 | 1 | 种类 |
13 | 1 | 校验和 |
14~25 | 12 | 长文件名节(6个字符) |
26~27 | 2 | 起始簇号 |
28~31 | 4 | 长文件名节(2个字符) |
所以一个目录登记项可以表示5+6+2共13个字符。第一个字节的低5位指明它在文件名中的顺序号,第6位为“1表明它是最后一项”,第5,7位未用置0。
最后两行是短目录项,一般遵从一下规则:
1、系统取长文件名的前6个字符加上“~1”形成短文件名,其扩展名不变;
2、如果已存在这个名字的文件,则符号“~”后的数字自动增加;
3、如果文件名内存在windows非法的字符,则以下划线“_”代替;
上图中可以看到其簇号还是0x08。