FAT文件系统介绍以及FatFs的移植

文章目录

  • FAT文件系统介绍以及FatFs的移植
    • 1、FAT文件系统介绍
      • 1.1 MBR分区
        • 1.1.1 MBR分区结构
        • 1.1.2 MBR的DPT分区表解析
      • 1.2 GPT分区
        • 1.2.1 GPT分区结构
        • 1.2.2 GPT各分区结构介绍
      • 1.3 FAT文件系统分析
        • 1.3.1 FAT简介
        • 1.3.2 DBR解析
        • 1.3.3 FSINFO扇区
        • 1.3.4 FAT表
        • 1.3.5 FAT表分析说明
        • 1.3.6 FAT表示例
        • 1.3.7 数据保存区
        • 1.3.8 目录项
    • 2、FatFs移植
      • 2.1 FatFs简介
      • 2.2 FatFs 模块层次结构
      • 2.3 下载地址
      • 2.4 FatFs文件系统文件介绍
    • 3、结合FatFs源码理解FAT文件系统
      • 3.1 FatFs的mount过程分析
      • 3.2 FatFs的read过程
    • 参考资料

1、FAT文件系统介绍

1.1 MBR分区

1.1.1 MBR分区结构

MBR位于磁盘的0号扇区,也就是第一个扇区。MBR由以下四个部分组成:

引导代码:引导代码占MBR分区的前446字节,负责整个系统启动。如果引导代码被破坏,系统将无法启动。

Windows磁盘签名:占引导代码后面的4字节,是Windows初始化磁盘写入的磁盘标签,如果此标签被破坏,则系统会提示“初始化磁盘”。

DPT分区表:占Windows磁盘标签后面的64个字节,是整个硬盘的分区表。

MBR结束标志:占MBR扇区最后2个字节,一直为“55 AA”。

下图是一个MBR扇区示例:

1.1.2 MBR的DPT分区表解析

磁盘在使用前都要进行分区,也就是将硬盘划分为一个个逻辑的区域。每一个分区都有一个确定的起始结束位置。MBR的DPT分区表位于引导代码结束以后的64个字节。其中每16个字节为一个分区表项,也就是在MBR扇区中只能记录4个分区信息。每一个分区表项的具体解析如下表:

存贮字节位 内容及含义
第1字节 引导标志。若值为80H表示活动分区,若值为00H表示非活动分区。
第2、3、4字节 本分区的起始磁头号、扇区号、柱面号。其中: 磁头号——第2字节; 扇区号——第3字节的低6位; 柱面号——为第3字节高2位+第4字节8位。
第5字节 分区类型符。 00H——表示该分区未用(即没有指定); 06H——FAT16基本分区; 0BH——FAT32基本分区; 05H——扩展分区; 07H——NTFS分区; 0FH——(LBA模式)扩展分区(83H为Linux分区等)。
第6、7、8字节 本分区的结束磁头号、扇区号、柱面号。其中: 磁头号——第6字节; 扇区号——第7字节的低6位; 柱面号——第7字节的高2位+第8字节。
第9、10、11、12字节 逻辑起始扇区号 ,本分区之前已用了的扇区数。
第13、14、15、16字节 本分区的总扇区数。

1.2 GPT分区

1.2.1 GPT分区结构

GPT磁盘分区结构解决了MBR只能分4个主分区的的缺点,理论上说,GPT磁盘分区结构对分区的数量是没有限制的。但某些操作系统可能会对此有限制。GPT磁盘分区结构由6部分组成,如下图:

1.2.2 GPT各分区结构介绍

保护MBR:保护MBR位于磁盘的0号扇区。只包含一个类型值为0xEE的分区项(第450个字节等于0xee)它的作用是阻止不能识别GPT分区的磁盘工具试图对其进行格式化等操作,所以该扇区被称为“保护MBR”。

EFI部分:

EFI信息区(GPT头):起始于磁盘的LBA1,通常也只占用这个单一扇区。其作用是定义分区表的位置和大小。GPT头还包含头和分区表的校验和,这样就可以及时发现错误。下表是GPT头的具体解析:

相对字节偏移量 (十六进制) 字节数 说明[整数皆以little endian方式表示]
00~07 8 GPT头签名“45 46 49 20 50 41 52 54”(ASCII码为“EFI PART”)
08~0B 4 版本号,目前是1.0版,其值是“00 00 01 00”
0C~0F 4 GPT头的大小(字节数),通常为“5C 00 00 00”(0x5C),也就是92字节。
10~13 4 GPT头CRC校验和(计算时把这个字段本身看做零值)
14~17 4 保留,必须为“00 00 00 00”
18~1F 8 EFI信息区(GPT头)的起始扇区号,通常为“01 00 00 00 00 00 00 00”,也就是LBA1。
20~27 8 EFI信息区(GPT头)备份位置的扇区号,也就是EFI区域结束扇区号。通常是整个磁盘最末一个扇区。
28~2F 8 GPT分区区域的起始扇区号,通常为“22 00 00 00 00 00 00 00”(0x22),也即是LBA34。
30~37 8 GPT分区区域的结束扇区号,通常是倒数第34扇区。
38~47 16 磁盘GUID(全球唯一标识符,与UUID是同义词)
48~4F 8 分区表起始扇区号,通常为“02 00 00 00 00 00 00 00”(0x02),也就是LBA2。
50~53 4 分区表总项数,通常限定为“80 00 00 00”(0x80),也就是128个。
54~57 4 每个分区表项占用字节数,通常限定为“80 00 00 00”(0x80),也就是128字节。
58~5B 4 分区表CRC校验和
5C~* * 保留,通常是全零填充

分区表:分区表区域包含分区表项。这个区域由GPT头定义,一般占用磁盘LBA2~LBA33扇区。分区表中的每个分区项由起始地址、结束地址、类型值、名字、属性标志、GUID值组成。分区表建立后,128位的GUID对系统来说是唯一的。分区表项的解析如下:

相对字节偏移量 (十六进制) 字节数 说明[整数皆以little endian方式表示]
00~0F 16 用GUID表示的分区类型
10~1F 16 用GUID表示的分区唯一标示符
20~27 8 该分区的起始扇区,用LBA值表示。
28~2F 8 该分区的结束扇区(包含),用LBA值表示,通常是奇数。
30~37 8 该分区的属性标志
38~7F 72 UTF-16LE编码的人类可读的分区名称,最大32个字符。

分区区域

GPT分区区域就是用户使用的分区,也是用户进行数据存储的区域。分区区域的起始地址和结束地址由GPT头定义。

GPT头备份

GPT头有一个备份,放在GPT磁盘的最后一个扇区,但这个GPT头备份并非完全GPT头备份,某些参数有些不一样。复制的时候根据实际情况更改一下即可。

分区表备份:

分区区域结束后就是分区表备份,其地址在GPT头备份扇区中有描述。分区表备份是对分区表32个扇区的完整备份。如果分区表被破坏,系统会自动读取分区表备份,也能够保证正常识别分区。

1.3 FAT文件系统分析

1.3.1 FAT简介

  • FAT(File Allocation Table,文件分配表)文件系统是windows操作系统所使用的一种文件系统,它的发展过程经历了FAT12、FAT16、FAT32三个阶段。FAT文件系统用“簇”作为数据单元。一个“簇”由一组连续的扇区组成,簇所含的扇区数必须是2的整数次幂。簇的最大值为64个扇区,即32KB。所有簇从2开始进行编号,每个簇都有一个自己的地址编号。用户文件和目录都存储在簇中。

  • FAT文件系统的数据结构中有两个重要的结构:文件分配表和目录项:
    文件分配表:文件和文件夹内容储存在簇中,如果一个文件或文件夹需要多于一个簇的空间,则用FAT表来描述,如何找到另外的簇。FAT结构用于指出文件的下一个簇,同时也说明了簇的分配状态。FAT12、FAT16、FAT32这三种文件系统之间的主要区别在与FAT项的大小不同。
    目录项:FAT文件系统的每一个文件和文件夹都被分配到一个目录项,目录项中记录着文件名、大小、文件内容起始地址以及其他一些元数据。

  • 在FAT文件系统中,文件系统的数据记录在“引导扇区中(DBR)”中。**引导扇区位于整个文件系统的0号扇区,是文件系统隐藏区域(也称为保留区)的一部分,我们称其为DBR扇区,DBR中记录着文件系统的起始位置、大小、FAT表个数及大小等相关信息。**在FAT文件系统中,同时使用“扇区地址”和“簇地址”两种地址管理方式。这是因为只有存储用户数据的数据区使用簇进行管理(FAT12和FAT16的根目录除外),所有簇都位于数据区。其他文件系统管理数据区域是不以簇进行管理的,这部分区域使用扇区地址进行管理。文件系统的起始扇区为0号扇区(逻辑0扇区)。

一个使用了FAT32文件系统的SD card的整体布局如下:

1.3.2 DBR解析

如下图,对读写FAT文件系统来说常用的就图中划线部分,48个字节,具体定义如下:

  • 0x00~0x02:3字节,跳转指令。
  • 0x03~0x0A:8字节,文件系统标志和版本号,这里为MSDOS5.0。
  • 0x0B~0x0C:2字节,每扇区字节数,0x0200=512
  • 0x0D~0x0D:1字节,每簇扇区数,0x08。
  • 0x0E~0x0F:2字节,保留扇区数,0x0C22=3106
  • 0x10~0x10:1字节,FAT表个数,0x02。
  • 0x11~0x12:2字节,FAT32必须等于0,FAT12/FAT16为根目录中目录的个数;
  • 0x13~0x14:2字节,FAT32必须等于0,FAT12/FAT16为扇区总数。
  • 0x15~0x15:1字节,哪种存储介质,0xF8标准值,可移动存储介质。
  • 0x16~0x17:2字节,FAT32必须为0,FAT12/FAT16为一个FAT 表所占的扇区数。
  • 0x18~0x19:2字节,每磁道扇区数,只对于“特殊形状”(由磁头和柱面分割为若干磁道)的存储介质有效,0x003F=63。
  • 0x1A~0x1B:2字节,磁头数,只对特殊的介质才有效,0x00FF=255。
  • 0x1C~0x1F:4字节,EBR分区之前所隐藏的扇区数,与MBR中地址0x1C6开始的4个字节数值相等。
  • 0x20~0x23:4字节,文件系统总扇区数,0x00E83800=15218688
  • 0x24~0x27:4字节,每个FAT表占用扇区数,0x000039EF=14831
  • 0x28~0x29:2字节,标记,此域FAT32 特有。
  • 0x2A~0x2B:2字节,FAT32版本号0.0,FAT32特有。
  • 0x2C~0x2F:4字节,根目录所在第一个簇的簇号,0x02。(虽然在FAT32文件系统下,根目录可以存放在数据区的任何位置,但是通常情况下还是起始于2号簇)
  • 0x30~0x31:2字节,FSINFO(文件系统信息扇区)扇区号0x01,该扇区为操作系统提供关于空簇总数及下一可用簇的信息。
  • 0x32~0x33:2字节,备份引导扇区的位置。备份引导扇区总是位于文件系统的6号扇区。
  • 0x34~0x3F:12字节,用于以后FAT 扩展使用。
  • 0x40~0x40:1字节,与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已。
  • 0x41~0x41:1字节,与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已 。
  • 0x42~0x42:1字节,扩展引导标志,0x29。与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
  • 0x43~0x46:4字节,卷序列号。通常为一个随机值。
  • 0x47~0x51:11字节,卷标(ASCII码),如果建立文件系统的时候指定了卷标,会保存在此。
  • 0x52~0x59:8字节,文件系统格式的ASCII码,FAT32。
  • 0x5A~0x1FD:共420字节,引导代码。
  • 0x1FE~0x1FF:签名标志“55 AA”。
    FAT文件系统将引导代码与文件形同数据结构融合在FAT32文件系统引导扇区的512字节中,90509字节为引导代码,而FAT12/16则是62509字节为引导代码。同时,FAT32还可以利用引导扇区后的扇区空间存放附加的引导代码。一个FAT卷即使不是可引导文件系统,也会存在引导代码。

1.3.3 FSINFO扇区

FAT32在保留区中增加了一个FSINFO扇区,用以记录文件系统中空闲簇的数量以及下一可用簇的簇号等信息,以供操作系统作为参考。FSINFO信息扇区一般位于文件系统的1号扇区,结构非常简单。

  • 0x200~0x203:4个字节,扩展引导标志“0x52526141”。
  • 0x204~0x3E3:480个字节,未使用,全部置0。
  • 0x3E4~0x3E7:4个字节,FSINFO签名“0x72724161”。
  • 0x3E8~0x3EB:4个字节,文件系统的空簇数。
  • 0x3EC~0x3EF:4个字节,下一可用簇号(0x00000002)。
  • 0x3F0~0x3FD:14个字节,未使用。
  • 0x3FE~0x3FF:2个字节,“55 AA”标志。
    温馨提示:通常情况下,文件系统的2号扇区结尾也会被设置“55 AA”标志。6号扇区也会有一个引导扇区的备份,相应的7号扇区应该是一个备份FSINFO信息扇区,8号扇区可以看做是2号扇区的备份。

1.3.4 FAT表

紧跟在保留分区后面的是FAT区,其由两个完全相同的FAT(File Allocation Table, 文件分配表)表单组成,FAT文件系统的名字也是因此而来。FAT 表是一组与数据簇号对应的列表。FAT2紧跟在FAT1之后,它的位置可以通过FAT1的位置加上FAT表的扇区数计算出来。

  • 文件系统分配磁盘空间按簇来分配。因此,文件占有磁盘空间时,基本单位不是字节而是簇,即使某个文件只有一个字节,操作系统也会给它分配一个最小单元:即一个簇。对于大文件,需要分配多个簇。同一个文件的数据并不一定完整地存放在磁盘中一个连续地区域内,而往往会分若干段,像链子一样存放。这种存储方式称为文件的链式存储。为了实现文件的链式存储,文件系统必须准确地记录哪些簇已经被文件占用,还必须为每个已经占用的簇指明存储后继的下一个簇的簇号,对于文件的最后一簇,则要指明本簇无后继簇。这些都是由FAT表来保存的,FAT 表对应表项中记录着它所代表的簇的有关信息:诸如是空,是不是坏簇,是否是已经是某个文件的尾簇等。
  • 对于文件系统来说,FAT表有两个重要作用:描述簇的分配状态以及标明文件或目录的下一簇的簇号。
  • 通常情况下,一个FAT文件系统会有两个FAT表,但有时也允许只有一个FAT表,FAT表的具体个数记录在引导扇区的偏移0x10字节处。
  • 由于FAT区紧跟在文件系统保留区后,所以FAT1在文件系统中的位置可以通过引导记录中偏移0x0E~0x0F字节处的“保留扇区数”得到,即M值。

1.3.5 FAT表分析说明

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

1.3.6 FAT表示例

  • 绿色划线:0号表项,0x0FFFFFF8,FAT表起始固定标识
  • 红色划线,1号表项,0x0FFFFFFF,不使用,默认值
  • 蓝色划线,2号表项,0x0FFFFFFF,标识文件结束,表项对应2号簇,根目录所在簇
  • 如何找到FAT表所在扇区:
    DBR的偏移0x0E-0x0F(0x0C22=3106)是保留区大小,保留区之后即为FAT1起始扇区,上图中偏移0x184400转换为扇区0x184400/512=3106,扇区从0计数,所以3106扇区即是FAT1所在扇区
  • 计算根目录起始扇区:
    N=保留区大小+2xFAT表大小=0x0C22+2x0x000039EF=32768
  • 将SD卡格式化,新建TEST.txt文件,大小为8.5KB,FAT表结构如下:

  • 红色划线:2号表项,对应2号簇,为根目录
  • 绿色划线:3号表项,对应3号簇,表项值为0x04,Test.txt的下一个簇为4号簇
  • 蓝色划线:4号表项,对应5号簇,表项值为0x05,Test.txt的下一个簇为5号簇
  • 黄色划线:5号表项,对应5号簇,表项值为0x0FFFFFFF,文件结束

1.3.7 数据保存区

  • 数据区是真正用于存放用户数据的区域。数据区紧跟在FAT2之后,被划分成一个个的簇。所有的簇从2开始进行编号,也就是说,2号簇的起始位置就是数据区的起始位置。
  • 虽然原则上FAT32允许根目录位于数据区的任何位置,但通常情况下它都位于数据区起始扇区。在FAT文件系统中,先要寻找数据区的第一簇(即2号簇)的位置,它不是位于文件系统开始处,而是位于数据区。从前面的学习知道,在数据区前面是保留区域和FAT区域,在前面还有MBR区域,这些区域都不使用FAT表进行管理。因此,数据区以前的区域只能使用扇区地址,而无法使用簇地址。
  • 数据区起始扇区号即是根目录扇区号,上面已计算得出32768。

1.3.8 目录项

目录所在的扇区,都是以32 Bytes划分为一个单位,每个单位称为一个目录项,即每个目录项的长度都是32 Bytes 。根目录由若干个目录项组成,一个目录项占用32个字节,可以是长文件名目录项、文件目录项、“.”目录项和“…”目录项等
此处只是简单的以上文中创建的TEST.txt为例说明短文件目录项的结构。

  • 0x00-0x07:文件名,不足8个字节0x20补全(短文件名8.3命名规则)

  • 0x08-0x0A:扩展名

  • 0x0B:文件属性,0x20表示归档

  • 0x0D:创建时间的10毫秒位

  • 0x0E-0x0F:文件创建时间

  • 0x10-0x11:文件创建日期

  • 0x12-0x13:文件最后访问日期

  • 0x14-0x15:文件起始簇号的高16位 0x0000

  • 0x16-0x17:文件最近修改时间

  • 0x18-0x19:文件最近修改日期

  • 0x1A-0x1B:文件起始簇号的地16位 0x0003

  • 0x1C-0x1F:文件的长度,0x2206=8710bytes=8.5K

2、FatFs移植

2.1 FatFs简介

FatFs是用于小型嵌入式系统的通用FAT / exFAT文件系统模块。FatFs模块是按照ANSI C(C89)编写的,并且与磁盘I / O层完全分开。因此,它独立于平台。它可以并入资源有限的小型微控制器中,例如8051,PIC,AVR,ARM,Z80,RX等。此处还提供了适用于小型微控制器的Petit FatFs模块。

特点

 DOS / Windows兼容的FAT / exFAT文件系统。

 平台无关。易于移植。

 程序代码和工作区的占用空间非常小。

 支持以下各种配置选项:

​ ANSI / OEM或Unicode中的长文件名。

​ exFAT文件系统,64位LBA和GPT可存储大量数据。

​ RTOS的线程安全。

​ 多个卷(物理驱动器和分区)。

​ 可变扇区大小。

​ 多个代码页,包括DBCS。

​ 只读,可选API,I / O缓冲区等…

2.2 FatFs 模块层次结构

底层接口

包括存储媒介读/写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。

中间层FATFS模块

实现了FAT 文件读/写协议。FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。

顶层应用层

使用者无需理会FATFS的内部结构和复杂的FAT 协议,只需要调用FATFS模块提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和f_close等,就可以像在PC 上读/写文件那样简单。

2.3 下载地址

http://elm-chan.org/fsw/ff/00index_e.html

此地址不仅仅包含资料包下载,还包括文件系统一些知 识,包括函数说明,函数调用实例等。

2.4 FatFs文件系统文件介绍

文件名 功能 说明
ffconf.h FatFs模块的配置文件 需要用户根据需求来配置
ff.h FatFs和应用程序模块的通用包含文件 不需要修改
ff.c FatFs模块源码 不需要修改
diskio.h FatFs和disk I / O模块的公共包含文件 不需要修改
diskio.c FatFs 和disk I / O 模块接口层文件 与平台相关的代码,需要用户根据存储介质来编写函数。
ffunicode.c 可选的Unicode 相关的转换函数
ffsystem.c 可选的与操作系统对接的各接口相关实现示例

移植FatFs的过程中,用户需要根据自己的实际需求来对配置文件ffconf.h进行配置,然后就是需要实现diskio.c中的底层I/O驱动接口。

3、结合FatFs源码理解FAT文件系统

3.1 FatFs的mount过程分析

–mount_volume

​ --stat = disk_initialize(fs->pdrv);//初始化I/O设备

​ --fmt = find_volume(fs, LD2PT(vol));//寻找Fat表

static UINT find_volume (    /* Returns BS status found in the hosting drive */FATFS* fs,        /* Filesystem object */UINT part        /* Partition to fined = 0:auto, 1..:forced */
)
{UINT fmt, i;DWORD mbr_pt[4];fmt = check_fs(fs, 0);                /* Load sector 0 and check if it is an FAT VBR as SFD format *///在这个函数中会load 0号扇区的数据,如果检查0号扇区符合DBR格式,那么返回。如果0号扇区的最后两个字节不是0xaa55,那么返回错误。if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is an FAT VBR as auto scan, not a BS or disk error *//* Sector 0 is not an FAT VBR or forced partition number wants a partition */#if FF_LBA64//在这里会进行gpt分区解析if (fs->win[MBR_Table + PTE_System] == 0xEE) {  /* GPT protective MBR? *///判断0号扇区是保护MBR才继续往下解析,第450字节为0xee    DWORD n_ent, v_ent, ofs;QWORD pt_lba;if (move_window(fs, 1) != FR_OK) return 4;   /* Load GPT header sector (next to MBR) *///load 1号扇区的数据,也就是load gpt头if (!test_gpt_header(fs->win)) {//校验gpt头 NOTICE("BL1: find_volume, test_gpt_header failed.\n");return 3;   /* Check if GPT header is valid */}//下面是gpt头的解析n_ent = ld_dword(fs->win + GPTH_PtNum);     /* Number of entries *///读取0x50-0x53得到分区表总项数pt_lba = ld_qword(fs->win + GPTH_PtOfs);   /* Table location *///读取0x48-0x4F得到分区表起始扇区号for (v_ent = i = 0; i < n_ent; i++) {     /* Find FAT partition */if (move_window(fs, pt_lba + i * SZ_GPTE / SS(fs)) != FR_OK) return 4;    /* PT sector *///前面已经得到分区表的起始扇区,在这里load分区表ofs = i * SZ_GPTE % SS(fs);                                               /* Offset in the sector *///if (!memcmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */v_ent++;fmt = check_fs(fs, ld_qword(fs->win + ofs + GPTE_FstLba));    /* Load VBR and check status *///每个分区表项的GPTE_FstLba字节(32)指定了该分区的起始扇区号,在这里会load该分区的起始扇区,检查是否符合DBR格式if (part == 0 && fmt <= 1) return fmt;          /* Auto search (valid FAT volume found first) */if (part != 0 && v_ent == part) return fmt;      /* Forced partition order (regardless of it is valid or not) *///}}return 3;    /* Not found */}
#endif//下面部分的代码是MBR分区的解析if (FF_MULTI_PARTITION && part > 4) return 3;    /* MBR has 4 partitions max */ //MBR最多支持4个主分区表项for (i = 0; i < 4; i++) {      /* Load partition offset in the MBR */mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba);//找到各个分区的起始扇区}i = part ? part - 1 : 0;     /* Table index to find first */do {                         /* Find an FAT volume */fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3; /* Check if the partition is FAT */ //检查是否存在FAT分区} while (part == 0 && fmt >= 2 && ++i < 4);return fmt;
}

find_volume函数,基本遵循如下流程:

(1)load 0号扇区,如果0号扇区符合DBR格式,那么返回,如果0号扇区的最后两个字节不是0xaa55,那么返回错误

(2)如果0号扇区不符合DBR格式,继续判读第450个字节是不是0xee,如果是,那么按照gpt的格式继续进行解析,检查是否存在FAT分区

(3)如果也不是gpt格式,那么按照mbr的格式解析,检查能找到FAT分区

find_volume找到fat分区的起始扇区(DBR)以后,那么继续进行DBR扇区的解析,如下:

 if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM;  /* (BPB_BytsPerSec must be equal to the physical sector size) */ //读取DBR的0x0B~0x0C得到每个扇区的字节数,这里必须和物理设备保持一致fasize = ld_word(fs->win + BPB_FATSz16);      /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);//得到FAT表所占的扇区数fs->fsize = fasize;fs->n_fats = fs->win[BPB_NumFATs];             /* Number of FATs */ //得到FAT表的个数if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM;    /* (Must be 1 or 2) */fasize *= fs->n_fats;                         /* Number of sectors for FAT area */fs->csize = fs->win[BPB_SecPerClus];         /* Cluster size */if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM;  /* (Must be power of 2) */fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);    /* Number of root directory entries */if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM;    /* (Must be sector aligned) */tsect = ld_word(fs->win + BPB_TotSec16);     /* Number of sectors on the volume */if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);nrsv = ld_word(fs->win + BPB_RsvdSecCnt);     /* Number of reserved sectors */if (nrsv == 0) return FR_NO_FILESYSTEM;           /* (Must not be 0) *//* Determine the FAT sub type */sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE);  /* RSV + FAT + DIR */if (tsect < sysect) return FR_NO_FILESYSTEM;  /* (Invalid volume size) */nclst = (tsect - sysect) / fs->csize;            /* Number of clusters */if (nclst == 0) return FR_NO_FILESYSTEM;      /* (Invalid volume size) */fmt = 0;if (nclst <= MAX_FAT32) fmt = FS_FAT32;if (nclst <= MAX_FAT16) fmt = FS_FAT16;if (nclst <= MAX_FAT12) fmt = FS_FAT12;if (fmt == 0) return FR_NO_FILESYSTEM;/* Boundaries and Limits */fs->n_fatent = nclst + 2;                       /* Number of FAT entries */fs->volbase = bsect;                         /* Volume start sector */fs->fatbase = bsect + nrsv;                   /* FAT start sector */fs->database = bsect + sysect;                   /* Data start sector */

可以看到FatFs的mount过程基本就是MBR、GPT和DBR的解析过程。

3.2 FatFs的read过程

在这里没有详细介绍read的详细流程,结合前面的fat文件系统介绍,大概过程如下在根目录扇区中先找到对应的目录项,在目录项中可以得到文件的起始簇号以及文件的大小,根据文件的起始簇号,就能找到保存了该文件的所有扇区地址。

参考资料

1、GUID(GPT)分区表详解

https://blog.csdn.net/u011164819/article/details/50720692

2、详解MBR分区结构以及GPT分区结构

https://blog.51cto.com/dengqi/1348951

3、FAT32文件系统快速入门

https://blog.csdn.net/u010650845/article/details/60881687

4、图解fat32文件系统设计

https://blog.csdn.net/qq_35579835/article/details/106754991?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-2.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-2.no_search_link

5、FATFS文件系统

https://www.pianshen.com/article/15371184643/

FAT文件系统介绍以及FatFs的移植相关推荐

  1. elm FatFs文件系统移植总结

    1 前言 本文将根据我的一些理解,针对elm FatFs文件系统做一个初步总结. 2 elm FatFs文件系统介绍 顾名思义FatFs文件系统就是针对FAT文件系统来的,主要是应用于MCU中,STM ...

  2. fatfs 文件属性_FatFs文件系统介绍

    实验要求 在SD驱动移植实验的基础上,加上FatFs文件系统,实现SD卡中文件的读写及其它操作 实验目的 了解FatFs文件系统的原理 掌握FatFs文件系统的移植方法 实现SD卡中文件的读写及其它操 ...

  3. STM32+雷龙SD NAND(贴片SD卡)完成FATFS文件系统移植与测试

    一.前言 在STM32项目开发中,经常会用到存储芯片存储数据. 比如:关机时保存机器运行过程中的状态数据,上电再从存储芯片里读取数据恢复:在存储芯片里也会存放很多资源文件.比如,开机音乐,界面上的菜单 ...

  4. 2021-08-11 TM32F103 Buffer FatFs 文件系统移植

    FatFs 本文展示了STM32 FatFs文件系统移植 内容涉及 : FatFs 文件系统移植 SPI函数移植过程 SPI字节数据模拟输出独写 缓存读写 USART串口的识别 IO口输入输出 按键的 ...

  5. 文件系统FATFS的移植教程

    最新FatFs:http://elm-chan.org/fsw/ff/00index_e.html 一.FATFS文件系统简介 FATFS是面向小型嵌入式系统的一种通用的FAT文件系统.它完全是由C语 ...

  6. FatFs文件系统移植过程及中度分析

    FatFs 是一个通用的文件系统(FAT/exFAT)模块,用于在小型嵌入式系统中实现FAT文件系统. FatFs 组件的编写遵循ANSI C(C89),完全分离于磁盘 I/O 层,因此不依赖于硬件平 ...

  7. 【STM32H7】第2章 ThreadX FileX文件系统介绍

    论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=100749 第2章   ThreadX FileX文件系统介绍 ...

  8. 【STM32F407】第2章 ThreadX FileX文件系统介绍

    论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=100749 第2章   ThreadX FileX文件系统介绍 ...

  9. STM32F103读取SD卡的数据(fat文件模式)

    实验目的 掌握SD卡协议原理,用STM32F103完成对SD卡的数据读取(fat文件模式). 实验原理 SD卡寄存器 SD卡总共有8个寄存器,用于设定或表示SD卡信息. 这些寄存器只能通过对应的命令访 ...

  10. STM32F103完成对SD卡的数据读取(fat文件模式)

    目录 一.关于SD卡 1.简介 2.SD卡的寄存器 3.SD卡读取与写入(SPI模式) 二.实验操作 1.仪器 2.代码 3.连线 4.烧录程序 5.串口调试助手初始化并写入文件 6.sd卡里hell ...

最新文章

  1. subst将文件夹目录虚拟成虚拟磁盘
  2. Flink状态后端配置(设置State Backend)
  3. OGG学习笔记04-OGG复制部署快速参考
  4. 编程软件python怎样开始学-Python 3.7从零开始学
  5. hausdorff距离
  6. char* 大小_SQL Server中char, nchar, varchar和nvarchar数据类型有何区别
  7. day39-Spring 05-Spring的AOP:不带有切点的切面
  8. 【Flink】Flink 反压机制 导致checkpoint 失败
  9. python安装离线包window_python 离线安装unrar库
  10. 在Python中查找字符串长度
  11. 智·御未来 亚信安全巡展·2017即将起航
  12. python图片二值化提高识别率
  13. 采用C#泛型实现状态(State)模式
  14. window10 下面固定本地 ip
  15. 2021年北京市促进服务外包发展专项资金申报时间及材料,补贴500万
  16. 循序渐进ActiveMQ(6)----使用zookeeper实现activemq的主从环境搭建
  17. 投诉百度快照对排名的影响
  18. 如何使用计算机上合并计算方法,excel如何使用合并计算
  19. Utgard连接OPC Server常见故障码及解决方案
  20. 数据库实验三 嵌套查询和视图操作

热门文章

  1. CDN最通俗易懂的CDN解释
  2. html设置背景颜色以及背景图片
  3. linux下sd分区扩容,实用技巧:Linux系统分区容量扩充的方法
  4. 盈世邮箱服务器pop3,Coremail私有协议为什么比POP3协议、IMAP协议更好
  5. 拼多多商品详情百亿补贴数据采集接口代码展示
  6. java 注解 controller_@Controller注解
  7. IP 地址由网络和主机两部分标识组成
  8. 单片机第1季:零基础学51单片机-蜂鸣器介绍
  9. 【@MaC 修改MySQL密码】
  10. 磁盘阵列RAID卡组建设置