实验4 文件系统模拟
- 格式:doc
- 大小:196.50 KB
- 文档页数:13
实验4 文件系统模拟一、实验目的:设计和实现基于FAT12的模拟磁盘卷及其I/O系统的文件存取操作基本功能函数,深入领会和理解文件系统的体系结构、工作原理和设计要领。
二、实验设计1.根据FAT12设计模拟磁盘(1.44MB软盘映像文件)的磁盘组织结构及文件或空闲盘块管理方法与描述用数据结构,并实现模拟磁盘的创建和格式化操作。
2.设计和实现模拟磁盘I/O操作暨物理盘块与缓冲区(缓冲区与物理盘块大小相同)间数据交互的两个函数。
3.构建和提供用户与文件系统之间的基本接口,包括目录和文件的创建、重命名、删除和显示操作,目录的进入操作以及文件的定位及读、写操作。
4.测试系统功能并给出有效证据。
三、源程序清单和说明#include <stdio.h>#include <string.h>#include <stdlib.h>#define BlockSize 512#define DirSize 32#define RootSize 2struct ReserveBlock{int sysblocknum;/*文件系统总扇区数*/int resblocknum;/*保留扇区扇区数*/int fatblocknum;/*FA T表扇区数*/int rootblocknum;/*根目录区扇区数*/char fillchar[BlockSize-4*sizeof(int)];/*填充字节*/};struct DirBlock{char filename[11]; /*文件名限长11个字符*/charfillchar[DirSize-4*sizeof(int)-sizeof(long int)-11];/*填充字节*/long filelen; /*文件长度*/int year,month,day; /*日期*/int firstblockaddr; /*文件首块扇区号*/};struct FCBBlock{int fileid; /*文件标识*/struct DirBlock fileinfo; /*目录信息*/long filepos; /*文件读写指针*/int fdtblockaddr; /*目录项所在块号*/int fdtblockindex; /*目录项所在块内序号*/struct FCBBlock *next;/*指向下一个文件控制块的指针*/};struct ReserveBlock sys1;struct FCBBlock *fcb;struct DirBlock fil[32],*dir;/*目录项*/ int *fat1;char *str,*ptr;char fillchar[BlockSize];FILE *fp;FILE *OPENSYS(char *filename){int i;fp=fopen(filename,"rb+");fread(&sys1,1,BlockSize,fp);fat1=(int *)malloc(sys1.sysblocknum);for(i=0;i<sys1.fatblocknum;i++)fread(fat1,sizeof(int)*sys1.sysblocknum,1,fp); /*把基本的文件系统都读进来*/fseek(fp,(sys1.fatblocknum+sys1.resblocknum )*BlockSize,0);/*修改文件指针的位置*/ dir=fil;/*目录指针*/fread(dir,DirSize*32,1,fp);return fp;}int CLOSESYS(FILE *stream){int i;fseek(stream,sys1.resblocknum*BlockSize,0);fwrite(fat1,sizeof(int)*sys1.sysblocknum,1,str eam);fseek(fp,(sys1.fatblocknum+sys1.resblocknum )*BlockSize,0);fwrite(dir,DirSize*32,1,fp);fclose(fp);return 1;}int FCREA TE(char *filename)/*建立文件*/ {int i,flag=0,j,k=0,flag1=0,flag2=0,a;int n,m;while(1){a=strlen(filename);/*文件名长度*/if(a>10){printf("文件名过长\n");printf("请重新输入:");scanf("%s",filename);}elsebreak;}while(1){for(i=0;i<32;i++)if(strcmp(filename,fil[i].filename)==0){printf("该文件名已存在\n");printf("请重新输入:");flag1=1;break;}if(flag1==0)break;scanf("%s",filename);flag1=0;}for(i=(sys1.fatblocknum+sys1.resblocknum+s ys1.rootblocknum);i<sys1.sysblocknum;i++) if(fat1[i]==0)flag++;/*统计磁盘上为空数目*/if(flag==0){ printf("磁盘已满");/*统计结果为0,则磁盘已满*/return 0;}printf("空闲块数:%d\n",flag);printf("请输入文件长度:");for(j=0;j<32;j++)if(fil[j].firstblockaddr==0)break;while(1){scanf("%d",&dir[j].filelen);/*输入目录项中文件的长度*/n=(dir[j].filelen/BlockSize)+(dir[j].filelen%Bl ockSize?1:0);if(n<0||n>flag)/*文件长度小于0或大于空闲的空间*/{printf("文件长度过长\n");printf("请重新输入:");}elsebreak;}for(i=(sys1.fatblocknum+sys1.resblocknum+s ys1.rootblocknum);i<sys1.sysblocknum;i++)/ *文件内容区域*/{ if(fat1[i]==0){k++;if(flag2==0){ dir[j].firstblockaddr=i+1;flag2=1;}else{ if(k>=n)/*n 文件长度*/{ fat1[m]=i+1;fat1[i]=-1;break;}elsefat1[m]=i+1;}m=i;}}strcpy(dir[j].filename,filename);dir[j].filename[a]='\0';printf("请输入年份:");scanf("%d",&dir[j].year);printf("请输入月份:");scanf("%d",&dir[j].month);printf("请输入日期:");scanf("%d",&dir[j].day);return (1);}void LISTDIR(void)/*显示目录*/{int i,flag=0;for(i=0;i<32;i++){if(fil[i].firstblockaddr!=0){if(flag==0)printf("filename \n");flag=1; /*标示*/printf("%s\n",fil[i].filename);}}}int FDELETE(char *filename)/*删除文件*/ {int i,j,k,n,flag=0;struct FCBBlock *p;/*文件控制块指针*/p=fcb;while(p){if(strcmp(filename,fil[p->fdtblockindex].filen ame)==0)/*目录项所在内序号*/{printf("文件已经打开,请先关闭文件\n");return 0;}elsep=p->next;}for(i=0;i<32;i++)/*查找要关闭的文件*/if(strcmp(filename,fil[i].filename)==0){ flag=1;break;}if(flag==0){printf("文件不存在\n");return 0;}j=fil[i].firstblockaddr;while(1){k=fat1[j-1];fseek(fp,(j-1)*BlockSize,0);/*将指针指向文件的第一个扇区的位置*/fwrite(&fillchar,1,BlockSize,fp);fat1[j-1]=0;if(k==-1)break;elsej=k;}memset(&fil[i],0,DirSize);return 1;}int FOPEN(char *filename)/*打开文件*/ {int i,j=0,k,flag=0;struct FCBBlock *p,*q,*r;p=fcb;for(i=0;i<32;i++)if(strcmp(filename,fil[i].filename)==0)/*找到要打开的文件*/{ flag=1;break;}if(flag==0){printf("文件不存在\n");return 0;}while(p){j++;if(strcmp(filename,fil[p->fdtblockindex].filen ame)==0){printf("文件已打开\n");return 0;}q=p;p=p->next;}if(fcb==NULL){ fcb=(struct FCBBlock *)malloc(sizeof(struct FCBBlock));fcb->fileid=j+1;/*文件标示*/fcb->filepos=0;/*文件读写指针*/fcb->next=NULL;/*指向下一个文件控制指针*/fcb->fdtblockindex=i;}else{ r=(struct FCBBlock *)malloc(sizeof(struct FCBBlock));r->fileid=j+1;r->filepos=0;r->next=NULL;r->fdtblockindex=i;q->next=r;}/*f->next=NULL; */return 1;}long FGETLEN(int fileid)/*获取文件指针*/ { struct FCBBlock *p;p=fcb;while(p){if(p->fileid==fileid)/*寻找要找的指针*/return(p->filepos);p=p->next;}printf("error\n");return(0);}int FCLOSE(char *filename)/*关闭文件*/ { int flag=0;struct FCBBlock *f,*p;f=fcb;if(strcmp(filename,fil[fcb->fdtblockindex].file name)==0){ flag=1;fcb=fcb->next;p=fcb;while(p){p->fileid-=1;p=p->next;}return flag;}p=f;f=f->next;while(f){if(strcmp(filename,fil[f->fdtblockindex].filena me)==0){ flag=1;p=f->next;/*p=p->next;*/while(p){ p=p->next;p->fileid-=1;}free(f);return flag;}p=f;f=f->next;}if(flag==0){ printf("文件未打开\n'");return flag;}return 0;}int FREAD(char *str, int n, int fileid)/*文件块读*/{ int m,i,j=0,k,l,len;char a[3];struct FCBBlock *p;p=fcb;while(p){if(p->fileid==fileid)break;elsep=p->next;}len=fil[p->fdtblockindex].filelen;/*文件长度*/l=p->filepos;/*文件读写指针:该块在文件的相对位置*/printf("现在打开文件:");printf("%d\n",l);printf("是否读入这个文件?(Y/N):");scanf("%s",a);if(a[0]=='n'||a[0]=='N'){printf("输入内容:");while(1){scanf("%d",&l);if(fil[p->fdtblockindex].filelen<(l+n))/*?*/printf("too large!\ninput again:");elsebreak;}}while(1){if(n>fil[p->fdtblockindex].filelen){printf("too large!\n");printf("input read size,again:");scanf("%d",&n);}elsebreak;}str=(char*)malloc(fil[p->fdtblockindex].filelen+1);m=(len/BlockSize)+(len%BlockSize?1:0);k=fil[p->fdtblockindex].firstblockaddr;if(m>1){ fseek(fp,(k-1)*BlockSize,0);fread(str,BlockSize,1,fp);k=fat1[k-1];for(i=1;i<(m-1);i++){fseek(fp,fat1[k-1]*BlockSize,0);fread(&str[i*BlockSize],BlockSize,1,fp);k=fat1[k-1];}fseek(fp,(k-1)*BlockSize,0);fread(&str[i*BlockSize],len-i*BlockSize,1,fp);}else{ fseek(fp,(k-1)*BlockSize,0);fread(str,len,1,fp);}str[n+l]='\0';if(l!=0)str=&str[l];p->filepos=n+l;printf("%s\n",str);return 1;}void FWRITE(char *ptr, int n, int fileid){ char a[3];long l;int m,i=0,j,k=0,num,flag=0,flag1=0,b;struct FCBBlock *p;p=fcb;while(p){if(p->fileid==fileid)break;elsep=p->next;}l=p->filepos;printf("现在打开文件:");printf("%d\n",l);printf("是否写入这个文件?(Y/N):");scanf("%s",a);if(a[0]=='n'||a[0]=='N'){printf("输入内容:");while(1){scanf("%d",&l);if(fil[p->fdtblockindex].filelen<(l+n))printf("too large!\ninput again:");elsebreak;}}j=(l/BlockSize)+(l%BlockSize?1:0);if(l==0)j=1;num=fil[p->fdtblockindex].firstblockaddr;for(i=1;i<j;i++)num=fat1[num];do{if(flag==0){fseek(fp,(num-1)*BlockSize+l-(i-1)*BlockSi ze,0);flag=1;}else{fseek(fp,(num-1)*BlockSize,0);num=fat1[num-1];}if(((n+l)-(i-1)*BlockSize)>BlockSize ){if(flag1==0){fwrite(&ptr[0],j*BlockSize-l,1,fp);flag1=1;}else{fwrite(&ptr[j*BlockSize-l+k*BlockSize],Blo ckSize,1,fp);}}else{ m=j*BlockSize-l+(k-1)*BlockSize;b=n-(j*BlockSize-l+(k-1)*BlockSize);fwrite(&ptr[m],b,1,fp);}k++;i++;}while(((n+l)-(i-1)*BlockSize)>1);p->filepos=l+n;}int FEOF(int fileid){int flag;struct FCBBlock *p;p=fcb;while(p){if(p->fileid==fileid)break;}if(p->filepos>fil[p->fdtblockindex].filelen)return 0;elsereturn 1;}long FGETPOS(int fileid){struct FCBBlock *p;p=fcb;while(p){if(p->fileid==fileid)return (p->filepos);elsep=p->next;}printf("error!\n");return(0);}int FSETPOS(int fileid, long offset){struct FCBBlock *p;p=fcb;while(p){ if(p->fileid==fileid){ while(offset>fil[p->fdtblockindex].filelen||of fset<0){printf("set error!zhe pos >file length\n");printf("input file pos ,again:");scanf("%d",offset);}p->filepos=offset;return 1;}elsep=p->next;}printf("error!\n");return(0);}void DISPLAY(){printf("请输入命令:\n");printf("建立文件:creat\n");printf("显示目录:list\n");printf("删除文件:del\n");printf("打开文件:open\n");printf("关闭文件:close\n");printf("文件块读:read\n");printf("文件块写:write\n");printf("退出:exit\n");}void test(char *filename){char *t,cmd[10],fname[12];struct FCBBlock *p;int i,j,n,flag,len,id,flag1=0;fp=OPENSYS(filename);while(1){DISPLAY();scanf("%s",cmd);if(!strcmp(cmd,"creat")){printf("请输入文件名:\n");scanf("%s",fname);flag=FCREA TE(fname);if(flag==1)printf("文件%s 创建成功\n",fname);}else if(!strcmp(cmd,"list"))LISTDIR();else if(!strcmp(cmd,"del")){scanf("%s",fname);flag=FDELETE(fname);if(flag==1)printf("文件%s 删除成功\n",fname);}else if(!strcmp(cmd,"open")){scanf("%s",fname);flag=FOPEN(fname);if(flag==1)printf("文件%s 打开\n",fname);}else if(!strcmp(cmd,"close")){scanf("%s",fname);flag=FCLOSE(fname);if(flag==1)printf("文件%s 关闭\n",fname);}else if(!strcmp(cmd,"read")){scanf("%s",fname);p=fcb;flag1=0;while(p){ if(!strcmp(fil[p->fdtblockindex].filename,fn ame)){printf("请输入文件大小:");scanf("%d",&len);id=p->fileid;flag=FREAD(str,len,id);flag1=1;}p=p->next;}if(flag1==0)printf("文件%s 未打开,请先打开文件\n",fname);}else if(!strcmp(cmd,"write")){scanf("%s",fname);p=fcb;flag1=0;while(p){ if(!strcmp(fil[p->fdtblockindex].filename,fn ame)){printf("请输入文件大小:");do{scanf("%d",&len);if(len>fil[p->fdtblockindex].filelen)printf("文件长度过大,请重新输入:");}while(len>fil[p->fdtblockindex].fil elen);id=p->fileid;ptr=(char *)malloc(len);scanf("%s",ptr);FWRITE(ptr,len,id);flag1=1;}p=p->next;}if(flag1==0)printf("文件%s 未打开,请先打开文件\n",fname);}else if(!strcmp(cmd,"exit")){flag=CLOSESYS(fp);break;}elseprintf("error!\n");}}int main(void){ struct ReserveBlock sys;char filename[]="fatsys.dat";int *fat;int i,j;fcb=NULL;memset(&sys,255,BlockSize);printf("请输入索要创建的文件系统的大小(5~32767):");scanf("%d",&(sys.sysblocknum));sys.resblocknum=1;sys.fatblocknum=sys.sysblocknum/(BlockSize /sizeof(int))+((sys.sysblocknum%(BlockSize/sizeof(int)))?1 :0);fat=(int*)malloc(BlockSize*sys.fatblocknum);memset(fat,255,BlockSize*sys.fatblocknum);memset(fat,0,sizeof(int)*sys.sysblocknum);sys.rootblocknum=RootSize;j=sys.resblocknum+sys.fatblocknum+sys.root blocknum;for (i=0;i<j;i++)fat[i]=-1;memset(&fillchar,0,BlockSize);fp=fopen(filename,"w+b");fwrite(&sys,1,BlockSize,fp);for (i=0;i<sys.fatblocknum;i++)fwrite(fat+i*BlockSize/sizeof(int),1,BlockSize ,fp);j=sys.resblocknum+sys.fatblocknum;for(i=0;i<(sys.sysblocknum-j);i++)fwrite(&fillchar,1,BlockSize,fp);fclose(fp);free(fat);test(filename);return 0;}四、算法及关键数据结构设计1.模拟磁盘的格式化操作2.磁盘I/O操作模拟函数readBlock(int i, char *p);该函数把i#逻辑块的内容读入到指针p指向的盘块缓冲(注意读入计数处理)。