一、嵌入式之FAT32文件系统(1)

1 FAT32文件系统介绍

参考文件

FAT32文件系统有几个基本的几个概念:

  • MBR(Master Boot Record,主引导记录)
  • DPT(Disk Partition Table,磁盘分区表)
  • DBR(Dos boot record,Dos引导记录)
  • FAT(File Allocation Table,文件分配表)

先拿一个真实的4G SD卡分析数据:

使用winhex物理方式查看,截一部分图:

一、嵌入式之FAT32文件系统(1)_第1张图片
MBR.png

1.1 主引导记录(MBR)

全称Master Boot Record,即主引导记录。
主引导记录分为两个部分,一个部分是前446字节,另外一个部分是后64字节。

1.1.1 前446字节

前446个字节,一般取值为0,不过有的时候也会有其他的设置值。

1.1.2 后64字节

这部分也叫DPT,全称Disk Partition Table,即磁盘分区表。
磁盘分区表有4个区,每个区有16字节,总体是64字节。因此,MBR字节数为512字节,刚好是一个扇区的数量。

DPT的4个部分,每一个部分的16字节含义如下表:

偏移 字节数 功能
00H 1字节 引导指示符,0x80表示可从此分区引导操作系统,通常取值为0。
01H 1字节 开始磁头
02H 2字节 前6位为开始扇区,后10位为开始柱面
04H 1字节 系统id,用于定义分区类型
05H 1字节 结束磁头
06H 2字节 前6位为结束扇区,后10位为结束柱面
08H 4字节 分区的开始扇区地址
12H 4字节 分区的总扇区数

00 82 03 00 0B E6 DC CA 00 20 00 00 00 E0 ED 00(16进制)

这里,就贴出来上面截图的数据内容。(我们使用的是小字节序)
0x00 :
通常的取值。

0x82 :
开始磁头。

0x03 0x00 :
实际为0x0003,按照2进制编码为0000 0000 0000 0011。
那么开始扇区为:0。
开始柱面为:3。

0x0B :
分区类型,为Win95 FAT32类型。

0xE6 :
结束磁头为230。

0xDC 0xCA:
实际为0xCADC,按照2进制编码为1101 1100 1100 1010。
那么结束扇区为:55。
结束柱面为:220。

0x00 0x20 0x00 0x00 :
实际为:0x00002000,也就是8192,为分区的开始扇区地址。那么我们后面就可以从这里去找DBR。

0x00 0xE0 0xED 0x00 :
实际为:0x00EDE000,也就是15589376,为分区的总扇区数。
从这里其实可以算出SD卡的容量。
也就是:
分区大小:15589376x512 = 7981760512。这个值大约是7.612G。
从物理0地址到起始地址:8192*512 = 4194304
那么总容量为:7981760512+4194304 = 7985954816。

1.2 分区引导扇区(DBR)

该部分包括一个叫BPB的内容。

先截出DBR部分的实际SD卡上的内容:

一、嵌入式之FAT32文件系统(1)_第2张图片
MBR.png

在WinHex下使用逻辑磁盘打开FAT32文件系统的存储介质来看,偏移位置与表示的含义有如下表所示:

偏移 字节数 格式
00H 3字节 EB 58 90
03H 8字节 4D 53 44 4F 53 35 2E 30(MSDOS5.0)
0BH 25字节 如下表(BPB描述)

25字节的分区块(BPB):

偏移 字节数 功能 举例
0BH 2字节 扇区字节数 0X0200,512字节
0DH 1字节 每簇扇区数 0x08,即每簇包括8个扇区
0EH 2字节 保留扇区数 0x0024,即保留36个扇区
10H 1字节 FAT表份数 0x02,即两个FAT表
11H 2字节 保留 0x0000
13H 2字节 保留 0x0000
15H 1字节 介质类型 0xF8即本地硬盘
16H 2字节 保留 0x0000
18H 2字节 每磁道扇区数 0x003F,即每磁道63扇区
1AH 2字节 磁头数 0x00FF,即255个磁头
1CH 4字节 隐藏扇区数 0x1F80,即8064个隐藏扇区
20H 4字节 磁盘总扇区数 0x0077F080,即总共7860352个扇区
24H 52字节 扩展分区参数块(扩展BPB) 细分如下表

扩展分区BPB:

偏移 字节数 功能 举例
24H 4字节 FAT表占用扇区数 0x00001DEE,即FAT表占7662个扇区
28H 4字节 未用 0x00000000
2CH 4字节 根目录入口簇号 0x00000002,即根目录从02号簇开始
30H 2字节 文件系统信息扇区号 0x0001,即扇区1
32H 2字节 备份引导扇区的位置 0x0006,即6号扇区(第7个扇区)
34H 12字节 未用 00 00 00 00 00 00 00 00 00 00 00 00
40H 1字节 物理磁盘号 00
41H 1字节 未用 00
42H 1字节 扩展引导标志 00
43H 4字节 磁盘序列号 通常为一随机数
47H 11字节 卷标ASCII 4E 4F 20 4E 41 4D 45 20 20 20 20 即NO NAME
52H 8字节 文件系统格式ASCII 46 41 54 33 32 20 20 20即FAT32
5AH 420字节 分区引导代码
1FEH 2字节 有效扇区结束标志 55 AA

按照定义,将实际的图 MBR.png分析如下:
从偏移为0x0BH地址开始:
00 02 10 96 04 02 00 00 00 00 F8 00 00 3F 00 FF 00 00 20 00 00 00 E0 ED 00 B5 1D 00 00

00 02 :
即0x0200,表示扇区字节数,也就是512字节。

10:
即0x10,每簇扇区数为16。也就是16512=81024=8K。

96 04:
即0x0496,保留扇区数为1174。

02:
即0x02,FAT表份数为2。

00 00:
即0x0000,为保留。

00 00:
即0x0000,为保留。

F8:
即为本地硬盘。

00 00:
即0x0000,为保留。

3F 00:
即0x003F,即每磁道扇区数为63。

FF 00:
即0x00FF,即磁头数为255。

00 20 00 00:
即0x00002000,即隐藏扇区数为8192。

00 E0 ED 00:
即0x00EDE000,即磁盘总扇区数为15589376。

B5 1D 00 00 :
即0x001DB5,即FAT表占用扇区数为7605。

好了,根据这些内容,可以计算出两个参数:

FAT1的开始扇区 = 分区开始扇区+ 保留扇区=8192+1174 = 9366。
FAT2的开始扇区 = FAT1的开始扇区+FAT表占用的大小 = 9366 + 7605 = 16971。
首目录簇 = FAT1的开始扇区+FAT的表份数 x FAT表占用的大小=9366+2*7605 = 24576。

继续追踪,找到首目录簇中的已经新建的文件。

a.png
b.png
一、嵌入式之FAT32文件系统(1)_第3张图片
a.b info.png

现在,先解析粘贴出来的每个部分的内容的含义。

具体内容下面的FAT中会说。

a.txt部分的解析:
41 20 20 20 20 20 20 20 54 58 54 20 18 8B 2A 90
96 4A A1 4A 00 00 0F 8C A1 4A 03 00 10 00 00 00

41 20 20 20 20 20 20 20:
表示文件名:“A TXT”

20 :
表示的是文件的属性。归档。

18:
为系统保留。

8B:
创建时间的10ms位。也就是1390ms。

2A 90:
也就是0x902A,换成2进制为1001 0000 0010 1010 。表示的是创建时间。
细分如下:

位数 含义
5bit
6bit
5bit 2秒

则时间值为:
时:0x12 = 18,
分:0x1 = 1,
秒:0xAx 2s + 1390ms= 10x 2s + (1390ms) = 21s,
所以创建时间为18:01:21。

96 4A:
也就是0x4A96,换成2进制为0100 1010 1001 0110,表示的是创建日期。
细分如下:

位数 含义
7bit
4bit
5bit

则日期值为:
年:1980+0x25 = 2017,
月:0x4 = 4,
日:0x16= 22,

所以,创建日期为2017年4月22日。

A1 4A:
也就是0x4AA1,换成2进制为0100 1010 1010 0001,表示的是最后访问日期。
则日期为:
年:1980+0x25 = 2017,
月:0x5 = 5,
日:0x1= 1,
所以,最后访问日期为2017年5月1日。

00 00:
起始簇高16位。

0F 8C:
也就是0x8C0F,换成2进制为1000 1100 0000 1111,表示的是最近修改时间。

时:0x11 = 17,
分:0x20 = 32,
秒:0xf x 2 = 30s,
所以最近修改时间为17:32:30。

A1 4A:
也就是0x4AA1,换成2进制为0100 1010 1010 0001,表示的是最近修改日期。
则日期为:
年:1980+0x25 = 2017,
月:0x5 = 5,
日:0x1= 1,
所以,最近修改日期为2017年5月1日。

03 00:
即0x0003,表示起始簇低16位,也就是说,起始簇高位与起始簇低位相或,得到0x00000003,起始簇为3。

10 00 00 00:
即0x00000010,表示文件数据长度,也就是16字节。

分析完a.txt,b.txt也一样分析即可。

从而可以得到的是,a.txt的内容位置在:(3-2)*16+24576 = 24592上。
后使用winhex进行验证,确认是正确的。

1.3 文件分配表(FAT)

文件分配表(FAT),是FAT文件系统中用于磁盘数据索引和定位而引进的一种链式结构。在FAT文件系统中,文件的存储依照FAT表制定的簇链式数据结构来进行。同时,FAT文件系统将组织数据时使用的目录也抽象为文件,以简化对数据的管理。

1.3.1 FAT1表位置的定位

如DBR所述,偏移0EH处存储了保留扇区的个数,而保留扇区数指的就是当前分区内DBR到FAT表之间的所有扇区的个数(包括DBR但不包括FAT表)。据此,可以定位FAT表所在的起始偏移位置了。

1.3.2 FAT2位置的定位

如DBR所述,偏移24H处存储了保留扇区的个数,知道FAT2是紧邻FAT1的。那么FAT2表的位置为:FAT1的起始偏移地址+FAT1的大小。

1.3.3 FAT表特性

FAT表由一系列大小相等的FAT表项组成,它有如下特性:

  • FAT32中每个簇的簇地址,使用32bit(4个字节)记录在FAT表中。FAT表中的所有字节位置以4个字节为单位进行划分,并对所有划分后的位置由0进行地址编号。0号地址与1号地址被系统保留并存储特殊标志内容。从2号地址开始,每个地址对应于数据区的簇号,FAT表中的地址编号与数据区中的簇号相同。我们称FAT中的这些地址为FAT表项,FAT表项中记录的值称为FAT表项值。
    当文件系统被创建,也就是进行格式化操作时,分配给FAT区域的空间将会被清空,在FAT1与FAT2的0号表项与1号表项写入特定值。由于创建文件系统的同时也会创建根目录,也就是为根目录分配了一个簇空间,通常为2号簇,所以2号簇所对应的2号FAT表项也会被写入一个结束标记。
    如果某个簇未被分配使用,它所对应的FAT表项内的FAT表项值即用0进行填充,表示该FAT表项所对应的簇未分配使用。
    当某个簇已被分配使用时,则它对应的FAT表项值也就是该文件的下一个存储位置的簇号。如果该文件结束于该簇,则在它的FAT表项中记录的是一个文件结束标记,对于FAT32而言,代表文件结束的FAT表项值为0x0FFFFFFF。
    如果某个簇存在坏扇区,则整个簇会用FAT表项值0x0FFFFFF7标记为坏簇,不再使用,这个坏簇标记就记录在它所对应的FAT表项中。
    由于簇号起始于2,所以FAT表的0号表项与1号表项不与任何簇对应。FAT32的0号表项值总是“F8FFFF0F”。1号表项可能被用于记录脏标志,以说明文件系统没有被正常卸载或者磁盘表面存在错误。不过此值似乎并不重要,因此我们只要了解就可以。正常情况下,1号表项值为“FFFFFFFF”或“FFFFFF0F"。
    在文件系统中新建文件时,如果新建的文件只占用一个簇,为其分配的簇所对应的FAT表项将会被写入结束标记。如果新建的文件不只占用一个簇,则在其所占用的每个簇对应的FAT表项中写入为其分配的下一簇的簇号,在最后一个簇对应的FAT表项中写入结束标记。
    新建目录时,只为其分配一个簇的空间,对应的FAT表项中写入结束标记。当目录增大超出一个簇的大小时,将会在空闲空间中继续为其分配一个簇,并在FAT表中为其建立FAT表链以描述它所占用的簇情况。
    对文件或目录进行删除操作时,它们所对应的FAT表项将会被清空,设置为0以表示其所对应的簇处于未分配状态。

1.4 根目录区

在FAT32文件系统中,根目录的位置不再硬性地固定,可以存储在分区内可寻址的任意簇内,不过通常根目录是最早建立的(格式化就生成了)目录表。所以,我们看到的情况基本上都是根目录首簇紧邻FAT2,占簇区顺序上的第1个簇(即2号簇)。同时,FAT32文件系统将根目录当做普通的数据文件来看,所有没有了目录项数的限制,在需要的时候可以分配空簇,存储更多的目录项。

1.4.1 起始偏移地址定位

  • 根目录起始扇区=保留扇区数+FAT×2+(起始簇-2)x每簇的扇区数
    目录区的一个目录项占用32个字节,可以是长文件名目录项、文件目录项、子目录项等。

对于短文件名格式的目录项:

字节偏移(16进制) 字节数 定义
00H~07H 8字节 文件名
08H~0AH 3字节 扩展名
0BH* 1字节 属性字节(如下表)
0CH 1字节 系统保留
0DH 1字节 创建时间的10毫秒位
0EH~0FH 2字节 文件创建时间
10H~11H 2字节 文件创建日期
12H~13H 2字节 文件最后访问日期
14H~15H 2字节 文件起始簇号的高16位
16H~17H 2字节 文件最近的修改时间
18H~19H 2字节 文件最近的修改日期
1AH~1BH 2字节 文件起始簇号的低16位
1CH~1FH 4字节 文件的长度

注意:*表示此字段在段文件目录项中,不可取值0FH。若取值为0FH,目录段为长文件名目录段。

0BH字段取值如下:

字段 取值 定义
0BH 00000000 读写
0BH 00000001 只读
0BH 00000010 隐藏
0BH 00000100 系统
0BH 00001000 卷标
0BH 00010000 子目录
0BH 00100000 归档

FAT32的一个重要的特点是完全支持长文件名。长文件名依然是记录在目录项中的。为了低版本的OS或程序能正确读取长文件名文件,系统自动为所有长文件名文件创建了一个对应的短文件名,使对应数据既可以用长文件名寻址,也可以用短文件名寻址。不支持长文件名的OS或程序会忽略它认为不合法的长文件名字段,而支持长文件名的OS或程序则会以长文件名为显式项来记录和编辑,并隐藏起短文件名。

  • 当创建一个长文件名文件时,系统会自动加上对应的短文件名,其原则如下:
    (1)取长文件名的前6个字符加上"~1"形成短文件名,扩展名不变。
    (2)如果已存在这个文件名,则符号"~"后的数字递增,直到5。

长文件名的实现有赖于目录项第12字节属性字节,当此字节的值为0FH时,支持长文件名的系统会将其当做长文件名的依据,而只支持短文件名的系统会认为是异常而忽略掉。系统将长文件名以13个字符为单位进行切割,每一组占据一个目录项。所以可能一个文件需要多个目录项,这时长文件名的各个目录项按倒序排列在目录表中,以防与其他文件名混淆。
长文件名中的字符采用unicode形式编码,每个字符占据2字节的空间。其目录项定义如:

字节偏移(16进制) 字节数 定义
00H 1字节 属性字节位意义,参考下表
01H~0AH 10字节 长文件名unicode码
0BH 1字节 长文件名目录项标志,取值0FH
0CH 1字节 系统保留
0DH 1字节 校验值(根据短文件名计算得出)
0EH~19H 12字节 长文件名unicode码
1AH~1BH 2字节 文件起始簇号(目前常置0)
1CH~1FH 4字节 长文件名unicode码

2 待续。。。

你可能感兴趣的:(一、嵌入式之FAT32文件系统(1))