C语言实现读取FAT12文件系统

来源:互联网 发布:印度废钞令 知乎 编辑:程序博客网 时间:2024/05/22 08:07

  假设要读取的FAT12文件系统的映像文件为跟程序在同一目录下的 a.img :

/*文件名不支持中文及符号。*/#include <stdio.h>#include <stdlib.h>#include <string.h>typedef unsigned char u8;//1字节typedef unsigned short u16;//2字节typedef unsigned int u32;//4字节int  BytsPerSec;//每扇区字节数int  SecPerClus;//每簇扇区数int  RsvdSecCnt;//Boot记录占用的扇区数int  NumFATs;//FAT表个数int  RootEntCnt;//根目录最大文件数int  FATSz;//FAT扇区数#pragma pack (1) /*指定按1字节对齐*///偏移11个字节struct BPB {u16  BPB_BytsPerSec;//每扇区字节数u8   BPB_SecPerClus;//每簇扇区数u16  BPB_RsvdSecCnt;//Boot记录占用的扇区数u8   BPB_NumFATs;//FAT表个数u16  BPB_RootEntCnt;//根目录最大文件数u16  BPB_TotSec16;u8   BPB_Media;u16  BPB_FATSz16;//FAT扇区数u16  BPB_SecPerTrk;u16  BPB_NumHeads;u32  BPB_HiddSec;u32  BPB_TotSec32;//如果BPB_FATSz16为0,该值为FAT扇区数};//BPB至此结束,长度25字节//根目录条目struct RootEntry {char DIR_Name[11];u8   DIR_Attr;//文件属性char reserved[10];u16  DIR_WrtTime;u16  DIR_WrtDate;u16  DIR_FstClus;//开始簇号u32  DIR_FileSize;};//根目录条目结束,32字节#pragma pack () /*取消指定对齐,恢复缺省对齐*/void fillBPB(FILE * fat12 , struct BPB* bpb_ptr);//载入BPBvoid printFiles(FILE * fat12 , struct RootEntry* rootEntry_ptr);//打印文件名,这个函数在打印目录时会调用下面的printChildrenvoid printChildren(FILE * fat12 , char * directory,int startClus);//打印目录及目录下子文件名int  getFATValue(FILE * fat12 , int num);//读取num号FAT项所在的两个字节,并从这两个连续字节中取出FAT项的值,int main() {FILE* fat12;fat12 = fopen("a.img","rb");//打开FAT12的映像文件struct BPB bpb;struct BPB* bpb_ptr = &bpb;//载入BPBfillBPB(fat12,bpb_ptr);//初始化各个全局变量BytsPerSec = bpb_ptr->BPB_BytsPerSec;SecPerClus = bpb_ptr->BPB_SecPerClus;RsvdSecCnt = bpb_ptr->BPB_RsvdSecCnt;NumFATs = bpb_ptr->BPB_NumFATs;RootEntCnt = bpb_ptr->BPB_RootEntCnt;if (bpb_ptr->BPB_FATSz16 != 0) {FATSz = bpb_ptr->BPB_FATSz16;} else {FATSz = bpb_ptr->BPB_TotSec32;}struct RootEntry rootEntry;struct RootEntry* rootEntry_ptr = &rootEntry;//打印文件名printFiles(fat12,rootEntry_ptr);fclose(fat12);}void fillBPB(FILE* fat12 , struct BPB* bpb_ptr) {int check;//BPB从偏移11个字节处开始check = fseek(fat12,11,SEEK_SET);if (check == -1) printf("fseek in fillBPB failed!");//BPB长度为25字节check = fread(bpb_ptr,1,25,fat12);if (check != 25)printf("fread in fillBPB failed!");}void printFiles(FILE * fat12 , struct RootEntry* rootEntry_ptr) {int base = (RsvdSecCnt + NumFATs * FATSz) * BytsPerSec;//根目录首字节的偏移数int check;char realName[12];//暂存将空格替换成点后的文件名//依次处理根目录中的各个条目int i;for (i=0;i<RootEntCnt;i++) {check = fseek(fat12,base,SEEK_SET);if (check == -1) printf("fseek in printFiles failed!");check = fread(rootEntry_ptr,1,32,fat12);if (check != 32)printf("fread in printFiles failed!");base += 32;if (rootEntry_ptr->DIR_Name[0] == '\0') continue;//空条目不输出//过滤非目标文件int j;int boolean = 0;for (j=0;j<11;j++) {if (!(((rootEntry_ptr->DIR_Name[j] >= 48)&&(rootEntry_ptr->DIR_Name[j] <= 57)) ||((rootEntry_ptr->DIR_Name[j] >= 65)&&(rootEntry_ptr->DIR_Name[j] <= 90)) ||((rootEntry_ptr->DIR_Name[j] >= 97)&&(rootEntry_ptr->DIR_Name[j] <= 122)) ||(rootEntry_ptr->DIR_Name[j] == ' '))) {boolean = 1;//非英文及数字、空格break;}}if (boolean == 1) continue;//非目标文件不输出int k;if ((rootEntry_ptr->DIR_Attr&0x10) == 0 ) {//文件int tempLong = -1;for (k=0;k<11;k++) {if (rootEntry_ptr->DIR_Name[k] != ' ') {tempLong++;realName[tempLong] = rootEntry_ptr->DIR_Name[k];} else {tempLong++;realName[tempLong] = '.';while (rootEntry_ptr->DIR_Name[k] == ' ') k++;k--;}}tempLong++;realName[tempLong] = '\0';//到此为止,把文件名提取出来放到了realName里//输出文件printf("%s\n",realName);} else {//目录int tempLong = -1;for (k=0;k<11;k++) {if (rootEntry_ptr->DIR_Name[k] != ' ') {tempLong++;realName[tempLong] = rootEntry_ptr->DIR_Name[k];} else {tempLong++;realName[tempLong] = '\0';break;}}//到此为止,把目录名提取出来放到了realName//输出目录及子文件printChildren(fat12,realName,rootEntry_ptr->DIR_FstClus);}}}void printChildren(FILE * fat12 , char * directory , int startClus) {//数据区的第一个簇(即2号簇)的偏移字节int dataBase = BytsPerSec * ( RsvdSecCnt + FATSz*NumFATs + (RootEntCnt*32 + BytsPerSec - 1)/BytsPerSec );char fullName[24];//存放文件路径及全名int strLength = strlen(directory);strcpy(fullName,directory);fullName[strLength] = '/';strLength++;fullName[strLength] = '\0';char* fileName = &fullName[strLength];int currentClus = startClus;int value = 0;int ifOnlyDirectory = 0; while (value < 0xFF8) {value = getFATValue(fat12,currentClus);if (value == 0xFF7) {printf("坏簇,读取失败!\n");break;}char* str = (char* )malloc(SecPerClus*BytsPerSec);//暂存从簇中读出的数据char* content = str;int startByte = dataBase + (currentClus - 2)*SecPerClus*BytsPerSec;int check;check = fseek(fat12,startByte,SEEK_SET);if (check == -1) printf("fseek in printChildren failed!");check = fread(content,1,SecPerClus*BytsPerSec,fat12);if (check != SecPerClus*BytsPerSec)printf("fread in printChildren failed!");//解析content中的数据,依次处理各个条目,目录下每个条目结构与根目录下的目录结构相同int count = SecPerClus*BytsPerSec;//每簇的字节数int loop = 0;while (loop < count) {int i;char tempName[12];//暂存替换空格为点后的文件名if (content[loop] == '\0') {loop += 32;continue;}//空条目不输出//过滤非目标文件int j;int boolean = 0;for (j=loop;j<loop+11;j++) {if (!(((content[j] >= 48)&&(content[j] <= 57)) ||((content[j] >= 65)&&(content[j] <= 90)) ||((content[j] >= 97)&&(content[j] <= 122)) ||(content[j] == ' '))) {boolean = 1;//非英文及数字、空格break;}}if (boolean == 1) {loop += 32;continue;}//非目标文件不输出int k;int tempLong = -1;for (k=0;k<11;k++) {if (content[loop+k] != ' ') {tempLong++;tempName[tempLong] = content[loop+k];} else {tempLong++;tempName[tempLong] = '.';while (content[loop+k] == ' ') k++;k--;}}tempLong++;tempName[tempLong] = '\0';//到此为止,把文件名提取出来放到tempName里strcpy(fileName,tempName);printf("%s\n",fullName);ifOnlyDirectory = 1;loop += 32;}free(str);currentClus = value;}; if (ifOnlyDirectory == 0)  printf("%s\n",fullName);//空目录的情况下,输出目录}int  getFATValue(FILE * fat12 , int num) {//FAT1的偏移字节int fatBase = RsvdSecCnt * BytsPerSec;//FAT项的偏移字节int fatPos = fatBase + num*3/2;//奇偶FAT项处理方式不同,分类进行处理,从0号FAT项开始int type = 0;if (num % 2 == 0) {type = 0;} else {type = 1;}//先读出FAT项所在的两个字节u16 bytes;u16* bytes_ptr = &bytes;int check;check = fseek(fat12,fatPos,SEEK_SET);if (check == -1) printf("fseek in getFATValue failed!");check = fread(bytes_ptr,1,2,fat12);if (check != 2)printf("fread in getFATValue failed!");//u16为short,结合存储的小尾顺序和FAT项结构可以得到//type为0的话,取byte2的低4位和byte1构成的值,type为1的话,取byte2和byte1的高4位构成的值if (type == 0) {return bytes<<4;} else {return bytes>>4;}}

原创粉丝点击