# FAT32文件系统


## FAT32文件系统结构

一个FAT32文件系统的磁盘主要由MBR、DBR、FAT表、数据区组成。由于评测使用的磁盘没有MBR区，因此我们只介绍DBR、FAT表、数据区。



### DBR区

该区域记录着文件系统的一些关键信息，例如有几个FAT表，每个FAT表的大小等。我们使用的信息主要如下：

```cpp
struct DBR {
	Uint32 BPB_RsvdSectorNum;  //保留扇区数⽬ 
	Uint32 BPB_FATNum;   //此卷中FAT表数 
	Uint32 BPB_SectorPerFATArea;   //⼀个FAT表扇区数 
	Uint32 BPB_HidenSectorNum; //隐藏扇区数
	Uint64 BPBSectorPerClus;//每个簇有多少个扇区
};
```

### FAT区
磁盘读取写入数据的最小单位是扇区，但是扇区还是太小了，我们存储数据的时候不会用扇区来做基本单位，而是使用簇，一个簇通常对应多个扇区。

FAT区的作用类似于索引，用于记录当前簇的下一个簇。需要注意的是前两个簇是不存在的，因此FAT区前两个簇的标识是固定的，从第二个簇开始。如果这个簇的标识是0x00000000，则表示当前簇未被使用。如果是0xFFFFFF0F，则表示该簇没有下一个簇，否则表示该簇的下一个簇的标识。

我们在评测中发现，有些簇的标识是0x8FFFFF0F，后来查阅资料知道[0x8FFFFF0F,0xFFFFFF0F]都可以标识簇的结束位置。

### 数据区


#### 文件夹

如果是文件夹对应的数据区，则数据区存放的为每32个字节一项的目录项。包含文件的属性、其实簇号、文件名、创建日期等各种信息。如果文件被删除，则目录项第一个字节为0xE5，未被使用则为0x00。凡是不是以0x00和0xE5开头的记录都是目录的数据，这些记录的格式可以通过检查它的属性字来判定。

目录项分为长目录项和短目录项。在FAT32中，所有的文件目录都有短文件名，即使用户赋予了这个文件一个长文件名。短⽂件名是DOS+FAT12/FAT16时代的产物，命名规则为8.3，8是指⽂件名，3是指扩展名(完整⽂件=⽂件名.扩展名)。


文件名超过8个字节或扩展名超出3个字节都是长⽂件名，FAT32⽂件系统完全⽀持长⽂件名，长⽂件名记录在⽬录项中，可能⼀个⽂件名占据多个⽬录项则会生成多个长目录项，最后一定搭配一个对应的短目录项。

#### 文件

如果是文件就简单了，数据区直接存放文件的数据。我们读取的时候直接读取二进制数据即可。


## 读取流程

初始化的时候，我们读取0号扇区，即DBR区，获取文件系统的一些关键信息。得到FAT表数量，FAT表大小，保留扇区数，我们就可以使用这些计算出根目录的地址（即二号簇的地址）。

当我们拿到一个路径，要读取文件时，首先根据根目录项，拿到文件路径第一节所在目录项，一直找到文件所在目录项，读取目录可以知道文件的起始簇在哪以及的创建日期等。我们根据文件的起始簇，找到对应的lba，然后直接读取即可，如果文件大小超出一个簇，我们就要到FAT区中寻找下一个簇，直到读取完成。


## 遇到的问题

我们文件系统遇到的第一个问题是我们写入的文件，把SD卡插到windows上，windows可以显示出来，但是双击打开提示没有这个文件。后来检查发现短目录项中0x0C位置是系统保留位置，而windows使用这个位置的数据判断文件名和拓展名的大小写，我们错误的设置了这个位置的数据。第二个问题是我们错误的认为簇的结束标志只有0xFFFFFF0F，导致在提交评测的时候SD卡驱动读取了一个非法的地址，导致我们的评测到某个函数就突然卡死了。





-----------------

By：PeaceSheep

2022.06.05