FAT
文件起源于
70
年代末
80
年代初,用于微软的
MS-DOS
操作系统。它开始被设计成一个简单的文件系统用于小于
500K
的软件盘。后来被功能被大大增强用于支持越来越大的媒质。现在的文件系统有
FAT12
,
FAT16
和
FAT32
三种子类。
FAT12
是最早的一版,主要用于软盘,它对簇的编址采用
12bit
宽度的数,所以称为
FAT12
。
12bit
的地址可以寻址
4096
个簇,事实上在
FAT12
中只能寻址
4078
个簇(在
Linux
下可寻址
4084
个簇),有一些簇号是不能用的,在后面会给出具体的说明。磁盘的扇区是用
16bit
的数进行计算的,所以磁盘的容量就被局限在
32M
空间之内。
在
FAT16
中,采用了
16bit
宽的簇地址,
32bit
宽扇区地址。虽然
32bit
的扇区地址可以寻址
2^32*512
,约
2
个
TB
的容量,
但于由规定每簇最大的容量不超过
1024*32
,所以
FAT16
文件系统的容量也就限制到了
2^16*1024*32
,大约
2.1GB
的空量,并且实际还达不到这个值。
FAT32
文件系统使用了
32bit
宽的簇地址,所以称为
FAT32
。但在微软件的文件系统中只使用了低
28
位,最大容量为
2^28*1024*32,
约
8.7TB
的空量。有的人认为
32bit
全用,最大容量为
2^32*1024*32
,这种说法是不正确的。
虽然
FAT32
具有容纳近乎
8.7TB
的容量,但实际应用中通常不使用超过
32GB
的
FAT32
分区。
WIN2000
及之上的
OS
已经不直接支持对超过
32GB
的分区格式化成
FAT32
,但
WIN98
依然可以格式化大到
127GB
的
FAT32
分区,但不推荐这样做。
下面是一个
FAT
分区的构成概况
引导扇区
|
其他保留扇区(可选)
|
FAT
表
1
|
FAT
表
2
|
根目录区
(仅
FAT12/16
)
|
数据区
(用于文件和目录)
|
需要说明的是:
1
.引导扇区和其他保留扇区一起称为保留扇区,而其他保留扇区是可选的,当没有时候,引导扇区后紧跟的就是
FAT
表
1
2
.根目录区是仅
FAT12/16
才有,
FAT32
的目录项位于数据区。由于
FAT12/16
的根目录区是一个固定的区域,所以它的根目录的项数是有限制的,意即不能在根录建立超过这个定数的目录项数。
(一)引导扇区与
BPB
BPB
(
BIOS Parametre Block
)是
FAT
文件系统中第一个重要的数据结构,它位于该
FAT
分区的第一个扇区,同时也属于
FAT
文件系统基本区域的保留区,
在下面的描述中。凡名称以
BPB_
开头的都是
BPB
的一部分,凡名称与
BS_
开头的项都是启动扇区的一部分,而不是属于
BPB
的内容,以下是启动扇区的结构
|
offset
(
byte
)
|
长度(
byte
)
|
描述
|
BS_jmpBoot
|
0x00
|
3
|
跳转指令,指向启动代码
|
BS_OEMName
|
0x03
|
8
|
建议值为“
MSWIN4.1”。有些厂商的FAT
驱动可能会检测此项,所以设为“
MSWIN4.1”可以尽量避免兼容性的问题
|
BPB_BytsPerSec
|
0x0b
|
2
|
每扇区的字节数,取值只能是以下几种:
512
,
1024
,
2048
或是
4096
。设为
512
会取得最好的兼容性,目前有很多
FAT
代码都是硬性规定每扇区的字节数为
512
,而不是实际的检测此值。但微软的操作系统能够很好支持
1024
,
2048
或是
4096
|
BPB_SecPerClus
|
0x0d
|
1
|
每簇的扇区数,其值必须中
2
的整数次方(该整数必须
>=0
),同时还要保证每簇的字节数不能超过
32K
,也就是
1024*32
字节
|
BPB_RsvdSecCnt
|
0x0e
|
2
|
保留扇区的数目,此域不能为
0
,
FAT12/FAT16
必须为
1
,
FAT32
的典型值取为
32
,,微软的系统支持任何非
0
值
|
BPB_BumFATs
|
0x10
|
1
|
分区中
FAT
表的份数,,任何
FAT
格式都建议为
2
|
BPB_RootEntCnt
|
0x11
|
2
|
对于
FAT12
和
FAT16
此域包含根目录中目录的个数(每项长度为
32bytes
),对于
FAT32
,此项必须为
0
。对于
FAT12
和
FAT16
,此数乘以
32
必为
BPB_BytesPerSec
的偶数倍,为了达到更好的兼容性,
FAT12
和
FAT16
都应该取值为
512
|
BPB_ToSec16
|
0x13
|
2
|
早期版本中
16bit
的总扇区,这里总扇区数包括
FAT
卷上四个基本分区的全部扇区,此域可以为
0
,若此域为
0
,那么
BPB_ToSec32
必须为
0
,对于
FAT32
,此域必为
0
。对于
FAT12/FAT16
,此域填写总扇区数,如果该值小于
0x10000
的话,
BPB_ToSec32
必须为
0
|
BPB_Media
|
0x15
|
1
|
对于“固定”(不可移动)存储介质而言,
0xF8
是标准值,对于可移动存储介质,经常使用的数值是
0xF0
,此域合法的取值可以取
0xF0,0xF8,0xF9,0xFA,0xFC,0xFD,0xFE,0xFF
。另外要提醒的是,无沦此域写入什么数值,同时也必须在
FAT[0]
的低字节写入相同的值,这是因为早期的
MSDOS 1.x
使用该字节来判定是何种存储介质
|
BPB_FATz16
|
0x16
|
2
|
FAT12/FAT16
一个
FAT
表所占的扇区数,对于
FAT32
来说此域必须为
0
,在
BPB_FATZ32
中有指定
FAT
表的大小
|
BPB_SecPerTrk
|
0x18
|
2
|
每磁道的扇区数,用于
BIOS
中断
0x13
,此域只对于有“特殊形状”(由磁头和柱面每分割为若干磁道)的存储介质有效,同时必须可以调用
BIOS
的
0x13
中断得到此数值
|
BPB_NumHeads
|
0x1A
|
2
|
磁头数,用于
BIOS
的
0x13
中断,类似于上面的
BPB_ SecPerTrk
,只对特殊的介质才有效,此域包含一个至少为
1
的数值,比如
1,4M
的软盘此域为
2
|
BPB_HidSec
|
0x1C
|
4
|
在此
FAT
分区之前所隐藏的扇区数,必须使得调用
BIOS
的
0x13
中断可以得到此数值,对于那些没有分区的存储介质,此域必须为
0
,具体使用什么值由操作系统决定
|
BPB_ToSec32
|
0x20
|
4
|
该卷总扇区数(
32bit
),这里的扇区总数包括
FAT
卷四个个基本分的全部扇区,此域可以为
0
,若此域为
0
,
BPB_ToSec16
必须为非
0
,对
FAT32
,此域必须是非
0
。对于
FAT12/FAT16
如果总扇区数大于或等于
0x10000
的话,此域就是扇区总数,同时
BPB_ToSec16
的值为
0
。
|
FAT32
的
BPB
的内容和
FAT12/16
的内容在地址
36
以前是完全一样的,从偏移量
36
开始,他们的内容有所区别,具体的内容要看
FAT
类型为
FAT12/16
还是
FAT32
,这点保证了在启动扇区中包含一个完整的
FAT12/16
或
FAT32
的
BPB
的内容,这么做是为了达到最好的兼容性,同时也为了保证所有的
FAT
文件系统驱动程序能正确的识别和驱动不同的
FAT
格式,并让他们良好地工作,因为他们包含了现有的全部内容
从
offset 36
开始
FAT12/FAT16
的内容开始区别于
FAT32
,下面分两个表格列出,下表为
FAT12/FAT16
的内容
名称
|
offset
(
byte
)
|
长度(
byte
)
|
描述
|
BS_drvNum
|
0x24
|
1
|
用于
BIOS
中断
0x13
得到磁盘驱动器参数,(
0x00
为软盘,
0x80
为硬盘)。此域实际上由操作系统决定
|
BS_Reseved1
|
0x25
|
1
|
保留(供
NT
使用),格式化
FAT
卷时必须设为
0
|
BS_VolID
|
0x26
|
1
|
扩展引导标记(
0x29
)用于指明此后的
3
个域可用
|
BS_BootSig
|
0x27
|
4
|
卷标序列号,此域以
BS_VolLab
一起可以用来检测磁盘是否正确,
FAT
文件系统可以用此判断连接的可移动磁盘是否正确,引域往往是由时间和日期组成的一个
32
位的值
|
BS_VolLab
|
0x2B
|
11
|
磁盘卷标,此域必须与根目录中
11
字节长的卷标一致。
FAT
文件系统必须保证在根目录的卷标文件列改或是创建的同时,此域的内容能得到时的更新,当
FAT
卷没有卷标时,此域的内容为“
NO NAME
”
|
BS_FilSysType
|
0x36
|
8
|
以下的几种之一:“
FAT12
”,“
FAT16
”,“
FAT32
”
不少人错误的认为
FAT
文件系统的类型由此域来确认,他细点你就能发现此域并不是
BPB
的一部分,只是一个字符串而已,微软的操作系统并不使用此此域来确定
FAT
文件的类型,;因为它常常被写错或是根本就不存在。
|
下表为
FAT32
的内容
名称
|
offset
(
byte
)
|
长度(
byte
)
|
描述
|
BPB_FATSz32
|
0x24
|
4
|
一个
FAT
表所占的扇区数,此域为
FAT32
特有,同时
BPB_FATSz16
必须为
0
|
BPB_Flags
|
0x28
|
2
|
此域
FAT32
特有。
Bits0-3:
不小于
0
的
FAT
(
active FAT
)数目,只有在镜像(
mirrorig
)禁止时才有效。
Bits 4-6:
保留
Bits 7
:
0
表示
FAT
实时镜像到所有的
FAT
表中
1
表示只有一个活动的
FAT
表。这个表就是
Bits0-3
所指定的那个
Bits8-15
:
保留
|
BPB_FSVer
|
0x2A
|
2
|
此域为
FAT32
特有,
高位为
FAT32
的主版本号,低位为次版本号,这个版本号是为了以后更高级的
FAT
版本考虑,假设当前的操作系统只能支持的
FAT32
版本号为
0.0
。那么该操作系统检测到此域不为
0
时,它便会忽略
FAT
卷,因为它的版本号比系统能支持的版式本要高
|
BPB_RootClus
|
0x2C
|
4
|
根目录所在第一个簇的簇号,通常该数值为
2
,但不是必须为
2
磁盘工具在改变根目录位置时,必须想办法让磁盘上第一个非坏簇作为根目录的第一个簇(比如第
2
簇,除非它已经被标记为坏簇),这样的话,如果此域正好为
0
的话磁盘检测工具也能轻松的找到根目录所在簇的位置
|
BPB_FSIfo
|
0x30
|
2
|
保留区中
FAT32
卷
FSINFO
结构所占的扇区数,通常为
1
在
Backup Boot
中会有一个
FSINFO
的备份,但该备份只是更新其中的指针,也就是说无论是主引导记录还是备份引导记录都是指向同一个
FSINFO
结构
|
BPB__BkBootSec
|
0x32
|
2
|
如果不为
0
,表示在保留区中引导记录的备数据所占的扇区数,通常为
6
。同时不建议使用
6
以外的其他数值
|
BPB_Reserved
|
0x34
|
12
|
用于以后
FAT
扩展使用,对
FAT32
。此域用
0
填充
|
BS_DrvNum
|
0x40
|
1
|
与
FAT12/16
的定义相同,只不过两者位于启动扇区不同的位置而已
|
BS_Reserved1
|
0x41
|
1
|
与
FAT12/16
的定义相同,只不过两者位于启动扇区不同的位置而已
|
BS_BootSig
|
0x42
|
1
|
与
FAT12/16
的定义相同,只不过两者位于启动扇区不同的位置而已
|
BS_VolID
|
0x43
|
4
|
与
FAT12/16
的定义相同,只不过两者位于启动扇区不同的位置而已
|
BS_FilSysType
|
0x47
|
11
|
与
FAT12/16
的定义相同,只不过两者位于启动扇区不同的位置而已
|
BS_FilSysType
|
0x52
|
8
|
通常设置为“
FAT32
”,请参照
FAT12/16
此部分的陈述。
|
关于
FAT
启动扇区还有一点重要的说明,我们假设里面的内容是按字节排序的,那么扇区
[510]
的内容一定
0x55
,扇区
[511]
的内容一定是
0xAA
很多
FAT
资数文档会把
0xAA55
说成是“启动扇区最后两字节的内容”,这样的陈述是正确的
—
仅仅是如果
—BPB_BytsPerSec
的值为
512
的话。若
BPB_BytsSec
的值大于
512
,该标记的位置并没有改变(虽然在启动扇区的最后两个字节写
0xAA55
并没有问题)
关于
BPB_ToSec16/32
这里再作一点补充:假设一现在我们有一块磁盘或一个分区,它的扇区数为
DskSz
,如果
BPB_aToSec(BPB_ToSec16
或是
BPB_ToSec32
基中不为
0
的那个
)
的值小于或等于
DskSz
并不会使该
FAT
卷在使用中出现什么错误,实际上
BPB_ToSec16/32
的值不要比
DskSz
小得离谱就不会有什么错误
这样做将造成磁盘空间的浪费,程序本身并不会认为该
FAT
卷存在什么错误,但是,如果
BPB_ToSec16/32
的值比
DskSz
大将会使
FAT
卷遭到严重的损坏,因为它超出了存储介质或是磁盘分区的边界。当
BPB_ToSec16/32
的值比
DskSz
大时,一些数据将不幸地被丢失
FAT文件系统数据结构C语言表示
FAT文件系统相关数据结构
struct fat_boot_sector {
uint8_t ignored[3]; /* 0x00 Boot strap short or near jump */
int8_t system_id[8]; /* 0x03 Name - can be used to special case
partition manager volumes */
uint8_t sector_size[2]; /* 0x0B bytes per logical sector */
uint8_t sectors_per_cluster; /* 0x0D sectors/cluster */
uint16_t reserved; /* 0x0E reserved sectors */
uint8_t fats; /* 0x10 number of FATs */
uint8_t dir_entries[2]; /* 0x11 root directory entries */
uint8_t sectors[2]; /* 0x13 number of sectors */
uint8_t media; /* 0x15 media code (unused) */
uint16_t fat_length; /* 0x16 sectors/FAT */
uint16_t secs_track; /* 0x18 sectors per track */
uint16_t heads; /* 0x1A number of heads */
uint32_t hidden; /* 0x1C hidden sectors (unused) */
uint32_t total_sect; /* 0x20 number of sectors (if sectors == 0) */
/* The following fields are only used by FAT32 */
uint32_t fat32_length; /* 0x24=36 sectors/FAT */
uint16_t flags; /* 0x28 bit 8: fat mirroring, low 4: active fat */
uint8_t version[2]; /* 0x2A major, minor filesystem version */
uint32_t root_cluster; /* 0x2C first cluster in root directory */
uint16_t info_sector; /* 0x30 filesystem info sector */
uint16_t backup_boot; /* 0x32 backup boot sector */
uint8_t BPB_Reserved[12]; /* 0x34 Unused */
uint8_t BS_DrvNum; /* 0x40 */
uint8_t BS_Reserved1; /* 0x41 */
uint8_t BS_BootSig; /* 0x42 */
uint8_t BS_VolID[4]; /* 0x43 */
uint8_t BS_VolLab[11]; /* 0x47 */
uint8_t BS_FilSysType[8]; /* 0x52=82*/
/* */
uint8_t nothing[420]; /* 0x5A */
uint16_t marker;
} __attribute__ ((__packed__));
struct msdos_dir_entry {
int8_t name[8],ext[3]; /* 00 name and extension */
uint8_t attr; /* 0B attribute bits */
uint8_t lcase; /* 0C Case for base and extension */
uint8_t ctime_ms; /* 0D Creation time, milliseconds */
uint16_t ctime; /* 0E Creation time */
uint16_t cdate; /* 10 Creation date */
uint16_t adate; /* 12 Last access date */
uint16_t starthi; /* 14 High 16 bits of cluster in FAT32 */
uint16_t time; /* 16 time, date and first cluster */
uint16_t date; /* 18 */
uint16_t start; /* 1A */
uint32_t size; /* 1C file size (in bytes) */
};
/* Up to 13 characters of the name */
struct msdos_dir_slot {
uint8_t id; /* 00 sequence number for slot */
uint8_t name0_4[10]; /* 01 first 5 characters in name */
uint8_t attr; /* 0B attribute byte */
uint8_t reserved; /* 0C always 0 */
uint8_t alias_checksum; /* 0D checksum for 8.3 alias */
uint8_t name5_10[12]; /* 0E 6 more characters in name */
uint16_t start; /* 1A starting cluster number, 0 in long slots */
uint8_t name11_12[4]; /* 1C last 2 characters in name */
};
uint8_t ignored[3]; /* 0x00 Boot strap short or near jump */
int8_t system_id[8]; /* 0x03 Name - can be used to special case
partition manager volumes */
uint8_t sector_size[2]; /* 0x0B bytes per logical sector */
uint8_t sectors_per_cluster; /* 0x0D sectors/cluster */
uint16_t reserved; /* 0x0E reserved sectors */
uint8_t fats; /* 0x10 number of FATs */
uint8_t dir_entries[2]; /* 0x11 root directory entries */
uint8_t sectors[2]; /* 0x13 number of sectors */
uint8_t media; /* 0x15 media code (unused) */
uint16_t fat_length; /* 0x16 sectors/FAT */
uint16_t secs_track; /* 0x18 sectors per track */
uint16_t heads; /* 0x1A number of heads */
uint32_t hidden; /* 0x1C hidden sectors (unused) */
uint32_t total_sect; /* 0x20 number of sectors (if sectors == 0) */
/* The following fields are only used by FAT32 */
uint32_t fat32_length; /* 0x24=36 sectors/FAT */
uint16_t flags; /* 0x28 bit 8: fat mirroring, low 4: active fat */
uint8_t version[2]; /* 0x2A major, minor filesystem version */
uint32_t root_cluster; /* 0x2C first cluster in root directory */
uint16_t info_sector; /* 0x30 filesystem info sector */
uint16_t backup_boot; /* 0x32 backup boot sector */
uint8_t BPB_Reserved[12]; /* 0x34 Unused */
uint8_t BS_DrvNum; /* 0x40 */
uint8_t BS_Reserved1; /* 0x41 */
uint8_t BS_BootSig; /* 0x42 */
uint8_t BS_VolID[4]; /* 0x43 */
uint8_t BS_VolLab[11]; /* 0x47 */
uint8_t BS_FilSysType[8]; /* 0x52=82*/
/* */
uint8_t nothing[420]; /* 0x5A */
uint16_t marker;
} __attribute__ ((__packed__));
struct msdos_dir_entry {
int8_t name[8],ext[3]; /* 00 name and extension */
uint8_t attr; /* 0B attribute bits */
uint8_t lcase; /* 0C Case for base and extension */
uint8_t ctime_ms; /* 0D Creation time, milliseconds */
uint16_t ctime; /* 0E Creation time */
uint16_t cdate; /* 10 Creation date */
uint16_t adate; /* 12 Last access date */
uint16_t starthi; /* 14 High 16 bits of cluster in FAT32 */
uint16_t time; /* 16 time, date and first cluster */
uint16_t date; /* 18 */
uint16_t start; /* 1A */
uint32_t size; /* 1C file size (in bytes) */
};
/* Up to 13 characters of the name */
struct msdos_dir_slot {
uint8_t id; /* 00 sequence number for slot */
uint8_t name0_4[10]; /* 01 first 5 characters in name */
uint8_t attr; /* 0B attribute byte */
uint8_t reserved; /* 0C always 0 */
uint8_t alias_checksum; /* 0D checksum for 8.3 alias */
uint8_t name5_10[12]; /* 0E 6 more characters in name */
uint16_t start; /* 1A starting cluster number, 0 in long slots */
uint8_t name11_12[4]; /* 1C last 2 characters in name */
};
具体可以参考下面的资料:http://download.csdn.net/detail/new_abc/4184969