www.pudn.com > BackUpFile.rar > BackUpFile.c
#include#include #include #include #include /*TC下运行需要(biosdisk())*/ /*宏定义*/ #define CATNUM 16*60 /*总的文件目录项*/ #define CATLEN 32 /*文件目录项的长度*/ #define MAXSIZE 512*16 /*数组的最大容量*/ #define HEAD 255 /*每个柱面磁头数*/ #define SECTOR 63 /*每个磁头扇区数*/ #define SECBYTE 512 /*每个扇区字节数*/ #define SECTOTAL 16 /*要读的扇区数*/ #define StackSize 500 /*栈的最大长度*/ /*结构体类型申明*/ typedef struct CHSVal /*存放扇区地址*/ { int cyl; int head; int sec; }CHS; typedef struct createtime /*记录时间*/ { short int sec; short int min; short int hour; }TIME; typedef struct createdate /*记录日期*/ { short int day; short int mon; short int year; }DATE; typedef struct diskinfo /*记录磁盘的基本属性*/ { int isActive; /*判断是否是活动驱动器*/ int fileSysType; /*记录驱动器的文件系统类型*/ int byteVals[10]; /*记录驱动器的大小以及起始和终止的扇区地址*/ long isNext; /*判断是否是最后一个分区*/ }DINFO; typedef struct BPBINFO { unsigned int secSize[2]; /*每扇区字节数*/ unsigned int cluSize; /*每簇扇区数*/ unsigned int keepSize[2]; /*保留扇区*/ unsigned int fatNum; /*FAT表数目*/ unsigned int fatSize[4]; /*每FAT扇区数*/ unsigned int secNum[2]; /*每磁道扇区数*/ unsigned int headNum[2]; /*磁头数*/ unsigned int hiddenSize[4]; /*隐藏扇区数*/ unsigned int driverSize[4]; /*当前驱动器总扇区数*/ unsigned int rootStart[4]; /*根目录起始地址*/ }BINFO; typedef struct FDTInfo /*记录FDT信息*/ { short int fName[8]; /*存放文件名*/ short int extName[3]; /*存放扩展名*/ short int createTime[2]; short int createDate[2]; short int startAdd[4]; /*起始簇地址*/ long fSize[4]; short int fProperty; long isEOF; /*用来判断FDT是否结束*/ }FDT; typedef struct retArr /*存放一个数组,处理1个字节*/ { int arr[8]; }ARR; typedef struct DVArr /*存放一个数组,处理两个字节*/ { int arr[16]; }DARR; //定义链栈的结构体 typedef struct node { int data; struct node *next; }*linkstack,stacknode; //置空栈 linkstack init_linkstack() { linkstack top; top=(linkstack)malloc(sizeof(stacknode)); top->next=NULL; return top; } //判空栈 int empty_linkstack(linkstack top) { if(top->next==NULL) { printf("栈空\n"); return -1; } else return 1; } //入栈 linkstack push_linkstack(linkstack *top,int x) { stacknode *s; s=(stacknode *)malloc(sizeof(stacknode)); s->data=x; s->next=*top; *top=s; return *top; } //出栈 linkstack pop_linkstack(linkstack top,int data[],int n) { stacknode *p; int i; if(top==NULL) return NULL; else { for(i=0;i data; p=top; top=top->next; free(p); } return top; } } /*函数申明*/ void ReadSec(char name[],int cyl,int head,int len); /*读取扇区地址*/ int RetByteLow(int byteVal); /*返回一个字节的底4位*/ int RetByteHigh(int byteVal); /*返回一个字节的高四位*/ long DataConversion(int arr[],int len,int r); /*将数组代表的数字转换成十进制(长度为len的Arr是r进制)*/ long StartAdd(FDT fdtInfo); /*计算文件的起始地址*/ void PrintProperty(int fProperty); /*显示文件属性*/ int IsFolder(int fProperty); /*判断FDT代表是否是文件夹*/ FDT RetCatalog(int catalog,FILE*fp); /*从文件目录表返回长度为32个字节的文件目录项*/ TIME RetCraeteTime(FDT fdtInfo); /*返回文件或文件夹创建或更新的时间*/ DATE RetCreateDate(FDT fdtInfo); /*返回文件或文件夹创建和更新的日期*/ void AnalyzeFDT(FILE*fp); /*分析文件目录项*/ void DisSecInfo(FILE*fp,int byte); /*显示扇区数据信息*/ void PrintLongName(); /*显示长文件名*/ void CombLongName(FILE*fp); /*把占多个目录项的长文件名合起来,显示出长文件名全名*/ CHS RetCHS(int byteVal1,int byteVal2,int byteVal3); /*返回起始终止扇区物理地址*/ DINFO RetDiskData(FILE *fp); /*返回驱动器基本信息*/ void DisDiskInfo(DINFO diskInfo); /*显示分析的驱动器基本信息*/ long RetFDTLBA(BINFO bpbInfo); /*计算FDT的逻辑首地址*/ CHS LBAToCHS(long LBA); /*逻辑地址专为CHS地址*/ void SaveSecData(FILE *fpmbr,FILE *fpdbr,FILE *fpfdt); /*读取扇区信息保存*/ BINFO RetBpbInfo(FILE *fp); /*返回驱动器的基本信息*/ void BackupFile(FILE *fpfdt,FILE *fpdbr,FILE *fpbk,SqStack *s); /*主函数*/ void main() { FILE *fpmbr,*fpdbr,*fpfdt,*fpbk; char ch; DINFO diskInfo; SqStack *S; S = (SqStack *)malloc(sizeof(SqStack)); InitStack(S); fpmbr=fopen("MBRInfo.TXT","wb+"); /*MBR信息*/ fpdbr=fopen("DBRInfo.TXT","wb+"); /*DBR信息*/ fpfdt=fopen("FDTInfo.TXT","wb+"); /*FDT信息*/ fpbk=fopen("bk.dat","wb+"); SaveSecData(fpmbr,fpdbr,fpfdt); /*以上注释行是动态获取C盘扇区信息的代码,在tc下替换下三行即可动态分析本机C盘信息*/ diskInfo=RetDiskData(fpmbr); /*读取扇区基本信息*/ while(1) { system("cls"); /*清屏函数*/ /*菜单显示*/ printf("\n\nA.Display the sector values of MBR(CHS=0,0,1)\n"); printf("B.Display the sector values of DBR(CHS=0,1,1)\n"); printf("C.Display the sector values of FDT\n"); printf("D.Display the basic information of driver C\n"); printf("E.Display the root directory information of driver C\n"); printf("F.Display the long name \n"); printf("K.Backup file.\n"); printf("Q.Exit the program!\n"); printf("-----------------------------------------------------------------------------------------\n"); printf("Please choose one option:"); scanf("%c",&ch); if (ch=='a'||ch=='A') /*显示主引导记录所在扇区信息*/ DisSecInfo(fpmbr,SECBYTE); else if(ch=='B'||ch=='b') /*显示BPB所在扇区数据*/ DisSecInfo(fpdbr,SECBYTE); else if(ch=='C'||ch=='c') /*显示FDT扇区数据*/ DisSecInfo(fpfdt,SECBYTE*SECTOTAL); else if (ch=='D'||ch=='d') /*显示C盘的基本属性*/ DisDiskInfo(diskInfo); else if(ch=='E'||ch=='e') /*显示C盘根目录各文件(夹)属性*/ AnalyzeFDT(fpfdt); else if(ch=='F'||ch=='f') /*显示长文件名*/ CombLongName(fpfdt); else if(ch=='k'||ch=='K') BackupFile(fpfdt,fpdbr,fpbk,S); else if (ch=='Q'||ch=='q') /*退出程序*/ { fclose(fpmbr); fclose(fpdbr); fclose(fpfdt); exit(0); } else if(ch==0x0a||ch==0x0d) /*回车或换行不处理*/ ; else /*输入其他字符提示出错*/ { printf("Input Error. Please input again!"); getch(); } } } /*返回一个字节的底4位*/ int RetByteLow(int byteVal) { return (byteVal&0x0f); /*位与运算(对应的两位中有一个为0则结果为0)*/ } /*返回一个字节的高四位*/ int RetByteHigh(int byteVal) { return ((byteVal>>4)&0x0f); } /*将数组代表的数字转换成十进制(长度为len的Arr是r进制)*/ long DataConversion(int arr[],int len,int r) { int i=0,j=0; long expt=0; /*记录权位大小*/ long retVal=0; /*返回十进制值*/ for (i=0;i i;j--) /*计算权位*/ expt=expt*r; retVal=retVal+expt; } return retVal; } /*转换成二进制*/ ARR ValToBin(int value,int len) { ARR arrBin; /*记录二进制位*/ int i=0,val=value; for (i=0;i =0;i--) /*switch to bin*/ { dbyte.arr[i]=val%2; val=val/2; } val=byteVal[0]; for (i=15;i>=8;i--) /*switch to bin*/ { dbyte.arr[i]=val%2; val=val/2; } return dbyte; } /*返回文件或文件夹创建或更新的时间*/ TIME RetCraeteTime(FDT fdtInfo) { int hour[5],min[6],sec[5]; int i=0,j=0; int timeArr[2]={0}; TIME cTime; DARR dByte; for(i=0;i<2;i++) timeArr[i]=fdtInfo.createTime[i]; /*必须把表示文件更新时间的两个字节存放在临时变量里*/ dByte=BytesToBin(timeArr); /*参数如果直接传fdtInfo.createTime会发生错误*/ for (i=0;i<5;i++) /*小时占5位*/ { hour[i]=dByte.arr[i]; cTime.hour=(short)DataConversion(hour,5,2); } for (i=5,j=0;i<11;i++,j++) /*分钟占6位*/ { min[j]=dByte.arr[i]; cTime.min=(short)DataConversion(min,6,2); } for (i=11,j=0;i<16;i++,j++) /*秒占5位,以2为增量的二进制*/ { sec[j]=dByte.arr[i]; cTime.sec=(short)DataConversion(sec,5,2)*2; } return cTime; } /*返回文件或文件夹创建和更新的日期*/ DATE RetCreateDate(FDT fdtInfo) { int year[7],mon[4],day[5]; int i=0,j=0; int dateArr[2]; DATE cData; DARR dByte; for(i=0;i<2;i++) dateArr[i]=fdtInfo.createDate[i]; /*必须把表示文件更新时间的两个字节存放在临时变量里*/ dByte=BytesToBin(dateArr); /*参数如果直接传fdtInfo.createDate会发生错误*/ for (i=0;i<7;i++) /*年占7位,(7位转十进制+1980即为年份)*/ { year[i]=dByte.arr[i]; cData.year=(short)DataConversion(year,7,2); } for (i=7,j=0;i<11;i++,j++) /*月份占7位*/ { mon[j]=dByte.arr[i]; cData.mon=(short)DataConversion(mon,4,2); } for (i=11,j=0;i<16;i++,j++) /*具体哪天占5位*/ { day[j]=dByte.arr[i]; cData.day=(short)DataConversion(day,5,2); } return cData; } /*从文件目录表返回长度为32个字节的文件目录项*/ FDT RetCatalog(int catalog,FILE*fp) { int j=0,count=0; // int i; int cat[CATNUM][CATLEN]; /*总共的文件目录项*/ unsigned int temp; FDT fdtInfo; /*记录文件目录项各字节代表的内容*/ // for (i=0;i =8&&j<=10) fdtInfo.extName[count]=temp; /*8~10字节是扩展名*/ if(j==22) count=0; if(j==11) fdtInfo.fProperty=temp; /*第11字节记录文件属性*/ if(j==22||j==23) fdtInfo.createTime[count]=temp; /*22,23字节记录文件修改时间*/ if(j==24) count=0; if(j==24||j==25) fdtInfo.createDate[count]=temp; /*24,25记录文件修改日期*/ if(j==20) count=2; if(j==20||j==21) /*文件其始簇,高位*/ fdtInfo.startAdd[count]=temp; if(j==26) count=0; if (j==26||j==27) fdtInfo.startAdd[count]=temp; /*文件起始簇簇地址*/ if(j==28) count=0; if(j>=28&&j<=31) /*共四个字节记录文件大小*/ fdtInfo.fSize[count]=temp; fdtInfo.isEOF=fdtInfo.isEOF+temp; } // rewind(fp); return fdtInfo; } /*计算len个字节的数据所表示的大小*/ long Size(unsigned int byteVals[],int len) { int sizeVal[MAXSIZE]={0}; /*byteVal low,byteVal high*/ int i=0,j=0; long size=0; for (i=0,j=2*len-1;i >6; /*取byteVal2的高两位 */ temp2=byteVal3; for (i=1;i>=0;i--) /*turn binary*/ { clyArr[i]=temp1%2; temp1=temp1/2; } for (i=9;i>=2;i--) { clyArr[i]=temp2%2; temp2=temp2/2; } chs.cyl=DataConversion(clyArr,10,2); chs.head=byteVal1; chs.sec=byteVal2&0x3f; /*取byteVal2的低六位表示扇区值*/ return chs; } /*返回扇区数据所代表的具体驱动器属性信息*/ DINFO RetDiskData(FILE *fp) { DINFO diskInfo; int i=0,count=0; int byteVal=0; for (i=0;i =447&&i<=449) /*start CHS*/ { diskInfo.byteVals[count]=byteVal; count++; } if (i>=451&&i<=453) /*end CHS*/ { diskInfo.byteVals[count]=byteVal; count++; } if (i>=458&&i<=461) /*current size */ { diskInfo.byteVals[count]=byteVal; count++; } if (i>=462&&i<=465) /*is next driver?*/ diskInfo.isNext=diskInfo.isNext+byteVal; } rewind(fp); return diskInfo; } /*显示驱动器基本信息*/ void DisDiskInfo(DINFO diskInfo) { CHS staCHS,endCHS; unsigned int dSize[4],i; if(diskInfo.isActive) printf("\n\nThe disk is Active!\n"); staCHS=RetCHS(diskInfo.byteVals[0],diskInfo.byteVals[1],diskInfo.byteVals[2]); endCHS=RetCHS(diskInfo.byteVals[3],diskInfo.byteVals[4],diskInfo.byteVals[5]); printf("The start CHS:%d,%d,%d\n",staCHS.cyl,staCHS.head,staCHS.sec); printf("The end CHS:%d,%d,%d\n",endCHS.cyl,endCHS.head,endCHS.sec); if(diskInfo.fileSysType==0x0b||diskInfo.fileSysType==0x0c) printf("The file system is : FAT32\n"); if(diskInfo.fileSysType==0x86||diskInfo.fileSysType==0x87) printf("The file system is : NTFS\n"); for (i=0;i<4;i++) dSize[i]=diskInfo.byteVals[6+i]; printf("This driver size is: %.4f M\n",((float)Size(dSize,4)*SECBYTE/1024/1024)); // printf("\n%ld\n",diskInfo.isNext); /* if(diskInfo.isNext) printf("It has next driver.\n"); else printf("It's the last driver.\n"); */ getch(); } /*一下是读取扇区信息并保存的的代码*/ BINFO RetBpbInfo(FILE *fp) { int i,count; char arrBPBInfo[512]; /*用整型还是用字符型?*/ BINFO bpbInfo; /*用char的时候一不注意就会出现一些诡异的问题*/ /* for (i=0,count=0;i<512;i++) arrBPBInfo[i]=fgetc(fp);*/ fread(arrBPBInfo,512,1,fp);/*用fread()时数组必须用字符型*/ for(count=0,i=11;count<2;count++,i++) bpbInfo.secSize[count]=arrBPBInfo[i]; bpbInfo.cluSize=arrBPBInfo[13]; for(count=0,i=14;count<2;count++,i++) bpbInfo.keepSize[count]=arrBPBInfo[i]; bpbInfo.fatNum=arrBPBInfo[16]; for(count=0,i=24;count<2;count++,i++) bpbInfo.secNum[count]=arrBPBInfo[i]; for(count=0,i=26;count<2;count++,i++) bpbInfo.headNum[count]=arrBPBInfo[i]; for(count=0,i=28;count<4;count++,i++) bpbInfo.hiddenSize[count]=arrBPBInfo[i]; for(count=0,i=32;count<4;count++,i++) bpbInfo.driverSize[count]=arrBPBInfo[i]; for(count=0,i=36;count<4;count++,i++) bpbInfo.fatSize[count]=arrBPBInfo[i]; for(count=0,i=44;count<4;count++,i++) bpbInfo.rootStart[count]=arrBPBInfo[i]; rewind(fp); return bpbInfo; } long RetFDTLBA(BINFO bpbInfo) { /* long keepSize,hiddenSize,fatSize,startClu; keepSize=Size(bpbInfo.keepSize,2); hiddenSize=Size(bpbInfo.hiddenSize,2); fatSize=bpbInfo.fatNum*Size(bpbInfo.fatSize,4); startClu=(Size(bpbInfo.rootStart,4)-2)*bpbInfo.cluSize; return (keepSize+hiddenSize+fatSize+startClu); */ return (Size(bpbInfo.keepSize,2)+Size(bpbInfo.hiddenSize,2)+bpbInfo.fatNum*Size(bpbInfo.fatSize,4)+(Size(bpbInfo.rootStart,4)-2)*bpbInfo.cluSize); } /*逻辑地址转换为物理地址*/ CHS LBAToCHS(long LBA) { CHS fdtAdd; fdtAdd.cyl=LBA/(255*63); fdtAdd.head=(LBA/63)%255; fdtAdd.sec=LBA%63+1; return fdtAdd; } /*读取扇区数据*/ void ReadSector(FILE *fp,int cyl,int head,int sec,int len) { char buffer[512*16]={NULL}; // int i=0; biosdisk(0x02,0x80,head,cyl,sec,len,buffer); // for(i=0;i<512*len;i++) // fputc(buffer[i],fp); fwrite(buffer,512,len,fp); rewind(fp); // memset(buffer,0,512*16); } /*保存扇区数据*/ void SaveSecData(FILE *fpmbr,FILE *fpdbr,FILE *fpfdt) { CHS fdtadd; BINFO bpbInfo; long LBA; // DINFO diskInfo; ReadSector(fpmbr,0,0,1,1); ReadSector(fpdbr,0,1,1,1); // diskInfo=RetDiskData(fpmbr); bpbInfo=RetBpbInfo(fpdbr); //获取分区的BPB信息 LBA=RetFDTLBA(bpbInfo); rewind(fpdbr); fdtadd=LBAToCHS(LBA); // printf("FDT start:%d,%d,%d\n",fdtadd.cyl,fdtadd.head,fdtadd.sec); ReadSector(fpfdt,fdtadd.cyl,fdtadd.head,fdtadd.sec,bpbInfo.cluSize); rewind(fpfdt); } //簇链寻址 void FindClu(FILE *fpdbr,FILE *fpbk,FDT fdtInfo,unsigned int temp[4]) { int i,count; unsigned int buff[512]; CHS bkSec,tmSec; long tmpLBA1,tmpLBA2,fatStart; BINFO bpbInfo=RetBpbInfo(fpdbr); fatStart=Size(bpbInfo.keepSize,2)+Size(bpbInfo.hiddenSize,4); tmpLBA1=(((StartAdd(fdtInfo))*4/Size(bpbInfo.secSize,2))+fatStart);//记录的是簇号所在的FAT扇区逻辑地址 tmSec=LBAToCHS(tmpLBA1); /*找到簇号所在的fat扇区,保留扇区数+隐藏扇区数=fat入口*/ for(i=(int)((StartAdd(fdtInfo))*4%Size(bpbInfo.secSize,2)),count=0;count<4;count++,i++)/*取得表示文件下一簇的簇号*/ temp[count]=buff[i]; for(;temp[1]+temp[2]+temp[3]+temp[0]!=780;) /*temp[1]+temp[2]+temp[3]+temp[0]!=780||0xff+0xff+0xff+0x0f==780*/ { //判断是否是结束标志 bkSec=LBAToCHS((Size(temp,4)-2)*bpbInfo.cluSize+RetFDTLBA(bpbInfo));/*获得下一个要备份的簇*/ fseek(fpbk,0,SEEK_END);// ReadSector(fpbk,bkSec.cyl,bkSec.head,bkSec.sec,bpbInfo.cluSize); /*备份第二簇*/ tmpLBA2=(Size(temp,4)*4/Size(bpbInfo.secSize,2))+fatStart; if(tmpLBA1!=tmpLBA2)//判断簇号是否在一个扇区 { tmpLBA1=tmpLBA2; tmSec=LBAToCHS(tmpLBA2); biosdisk(0x02,0x80,tmSec.head,tmSec.cyl,tmSec.sec,1,buff); } for(i=(int)((Size(temp,4))*4%Size(bpbInfo.secSize,2)),count=0;count<4;count++,i++) temp[count]=buff[i]; } } //备份根目录下的文件 void BackupFile(FILE *fpfdt,FILE *fpdbr,FILE *fpbk,SqStack *S) { FDT fdtInfo; //记录文件的目录登记项 CHS bkSec,tmSec,subFdtSec; //tmSec记录的是表示占用情况的FAT扇区 FILE *fpSubFdt[StackSize]; // BINFO bpbInfo; //记录分区的各个信息 int i=0,catNum=0,count; unsigned int temp[4]={0}; //记录簇链中的簇号 unsigned char buff[512]; // long tmpLBA1,tmpLBA2,fatStart; long j=0; int fpcount=-1; //记录目录登记项的个数 bpbInfo=RetBpbInfo(fpdbr); //获取分区的BPB信息 fatStart=Size(bpbInfo.keepSize,2)+Size(bpbInfo.hiddenSize,4);//获取FAT的其始地址 for(catNum=0;catNum top==-1) { push(S,fpfdt); printf("\nfdt\n"); getch(); } else { printf("\nIt's subFdt\n"); getch(); push(S,fpSubFdt[fpcount]); } BackupFile(fpSubFdt[fpcount],fpdbr,fpbk,S); //为什么程序进入子目录后无法返回上级目录 } //本目录登记项遍历完毕后,返回上一级目录 else if(fdtInfo.isEOF==0)//目录登记项遍历完毕可能还有另外一个条件:目录登记项没有全零的项 { fpfdt=pop(S); if(StackEmpty(S)) exit(-1); BackupFile(fpfdt,fpdbr,fpbk,S); } } // printf("catNum=%d ",catNum); // fclose(fptmp); fclose(fpbk); rewind(fpfdt); rewind(fpdbr); // fclose(fpSubFdt); getch(); }