【FatFs】FAT32文件系统协议总结(理论+实践)

相关文章

《【SDIO】SDIO、SD卡、FatFs文件系统相关文章索引》

1.前言

本篇文章主要是介绍FAT 格式分区内数据是如何存储的FAT 分区格式Microsoft 最早支持的分区格式,依据 FAT 表中每个簇链的所占位数(有关概念,后面会讲到)分为 FAT12FAT16FAT32 种格式"变种",但其基本存储方式是相似的。我们在嵌入式系统中使用的最多的是FAT32,所以后面主要介绍的是FAT32

在介绍 FAT32文件系统前,我们需要先了解一下硬盘基本知识:磁头、磁道、扇区、柱面等,方便后面对FAT32文件系统的理解。

2.硬盘基本知识

硬盘基本概念包括:

  1. 盘片(platter)
  2. 磁头(head)
  3. 磁道(track)
  4. 扇区(sector)
  5. 柱面(cylinder)
  • 盘片 片面 和 磁头
    硬盘中一般会有多个盘片组成,每个盘片包含两个面,每个盘面都对应地有一个读/写磁头。受到硬盘整体体积和生产成本的限制,盘片数量都受到限制,一般都在5片以内。盘片的编号自下向上从0开始,如最下边的盘片有0面和1面,再上一个盘片就编号为2面和3面。如下图:
  • 扇区 和 磁道
    下图显示的是一个盘面,盘面中一圈圈灰色同心圆为一条条磁道,从圆心向外画直线,可以将磁道划分为若干个弧段,每个磁道上一个弧段被称之为一个扇区(图践绿色部分)。扇区是磁盘的最小组成单元,通常是512字节。(由于不断提高磁盘的大小,部分厂商设定每个扇区的大小是4096字节)
  • 磁头 和 柱面
    硬盘通常由重叠的一组盘片构成,每个盘面都被划分为数目相等的磁道,并从外缘的“0”开始编号,具有相同编号的磁道形成一个圆柱,称之为磁盘的柱面。磁盘的柱面数与一个盘面上的磁道数是相等的。由于每个盘面都有自己的磁头,因此,盘面数等于总的磁头数。 如下图
  • 磁盘容量计算
    存储容量 = 磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数

每个磁道的扇区数一样是说的老的硬盘,外圈的密度小,内圈的密度大,每圈可存储的数据量是一样的。
新的硬盘数据的密度都一致,这样磁道的周长越长,扇区就越多,存储的数据量就越大。

  • 块/簇
    磁盘块/簇是虚拟出来的概念,逻辑上的定义,多个扇区组合成一个块/簇。 扇区是物理上的概念,物理擦除、读写的最小单位。块/簇是操作系统中最小的逻辑存储单位。操作系统与磁盘打交道的最小单位是磁盘块/簇

Windows下如NTFS等文件系统中叫做在簇(cluster)
在在Linux下如Ext4等文件系统中叫做在块(block)
每个簇或者块可以包括2、4、8、16、32、64…2的n次方个扇区。

3.FAT卷的组织架构介绍

一个用FAT格式化的卷组织如下图所示:
在这里插入图片描述
下表描述了FAT卷上的每个组织结构:

组件描述
Boot Sector引导扇区:包含BIOS参数块,该参数块存储有关卷布局和文件系统结构的信息,
以及加载Windows 的引导代码。
Reserved Sectors保留扇区:在第一个FAT开始之前的扇区数量,包括引导扇区。
FAT 1原始FAT表(可以简单理解FAT表为目录表,记录数据存储的位置。)
FAT 2 (Duplicate)FAT表的备份(为了防止原始FAT表被破坏后可以恢复)
Root folder描述根目录分区中的文件和文件夹。
Other folders and all files包含文件系统中文件和文件夹的数据。

4.FAT32引导扇区(Boot Sector)

FAT32引导扇区在结构上与FAT16引导扇区非常相似,但是FAT32 BPB(BIOS Parameter Block)包含额外的字段。下表描述了用FAT32文件系统格式化的卷的引导扇区的各个部分。

字节位移字段长度字段名
0x003 个字节 跳转指令(Jump instruction)
0x03 8 个字节厂商标志和 os 版本号(OEM ID)
0x0B 53 个字节BPB(BIOS Parameter Block)
0x4026 个字节扩展 BPB(Extended BPB)
0x5A 420 个字节引导程序代码(Bootstrap code)
0x01FE2 个字节有效结束标志(End of sector marker)

下面的示例演示了FAT32卷上的引导扇区的十六进制数据:
在这里插入图片描述
下面两个表说明了FAT32卷的BPB和扩展的BPB的布局,示例值对应于FAT32卷上引导扇区的数据。

FAT32 分区的 BPB 字段
字节
位移
字段
长度
(字节)
对应取值名称和定义
0x0B20x0200扇区字节数(Bytes Per Sector) 硬件扇区的大小。
本字段合法的十进制值有 512、1024、2048 和 4096。对大多数磁盘来说,本字段的值为512
0x0D10x20每簇扇区数(Sectors Per Cluster),一簇中的扇区数。
一个卷默认的簇大小取决于该卷的大小。本字段的合法十进制值有 1、2、4、8、16、32、64 和 128。
0x0E20x092A保留扇区数(Reserved Sector) 第一个 FAT 开始之前的扇区数,包括引导扇区。
0x1010x02FAT 数(Number of FAT) 该分区上 FAT 的副本数。本字段的值一般为 2
0x1120x0000根目录项数(Root Entries) 只有 FAT12/FAT16 使用此字段。对 FAT32 分区而言,本字段必须设置为 0
0x1320x0000小扇区数(Small Sector) (只有 FAT12/FAT16 使用此字段)对 FAT32 分区而言,本字段必须设置为 0
0x1510xF8媒体描述符( Media Descriptor) 提供有关媒体被使用的信息。值 0xF8 表示硬盘,0xF0 表示高密度的 3.5寸软盘。
0x1620x0000每 FAT 扇区数(Sectors Per FAT) 只被 FAT12/FAT16 所使用,对 FAT32 分区而言,本字段必须设置为 0
0x1820x003F每道扇区数(Sectors Per Track) 包含使用 INT 13h 的磁盘的“每道扇区数”几何结构值。
该分区被多个磁头的柱面分成了多个磁道
0x1A20x00FF磁头数(Number of Head) 本字段包含使用 INT 13h 的磁盘的“磁头数”几何结构值。
0x1C40x0000003F 隐藏扇区数(Hidden Sector) 该分区上引导扇区之前的扇区数。在引导序列计算到根目录的数据区的绝对位移的
过程中使用了该值。本字段一般只对那些在中断 13h 上可见的媒体有意义。在没有分区的媒体上它必须总是为 0
0x2040x03B723C1 总扇区数(Large Sector) 本字段包含 FAT32 分区中总的扇区数
0x2440x00003B6B每 FAT 扇区数(Sectors Per FAT) (只被 FAT32 使用)该分区每个 FAT 所占的扇区数。计算机利用这个数和 FAT
数以及保留扇区数(本表中所描述的)来决定根目录从哪里开始。该计算机还可以从目录中的项数决定该分区的
用户数据区从哪里开始
0x2820x0000扩展标志(Extended Flag) (只被 FAT32 使用)该两个字节结构中各位的值为:
位 0-3:活动 FAT 数(从 0 开始计数,而不是 1).只有在不使用镜像时才有效
位 4-6:保留
位 7:0值意味着在运行时FAT被映射到所有的FAT,1值表示只有一个 FAT是活动的
位 8-15:保留
0x2A20x0000文件系统版本(File ystem Version) 只供 FAT32 使用,高字节是主要的修订号,而低字节是次要的修订号。
本字段支持将来对该 FAT32 媒体类型进行扩展。
0x2C40x00000002根目录簇号(Root Cluster Number) (只供 FAT32 使用) 根目录第一簇的簇号。
本字段的值一般为 2,但不总是如此
0x3020x0001文件系统信息扇区号(File System Information Sector Number) (只供 FAT32 使用)FAT32 分区的保留区中的
文件系统信息(File System Information, FSINFO)结构的扇区号。其值一般为 1。在备份引导扇区(Backup
Boot Sector)中保留了该 FSINFO 结构的一个副本,但是这个副本不保持更新
0x3220x0006备份引导扇区(Backup Boot Sector) 非“0”表示存储引导扇区副本的扇区号。该字段的值通常为6。
0x341212 个字节均为 0x00 保留(Reserved) (只供 FAT32 使用)供以后扩充使用的保留空间。本字段的值总为 0
FAT32 分区的扩展 BPB 字段
字节
位移
字段
长度
(字节)
对应取值名称和定义
0x4010x80物理驱动器号( Physical Drive Number) 与 BIOS 物理驱动器号有关。软盘驱动器被标识为 0x00,物理
硬盘被标识为 0x80,而与物理磁盘驱动器无关。一般地,在发出一个 INT 13h BIOS 调用之前设置该值,
具体指定所访问的设备。只有当该设备是一个引导设备时,这个值才有意义
0x4110x00保留(Reserved) FAT32 分区总是将本字段的值设置为 0
0x4210x29扩展引导标签(Extended Boot Signature) 本字段必须要有能被 Windows 2000 所识别的值 0x28 或 0x29
0x4340xBC0C96E0分区序号(Volume Serial Number) 在格式化磁盘时所产生的一个随机序号,它有助于区分磁盘
0x4711"NO NAME"卷标(Volume Label) 本字段只能使用一次,它被用来保存卷标号。现在,卷标被作为一个特殊文件保存在根目录中
0x528"FAT32"系统 ID(System ID) FAT32文件系统中一般取为"FAT32"

通过上面Boot Sector表格了解到重要信息总结如下:

  • 扇区字节数和每簇扇区数
    硬件扇区的大小为512Bytes,每个簇占用扇区数为32个扇区
  • 保留扇区数
    我们可以通过保留扇区数可以找到FAT表的起始位置,FAT Table Start Address = 0x092A * 512 = 0x125400 Bytes。确实在地址0x125400位置找到了FAT表,如下:(后面还会详细分析FAT表)
    在这里插入图片描述
  • 总扇区数
    通过总扇区数可以计算得到SD卡的总容量大小:0x03B723C1 * 512 = 31914951168 Bytes
    在这里插入图片描述
  • 根目录开始地址
    根目录开始地址的计算公式如下:
    根目录开始地址 = ((保留扇区数) + (每 FAT 扇区数) * (FAT 数)) * 扇区字节数
    根目录开始地址 = (0x092A + 0x00003B6B * 0x02) * 512 = 0x1000000 Bytes
    在这里插入图片描述

5.FAT32根目录(Root folder)

根文件夹描述根分区中的文件和文件夹。FAT32根文件夹结构的结构分为2种:短文件格式长文件格式

  • 短文件格式

    1. 对于短文件名,系统将文件名分成两部分进行存储,即主文件名+扩展名。0x0~0x7字节记录文件的主文件名,0x8~0xA记录文件的扩展名,取文件名中的ASCII码值。不记录主文件名与扩展名之间的"."主文件名不足 8 个字符以空白符(20H)填充,扩展名不足 3 个字符同样以空白符(20H)填充。0x00 偏移处的取值若为 00H,表明目录项为空;若为E5H,表明目录项曾被使用,但对应的文件或文件夹已被删除。(这也是误删除后恢复的理论依据)。文件名中的第一个字符若为“.”“..”表示这个簇记录的是一个子目录的目录项。“.”代表当前目录“..”代表上级目录
    2. 0xB的属性字段:可以看作系统将 0xB的一个字节分成 8 位,用其中的一位代表某种属性的有或无。如 00000101 就表示这是个文件,属性是只读、系统。
    3. 0x0E~0x0F文件创建时间字段
      Bit 0~4:为文件创建时间字段秒/2的值;
      Bit 5~10:为文件创建时间字段分钟的值;
      Bit 11~15:为文件创建时间字段小时的值;
      在这里插入图片描述
    4. 0x10~0x11文件创建日期字段
      Bit 0~4:为文件创建日期字段日期数的值;
      Bit 5~8:为文件创建日期字段月份的值;
      Bit 9~15:为文件创建时间字段年号-1980的值
      在这里插入图片描述
    5. 0x14 ~ 0x15和0x1A~0x1B文件起始簇号:它存放文件或目录的表示文件的起始簇号,系统根据掌握的起始簇号在FAT表中找到入口,然后再跟踪簇链直至簇尾,同时用 0x1C~0x1F处字节判定有效性。就可以完全无误的读取文件(目录)了。
    6. 普通子目录的寻址过程也是通过其父目录中的目录项来指定的,与数据文件(指非目录文件)不同的是目录项偏移 0xB的第 4 位置 1,而数据文件0

    具体FAT32短文件格式表格如下:
    在这里插入图片描述

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

    1. 取长文件名的前 6 个字符加上"~1"形成短文件名,扩展名不变。
    2. 如果已存在这个文件名,则符号"~"后的数字递增,直到 5
    3. 如果文件名中"~"后面的数字达到 5,则短文件名只使用长文件名的前两个字母。通过数学操纵长文件名的剩余字母生成短文件名的后四个字母,然后加后缀"~1"直到最后。
    4. 如果存在老 OS 或程序无法读取的字符,换以"_"

    长文件名的实现有赖于目录项偏移为 0xB 的属性字节,当此字节的属性为:只读、隐藏、系统、卷标,即其值为 0FH 时,DOS 和 WIN32 会认为其不合法而忽略其存在。系统将长文件名以 13 个字符为单位进行切割,每一组占据一个目录项。所以可能一个文件需要多个目录项,这时长文件名的 各个目录项按倒序排列在目录表中,以防与其他文件名混淆。长文件名中的字符采用 unicode 形式编码,每个字符占据 2 字节的空间。

在这里插入图片描述

NOTE:系统在存储长文件名时,总是先按倒序填充长文件名目录项,然后紧跟其对应的短文件名。从以上的表格可以看出,长文件名中并不存储对应文件的文件开始簇、文件大小、各种时间和日期属性。文件的这些属性还是存放在短文件名目录项中,一个长文件名总是和其相应的短文件名一 一对应,短文件名没有了长文件名还可以读,但长文件名如果没有对应的短文件名,不管什么系统都将忽略其存在。所以短文件名是至关重要的。

下面的截图为SD卡根目录(Root folder)实例解析:
在这里插入图片描述
下面通过实例文件夹:System Volume Information来解析里面的数据,如下:
在这里插入图片描述

通过上面实例表格了解到重要信息总结如下:

  • 文件名称和属性
    文件名:System Volume Information
    属性:目录系统隐藏
  • 文件创建时间
    文件创建时间的值为0xAA7D,按照前面介绍的公式解析时间为21:19:58,解析过程如下:
    在这里插入图片描述
  • 文件创建日期
    文件创建时间的值为0x5276,按照前面介绍的公式解析时间为2021/03/22,解析过程如下:
    在这里插入图片描述
  • 文件起始簇号
    文件起始簇号的值为0x00000003,说明该文件的起始地址为:
    文件地址 = 根目录开始地址 + ((起始簇号 - 根目录簇号(Root Cluster Number)) * 每簇扇区数(Sectors Per Cluster) * 扇区字节数(Bytes Per Sector))
    文件地址 = 0x1000000 + ((3 - 2) * 32 * 512) = 0x1004000 Bytes
    经过计算可以得到文件起始存放位置在0x1004000,然后验证果然在该位置找到了文件夹:System Volume Information存放的数据,如下:
    在这里插入图片描述

6.FAT32 FAT表

FAT表记录了磁盘数据文件的存储链表,对于数据的读取而言是极其重要的,以至于Microsoft为其开发的FAT文件系统中的FAT表创建了一份备份,就是我们看到的FAT2。FAT2 与FAT1 的内容通常是即时同步的,也就是说如果通过正常的系统读写对FAT1 做了更改,那么FAT2 也同样被更新。

FAT表工作的原理:当存储一个大的文件时,会以为单位拆分成多个簇存放在磁盘,它们的存放的簇号并不一定是连续的,所以这里用到了FAT表,将该文件所用到的簇号串联起来。

例如截图如下,绿色的部分为存储文件的数据,FAT表查询顺序如下:

  1. 根目录(Root folder)找到该文件的起始簇号 12,并且读取簇号 12地址的文件数据。
  2. FAT表中,找到簇号12存放的下一个簇号为13,并且读取簇号 13地址的文件数据。以此类推到簇号65
  3. FAT表中,找到簇号65存放的下一个簇号为87,并且读取簇号 87地址的文件数据。下一次FAT表查询直接从簇号65跳转到簇号 87
  4. 经过上面的连续查询FAT,直到读取FF标记,代表文件读取完成。

在这里插入图片描述

NOTE:以上的分析只是理论上的,和实际使用有一些差异。后面会以实际的例子来介绍FAT表整个的工作过程。

下面通过实例根目录(Root folder)文件:stm32f4xx_gpio.c来介绍FAT表的使用:
在这里插入图片描述
通过上面实例表格了解到重要信息总结如下:

  • 文件起始簇号
    文件起始簇号0x0000 000C,说明该文件的起始地址为:
    文件地址 = 根目录开始地址 + ((起始簇号 - 根目录簇号(Root Cluster Number)) * 每簇扇区数(Sectors Per Cluster) * 扇区字节数(Bytes Per Sector))
    文件地址 = 0x1000000 + ((0x0C - 2) * 32 * 512) = 0x1028000 Bytes
    经过计算可以得到文件起始存放位置在0x1028000,然后验证果然在该位置找到了文件:stm32f4xx_gpio.c存放的数据,如下:
    在这里插入图片描述
  • 文件大小
    文件大小0x0000 6011(24593),在下面的文件属性截图可以查看到文件大小确实为24593字节
    ???为什么占用磁盘空间为32768字节????
    因为系统读写磁盘的单位为簇为单位,存放数据不满足一个簇时也将占用这整个簇(其它文件也无法使用该簇多余的空间),所以这里占用空间32768字节 = 2簇 * 32 * 512 字节 = 32768字节这样计算得来。
    在这里插入图片描述

读取完文件起始簇号存放的文件数据后,就查询下一个簇号存放数据。 FAT表以簇为单位,标识分区中空间的使用情况(每个标识占4字节)。FAT前2簇为保留簇(簇0和簇1),不分配给文件使用,其内容含义如下所示:

  • FAT16:F8 FF FF FF
  • FAT32:F8 FF FF 0F FF FF FF FF

一个FAT表项值表明了文件占用的一个簇号并指明下一簇号的位置,说明读取完簇号0x0C(12)后读下一个簇号0x0D(13),其示意图如下图所示:

在这里插入图片描述

FAT表按顺序依次记录了该盘各簇的使用情况,是一种位示图法。每簇的使用情况用32位二进制填写,未被分配的簇相应位置写;坏簇相应位置填入特定值;已分配的簇相应位置填入非零值,具体为:如果该簇是文件的最后一簇,填入的值为FFFFFF0FH(即0x0FFFFFFF),如果该簇不是文件的最后一簇,填入的值为该文件占用的下一个簇的簇号,这样,正好将文件占用的各簇构成一个簇链,保存在FAT表中。0000000H、00000001H两簇号不使用,其对应的两个DWORD位置(FAT表开头的8个字节)用来存放该盘介质类型编号。

FAT表的大小就由该逻辑盘数据区共有多少簇所决定,取整数个扇区。

文件系统被创建,也就是进行格式化操作时,分配给FAT区域的空间将会被清空,在FAT1与FAT20号表项1号表项写入特定值。由于创建文件系统的同时也会创建根目录,也就是为根目录分配了一个簇空间,通常为2号簇,所以2号簇所对应的2号FAT表项也会被写入一个结束标记,如上图所示。

如果某个簇存在坏扇区,则整个簇会用FAT表项值0xFFFFFF7标记为坏簇,不再使用,这个坏簇标记就记录在它所对应的FAT表项中。

文件系统中新建文件时,如果新建的文件只占用一个簇,为其分配的簇对应的FAT表项将会写入结束标记。如果新建的文件不只占用一个簇,则在其所占用的每个簇对应的FAT表项中写入为其分配的下一簇的簇号,在最后一个簇对应的FAT表象中写入结束标记。

新建目录时,只为其分配一个簇的空间,对应的FAT表项中写入结束标记。当目录增大超出一个簇的大小时,将会在空闲空间中继续为其分配一个簇,并在FAT表中为其建立FAT表链以描述它所占用的簇情况。

文件或目录进行操作时,他们所对应的FAT表项将会被清空,设置为0以表示其所对应的簇处于未分配状态。

7.如何使用WinHex工具查看磁盘数据

我们在分析FAT32文件系统时,需要用到WinHex工具查看磁盘上的原始数据。操作步骤如下:

  1. 安装WinHex工具
    安装完成后的工具图标如下:
    在这里插入图片描述
  2. 打开WinHex工具
    查看磁盘的原始数据需要以管理员的方式打开。
    在这里插入图片描述
  3. 打开磁盘
    选择Tools —> Open Disk打开磁盘
    在这里插入图片描述
  4. 选择需要打开的磁盘
    在这里插入图片描述
  5. 查看磁盘数据
    选择Partition,然后鼠标键右击选择Template可以查看Boot Sector数据
    在这里插入图片描述
  6. 查看FAT32 Boot Sector数据
    FAT32 Boot Sector数据详细分析可以查看上面的分析。
    在这里插入图片描述
  7. 查看FAT32分区数据
    可以鼠标双击Partition,进入FAT32分区数据。
    在这里插入图片描述

8.参考资料

  1. FAT32文件系统参考资料
    在这里插入图片描述
    下载地址如下:
    https://download.csdn.net/download/ZHONGCAI0901/16158151

  2. 硬盘基本知识(磁头、磁道、扇区、柱面)
    https://www.pianshen.com/article/8880114034/

  3. FAT32文件系统–For TF卡
    https://www.pianshen.com/article/5359401055/

  4. Microsoft MSDN FAT File System
    https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc778296(v=ws.10)?redirectedfrom=MSDN

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值