本文记录FAT文件系统的学习内容,不是文件系统的详细说明文档。
FAT,File Allocation Table,文件分配表。有FAT12,FAT16和FAT32三种类型,FAT后面的数字指的是每个FAT entry的大小,比如FAT32指的是 FAT entry = 32bit。 FAT文件系统是相对比较古老的文件系统,随着时间的推移,FAT12和FAT16使用已经不多了,现在常见是FAT32。 FAT文件系统与NTFS、ext4、xfs这些文件系统相比,有明显的问题,但是它原理简单,到现在还有很多地方在使用,比如操作系统启动分区(UEFI需要一个FAT32启动分区),一些电视机之类的多媒体设备识别FAT32文件系统等。
上图是FAT文件系统的布局图,其中中间部分的FAT Region就是FAT文件系统的最核心部分:文件分配表。
1. 区域如何分配
布局图中将整个文件系统分成是4个区域:
- Reserved Region: 保留区域,保存文件系统的属性
- FAT Region: FAT区,一般有连续的两个FAT
- Root Directory Region: 保存根目录的内容,FAT32没有这个部分
- File and Directory Data Region: 数据区
保留区域的作用很重要,里面保存了整个文件系统的重要信息。 BPB(BIOS Parameter Block),同时也是 Boot Sector 启动扇区,指的都是保留分区中的第一个扇区(sector 0)。 这部分内容类似于其他文件系统说的超级块(super block)。 这部分内容是需要重点关注的,下面列出一些重要的参数:
- BPB_RsvdSecCnt: 14bit开始,长度2bit,保留区的扇区数量,用于计算保留区的大小;
- BPB_NumFATs: FAT的数量,一般是2个;
- BPB_FATSz32: FAT32类型的FAT区域扇区数,用于计算FAT区域的大小;然后推算数据区的开始位置;
- BPB_SecPerClus: 数据区以cluster(簇)为单位进行划分,cluster是sector的整数倍,一般是4,8…
- BPB_BytsPerSec: 扇区字节数,一般512,也可以1024,4096等
以上我们可以计算出(只考虑fat32,无RootDir区域):
- FAT区域起始扇区 fat_start_sec = BPB_RsvdSecCnt
- 数据区域起始扇区 data_start_sec = BPB_RsvdSecCnt + BPB_NumFATs * BPB_FATSz32
2. FAT 区域
- FAT32的FAT区域是一个数组,每个成员是32bit的无符号整数,该整数指向数据区域的cluter ID。举个例子,现在需要查找一个文件:如果该文件的第1个cluster id=i,那么第2个cluster id = fat[i],然后跳转到相应的cluter位置读取数据即可。
- 如果某个成员的值0x0fffffff, 表示该文件后续没有cluster了,还有一些其他的特殊值请参考手册
- FAT[0]一般是0x0ffffff8, 如果是U盘的话可能是0x0ffffff0, 从BPB_Media参数得来
- FAT[1]=0xffffffff,保留值,不使用
- FAT[2]开始对应cluster ID, 也就说最小ClusterID=2,但是对应的数据区是第0块Cluster区域
- FAT区域最后可能有好多0值,表示未分配
所以:
# 没有 cluster_id 0 和 1, fat[0]和fat[1]作为标识位用
data[0] <--> cluster_id=2 <--> fat[2]
data[1] <--> cluster_id=3 <--> fat[3]
...
3. 目录和文件的存储
数据区存放的就是正儿八经的目录和文件了,那么如何来存放呢? FAT32使用了一个简单的 目录结构(Directory Structure): 大小为32B,内容包括目录名称、目录属性、创建时间等、第一个Cluster、文件大小等基本信息。 注意:文件也用这个目录结构来存放基本信息,区别在于目录属性的不同。另外目录对应的Cluster里面存储的是该目录下边的文件或目录的目录结构(Directory Structure),文件对应的Cluster里面存放的就是真正的文件二进制数据了。
那么第一个文件或者目录的目录结构(Directory Structure)在哪里呢? – BPB扇区中有一个参数BPB_RootClus,保存了FAT32文件系统根目录对应的Cluster ID,一般=2,从这里可以查看到根目录下的目录结构,从而继续搜索下去,就能遍历整个文件系统了。
一张图来看下过程:
4. 其他
感觉有一些细节并没有在参考文件中明确写,下面的FAT32是使用mkfs.fat创建:
# mkfs.fat -v -F 32 -s 8 -S 512 fs.img
# mount fs.img ttt
(1) 如果删除一个文件,会发生什么变化?
我们文件系统中有一个文件aaa/bbb.bmp, aaa目录结构存放位置0x24000,bbb.bmp目录结构存放位置0x25040,bbb.bmp数据存放位置0x26000开始,现在将该文件删除后,只是在长名称和短名称目录结构的0号位置写入0xe5(长名称结构在前,短名称结构在后),其他未改变,并没有将数据进行置0操作。
(2) 再写入另一个文件会怎么样?
可见删除标记的bbb.bmp目录结构已经被覆盖了。
root:aaa# cat /etc/services > cccc.txt
root:aaa# hexdump -C ../../fs.img -s 0x25000 |head
00025000 2e 20 20 20 20 20 20 20 20 20 20 10 00 4f 78 31 |. ..Ox1|
00025010 9d 55 9d 55 00 00 78 31 9d 55 03 00 00 00 00 00 |.U.U..x1.U......|
00025020 2e 2e 20 20 20 20 20 20 20 20 20 10 00 4f 78 31 |.. ..Ox1|
00025030 9d 55 9d 55 00 00 78 31 9d 55 00 00 00 00 00 00 |.U.U..x1.U......|
00025040 41 63 00 63 00 63 00 63 00 2e 00 0f 00 36 74 00 |Ac.c.c.c.....6t.|
00025050 78 00 74 00 00 00 ff ff ff ff 00 00 ff ff ff ff |x.t.............|
00025060 43 43 43 43 20 20 20 20 54 58 54 20 00 57 57 0a |CCCC TXT .WW.|
00025070 9e 55 9e 55 00 00 57 0a 9e 55 e2 00 80 38 00 00 |.U.U..W..U...8..|
00025080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
根据参考资料的目录项数据结构内容来分析cccc.txt目录项0x25060,可以得到第一个cluster_id=#226, 地址是0x104000,原有bbb.bmp cluster_id=#3, 数据地址0x26000并没有被覆盖。
(3) 重命名文件会怎样?
root:aaa# mv cccc.txt dddd.txt
root:aaa# hexdump -C ../../fs.img -s 0x25040 |less
root:aaa# hexdump -C ../../fs.img -s 0x25040 |head
00025040 e5 63 00 63 00 63 00 63 00 2e 00 0f 00 36 74 00 |.c.c.c.c.....6t.|
00025050 78 00 74 00 00 00 ff ff ff ff 00 00 ff ff ff ff |x.t.............|
00025060 e5 43 43 43 20 20 20 20 54 58 54 20 00 57 57 0a |.CCC TXT .WW.|
00025070 9e 55 9e 55 00 00 57 0a 9e 55 e2 00 80 38 00 00 |.U.U..W..U...8..|
00025080 41 64 00 64 00 64 00 64 00 2e 00 0f 00 78 74 00 |Ad.d.d.d.....xt.|
00025090 78 00 74 00 00 00 ff ff ff ff 00 00 ff ff ff ff |x.t.............|
000250a0 44 44 44 44 20 20 20 20 54 58 54 20 00 57 57 0a |DDDD TXT .WW.|
000250b0 9e 55 9e 55 00 00 57 0a 9e 55 e2 00 80 38 00 00 |.U.U..W..U...8..|
000250c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
可以看到原cccc.txt目录结构(0x25040)0号位被标记删除,并创建新的dddd.txt的目录结构(0x25080),其余均没有变化。
(4)链接操作? 不行。
root:aaa# ln dddd.txt ln.txt
ln: failed to create hard link 'ln.txt' => 'dddd.txt': Operation not permitted
root:aaa# ln -s dddd.txt ln.txt
ln: failed to create symbolic link 'ln.txt': Operation not permitted
参考资料
- Microsoft FAT Specification 对FAT进行了非常详细的说明