step1: 读物理扇区,得到引导扇区(逻辑扇区0)的偏移地址。利用Read_Block读取0地址处512bytes.
struct partsector
{
BYTE psPartCode[512-64-2];
BYTE psPart[64];
BYTE psBOOTSIG0;
BYTE psBOOTSIG1;
#define psBOOTSIG0 0x55;
#define psBOOTSIG1 0xaa;
};
使用psPart处开始的64byte的前16byte.
struct partrecord // 16 字节
{
BYTE prIsActive; // 0x80 代表该分区为缺省分区
BYTE prStartHead; // 该分区入口的磁头地址
WORD prStartCylSect; // 该分区入口的扇区地址和柱面地址
BYTE prPartType; // 该分区类型
BYTE prEndHead; // 该分区结束的扇区地址
WORD prEndCylSect; // 该分区结束柱面地址
DWORD prStartLBA; // 该分区内第一个扇区地址
DWORD prSize; // 该分区内包含的扇区总数
};
那么可以从prStartLBA读取引导扇区。为了后面的举例这里取prStartLBA=97;
step2:读取引导扇区,获取文件系统基本配置信息。利用Read_Block读取prStartLBA地址处512bytes.
struct bootsector710
{
BYTE bsJump[3]; // 跳转指令
BYTE bsOEMName[8]; // 厂商标识和OS版本
BYTE bsBPB[53]; // BIOS 参数块
BYTE bsExt[26]; // 扩展BPB
BYTE bsBootCode[418]; // 引导扇区代码
BYTE bsBootSectSig2;
BYTE bsBootSectSig3;
BYTE bsBootSectSig0; // 引导扇区签名0x55
BYTE bsBootSectSig1; // 引导扇区签名0xAA
#define BOOTSIG0 0x55
#define BOOTSIG1 0xaa
#define BOOTSIG2 0
#define BOOTSIG3 0
};
使用bsBPB开始的53个byte.
struct bpb710
{
WORD bpbBytesPerSec; // 每扇区字节数
BYTE bpbSecPerClust; // 每簇扇区数
WORD bpbResSectors; // 保留区域中的保留扇区数
BYTE bpbFATs; // FAT表的分数
WORD bpbRootDirEnts; // 根目录项数
WORD bpbSectors; // 存储卷上的的扇区总数
BYTE bpbMedia; // 存储介质描述
WORD bpbFATsecs; // FAT表所占的扇区数
WORD bpbSecPerTrack; // 每道扇区数
WORD bpbHeads; // 磁头数
DWORD bpbHiddenSecs; //隐藏扇区数
DWORD bpbHugeSectors; // 总扇区数
DWORD bpbBigFATsecs;//每个FAT所占扇区数
WORD bpbExtFlags; //扩展标识
#define FATNUM 0xf
#define FATMIRROR 0x80
WORD bpbFSVers; // 文件系统版本
#define FSVERS 0
DWORD bpbRootClust; //根目录簇号
WORD bpbFSInfo; // 文件系统信息扇区号
WORD bpbBackup; // 备份引导扇区
};
所以可以得到的信息有,并举例:
bpbBytesPerSec = 512; // 每扇区字节数
bpbSecPerClust = 4; // 每簇扇区数
bpbResSectors = 4,那么第一个FAT所在扇区为引导扇区(97)+保留扇区(4)=扇区101; // 保留区域中的保留扇区数
bpbFATs=2,即有2个FAT表; // FAT表的分数
bpbRootDirEnts = 512,表示根目录有512登记项,根目录大小固定为32个扇区; // 根目录项数
bpbFATsecs = 242,表示每个FAT占用242个扇区;
Step3: 如何计算得到进一步的信息。
可以得到重要的信息有:
1.每个扇区多少字节
2.每个簇有多少扇区
3.保留扇区数
4.有多少个FAT表
5.根目录容许的登记项数目
6.每个FAT表多少个扇区
7.总的扇区数
8.文件系统类型
将要计算得到的重要信息:
主要是各个区的偏移地址。
1. FAT1地址为引导扇地址+保留扇区数
即FAT1.offset = prStartLBA + bpbResSectors
2. 如果存在FAT2, 那么FAT2地址为FAT1偏移地址+每个FAT占扇区数
即FAT2.offset = FAT1.offset + bpbFATsecs
3. FDT即根目录地址为FAT1+FAT表数*每个FAT占扇区数
即FDT.offset = FAT1.offset + bpbFATs* bpbFATsecs
step4: FDT表和FAT表的具体介绍,这将帮助我们寻找正确的簇。
首先FDT表,每个FDT表固定有32个扇区和512个文件登记信息,所以每个文件登记信息为32byte.
struct file_entry //32byte
{
BYTE file_name[8];
BYTE file_ext[3];
BYTE file_attri;
BYTE lower_case;
BYTE file_creat_ms;
WORD file_creat_time;
WORD file_creat_year_month;
WORD file_askfor;
WORD file_cluster_high16;
WORD file_revise_time;
WORD file_revise_year_month;
WORD file_start_cluster;
DWORD file_length;
};
FDT表最重要的就是后6个byte。最后4个byte表数该文件长度,从而推断这个文件占用多少簇。倒数5到6这2个字节指明这个文件开始的簇号,知道文件的首簇号就可以查看FAT表的相应信息,就可得到该文件占用的所有簇的簇号。
其次FAT表记录每个数据簇的状态,且每个数据簇的状态占用2个字节
如果这2个字节等于0xFFFF,代表该簇已经被使用,并且文件在该数据簇中结束。
如果这2个字节等于0x0001-0xFFFE,代表该簇被使用,并且文件没有结束,文件的下一数据簇的簇号就等于这2个字节的大小。
这样就可以依次将文件的所有簇号获得并保存。
step5 : 依据FDT表给出的簇号读取文件。
(1) 从文件得到首簇号为0x2fe4,那么其在FAT中的位置为FAT地址(0xca00)+0x2fe4*2=0x129c8.
(2) 到0x129c8获取下一簇号为0x46f4, 那么下一簇地址为0xca00+0x46f4*2=0x157e8.
(3) 到0x157e8获取其值为0xFFFF,表明文件到此结束。
(4) 首先读取首簇号的文件内容,其内容地址为数据簇0地址(0x4c200)+0x2fe4*4*512 = 0x183e200,那么其扇区为0x183e200/512=49649,也就是说从49649开始到496512的4个扇区都是首数据簇给出的文件内容。
个人原创,转载的话请注明出处,^_^