瞥一眼 FAT32,手撸文件系统

FAT 32

FAT(File Allocation Table),最早在DOS v1.0 中被引入,是一种极简的文件系统,占用空间,是目前最常见的文件系统之一。

发展历程

FATX系列文件系统的不同版本都是针对不同的文件存储介质(storage media)规模设计的。

FAT12FAT 12 是专为软盘设计的,最大可管理 16 兆字节的大小,因为它使用 12 位来寻址磁盘组。

FAT16FAT 16 是为早期硬盘设计的,可处理的最大簇大小为 64K * 簇大小。硬盘越大,簇的大小就越大,这会导致磁盘上出现大量的 “闲置空间”(slack space)。

FAT32FAT 32 由 Windows95-B 和 Windows98 引入。FAT32 解决了 FAT 的一些问题。不再有最大 64K 的簇!虽然 FAT32 每个 FAT 条目使用 32 位,但实际上只有最下面的 28 位用于寻址磁盘上的磁簇(最上面的 4 位为保留位)。由于每个 FAT 条目有 28 位,文件系统在一个分区中最多可寻址约 2.7 亿个群集。这使得超大硬盘仍能保持相当小的簇大小,从而减少文件之间的空闲空间。

ExFATExFAT 是用于 SDXC 卡的文件系统,由微软创建。它是 FAT32,每个 FAT 条目实际上有 32 位,能指示文件在磁盘上是完全连续的(允许你跳过读取 FAT),还有一些更高级的功能和完全重新设计的文件输入系统。

VFATVFAT 是 FAT 文件系统的扩展,可以使用长文件名(最多 255 个字符)。它由 Windows 95 首次引入,使用了一种 “笨办法”,即用 "卷标 "属性标记长文件名,然后将文件名以 11 个字节的块存储在顺序目录条目中。

实现细节

FAT 文件系统将存储介质视为扁平的磁簇阵列。如果物理介质不是以扇区的平面列表来处理数据(如老式硬盘和软盘),那么在将簇号发送到磁盘之前就需要进行转换。

存储介质分为三个基本区域:

  • 启动记录 (The boot record)
  • 文件分配表 (FAT,The File Allocation Table)
  • 目录和数据区(The directory and data area)

如果物理介质不是以扇区的平面列表来处理数据

这段话的意思是,如果物理介质(例如老式硬盘和软盘)不是将数据作为扇区的线性列表来寻址的,那么在将簇号发送到磁盘之前,需要对簇号进行转换。

在现代硬盘中,数据通常被组织成线性的扇区列表,每个扇区都有一个唯一的扇区号。但是,在一些老式的硬盘和软盘中,数据可能被组织成不同的方式,例如使用簇(cluster)的概念来组织数据。簇是一组相邻的扇区,通常是2个或4个扇区的大小。在这种情况下,每个簇都有一个唯一的簇号,而不是每个扇区都有一个唯一的扇区号。这种组织方式可以提高磁盘的存储效率,但也需要进行簇号到扇区号的转换,以便正确地访问磁盘上的数据。

因此,如果文件系统使用簇号来寻址数据,而不是扇区号,那么在将簇号发送到磁盘之前,需要将簇号转换为对应的扇区号。这个过程称为簇号到扇区号的转换。这个转换过程通常由文件系统驱动程序来完成,以确保文件系统能够正确地访问磁盘上的数据。

Boot Record

“The boot record”(引导记录)是指存储在磁盘的第一个扇区的特殊区域。它也被称为引导扇区(boot sector)或主引导记录(master boot record,MBR)。

存储在磁盘的第一个扇区的特殊区域

指的是启动记录占一个扇区,始终位于 "分区 "的逻辑零号扇区。如果介质没有分区,那么这就是介质的起始位置。这是计算机加载时最容易找到的分区扇区。

引导记录是一个重要的数据结构,它包含了启动计算机所需的关键信息。当计算机启动时,BIOS(基本输入/输出系统)会读取磁盘的引导记录,并执行其中的引导代码。这段引导代码负责加载操作系统的核心部分,从而完成系统的启动过程。

引导记录通常包含以下内容:

  • 引导代码:这是一段特定的机器代码,用于初始化计算机硬件、加载操作系统的核心部分,并将控制权转交给操作系统。

  • 分区表:引导记录还包含一个分区表,用于描述磁盘上的分区布局。分区表记录了每个分区的起始位置、大小和文件系统类型等信息。

  • 引导标志:引导记录中还包含一个引导标志,用于指示该扇区是否为引导扇区。

File Allocation Table

文件分配表 (FAT) 是存储在存储介质上的一个表,用于显示磁盘上所有数据集群的状态和位置。它可以被视为磁盘的 “目录”。簇可能可供使用,可能被操作系统保留,可能因磁盘上的坏扇区而不可用,也可能被文件使用。文件的簇不一定在磁盘上紧挨在一起。事实上,它们很可能分散在磁盘的各个角落。FAT 允许操作系统跟踪文件中的簇 “链”。

FAT 32 使用 28 位来寻址磁盘上的群集。最高 4 位为保留位。exFAT 使用完整的 32 位来编码扇区号。

unsigned char FAT_table[sector_size];
unsigned int fat_offset = active_cluster * 4;
unsigned int fat_sector = first_fat_sector + (fat_offset / sector_size);
unsigned int ent_offset = fat_offset % sector_size;
 
//at this point you need to read from sector "fat_sector" on the disk into "FAT_table".
 
//remember to ignore the high 4 bits.
unsigned int table_value = *(unsigned int*)&FAT_table[ent_offset];
if (fat32) table_value &= 0x0FFFFFFF;
 
//the variable "table_value" now has the information you need about the next cluster in the chain

如果 "table_value "大于或等于 (>=) 0x0FFFFFF8(或 exFAT 的 0xFFFFFFF8),则链中不再有任何簇。这意味着整个文件已被读取。如果 "table_value "等于(==)0x0FFFFFF7(或 exFAT 为 0xFFFFFFF7),则该簇被标记为 "坏 "簇。坏 "簇容易出错,应避免使用。如果 "table_value "不属于上述情况,那么它就是文件中下一个簇的簇号。

索引 0 和 1 下的条目被保留。保留第 0 个条目是因为索引 0 被用作其他条目的值,表示给定的簇是空闲的。第 0 个条目必须保留 BPB_Media 字段低 8 位的值,其余位必须置 0。例如,如果 BPB_Media 为 0xF8,则第 0 个条目应为 0xFFFFFFF8。第一个条目是为将来保留的,其值必须为 0xFFFFFFFF。

Programming Guide

读取引导扇区

引导扇区始终位于逻辑扇区编号 0 处。你可以将引导扇区读入一个数组并访问其中的成员,也可以将其读入一个结构并通过结构访问。无论哪种方式,引导扇区中的值都需要随时可用,这样才能在 FAT 文件系统中做很多事情。


typedef struct fat_extBS_32
{
	//extended fat32 stuff
	unsigned int		table_size_32;
	unsigned short		extended_flags;
	unsigned short		fat_version;
	unsigned int		root_cluster;
	unsigned short		fat_info;
	unsigned short		backup_BS_sector;
	unsigned char 		reserved_0[12];
	unsigned char		drive_number;
	unsigned char 		reserved_1;
	unsigned char		boot_signature;
	unsigned int 		volume_id;
	unsigned char		volume_label[11];
	unsigned char		fat_type_label[8];
 
}__attribute__((packed)) fat_extBS_32_t;
 
typedef struct fat_extBS_16
{
	//extended fat12 and fat16 stuff
	unsigned char		bios_drive_num;
	unsigned char		reserved1;
	unsigned char		boot_signature;
	unsigned int		volume_id;
	unsigned char		volume_label[11];
	unsigned char		fat_type_label[8];
 
}__attribute__((packed)) fat_extBS_16_t;
 
typedef struct fat_BS
{
	unsigned char 		bootjmp[3];
	unsigned char 		oem_name[8];
	unsigned short 	        bytes_per_sector;
	unsigned char		sectors_per_cluster;
	unsigned short		reserved_sector_count;
	unsigned char		table_count;
	unsigned short		root_entry_count;
	unsigned short		total_sectors_16;
	unsigned char		media_type;
	unsigned short		table_size_16;
	unsigned short		sectors_per_track;
	unsigned short		head_side_count;
	unsigned int 		hidden_sector_count;
	unsigned int 		total_sectors_32;
 
	//this will be cast to it's specific type once the driver actually knows what type of FAT this is.
	unsigned char		extended_section[54];
 
}__attribute__((packed)) fat_BS_t;

你可能感兴趣的:(从物理定律到编程语言,单片机,stm32,操作系统,文件系统,fat32)