基于Fat32文件系统的预分配

732 阅读12分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

  一、前言

    硬盘是用来存储数据的,为了使用和管理方便,这些数据以文件的形式存储在硬盘上。任何操作系统都有自己的文件管理系统,不同的文件系统又有各自不同的逻辑组织方式。例如:常见的文件系统有FAT,NTFS,EXT,UFS,HFS+等等。本博客是基于linux的FAT32文件系统讲解,应用于嵌入式产品磁盘存储的预分配。

二、FAT32文件系统结构

FAT32文件系统由DBR及其保留扇区,FAT1,FAT2和DATA四个部分组成,其机构如下图:

DBR 及保留区FAT1FAT2数据区

这些结构是在分区被格式化时创建出来的,含义解释如下:

DBR及其保留扇区:DBR的含义是DOS引导记录,也称为操作系统引导记录,在DBR之后往往会有一些保留扇区。

FAT1:FAT的含义是文件分配表,FAT32一般有两份FAT,FAT1是第一份,也是主FAT。

FAT2:FAT2是FAT32的第二份文件分配表,也是FAT1的备份。

DATA:DATA也就是数据区,是FAT32文件系统的主要区域,其中包含目录区域。

保留区从第一扇区开始,保存了该逻辑盘每扇区字节数,每簇对应的扇区数等等重要参数和引导记录,之后还留有若干保留扇区。

文件分配表区共保存了两个相同的文件分配表,因为文件所占用的存储空间(簇链)及空闲空间的管理都是通过 FAT 实现的,FAT如此重要,保存两个以便第一个损坏时,还有第二个可用。文件系统对数据区的存储空间是按簇进行划分和管理的,簇是空间分配和回收的基本单位,即,一个文件总是占用若干个整簇,文件所使用的最后一簇剩余的空间就不再使用,而是浪费掉了。

根目录区(ROOT 区)是不固定区域、不固定大小的,可看作是数据区的一部分。一般情况下从第二簇开始使用,大小视需要增加。

2.1、WinHex工具磁盘分析Fat32文件系统

    2.1.1选择打开磁盘

                               

2.1.2选择磁盘

                               

                              

WinHex工具分析出Fat32文件系统中的各个分区信息。

三、分析FAT32文件系统的DBR

  FAT32文件系统的DBR有5部分组成,分别为跳转指令,OEM代号,BPB,引导程序和结束标志。如下图是一个完整的FAT32文件系统的DBR。

跳转指令:本身占2字节它将程序执行流程跳转到引导程序处。

OEM代号:这部分占8字节,其内容由创建该文件系统的OEM厂商具体安排。

BPB:FAT32的BPB从DBR的第12个字节开始,占用79字节,记录了有关该文件系统的重要信息,各参数解释如下表:

起始字节定义字节数备注
0x0跳转指令3
0x3文件系统标志和版本8有各种默认值:MSDOC5.0
0x0B每个扇区字节数2有的可能是1024、2048、4096
0x0D每簇扇区数1这个值不能为0,而且必须是2的整数次方,比如1、2、4、8、16、32、64、128.但是这个值不能使每个簇超过32KB字节
0x0E保留扇区数2
0x10Fat表分数2
0x11Fat16中根目录的文件总数2
0x13FAT16扇区总数2
0x15哪种储存介质1
0x161个FAT16 表所占的扇区数2
0x18每磁道扇区数2仅仅对于有“特殊形状”(由磁头和柱面每 切割为若干磁道)的存储介质有效,63(0x00 3F)
0x1A磁头数2仅仅对特殊的介质才有效,255(0x00 FF)
0x1CEBR分区之前所隐藏的扇区数4
0x20文件系统总扇区数4
0x24每一个FAT32表占用扇区数4
0x28标记2此域FAT32 特有
0x2A根目录起始簇号4默认为2
030FSINFO(文件系统信息扇区)扇区号2文件系统信息扇区默认为1,该扇区为操作 系统提供关于空簇总数及下一可用簇的信息,参考表:2.1.2
0x32备份引导扇区的位置2备份引导扇区总是位于文件系统 的6号扇区
0x34FAT 系统待扩展使用12
0x401
0x411
0x421
0x43卷序列号4通常为一个随机值
0x47卷标11建立文件系统的时候指定了卷 标,会保存在此
0x52文件系统格式的ASCII码8Fat32
0x5A未使用410
0x1FE签名标记2默认0x55 0xAA

3.1、引导扇区数据解析

                           

有用的内容用彩色线标志下

⑴.灰色线内容:EB 59 90 跳转指令

⑵.灰色点线内容:4D 53 44 4F 53 35 2E 30 为厂商标志和os 版本号,这里是MSDOS5.0

⑶.红色部分:00 20 (偏移地址0BH,长度2)注意这里数据的布局,高地址放高字节,低地址放低字节(数据为小端格式组织),所以数据应该是0200,就是512。表示的意思是,该磁盘每个扇区有512个字节。有的可能是1024、2048、4096.

⑷.黄色部分:08 (偏移地址0DH,长度1)表示的意思是每个簇有8个扇区。这个值不能为0,而且必须是2的整数次方,比如1、2、4、8、16、32、64、128.但是这个值不能使每个簇超过32KB字节。

⑸.蓝色部分:24 00 (偏移地址0EH,长度2),转换一下,就是00 24,意思是保留区域中的保留扇区数为36个。那么就可以知道下面的FAT1区的开始的地址就是:0x24*0x200(每个扇区的字节数)=0x4800,

⑹.粉色部分:02 (偏移地址10H,长度1),此卷中的FAT结构的份数为2,另外一个是备份的。

⑺.黑色部分:C6 03  (偏移地址24H,长度2)转换一下,03C6,每个FAT占用的扇区数。那么每个扇区占用的字节数就是0x03c6*200=78C00。根据启动区、FAT1、FAT2、根目录、数据区的次序,可以依次计算出它们的地址了。

启动区:理所当然是0x00;

FAT1:0x4800;

FAT2:0x4800 + 0x78C00 = 7D400;

根目录区:7D400 + 78C00 = F6000;

数据区的地址,等等再计算。这个只是计算,可以看看是不是和实际的一致。

Fat1起始地址:

                             

Fat2起始地址:

                             

根目录起始地址:

                             

为什么要计算SD数据的读取要给出地址,而且每次读取都是一个整扇区,512个字节。找出这些地址后,可以很方便的找到数据。

3.2、文件系统信息扇区数据解析

FAT32文件系统在DBR的保留扇区中安排了一个文件系统信息扇区,用以记录数据区中空闲簇的数量及下一个空闲簇的簇号,该扇区一般在分区的1号扇区,也就是紧跟着DBR后的一个扇区,其内容如下:

起始字节定义字节数备注
0x00扩展引导标志40x52526141
0x04未使用480全部置0
0x1E4FSINFO签名:40x72724161
0x1E8文件系统的空簇数4
0x1EC下一可用簇号4
0x1F0未使用14
0x1FE签名标记2默认0x55 0xAA

示例数据如下:

                                             

 52 52 61 41:拓展引导标签

接下来480字节未使用,如果安装了操作系统在这个分区上的话应该是有用的。

 72 72 41 61:文件系统信息签名

 00 14 56 7F:空闲簇数,约为20.3Gb

 00 00 00 03:下一个空闲簇号

 接下来的14个字节:未用

 55 AA:结束标志

引导程序代码:FAT32的DBR引导程序占用420字节,对于没有安装操作系统的分区来说这段程序是没有用处的。

结束标志:DBR的结束标志与MBR,EBR的结束标志相同,为“55 AA”。

四、分析FAT32文件系统的FAT表

FAT32 系统簇号用32 位二进制数表示,大致从 00000002H 到 FFFFFEFFH 个可用簇号。FAT表按顺序依次记录了该盘各簇的使用情况,是一种位示图法。每簇的使用情况用 32 位二进制填写,未被分配的簇相应位置写零;坏簇相应位置填入特定值;已分配的簇相应位置填入非零值,具体为:如果该簇是文件的最后一簇,填入的值为 FFFFFF0FH,如果该簇不是文件的最后一簇,填入的值为该文件占用的下一个簇的簇号,这样,正好将文件占用的各簇构成一个簇链,保存在 FAT 表中。0000000H、00000001H两簇号不使用, 其对应的两个 DWORD 位置(FAT 表开头的 8 个字节)用来存放该盘介质类型编号。FAT 表的大小就由该逻辑盘数据区共有多少簇所决定,取整数个扇区。

                                       

Fat表编号从0开始计数,每4字节表示数据区每个簇的使用情况,编号为0和1的簇用来表示存放该盘介质类型编号,所以簇号一般从2开始计数,且簇号2一般默认用来存储根目录簇的使用情况。

4.1 FAT表结构及作用

(1)FAT32文件一般有两份FAT,他们由格式化程序在对分区进行格式化时创建,FAT1是主,FAT2是备份。

(2)FAT1跟在DBR之后,其具体地址由DBR的BPB参数中指定,FAT2跟在FAT1的后面。

(3)FAT表由FAT表项构成,我们把FAT表项简称FAT项,每个FAT项占用4字节。

(4)每个FAT项都有一个固定的编号,这个编号从0开始。

(5)FAT表项的前两个FAT项为文件系统保留使用,0号FAT为介质类型,1号FAT为文件系统错误标志。

(6)分区的数据区中每个簇都会映射到FAT表中的唯一一个FAT项,因为0号FAT和1号FAT被系统占用,用户的数据从2号FAT开始记录。

(7)如果某个文件占用很多个簇,则第一个FAT项记录下一个FAT项的编号(既簇号),如果这个文件结束了,则用“0F FF FF FF”表示。

(8)分区格式化后,用户文件以簇为单位存放在数据区中,一个文件至少占用一个簇。

(9)FAT的主要作用是标明分区存储的介质以及簇的使用情况。

4.2 定位FAT绝对位置的方法如下:

(1)首先从MBR的分区表中得知分区的起始扇区,偏移到此扇区。

(2)从DBR的BPB中得知DBR的保留扇区数,FAT表的个数,FAT表的大小。

(3)因此FAT1=分区起始扇区+DBR保留扇区,FAT2=分区起始扇区+DBR保留扇区+FAT1。

五、分析FAT32文件系统的数据区

数据区的位置在FAT2的后面,具体定 位方式如下;

1、通过MBR中的分区表信息得知分区的起始位置。

2、通过分区中DBR得知DBR的保留扇区数以及FAT表的大小,FAT表的个数。

3、通过上面的信息就可以找到数据区的起始位置,根目录=数据区的起始扇区+(簇大小*2)。

数据区的内容主要由三部分组成:根目录,子目录和文件内容。在数据区中是以“簇”为单位进行存储的,2号簇被分配给根目录使用。

5.1根目录区详解

根目录的定位方式为:根目录=分区起始扇区+DBR保留扇区+(FAT表2)+(簇大小2)

                                   

FAT32文件系统中,分区根目录下的文件和目录都放在根目录区中,子目录中的文件和目录都放在子目录区中,并且没每32个字节为一个目录项,每个目录项纪录着一个目录或文件(也可能是多个目录项记录一个文件或目录),如上图所示就是一个目录项。

在FAT32文件系统中,目录项可以分为四类:卷标目录项、“.”和“..”目录项、短文件名目录项、长文件名目录项。

卷标目录项:卷标就是分区的名字,可以在格式化分区时创建,也可以随意修改,长度为11字节。

“.”和“..”目录项:“.”表示当前目录,“..”表示上一层目录。这两个目录项多存在子目录中。

短文件名目录项:所谓短文件名既文件名的“8.3”格式,此格式支持主文件名不能超过8字节,扩展名不能超过3字节。短文件名目录始终存放在一个目录项中。

5.2、目录项32字节解析

根目录区中的目录项变化较多,一个目录项仍占 32 字节,可以是文件目录项、子目录项、卷标项(仅根目录有)、已删除目录项、长文件名目录项等。全部 32 字节的定义如下:

起始字节定义字节数备注
0文件正名8
8文件扩展名3
11文件属性1按二进制位定义,最高两位保留未用,0至5位分别是只读位、隐藏位、系统位、卷标位、子目录位、归档位。
12长文件名扩展2用来存储其对应的短文件名目录项的文件名字节校验和等
14文件创建时间216 位二进制的文件建立时间,其中的高5位为小时,次6位为分钟,最低5位为秒[0-32],一个度量单位为2秒
16文件创建日期216 位二进制的文件建立日期,其中的高7位为相对于1980年的年份值,次4位为月份,后5位为月内日期。
18文件最新访问日期2参考文件创建日期
20文件起始簇高16位2
22文件最新修改时间2参考文件创建时间
24文件最新修改日期2参考文件创建日期
26文件起始簇低16位2
28文件长度4

5.3、文件数据存放

    从文件的大小可以计算出,需要占用多少个簇。根据前面的数据,每个簇放8个扇区,每个扇区512个字节,那么一个簇的空间就是4096字节了,4KB。那么11639字节需要3个簇,这三个簇的开始的地址就可以计算出来了。

Fat表1如下:

                      

    上面已经知道开始簇开始的地址了:03,Fat表1中编号为3的簇中数据数据为:04 00 00 00 ,表示文件占用下一个簇为第4簇,同理编号为4簇告诉我们,占用编码为5的簇,编号为5的簇保存着:FF FF FF 0F告诉我们这是一个结束簇,刚好文件占用了三个簇,簇编号为3、4、5。到这里有个很重要的概念出来了,预分配文件怎么形成?1、在根目录区建立一个有效的32字节目录项;2、根据目录项中的起始簇号和文件大小,更新两份Fat表中的相关簇记录。即可完成文件的预分配工作,但文件中的数据失效数据。

第三簇起始地址:F6000(根目录区地址)+ (03-2)*08(多少扇区每簇)*200(多少字节每扇区)=F7000

第四簇起始地址:F6000+(04-2)08200 = F8000

第五簇起始地址:F6000+(05-2)08200 = F9000

簇3起始数据:

                          

簇4起始数据:

                        

簇5起始数据:                  

                        

六、FAT32文件系统总结

上述的内容已经简单的介绍了FAT32文件系统,下面根据定位某个文件来详细的了解FAT32文件系统是如何存储数据的。

1、根据磁盘0号扇区MBR的分区表得知分区的起始位置,既DBR;

2、根据DBR中BPB记录的信息,得知DBR保留扇区数,FAT的大小,FAT的个数;

3、根据上述信息可以算出数据的起始位置,数据区=分区起始扇区+DBR保留扇区+(FAT表*2);

4、计算根目录所在的绝对位置,根目录=数据区的起始扇区+(簇大小*2);

5、根据根目录中的目录项信息得知,根目录下的文件以及子目录等所对应的簇;

6、根据文件的簇号就可以找到文件内容的绝对扇区;

7、如果一个文件占用多个簇,则需要根据FAT表项得知下一个数据簇的簇号。

7、如果根目录下的目录项是子目录的话,则根据子目录中的文件目录项得知文件内容的簇号;

8、如果子目录中还有子目录的话,则根据这种方法一直找下去即可。

七、预分配文件生产原理

    一个新的磁盘在分区和格式化为Fat32文件系统之后,读Fat32文件系统的启动扇区信息,获取Fat表的起始地址(一般2个fat表),数据区的起始地址。数据区起始地址之后的第一个簇是根目录区,根目录区中每32个字节记录一个短目录项,所以当我们规定的文件名符合短目录项命名规则(文件正名小于等于8字节,文件扩展名为3字节)时,可以通过直接偏移到根目录区,将每一生成好的文件信息按32字节目录项规则填充,同时对系统Fat表中簇的使用记录进行同步更新,理论上就完成了文件系统的预分配工作。

7.1、检测系统磁盘个数

根据/proc/partition系统文件信息,确定设备中存在几个磁盘文件,并初始化磁盘的基本信息,挂在磁盘到指定目录。

7.2、预分配文件系统生成

    1、读取磁盘启动区的基本信息,解析磁盘扇区大小、簇大小、Fat1起始地址和大小、Fat2起始地址和大小、数据区起始地址。数据区起始地址即根目录起始地址。

    2、在根目录区新建/video目录(写入32字节目录项信息),并指定其数据(该目录下文件或目录的“目录项”)起始簇为03号簇,同时更新Fat表1,2的03簇信息(00簇与01簇用来存放该盘介质类型编号,02簇用来存放根目录,所以从03簇开始)。

    3、在03簇的起始地址新建 . (当前目录)和 ..(上一级目录)目录项(写入32字节目录项信息),当前目录项数据起始簇号为03,上一级目录的数据起始簇号为00,更新Fat表1、2。当前目录和上一级目录占用03簇的前64字节。

    4、从03簇的第三个目录项开始写入Video0的录像信息等文件,同时根据Video0文件大小,计算出视频文件使用多少簇。根据簇的使用情况更新Fat表1、2,如果该簇是文件的最后一簇,填入的值为 FFFFFF0FH,否则填入的值为该文件占用的下一个簇的簇号。假设Video0专用了6个连续的簇(6-11),则在Fat表06-11簇中依次写入:

0x00000007 0x00000008 0x00000009 0x0000000A 0x0000000B 0xFFFFFF0F信息,则完成Video0视频文件的预分配。

7.3、实例解析

下面使用一个64GB的SD卡做实例讲解。

1、使用WinHex.exe工具打开SD卡所在分区,这里是G盘。

                    

在启动扇区中取出扇区大小、每簇扇区数等重要信息:

偏移地址数据项大小(字节)
0x0B扇区大小0200
0x0D每簇扇区数20
0x0E保留扇区数0006
0x24一个FAT32表所占扇区数73481.

2.、计算出簇大小、FAT32表大小、FAT表地址、根目录地址。

簇大小          =   每簇扇区数      × 扇区大小            =   4000

FAT32表大小     =   扇区大小        × FAT32表扇区数   =   E69000

FAT1表地址      =   扇区大小        × 保留扇区数          =   C00

FAT2地址        =   FAT1位置        +   FAT32大小       =   E69C00

根目录地址      =   FAT2位置        +   FAT32大小           =   1CD2C00

第3簇地址 =   根目录地址 + (3-2)× 簇大小 =   1CD6C00

第4簇地址 =   根目录地址 + (4-2)× 簇大小 =   1CDAC00

3、在根目录区新建/video目录及相关预分配文件。

(1) 在根目录区写入短目录结构的/video目录项,数据区对应为03簇。

                          

(2) 更新两张 FAT表相应簇的使用情况,这里由于/video目录下文件数较多,使用了两个簇,即03簇与04簇。所以在FAT表中03簇对应地址填写入下一簇的地址(04 00 00 00),04簇是最后一簇所以写入FF FF FF 0F。

                         

(3) 在03簇(图-6.3.4.3)与04簇(图-6.3.4.4)数据区依次写入当前目录(./)、上级目录(../)、预分配文件(bsjVideo0)目录项。

                        

                       

\