fat12文件系统

图片来源于网络

fat12文件系统简介

FAT文件系统遵行已用了多年的软件方法来进行规范。它在1977年由比尔·盖茨和马斯·麦当劳为了管理磁盘而发明,并在1980年被添·彼得逊的86-DOS操作系统采用。这也是86-DOS操作系统与CP/M操作系统最大的不同点,若非此项差异,86-DOS操作系统与CP/M操作系统几乎可说完全相同。

初期的FAT就是现在俗称的FAT12。作为软盘的文件系统,它有几项限制:不支持分层性结构,簇定址只有12位(这使得控制FAT有些棘手)而且只支持最多32M(216)的分区。当时入门级的磁盘是5.25"、单面、40磁道、每个磁道8个扇区、容量略少于160KB。上面的限制超过了这个容量一个或几个数量级,同时允许将所有的控制结构放在第一个磁道,这样在读写操作时移动磁头。这些限制在随后的几年时间里被逐步增大。由于唯一的根目录也必须放在第一个磁道,能够存放的文件个数就限制在几十个。

文件系统结构

在这里插入图片描述
简单来说,一个fat12文件系统由保留区(保留区一般只有主引导区)、fat1表,fat2表、根目录、数据区构成。

在这里插入图片描述主引导区结构:
在这里插入图片描述
主引导区的重要参数如下:
在这里插入图片描述

fat1表记录了文件系统的所有簇号,fat2表是对fat1表的复制。一般来说,fat表第一个簇号和第二个簇号不能使用,所以簇号从第2个开始计算,即一个簇号位于3号位置,那么数据从第1簇开始储存。(簇号指向下一个簇的位置);

在这里插入图片描述

根目录中条目结构:
在这里插入图片描述
以下为fat12镜像文件中的的根目录,其中含有FAT.PDF和BLOCK.C两个长度不为零的文件,后面以此二例介绍如何根据簇号寻找文件储存的地址:
在这里插入图片描述
由前面分析得到:
此fat12文件系统扇区大小为512字节,
保留区占1个扇区
含有fat表2个,每个fat表占3个扇区
根目录最多有512个条目,已知每个条目长度32字节,换算成扇区大小,即根目录占32个扇区
而FAT.PDF首簇号为06,查找fat表,为007。

在这里插入图片描述易看出fat表中簇号依次为:
ff8 fff 000 004 fff fff 007 008 009 00a 00b 00c 00d……
找到第6号位置上的簇号007,说明下一段文件保存在第7号位置,找到第7号位置上的簇号,发现下一段文件保存在第8号位置,一次类推,知道得到下个位置上的簇号为ff8-fff,文件簇表结束。

有点扯远了,知道了文件存储的首簇号,可以算出文件存储偏移地址,ff8 fff两个位置不用,故FAT.PDF从第4簇开始存储:
(1+2*3+32)*512+ (6-2)* 4* 512=0x6600
即:
(保留区占扇区数+fat表数量*fat表占扇区数+根目录占扇区数)*扇区占字节数+(首簇号位置-不用的簇号数量)*每个簇占扇区数*扇区占字节数

到0x6600位置,发现文件就从那里开始存储
在这里插入图片描述

同理,BLOCK.C文件偏移地址:
(1+2*3+32)*512+(3-2)*4*512=0x5600

在这里插入图片描述

示例(提取fat12中的pdf):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
	
	
unsigned short secBytes;//每个扇区的字节数
unsigned char secPerClus;//每个簇的扇区数
unsigned char rsvdSecCnt;//保留区所用扇区数 
unsigned char fatCnt;//fat表数量 
unsigned char fatSecCnt;//fat表占的扇区数 
unsigned short rootEntCnt;//根目录最大文件条目数
unsigned char name_ext[3];//文件扩展名 
unsigned short firstClus;//pdf首簇号 
unsigned int size;//pdf文档大小


//由当前簇号查询下一簇号 
int getNextClus(FILE*fp_in,unsigned short thisClus,unsigned short*nextClus){
	unsigned char tmp[3]={0};
	if(thisClus%2==0){
		fseek(fp_in,rsvdSecCnt*secBytes+thisClus*3/2,0);
		fread(&tmp[0],1,1,fp_in);
		fread(&tmp[1],1,1,fp_in);
		*nextClus=tmp[0]+((tmp[1]&0xf)<<8);
	}
	else{
		fseek(fp_in,rsvdSecCnt*secBytes+(thisClus-1)*3/2+1,0);
		fread(&tmp[0],1,1,fp_in);
		fread(&tmp[1],1,1,fp_in);
		*nextClus=((tmp[0]&0xf0)>>4)+(tmp[1]<<4);
	}
}


int main(){
	int start=0,end=0;
	FILE *fp_in,*fp_out;
	if((fp_in=fopen("d:\\fat12.img","rb"))==NULL){
		perror("can not open file_in:");
		return -1;
	}
	if((fp_out=fopen("d:\\test.pdf","wb"))==NULL){
		perror("can not open file_out:");
		return -1;
	}
		
	//开始读取fat镜像文件参数 
	fseek(fp_in,0xb,0);
	fread(&secBytes,2,1,fp_in);
	fseek(fp_in,0xd,0);	
	fread(&secPerClus,1,1,fp_in);
	fseek(fp_in,0xe,0);
	fread(&rsvdSecCnt,1,1,fp_in);	
	fseek(fp_in,0x10,0);
	fread(&fatCnt,1,1,fp_in);
	fseek(fp_in,0x11,0);
	fread(&rootEntCnt,2,1,fp_in);
	fseek(fp_in,0x16,0);
	fread(&fatSecCnt,1,1,fp_in);
	printf("secBytes: %d\n",secBytes);
	printf("secPerClus: %d\n",secPerClus);
	printf("rsvdSecCnt: %d\n",rsvdSecCnt);	
	printf("fatCnt: %d\n",fatCnt);
	printf("rootEntCnt: %d\n",rootEntCnt);
	printf("fatSecCnt: %d\n",fatSecCnt);
	
	fseek(fp_in,(rsvdSecCnt+fatCnt*fatSecCnt)*secBytes,0);
	while(strncmp((char*)name_ext,"PDF",3)){  //查找文件后缀名到PDF为止 
		fseek(fp_in,0x8,1);
		fread(name_ext,3,1,fp_in);
		fseek(fp_in,21,1);
	}
	fseek(fp_in,-6,1);
	fread(&firstClus,2,1,fp_in);
	fread(&size,4,1,fp_in);
	printf("firstClus: %d\n",firstClus);
	printf("size: %d\n",size);
	
	unsigned short tmpClus,nextClus; 
	unsigned char data[secPerClus*secBytes+1];//储存每簇中的数据 
	tmpClus=firstClus;
	while(tmpClus<0xff8){ //如果不为簇尾,则继续读 
		memset(data,0,sizeof(data));
		fseek(fp_in,(rsvdSecCnt+fatCnt*fatSecCnt+(tmpClus-2)*secPerClus)*secBytes+rootEntCnt*32,0);
		if(!fread(data,secPerClus*secBytes,1,fp_in))
			return -1;
		fwrite(data,1,secPerClus*secBytes,fp_out);
		getNextClus(fp_in,tmpClus,&nextClus);
		tmpClus=nextClus;
	}
		
	fclose(fp_in);
	fclose(fp_out);
	printf("\npdf读取完毕!\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值