SD 卡中FAT16 文件分析
我们通常使用的硬盘的结构基本是这样的:一个电机带着N 张盘片,通过磁头对上面的存储空间对写读写。每张盘面被分为多个磁道,每个磁道上又有多个扇区。一般一个硬盘还有多个磁头。为了便于管理,人们搞出来一个文件系统,常见的就是FAT16 和FAT32 以及NT 系统上的NTFS 。当然,半导体存储器虽然没有了这些机械的结构,但文件系统格式当时是在磁盘上搞出来的,所以有些格式还是得照它的模样来做的。这里,我们仅分析最常见的一种FAT16 格式,即每个扇区大小为512 字节,每个簇由32 个扇区组成的这一种FAT 格式,其他的大家可以自己查找相关资料。由于这个资料是我自己为了使用SD 卡而临时整理出来的,所以仅供大家参考之用。
下面以一张SD 卡里的内容分析一下FAT16 ,用于帮助大家用单片机操作SD 卡。
上面为一个512M 的SD 卡的第一个物理扇区,大小为512B,常称为引导扇区。即MBR (主引导记录)。这个区在电脑硬盘上这个就是bios 执行完ROM 中的程序后在磁盘上访问的第一块空间,这里有一些引导信息。长度为466字节,地址为0x00~0x1BD 。从1BE 开始,每16 个字节代表一个分区,共有4 个,我这张SD 卡只有一个分区,所以只有1BE-1CD 有内容,后面三个都是空的。这四个16 字节的表项就是我们所常说的分区表。
偏移
|
例子中的地址
|
长度
|
内容
|
0
|
1BE
|
1
|
激活标记,如果是活动分区那么这个为80,否则为00
|
1
|
1BF
|
1
|
分区起始的磁头号,这里为03,但对电子盘来说已经没有意义了
|
2
|
1C0
|
2
|
起始扇区和柱面号,低6 位是扇区号,高2 位是柱面号的9,10 位, 高8 位是术在号的低8 位
|
4
|
1C2
|
1
|
分区类型,0x0B = FAT32, 0x83 = Linux,00 表示未用。06 估计是FAT16。
|
5
|
1C3
|
1
|
分区结束的磁头号
|
6
|
1C4
|
2
|
分区结束的扇区和柱面号。与起始扇区柱面号的格式一样
|
7
|
1C6
|
4
|
在线性寻址方式下的分区相对扇区地址(对于基本分区即为绝对地址)。没看懂上面的话,但知道从这个地址里边读到的内容就是逻辑地址的0 扇区。
|
12
|
1CA
|
4
|
分区的总扇区数,这里为0x0F4317=1000215
|
从物理扇区的E9 处,也就是逻辑0 扇区读取数据,内容如下图
这个区的具体内容如下
名称
|
偏移
|
长度
|
内容说明,主要是上面为例
|
BS_jmpBoot
|
0
|
3
|
一般为EB xx 90 或E9 xx xx
|
OEMName
|
3
|
8
|
无所谓,只是一个名子
|
每扇字节数
|
0B
|
2
|
00 02 也就是0x0200=512,说明一个扇区是512 字节
|
每簇扇区数
|
0D
|
1
|
20,即每簇32 个扇区,也就是说它的一个簇=32*512=16K
|
保留扇区数
|
0E
|
2
|
从第1 扇区开始被保留的扇区数,FAT16 必须为1
|
FAT 表份数
|
10
|
1
|
一般都是两个FAT 表, 两者一样。
|
根目录项数
|
11
|
2
|
为了兼容性,一般FAT16 为512,即00 02
|
TotSec16
|
13
|
2
|
总扇区数,当扇区多大0x10000 时就放在偏移为TotSec32 处。很显然,512M=1M 个扇区,大于0x100000。所以这里为0。
|
介质种类
|
15
|
1
|
0xF8 表示固定存储介质, F0 表示移动存储介质,还有0xF9,FA,FB,FC,FD,FE 和FF 都是合法的值。但它必须和FAT 表中的FAT[0]一致。
|
FATSz16
|
16
|
2
|
7B 00=123 表示一个分区表占123 个扇区
|
SecPerTrk
|
18
|
2
|
每磁道的扇区数,由于这不是硬盘,所以这里没有意义
|
磁头数
|
1A
|
2
|
磁头数,同上
|
HiddSec
|
1C
|
4
|
FAT 表所在的分区前面隐藏的扇区数,这里为E9=233
|
TotSec32
|
20
|
4
|
17 43 0f 00 即0xf4317=1000215, 由此可见,这个卡的容量=512B*1000215=512M
|
DrvNum
|
24
|
1
|
一般硬盘为0x80 软盘为0x00
|
保留
|
25
|
1
|
供NT 用的,这里必须为0
|
BootSig
|
26
|
1
|
29,扩展引导标记,这表后面的三个域是可用的。当然,这里这个一个域。
|
VolID
|
27
|
4
|
就是一个ID,内容随便
|
VolLab
|
2B
|
11
|
卷标,不要说吧。长度11 个字,这里是NO NAME
|
FilesysType
|
36
|
8
|
这里是FAT16
|
可执行代码
|
3E
|
347
|
如果是引导分区那么会有相应的数据,这里全为0 了
|
1 分区头
|
1BE
|
1
|
0x80 和0x00,80 是表示缺省分区(一般是C 盘)
|
|
1BF
|
1
|
开始的磁头地址
|
|
1C0
|
2
|
开始的扇区地址和柱面地址, 扇区地址占用了1C0 的低6 位, 高2 位和1C1 组成了柱面地址
|
|
1C2
|
1
|
分区类型
|
|
1C3
|
1
|
结束的磁头
|
|
1C4
|
2
|
结束的扇区和柱面
|
|
1C6
|
4
|
分区内第一个扇区地址
|
|
1CA
|
4
|
分区内的总扇区数
|
2 分区
|
1CE
|
16
|
结构同上,第3,4 也是这样,每个区16 字节
|
签名
|
1FE
|
2
|
55 AA
|
以上是一张SD 卡的BPB(BIOS 参数数据块),从上面我们可以得到一些有用的信息:
1. 卡的大小是512M
2. 每个簇有32 个扇区,即16K
3. 卡的总扇区数1000215,隐含区数233
4. FAT 表的大小为123 个扇区根据FAT16 的格式,主引导区后就是两个一样的分区表,分区表后面又跟了32个扇区作为根目录区。然后后面就是存放文件和文件夹的地方了。每个分区表既然大小算出来是123 个扇区,那么FAT1 在1-123 扇区,FAT2 就是124-246 扇区,根目录就是247-278,数据区开始于279。
在主引导区后面就是FAT 表了。从上面可以得知一个FAT 表是123 个扇区。它里边的内容很简单,里边的内容就是指出下一个簇在哪里。你的盘有多少个簇,那么它的FAT 表就要有多少个项来描述它们。因为FAT16 是用2 个字节(16 位)来描述一个簇的,所以这时FAT 表的大小就应该是2 位的簇数个字节。FAT 表中,第4,5 个簇表示第2 个簇,第6,7 个字节表示第3 个簇,第8,9 字节表示第4 个簇……。就这样,每一个簇都有两个和它对应的字节。这两个字节里面存放的数据就是下一个16K 数据所在的簇号。2 个字节最大能表示65535, 一个簇最大为32K ,所以FAT16 最多能给65565*32K≈2G。这就是FAT16 格式为什么分区不能大于2G 的原因。实际上,并不是所有的数值都代表簇号,有几个值被赋于了特定的含义,我们先看看这几个特殊值代表的含义。
序号
|
数值
|
含义
|
|
FFF8
|
磁盘标识字。
|
|
FFFF
|
第一簇已经被占用
|
|
0000
|
未使用的簇
|
|
0002-FFEF
|
使用的簇
|
|
FFF0-FFF6
|
系统留的,一般不会出现这几个簇号
|
|
FFF7
|
坏簇,在写文件时不能向它里边写
|
|
FFF8-FFFFF
|
表示这是最后一个簇了,文件到此结束了
|
看一个例子吧
上面是我的SD 卡中第一个扇区的内容。它一开始就是F8 FF FF FF,从前面的特殊数值中可以知道,这就是硬盘的标识,并且第1 簇已经被占用了。我的SD 卡里有一个文件,名子叫dssd.bin ,它是我把卡买回来后拷进去的第一个文件。它的第一个簇的地址是0x0002。这个地址从哪里得来的要看后面的内容了,暂且就把它当已知条件吧。这也就是说, 在SD 卡的第2 个簇里边存放着dssd.bin 的第1 个16K 数据,那么它的第二个16K 放在哪里呢,我们要看FAT 表,每2 个簇对应于FAT 表中的第4,5 个字节,里边的内容为0003,也就是说第2 个16K数据在第3 个簇里。第3 个簇对应的FAT 表中的数据又是什么呢,原来是0004,也就是说第3 个16K 的数据在第4 个簇里。这样继续跟踪,我们发现,第9 个簇里的数据是FFFF,FFFF 是什么意思?看一下特殊数值的含义,原来这是最后一个簇,也就是说, 我的dssd.bin 文件到此为止。于是我们只要跟着FAT 表的“指路”顺利地把dssd.bin 文件从SD 卡中找到了。它在卡里占用了8 个簇,我的卡里边1 个簇为16K,所以这个文件的大小也就最多为128K 了。所以我们只要根据SD 卡的读写方法,把第2-8 簇里的内容读出来就OK 了。
注意一下,我这张卡是为了学习FAT16 而买的,没有碎片,所以文件的簇和簇都是连在一起的,但实际上并不一定都是连着的,一定要通过FAT 表中的指示去寻找下一个簇所在的位置。
说完FAT 表,下面应该来看根目录区了。根目录区里面放的东西就是根目录下所见的东西,根据对引导扇区的分析,我们可以找到根目录区在第247 扇内。用winhex 打开第247 个扇区
FAT16 和FAT32 每个文件名都占32 个字节,这里放的是短文件名,也就是“8.3”格式的。但FAT16 的根目录区只有32 个扇区,计算一下,每个扇区512 字节,共32 个扇区,而每个文件要占用32 个字节,很显然,根目录只能放512 个文件了。因此,FAT16 的根目录下只能放512 个文件(及文件夹)就是这个原因。
先看前32 字节,它的内容是这样的就看最前面的32 字节吧,它表示了一个文件(或文件夹),现在对它分析一下。前11 个字节是文件名。从后面的ASCII 表中可以看出,它就是我写进去的那个名为dssd.bin。第0x0B 个字节内容为0x20,可以知道它的属性为存档,这与我们从windows 中观察到的它的属性是一致的。大小为128K,也与我们的分析一致。
-
liuliuliuliu
我用CMD17 指令,地址为0;(0X51,0X00,0X00,0X00,0X00,0X95),读出的数据前几个字节是08,f7,20,f7,52,f6,f8,61,
就是没有E8或者E9所以怀疑地址不对.卡是2G的内存卡.
-
|