FAT16文件系统学习笔记(2009/12/31)
2010-05-04 11:13
561 查看
SD+FAT16文件系统学习笔记
―――LSHICEMAN、091231
一、物理扇区0(MBR)
物理扇区0常称为引导扇区(MBR).读取出SD卡的物理扇区0,在物理扇区0的0x1C6~0x1C9这4个字节中,可以得到逻辑扇区0(主引导区)的物理扇区地址.可能是因为我不会用WinHex,无法打开物理扇区,只能选择打开逻辑扇区.所以只有从开发板上读出物理扇区0的信息,然后用UART输出.我的SD卡物理扇区0的部分内容如下:
0 1
2 3 4
5 6 7 8
9 A B
C D E F
1B0 0 0
0 0 0
0 0 0 0
0 0 0
0 0 0 2
1C0 c 0
6 3f ff b7 89 0 0
0 77 91 3a 0 0
0
1D0 0
0 0 0
0 0 0 0
0 0 0
0 0 0 0
0
1E0 0 0
0 0 0
0 0 0 0
0 0 0
0 0 0 0
1F0 0 0
0 0 0
0 0 0 0
0 0 0
0 0 55 aa
前446字节为一些引导信息,地址为
0x00~0x1BD。从0x1BE开始,每16字节就为一个分区的信息,我的SD卡只有一个分区,所以只有0X1BE~0X1CD有内容.最后两个字节0X55、0XAA为签名.从0X1C6~0X1C9可以知道逻辑扇区0的位置。我这里为89
00 00 00,即0X89,所以第137个物理扇区为逻辑扇区0.这16字节的分区信息的其它内容参考下表(表截图于jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
二、主引导区逻辑扇区0(BPB--BIOS参数数据块)
知道了逻辑扇区0的物理扇区位置,接下来的文件系统操作都是基于这个逻辑扇区0,但SD卡的读、写扇区的操作都是从物理扇区地址计算的,比如我想读出逻辑扇区0的数据,我这里就是ReadSingelBlock(137,buffer).我的SD逻辑分区0的内容如下:
从这里,我们可以得到每扇区的字节数,每簇的扇区数,FAT表所占的扇区数,总扇区数(逻辑扇区),隐藏扇区数(逻辑扇区0前面的物理扇区数),详细内容参考下表(表截图于
jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
对于上表,通过我的SD卡的逻辑扇区0中的数据可得出:每扇区的字节数为512,每簇的扇区数是0X40(64),既32KB,FAT表的SIZE为0XEB(235)个扇区,总逻辑扇区数为0X003A9177(3838327),隐藏扇区数为0X89(137).
三、FAT表
逻辑扇区0之后,跟着的就是两张一模一样的FAT表,从上可知FAT表的SIZE为235,所以第一张FAT表的扇区地址是1~235,第二张FAT表的扇区地址是236~470,只要加上隐藏的扇区数,就可以计算出物理扇区的地址,因为FAT文件系统的操作是基于物理扇区地址的。FAT表用两个字节表示一个簇,第0簇用第0、1字节表示,第1簇用第2、3字节表示,以此类推。这两个字节里的数值指出下一簇的序号,用查FAT表的方法,就可以知道存放着一个文件的所有簇,当然,一个文件的簇可能并不是连续的。结束簇的值是0XFFFF其它特殊值的含义如下表(表截图于jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
结合上表,可以看出,第0、1簇已经为文件系统所用了,所以我们储存文件就是从第2簇开始的。综合上面分析过的,第2个簇的物理扇区地址=隐藏的扇区数+FAT保留的扇区数+FAT表的扇区数*2+根目录扇区数(FAT16的根目录扇区数固定为32),我的SD卡为137+1+235*2+32=640。
四、根目录
根目录里记录着在SD卡的根目录上的文件,包括文件夹,用32个字节来保存根目录下一个文件的信息。FAT16的根目录扇区数为32,因为一个文件信息占32字节,所以FAT16的根目录下的文件最大数为512个。这32个字节的内容如下表(表截图于
jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
一般文件对照上表就可以查出相关信息,特殊的是文件夹。如果根目录下的文件信息显示这个文件是文件夹的话,进入相关簇,可以看到,这个文件夹的簇的格式和根目录也是一样的,也是用32个字节记录文件信息,如果这里面还是有文件夹,则以此类推下去。无论这个文件夹里面是否有文件,里面总会有两个32字节的文件信息。如下图是我的SD卡的SD卡的根目录下的一个文件夹,这个文件夹在第2簇,这个文件夹里面是空的,名为123。
可以看到第一个文件名为0X2E,0X2E在ASCII中表示”.”,表示这是一个目录,0X20表示空格。这个文件就表示是当前目录,在DOS中,也是用”.”表示当前目录的。可以再看一下这个文件的所在簇,就是第2簇,所以这个就表示是当前文件夹。接下来,第三、四行数据显示文件名是0X2E
0X20 0X20……,0X2E 0X2E就是“..”,这就是表示上一级目录,可以看一下这个文件的簇地址,是00,00就表示是根目录。
fat.h:
fat.c:
―――LSHICEMAN、091231
一、物理扇区0(MBR)
物理扇区0常称为引导扇区(MBR).读取出SD卡的物理扇区0,在物理扇区0的0x1C6~0x1C9这4个字节中,可以得到逻辑扇区0(主引导区)的物理扇区地址.可能是因为我不会用WinHex,无法打开物理扇区,只能选择打开逻辑扇区.所以只有从开发板上读出物理扇区0的信息,然后用UART输出.我的SD卡物理扇区0的部分内容如下:
0 1
2 3 4
5 6 7 8
9 A B
C D E F
1B0 0 0
0 0 0
0 0 0 0
0 0 0
0 0 0 2
1C0 c 0
6 3f ff b7 89 0 0
0 77 91 3a 0 0
0
1D0 0
0 0 0
0 0 0 0
0 0 0
0 0 0 0
0
1E0 0 0
0 0 0
0 0 0 0
0 0 0
0 0 0 0
1F0 0 0
0 0 0
0 0 0 0
0 0 0
0 0 55 aa
前446字节为一些引导信息,地址为
0x00~0x1BD。从0x1BE开始,每16字节就为一个分区的信息,我的SD卡只有一个分区,所以只有0X1BE~0X1CD有内容.最后两个字节0X55、0XAA为签名.从0X1C6~0X1C9可以知道逻辑扇区0的位置。我这里为89
00 00 00,即0X89,所以第137个物理扇区为逻辑扇区0.这16字节的分区信息的其它内容参考下表(表截图于jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
二、主引导区逻辑扇区0(BPB--BIOS参数数据块)
知道了逻辑扇区0的物理扇区位置,接下来的文件系统操作都是基于这个逻辑扇区0,但SD卡的读、写扇区的操作都是从物理扇区地址计算的,比如我想读出逻辑扇区0的数据,我这里就是ReadSingelBlock(137,buffer).我的SD逻辑分区0的内容如下:
从这里,我们可以得到每扇区的字节数,每簇的扇区数,FAT表所占的扇区数,总扇区数(逻辑扇区),隐藏扇区数(逻辑扇区0前面的物理扇区数),详细内容参考下表(表截图于
jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
对于上表,通过我的SD卡的逻辑扇区0中的数据可得出:每扇区的字节数为512,每簇的扇区数是0X40(64),既32KB,FAT表的SIZE为0XEB(235)个扇区,总逻辑扇区数为0X003A9177(3838327),隐藏扇区数为0X89(137).
三、FAT表
逻辑扇区0之后,跟着的就是两张一模一样的FAT表,从上可知FAT表的SIZE为235,所以第一张FAT表的扇区地址是1~235,第二张FAT表的扇区地址是236~470,只要加上隐藏的扇区数,就可以计算出物理扇区的地址,因为FAT文件系统的操作是基于物理扇区地址的。FAT表用两个字节表示一个簇,第0簇用第0、1字节表示,第1簇用第2、3字节表示,以此类推。这两个字节里的数值指出下一簇的序号,用查FAT表的方法,就可以知道存放着一个文件的所有簇,当然,一个文件的簇可能并不是连续的。结束簇的值是0XFFFF其它特殊值的含义如下表(表截图于jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
结合上表,可以看出,第0、1簇已经为文件系统所用了,所以我们储存文件就是从第2簇开始的。综合上面分析过的,第2个簇的物理扇区地址=隐藏的扇区数+FAT保留的扇区数+FAT表的扇区数*2+根目录扇区数(FAT16的根目录扇区数固定为32),我的SD卡为137+1+235*2+32=640。
四、根目录
根目录里记录着在SD卡的根目录上的文件,包括文件夹,用32个字节来保存根目录下一个文件的信息。FAT16的根目录扇区数为32,因为一个文件信息占32字节,所以FAT16的根目录下的文件最大数为512个。这32个字节的内容如下表(表截图于
jimsboy(海洋之星)的“SD卡中
FAT16 文件分析”一文中)。
一般文件对照上表就可以查出相关信息,特殊的是文件夹。如果根目录下的文件信息显示这个文件是文件夹的话,进入相关簇,可以看到,这个文件夹的簇的格式和根目录也是一样的,也是用32个字节记录文件信息,如果这里面还是有文件夹,则以此类推下去。无论这个文件夹里面是否有文件,里面总会有两个32字节的文件信息。如下图是我的SD卡的SD卡的根目录下的一个文件夹,这个文件夹在第2簇,这个文件夹里面是空的,名为123。
可以看到第一个文件名为0X2E,0X2E在ASCII中表示”.”,表示这是一个目录,0X20表示空格。这个文件就表示是当前目录,在DOS中,也是用”.”表示当前目录的。可以再看一下这个文件的所在簇,就是第2簇,所以这个就表示是当前文件夹。接下来,第三、四行数据显示文件名是0X2E
0X20 0X20……,0X2E 0X2E就是“..”,这就是表示上一级目录,可以看一下这个文件的簇地址,是00,00就表示是根目录。
fat.h:
#ifndef _FAT_H_ #define _FAT_H_ /*-------------------定义返回代码----------------------------------*/ #define FAT_OK 0x00 #define AA55_ERROR 0x01 #define JMPBOOT_ERROR 0x02 /*--------------------定义数据结构体---------------------------------*/ typedef __packed struct { unsigned char Activity; //活动分区标记,如果为0x80,则为活动分区,0则不为 unsigned char StartHead; //分区起始磁头号 unsigned short Start_SectorCylinder; //起始扇区和柱面号 unsigned char Type; //分区类型,0x0b=fat32,0x83=linux,0x06=fat16 unsigned char EndHwad; //分区结束磁头号 unsigned short End_SectorCylinder; //结束扇区和柱面号 unsigned int FirLogSec; //分区的第一个扇区(逻辑扇区0) unsigned int Sectors; //分区的总扇区数 }DPT; typedef __packed struct { unsigned char Info[446]; //引导信息 DPT subarea0; //分区0信息 DPT subarea1; //分区1信息 DPT subarea2; //分区2信息 DPT subarea3; //分区3信息 unsigned short aa55; //签名:0xaa ,0x55 }MBR; typedef __packed struct { unsigned char JmpBoot[3]; //这应该为0XEB 0X?? 0X90 或 0XE9 0X?? 0X?? //(低字节在前) unsigned long OEMName; //名字 unsigned short BytesPerSec; //每扇区字节数 unsigned char SecPerClust; //每簇扇区数 unsigned short ResSectors; //保留扇区数 unsigned char Fats; //FAT表份数 unsigned short RootDirEnts; //根目录项数(根目录存放文件数) unsigned short ToSec16; //总扇区数的低16位 unsigned char Medium ; //介质种类, 0xF8 表示固定存储介质,F0 表示移动存//储介质,还有0xF9,FA,FB,FC,FD,FE 和 FF 都是合//法的值。但它必须和 FAT表中的 FAT[0]一致。 unsigned short FATSize; //FAT表的扇区数 unsigned short SecPerTrk; //每磁道扇区数(不是硬盘,没意义) unsigned short Heads; // 磁头数,同上 unsigned int HideSec; // FAT表所在的分区前面隐藏的扇区数,等于ResSectors unsigned int ToSec32; //总扇区数的高32位 unsigned char DrvNum; //一般硬盘为0x80 软盘为 0x00 unsigned char reserved; //供NT用的,这里必须为 0 unsigned char BootSig; // 扩展引导标记 unsigned int VolID; //ID unsigned char VolLab[11]; //卷标 unsigned char FilesysType[8]; //文件系统名字 unsigned char code[347]; //可执行代码, 如果是引导分区那么会有相应的数据 DPT Subarea0; //分区0信息,和MBR里的分区信息一样,也可能为0 DPT Subarea1; //分区1信息 DPT Subarea2; //分区2信息 DPT Subarea3; //分区3信息 unsigned short aa55; //签名:0xaa ,0x55 }BPB; /*-------------------函数声明----------------------------------*/ unsigned char FAT_Init(void); #endif
fat.c:
#include "FAT.H" /*----------------------定义全局变量-------------------------------*/ unsigned long Capability; //容量 unsigned int BytesPerSec; //每扇区字节数 unsigned char SecPerClust; //每簇扇区数 unsigned int FirLogSec; //第一个逻辑扇区的物理号 unsigned int FirFATSec; //第一个FAT表的第一个扇区地址(物理) unsigned int FATSecs; //一个FAT表占的扇区数 unsigned long FirDirClust = 2; //根目录簇号(因为是FAT16,所以为2.暂时未支持FAT32) unsigned long RootDirSec; //根目录所在扇区 unsigned long FirDataSec; //数据区的第一个扇区 /*-----------------------函数定义------------------------------*/ /**************************************************** * 函数名: unsigned char FAT_Init(void) * 功 能: 初始化FAT文件系统(不包括SD卡的初始化) * 参 数: 无 * 返回值: 返回FAT_OK则初始化成功,其它的则失败 ****************************************************/ unsigned char FAT_Init(void) { unsigned char buf[512]; MBR *MBR_Temp; BPB *BPB_Temp; //read_sigleblock(0,buf); //读取物理扇区0的数据 MBR_Temp = (MBR *)buf; //转换成指针 if(MBR_Temp->aa55!=0xaa55){ //判断签名是否正确 return AA55_ERROR; } FirLogSec = MBR_Temp->subarea0.FirLogSec; //得到逻辑扇区0的地址 //read_sigleblock(FirLogSec,buf); //读取逻辑扇区0的数据 BPB_Temp = (BPB *)buf; //转换成指针 if( BPB_Temp->JmpBoot[0]!=0xeb || BPB_Temp->JmpBoot[2]!=0x90 || BPB_Temp->JmpBoot[0]!=0xe9 ){ //判断JMPBOOT是否正确 return JMPBOOT_ERROR; } if(BPB_Temp->aa55!=0xaa55){ //判断签名是否正确 return AA55_ERROR; } Capability = BPB_Temp->BytesPerSec * ( (BPB_Temp->ToSec32<<16) || BPB_Temp->ToSec16 ); //计算容量 BytesPerSec = BPB_Temp->BytesPerSec; //得到每扇区字节数 SecPerClust = BPB_Temp->SecPerClust; //得到每簇扇区数 FATSecs = BPB_Temp->FATSize; //得到FAT表的大小(所占扇区数) FirFATSec = FATSecs+1; //得到第一个FAT表的首扇区 RootDirSec = FirFATSec + (FATSecs * BPB_Temp->Fats); //根目录所在扇区 FirDataSec = RootDirSec + (BPB_Temp->RootDirEnts*32)>>9; //数据区的第一个扇区 return FAT_OK; }
相关文章推荐
- SD卡FAT16文件系统的学习笔记
- SD+FAT16文件系统学习笔记1
- SD卡FAT16文件系统的学习笔记
- Linux鸟哥私房菜学习笔记_第八章Linux磁盘与文件系统管理
- [文件系统]文件系统学习笔记(一)---基本概念以及inode
- hadoop学习笔记:hadoop文件系统浅析
- 黑马程序员 C#学习笔记⑦ 文件系统数据一FileStream
- Linux内核设计与实现 学习笔记(3)虚拟文件系统
- C/C++学习笔记26:(一)C文件系统概述
- Python学习笔记_文件系统
- [文件系统]文件系统学习笔记(八)---mount系统调用(代码相关)
- php学习笔记(十一)文件系统
- python 系统学习笔记(八)---文件操作
- 2016.3.27-学习笔记:裸板程序、U-Boot、内核、文件系统的烧写
- Linux 程序设计学习笔记----文件管理系统
- FreeBSD学习笔记21-Unix文件系统
- MongoDB 学习笔记(五):固定集合、GridFS文件系统与服务器端脚本
- 云计算学习笔记004---hadoop的简介,以及安装,用命令实现对hdfs系统进行文件的上传下载
- Java学习笔记--NIO2文件系统