分类: 嵌入式
2014-07-25 19:40:32
FAT文件系统整体概述
MBR:0扇区,分区记录,不一定每个磁盘都有MBR. |
|
DBR:可能位于0扇区,若不在0扇区则由MBR计算得到他的位置,以0XEB开始,记录该分区重要参数 |
保留扇区:可能是32个扇区,也有可能不是。 |
第一个FAT表:存储了目录与文件数据的链式存储结构 |
第二个FAT表:作为第一个FAT的备份,防止损坏 |
第二簇:第一个目录所在的簇号,以下顺序是第三簇第四簇 |
第三簇开始:记录了目录和文件数据,存储单位是簇,簇与簇之间不一定联系,链式关系要参照FAT表 |
。。。。。。。。 |
|
|
第n簇 |
MBR结构:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
00 |
02 |
0C |
00 |
0B |
38 |
F8 |
B8 |
89 |
00 |
00 |
00 |
77 |
9F |
3A |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
55 |
AA |
MBR前面的数据全部是启动代码,从第446个字节开始为分区记录0、分区记录1、分区记录2和分区记录3.每个分区记录占16个字节,最后以0x55和0xAA结束。该分区表只有一个分区,所以后边的分区记录都是0.
分区记录的16个字节的意义如下:
标识 长度 介绍 值
Active 1字节 0x80表示分区有效,0x00表示无效 0x00
StartHeat 1字节 分区的开始头 0x02
StartCylSec 2字节 开始柱面与扇区 0x0c 0x00
PartType 1字节 分区的类型 0x0b
EndHead 1字节 分区的结束头 0x38
EndCylSec 2字节 结束柱面与扇区 0xf8 0xb8
StartLBA 4字节 分区的第一个扇区 0x89 0x00 0x00 0x00 (137扇区)
Size 4字节 该分区的大小(扇区的个数) 0x77 0x9f 0x3a 0x00
(说明:数据存储为小端格式:低地址放字节数据)
由以上得知我的磁盘的第一个扇区为0x89即第137个扇区,也就是DBR所在的开始扇区,也就是BPB所在的扇区。磁盘的大小为0x3a9f77即1875M,也就是2G。
DBR结构里的BPB结构如下:
DBR里面BPB的内容如下:
标识 字节数 介绍 值
BytesPerSec 2字节 每扇区字节数 0x00 0x02 512字节
SecPerClus 1字节 每簇扇区数 0x08 8个扇区
RsvdSecCnt 2字节 保留扇区数目 0x26 0x00 38个扇区
NumFATs 1 字节 FAT表数 0x02 2个FAT表
RootEntCnt 2字节
TotSec16 2字节
Midia 1
FATSz16 2
SecPerTrk 2
NumHeads 2
HiddSec 4
TotSec32 4 总扇区数 0x77 0x9f 0x3a 0x00
FATSz32 4 一个FAT表的扇区数 0xa1 0x0e 0x00 0x00 3745个扇区
ExtFlags 2
FSVer 2
RootClus 4 第一个目录簇号 0x02 第2簇(前面有第0簇和第1簇)
FSInfo 2
BkBootSec 2
Reserved 12
DrvNum 1
Reserved1 1
BootSig 1
VolID 4
FilSysType 11
FilSysType1 8
由以上还可以计算出以下几个重要参数:
BPB所在的扇区BPB_Sector_No就是第一个分区即137扇区
保留扇区数:0x0026即保留扇区数为38.
第一个FAT表所在的扇区FirstFATSector:BPB_Sector_No+保留扇区=137+38=175扇区
一个FAT表的扇区数:0x00000ea1即3745个扇区。
第一个目录的扇区号FirstDirSector=FirstFATSector+FATSz32*2=7665扇区
第一个目录所在的簇号为0x02即第二簇。
每簇扇区数:0x08即8个扇区,每个扇区512字节即4K.
FAT文件系统中,簇是存取数据的最小单元,即4K为最小单元
根目录的内容:根目录就是记录了文件和目录的相关记录,描述文件的32个字节含义如下:
标识
deName 8字节 文件名,不足补空格
deExtension 3字节 扩展名,不足补空格
deAttributes 1字节 文件属性10的时候表示子目录(文件夹)
deLowerCase 1字节 固定为0
deCHundredth 1字节 忽略
deTime 2字节 创建时间
deCDate 2字节 创建日期
deADate 2字节 最后访问日期
deHighClust 2字节 文件开始簇的高两个字节
deMTime 2字节 最后修改时间
deMDate 2字节 最后修改日期
deLowCluster 2字节 文件开始簇的低两个字节
deFileSize 4字节 该文件的大小,单位是字节
读取文件所需要的参数:文件的名字、文件的属性、文件的开始簇、当前簇、当前扇区、扇区中的偏移量、文件当前到文件开始的偏移量,也就是读到了多少个数据、文件的大小以及文件的名字之类的
簇项:记录该簇连接到下一簇的簇地址。比如说文件的开始簇是第四簇,则在第四个簇项则记录文件下一个簇的地址,若文件没有下一簇,则第四簇就是FF FF FF 0F. 以第0个簇项开始计算。一个簇项占用四个字节,一个扇区512个字节,则一个扇区可以记录128个簇项。例如根目录所在的簇是第二簇,则在FAT表的第二簇就记录着根目录所占下一簇的地址,若根目录没有下一个簇,则第二个簇项的值为FF FF FF 0F。假如一个簇项的值为0x00 0x00 0x05 0x05,则可以根据此来计算下一个簇的簇项的位置。下一簇的位置是1285,那么下一个簇项的位置在何处?由1285/128=10,可以知道这个簇项偏离FAT表的第一个扇区有10个扇区。而在该扇区的哪个位置呢?由1285%128=5,所以在该扇区的第五个簇项!
当首簇即根目录记录文件和目录项没有空间了,也就是第二簇的八个扇区已经记满,那么首簇通过FAT表链到其他的簇,继续记录文件和目录,这就解决了文件和目录过多的情况。
底层接口函数:FAT32_ReadSector( )、FAT32_WriteSector( )
初始化函数void FAT32_Init( struct FAT32_Init_Arg *arg) :初始化的目的是从MBR和DBR中读取一些重要的参数装入该结构体中,以备后面使用。
该结构体的成员有:
BPB_Sector_No:BPB所在的扇区
Total_Size: 总的容量
FATsetors: FAT表的大小
FirstDirClust: 第一个目录所在的簇
BytersPerSector: 每个扇区的字节数
SectorsPerClust: 每个簇的扇区数
FirstFATsector: 第一个FAT表所在的扇区
FirstDirSector: 第一个簇所在的扇区
进入目录函数unsigned long FAT32_Enter_Dir(char *path):目录的路径是一个字符串,比如ab\cd\ef的形式。返回相应目录的开始簇,如果进入目录失败(可能是目录不存在),则会返回0.并且用全局变量temp_dir_cluster记录了最近一级目录的最后簇。
寻找下一簇函数unsigned long FAT32_GetNextCluster(unsigned long LastCluster):函数的功能是获得下一簇的簇号,参数是当前的簇,返回下一簇的簇号。N簇的簇项所在扇区为(N/128)+ FirstFATsector; N簇的簇项在该扇区中的偏移量:N%128
打开文件函数unsigned char FAT32_OpenFile(struct FileInfoStruct *pfi, char *path):首先 说明文件的路径形式为a\b\test.txt,返回1表示打开文件成功返回0表示打开文件失败。用“进入目录”函数进入文件/目录项所在的目录。文件的信息结构为:
FileName:文件名
FileStarCluster:文件开始簇
FileCurCluster:文件当前簇
FileSize:文件大小
FileCurSector:文件当前扇区
FileCurPos:文件当前扇区的偏移量
FileCurOffset:文件当前偏移量
Rec_Sec: 文件目录项所在的扇区
nRec: 文件目录项在扇区中的偏移量
FileAttr: 文件属性
FileCreateTime:文件创建时间
FileCreateDate:文件创建日期
FileMTime:文件修改时间
FileMDate:文件修改日期
FileaADate:文件访问日期
unsigned char FAT32_Seek_File( struct FileInfoStruct *pfi, unsigned long offset):文件定位函数:返回0说明定位失败返回1说明定位成功,参数是文件当前的信息,定位成功后这些信息将会被修改。
unsigned long FAT32_ReadFile(struct FileInfoStruct *pfi, unsigned long offset, unsigned long len, unsigned char *pbuf):文件读取函数:返回实际读取到的字节数,如果返回0说明读取失败。参数FileInfoStruct文件结构体,包含了文件的位置,offset为文件的偏移量,len为要读取数据的长度,如果超过文件长度,读取的实际数据长度是文件大小与偏移量的差值。
pbuf为数据缓冲区,读取到的数据放在其中。