fat12 filesystem
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
fat12
fat12_test
image
.gitignore BPB May 12, 2017
LICENSE
README.md

README.md

fat12

🔢 welcome to commit issue

文件说明

image/ : fat12格式测试文件

DiskLib.[h|lib|dll] : 动态链接库文件

fat12/ : FAT12动态链接库目录

fat12_test/ : 测试程序目录

fat12引导扇区字段说明

名称 偏移(BYTE) 长度(BYTE) 内容 软盘参考值
BS_jmpBoot 0 3 - jmp LABEL_START && nop
BS_OEMName 3 8 厂商名 'Forrest Y'
BPB_BytsPerSec 11 2 每扇区字节数 0x200(512字节)
BPB_SecPerClus 13 1 每簇扇区数 0x01
BPB_RsvdSecCnt 14 2 Boot记录占用多少 0x01
BPB_NumFATs 16 1 共有多少FAT表 0x02
BPB_RootEntCnt 17 2 根目录文件数最大值 0xE0(224)
BPB_TotSec16 19 2 扇区总数 0xB40(2280)
BPB_Media 21 1 介质描述符 0xF0
BPB_FATSz16 22 2 每FAT扇区数 0x09
BPB_SecPerTrk 24 2 每磁道扇区数 0x12
BPB_NumHeads 26 2 磁头数 0x02
BPB_HiddSec 28 4 隐藏扇区数 0
BPB_TotSec32 32 4 如果BPB_TotSec16是0,由这个值记录扇区数 0xB40(2280)
BS_DrvNum 36 1 中断13的驱动器号 0
BS_Reserved1 37 1 未使用 0
BS_BootSig 38 1 扩展引导标记 0x29
BS_VolD 39 4 卷序列号 0
BS_VolLab 43 11 卷标 'OrangeS0.02'
BS_FileSysType 54 8 文件系统类型 'FAT12'
引导代码 62 448 引导代码、数据及其他填充字符等
结束标志 510 2 0xAA55

fat1

​ 在偏移512字节处开始(即200h),每个fat项占用12bit,fat表开始3个字节不用于用户文件分配,也就是占用了0簇和1簇,所以用户的数据从簇2开始分配。

​ Fat表从头开始按3字节分成一组,一组中第2字节的低半字节作为最高半字节和一组中第1字节组成整数表示一个簇号,第2字节的高半字节作为最低半字节和第3字节组成整数表示一个簇号。

​ 我们只需要知道一个文件的首簇号,根据该簇号内容指向的下一个簇号寻找,直到遇到簇号对应内容为0xfff则停止索引,说明已经到了文件末尾。

根目录表字段说明

名称 偏移 长度 描述
DIR_Name 0 0xB 文件名8个字节,扩展名3个字节,文件名不够8字节用空格0x20填充
DIR_Attr 0xB 1 文件属性,卷标项是0x28,文件项是0x20,目录是0x10
保留 0xC 10
DIR_WrtTime 0x16 2 最后修改时间
DIR_WrtDate 0x18 2 最后修改日期
DIR_FstClus 0x1A 2 此条目对应开始的簇号
DIR_FileSize 0x1C 4 文件大小

如何寻找首簇号

根目录起始地址:1(boot区大小)+2(fat数)*9(fat的扇区数)*512(扇区大小)=0x2600h

​ 从boot记录获取根区记录数,缺省224条。读出所有记录,每条记录32字节,其开始字段为文件名,比较文件名匹配则找到记录,从首簇字段(偏1ah处)获得首簇号。

如何定位多级目录

​ e.g. a:\tem\tem.txt

​ 目录tem作为一个目录项存储在根目录区中。这样可找到tem目录,且目录项属性应该不是文件(0x20),而是其它。于是可以继续查找。

​ 目录tem本身存储为一个文件,和根目录区一样格式,由32字节的目录项组成。这样tem下的不论是文件还是子目录均由一个目录项登记。而tem目录文件的大小可以随意(不同于根目录),因为文件存储空间可以用fat表的簇链来表示。这样找tem目录项后,从首簇字段获取到tem的目录文件(即类似根目录表),遍历其中的32字节目录项,查找是否存在某个文件或目录即可。  如此,即可形成多层次的目录嵌套。

​ 先来看看fat12格式文件系统的格式:

数据区(长度非固定)
根目录区(长度非固定)
FAT12(9扇区)
FAT12(9扇区)
引导扇区(1扇区)

​ 可以计算得出,根目录区的起始地址为(1+9+9)*512=0x2600h,假定根目录区大小为0x1c00(软盘缺省值224*32Bytes),则数据区起始偏移为0x2600+0x1c00=0x4200

​ 又例如:Mytxt.txt的簇号为5,减去开始两个号分配给系统对用户区而言,实际是第4个簇(簇号为3)。前面已知用户数据区从0x4200开始,那么,文件实际起始偏移是0x4200+3*512 = 0x4800

“.”和".."

​ 空目录下会有两个目录项,一个是“.”,即2E,一个是“..”,即2E2E,代表了当前目录和上级目录。“.”是当前目录的别名,首簇就应该指向自己,而“..”首簇就改指向上级目录文件的首簇。如果上级目录是根目录,根目录区并没有在用户数据区分配内容。如何填写其簇号呢?其实只要让系统明白这是根目录即可。既然用户簇从2开始(其实这正是从2开始的原因,将特殊簇号留给特殊条目),用0或1作为根目录代表都可以,从实际看,用0代表根目录。

总结文件查找算法

1、先查看根目录区,是否有匹配的目录,如果有,通过对应目录项的首簇段获取其目录文件的首簇号。

2、通过fat表获得该目录文件的全部内容,遍历该文件,一次偏移32字节继续查找目录项,匹配查询路径中对应的项。如果查到则类似1,2查找对应的目录文件及目录项,否则说明找不到,结束。

3、如果在倒数第一层目录文件中找到了被查文件的目录项,从中获取首簇号,即可通过fat表访问该文件整个相关簇。

删除一个文件

​ 目录项第一个字节修改为E5代表删除。

回收已用的簇

​ 在fat表中,从被删除文件的首簇开始,将每个fat项置为00,实际文件扇区内容不用修改,这应该就是所谓的标记删除了吧,所以我们可以找到e5打头的目录项尝试恢复文件嘿嘿~

如何创建一个文件

1、创建文件时,需要首先定位到文件所在的目录文件,然后查找目录项(以32字节为偏移递增),如果第一个字节为0或e5表示可用。

2、根据文件大小计算出需要的簇数目,然后从fat首部开始(第4个字节),查看值为0的项,如果是则可用。找到第一个为0的项,将其索引值(以0开始)写入步骤1找到的目录项的首簇段。接着搜寻为0的项,将其索引值写入前一步找到的项。这样形成一个链,如果是最后一簇,其对应的簇项的值为fff。

3、填写文件目录项的创建时间,属性,大小等字段。

调试

用好压2345打开文件系统,就可以直接看到里面的目录、文件,用于直观查看运行效果!但是细节的内容建议使用ultraEdit打开查看文件镜像二/十六进制码,确认格式是否正确。

LICENSE

MIT