fat12文件系统
fat12文件系統
- 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;
}
總結
- 上一篇: C语言调用easyX图形库画圆盘时钟
- 下一篇: C语言实现将彩色bmp图像转化为灰图、灰