文件系统
一、实验简介
在模拟的I/O系统之上开发一个简单的文件系统。用户通过create, open, read等命令与文件系统交互。文件系统把磁盘视为顺序编号的逻辑块序列,逻辑块的编号为0至L − 1。I/O系统利用内存中的数组模拟磁盘。
二、实验内容
设计一个文件系统
(1)用磁盘中的一个文件(大小事先指定,512KB)来模拟一个磁盘
(2)设计一个I/O系统,用来实现磁盘文件与模拟磁盘之间的数据存储
(3)设计一个文件系统,用来实现模拟磁盘与用户之间的人机交互
三、程序设计
3.1.I/O系统
实际物理磁盘的结构是多维的:有柱面、磁头、扇区等概念。I/O系统的任务是隐藏磁盘的结构细节,把磁盘以逻辑块的面目呈现给文件系统。逻辑块顺序编号,编号取值范围为0至L−1,其中L表示磁盘的存储块总数。
本次实验中,我利用数组ldisk[C][H][B]构建磁盘模型,其中CHB 分别表示柱面号,磁头号和扇区号。每个扇区大小为512字节。
I/O系统实现的功能是:
(1)从文件系统接收命令,根据命令指定的逻辑块号把磁盘块的内容读入命令指定的内存区域;(把逻辑块x的内容读入到指针p指向的内存位置,拷贝的字符个数为strlen)
int read_block(int x, char *p, int strlen)
{
int i,j,k;
i=x/(H*B);
j=(x-i*H*B)/B;
k=(x-i*H*B-j*B);
strncpy(p, &ldisk[i][j][k], strlen);
return 0;
}
(2)从文件系统接收命令,把命令指定的内存区域内容写入磁盘块;(把指针p指向的内容写入逻辑块x,拷贝的字符个数为strlen)
int write_block(int x, char *p, int strlen)
{
int i,j,k;
i=x/(H*B);
j=(x-i*H*B)/B;
k=(x-i*H*B-j*B);
strncpy(&ldisk[i][j][k], p, strlen);
return 0;
}
(3)用来把数组ldisk 存储到文件;
int FileToArray()
{
int i,j,k;
fseek(Disk,0,SEEK_SET);
for(i=0; i<C; i++)
{
for(j=0; j<H; j++)
{
for(k=0; k<B; k++)
{
if(fread(&ldisk[i][j][k],512,1,Disk)!=1)
{
printf("文件内容恢复到数组失败!\n");
k=B;
j=H;
i=C;//退出
}
}
}
}
return 1;
}
(4)用来把文件内容恢复到数组ldisk;
int ArrayToFile()
{
int i,j,k;
fseek(Disk,0,SEEK_SET);
for(i=0; i<C; i++)
{
for(j=0; j<H; j++)
{
for(k=0; k<B; k++)
{
if(fwrite(&ldisk[i][j][k],512,1,Disk)!=1)
{
printf("数组存储到文件失败!\n");
k=B;
j=H;
i=C;//退出
}
}
}
}
return 1;
}
I/O系统代码整体架构:
3.2.文件系统(位于I/O系统之上)
自定义:
#define BlkNum 512 //磁盘块的数目(编号从0开始)
#define BlkSize 1024 //磁盘块大小为1K
3.2.1 文件系统的组织
磁盘的前4个块是保留区(超级块),其中包含如下信息:
位图和文件描述符。位图用来描述磁盘块的分配情况。位图中的每一位对应一个逻辑块。创建或者删除文件,以及文件的长度发生变化时,文件系统都需要进行位图操作。
前5个块的剩余部分包含一组文件描述符。每个文件描述符包含如下信息:
(1)文件长度,单位字节
(2)文件分配到的磁盘块号数组。该数组的长度是系统参数。(我设置为4)
定义结构体:
typedef struct
{
char blk_map[BlkNum];//磁盘块位图
char inode_map[InodeNum];//文件描述符位图
char blk_used[4];//已被使用的磁盘块数目
char inode_used[4];//已被使用的文件描述符数目
} SuperBlk;//超级块(保留区)
typedef struct
{
char blk_identifier[BlkPerNode][4];//占用的磁盘块编号
char blk_num[4];//占用的磁盘块数目
char file_size[4];//文件的大小
} Inode;//文件描述符
自定义常量:
#define InodeNum 112//文件描述符数目
#define BlkPerNode 4//每个文件包含的最大的磁盘块数目
#define K 4//超级块占磁盘块数目(0\1\2\3)
#define SuperBlkBeg 0//超级块起始磁盘块(0)
#define InodeBeg 1//文件描述符起始磁盘块(1\2\3)
自定义变量:
SuperBlk super_blk;//文件系统的超级块
Inode record_inode[InodeNum];//文件描述符使用情况
功能函数:
void show_blk_map()//显示磁盘块使用情况,0代表未被使用,1代表已使用
{
int i=0;
for(i=0; i<BlkNum; i++)
{
printf("%c ",super_blk.blk_map[i]);
if((i+1)%24==0)
printf("\n");
}
printf("\n\t已被使用的磁盘块数目为:%d\n",char4TOint(super_blk.blk_used));
}
void show_inode_map()//显示文件描述符使用情况,0代表未被使用,1代表已使用
{
int i=0;
for(i=0; i<InodeNum; i++)
{
printf("%c ",super_blk.inode_map[i]);
if((i+1)%24==0)
printf("\n");
}
printf("\n\t已被使用的文件描述符数目为:%d\n",char4TOint(super_blk.inode_used));
}
3.2.2目录
文件系统中仅设置一个目录,该目录包含文件系统中的所有文件。除了不需要显示地创建和删除之外,目录在很多方面和普通文件相像。目录对应0号文件描述符。初始状态下,目录中没有文件,所有,目录对应的描述符中记录的长度应为0,而且也没有分配磁盘块。每创建一个文件,目录文件的长度便增加一。目录文件的内容由一系列的目录项组成,其中每个目录项由如下内容组成:
(1)文件名 (2)文件描述符序号
定义结构体:
typedef struct
{
char name[20];//文件名
char inode_num[4];//文件描述符序号
} Dir;//目录
自定义常量:
#define MaxDirNum 112//目录所支持的最大的文件数
自定义变量:
Dir dir_table[MaxDirNum];//目录使用情况
功能函数:
int directory()//显示所有文件及其长度,以及占用磁盘号
{
int i=0,j=0,k=0,x=0;
if(char4TOint(super_blk.inode_used)==1)
{
printf(" 文件系统未含有文件!\n");
}
else
{
for(i=1; i<InodeNum; i++)
{
if(super_blk.inode_map[i]=='1')
{
for(j=0; j<MaxDirNum; j++)
{
if(char4TOint(dir_table[j].inode_num)==i)
break;
}
printf(" 文件名为:");
for(x=0; x<20; x++)
{
if(dir_table[j].name[x]!='!')
printf("%c",dir_table[j].name[x]);
}
printf(" 文件大小为:%d字节\n",char4TOint(record_inode[i].file_size));
if(char4TOint(record_inode[i].blk_num)==0)
{
printf(" 文件未占用磁盘块!");
}
else
{
printf(" 文件占用的磁盘块编号为: ");
for(k=0; k<char4TOint(record_inode[i].blk_num); k++)
printf("%d ",char4TOint(record_inode[i].blk_identifier[k]));
}
printf("\n\n");
}
}
}
return 0;
}
3.2.3 文件的创建与删除
创建文件时需要进行如下操作:
(1)检查目录中是否已含有文件名相同文件存在
(2)检查文件系统存储文件是否已达上限
(3)找一个空闲文件描述符(扫描record_inode[1]~record_inode[InodeNum])
(4)在文件目录里为新创建的文件分配一个目录项
(5)在分配到的目录项里记录文件名及描述符编号
(6)返回状态信息(如有无错误发生等)
创建文件函数:
int create(char *filename)//根据指定的文件名创建新文件
{
int i;
//printf("%d\n",strlen(filename));
if(strlen(filename)>=20)
{
printf(" 文件名过长!\n");
return -1;
}
for(i=0; i<MaxDirNum; i++)
{
if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
{
printf(" 文件系统中已存在该文件,请更换文件名或将已存在文件删除!\n");
return -1;
}
}
if(char4TOint(super_blk.inode_used)>=InodeNum)
{
printf(" 文件系统中存储文件已达上限,请先删除一些不必要的文件后再创建新文件!\n");
return -1;
}
strncpy(dir_table[char4TOint(super_blk.inode_used)].name,filename,strlen(filename));
for(i=1; i<InodeNum; i++)
{
if(super_blk.inode_map[i]=='0')
{
intTOchar4(i,dir_table[char4TOint(super_blk.inode_used)].inode_num);
intTOchar4(0,record_inode[i].blk_num);
intTOchar4(0,record_inode[i].file_size);
super_blk.inode_map[i]='1';
break;
}
}
i=char4TOint(super_blk.inode_used)+1;
intTOchar4(i,super_blk.inode_used);
printf(" 文件%s创建成功!\n",filename);
return 0;
}
删除文件时需要进行如下操作(假设文件没有被打开):
(1)在目录里搜索该文件的描述符编号
(2)删除该文件对应的目录项并更新位图
(3)释放文件描述符
(4)返回状态信息
注:当文件没已打开时,只有先关闭文件,才可进行删除
删除文件函数:
int destroy(char *filename)//删除指定文件
{
int i,j,k;
char use[512];
for(i=0; i<OpenFileNum; i++)
{
if(strcmp(OpenFile_table[i].name, filename)==0)
{
printf(" %s文件已打开,请先关闭文件后再进行删除。\n",filename);
return -1;
}
}
for(i=1; i<MaxDirNum; i++)
{
if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
{
strncpy(dir_table[i].name, "!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].file_size);
if(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num)!=0)
{
memset(&use, ' ', 512);
//printf("%d\n",char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0]));
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2+1,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2+1,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2+1,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2+1,use,512);
k = char4TOint(super_blk.blk_used)-4;
intTOchar4(k,super_blk.blk_used);
}
for(j=0; j<char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num); j++)
{
super_blk.blk_map[char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j])]='0';
intTOchar4(BlkNum,record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j]);
}
intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].blk_num);
super_blk.inode_map[char4TOint(dir_table[i].inode_num)]='0';
intTOchar4(InodeNum,dir_table[i].inode_num);
i=char4TOint(super_blk.inode_used)-1;
intTOchar4(i,super_blk.inode_used);
printf(" %s文件已删除!\n",filename);
break;
}
}
if(i==MaxDirNum)
{
printf(" 没有在目录中找到该文件,请确保输入的文件名正确!\n");
}
return 0;
}
3.2.4 文件的打开与关闭
文件系统维护一张打开文件表。打开文件表的长度固定,其表目含如下信息:
(1)读写指针 (2)文件名 (3)文件描述符
文件被打开时,便在打开文件表中为其分配一个表目;文件被关闭时,其对应的表目被释放。
定义结构体:
typedef struct
{
int pointer1;//读写指针(选择盘块)
int pointer2;//读写指针(盘块内偏移)
char name[30];//文件名
int inode_num;//文件描述符序号
} OpenFile;//已打开文件
自定义常量:
#define OpenFileMaximumNum 10//文件系统同时打开文件最大数目
自定义变量:
OpenFile OpenFile_table[OpenFileMaximumNum];//已打开文件
int OpenFileNum=0;//已打开文件数目
打开文件时需要进行的操作如下:
(1)搜索目录找到文件对应的描述符编号
(2)在打开文件表中分配一个表目
(3)在分配到的表目中把读写指针置为0,并记录描述符编号
(4)返回文件对应的描述符编号
打开文件函数:
int open_file(char *filename)//打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作
{
int i;
if(OpenFileNum>OpenFileMaximumNum)
{
printf(" 此时已打开文件数目达到文件系统最大要求,如要继续打开此文件,请先关闭一些不再使用的文件!\n");
return -1;
}
for(i=0; i<MaxDirNum; i++)
{
if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
{
strcpy(OpenFile_table[OpenFileNum].name, filename);
OpenFile_table[OpenFileNum].inode_num = char4TOint(dir_table[i].inode_num);
OpenFileNum++;
printf(" %s文件已打开,文件索引号为%d。\n",filename,char4TOint(dir_table[i].inode_num));
break;
}
}
if(i==MaxDirNum)
{
printf(" 没有在目录中找到该文件,请确保输入的文件名正确!\n");
}
return char4TOint(dir_table[i].inode_num);
}
关闭文件时需要进行的操作如下:
(1)释放该文件在打开文件表中对应的表目
(2)返回状态信息
关闭文件函数
int close_file(int index)//关闭指定文件
{
int i=0,j=0,judge=0;
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
printf(" %s文件已关闭。\n",OpenFile_table[i].name);
for(j=i; j<OpenFileNum-1; j++)
{
OpenFile_table[j].inode_num = OpenFile_table[j+1].inode_num;
strcpy(OpenFile_table[j].name, OpenFile_table[j+1].name);
OpenFile_table[j].pointer1 = OpenFile_table[j+1].pointer1;
OpenFile_table[j].pointer2 = OpenFile_table[j+1].pointer2;
}
OpenFile_table[j].inode_num = InodeNum;
strcpy(OpenFile_table[j].name, "\0");
OpenFile_table[j].pointer1 = 0;
OpenFile_table[j].pointer2 = 0;
OpenFileNum--;
judge = 1;
break;
}
}
if(judge==0)
{
printf(" 没有在已打开文件中找到该文件,请确保输入的索引号正确!\n");
}
return 0;
}
3.2.5 文件读写
文件打开之后才能进行读写操作.读操作需要完成的任务如下:
(1)计算读写指针对应的位置在读写缓冲区中的偏移
(2)把从模拟磁盘中读入数据(或向模拟磁盘中写入缓冲区数据),直到发生下列事件之一:到达文件尾或者已经拷贝了指定的字节数。
指针偏移函数:
/*把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,
它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置*/
int lseek_file(int index, int pos)
{
int i=0;
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
if(char4TOint(record_inode[index].file_size) == 0)
{
printf(" 该文件尚未存储任何内容,不允许偏移读写指针!\n");
}
else
{
if(char4TOint(record_inode[index].file_size) < pos)
{
printf(" 该文件允许偏移读写指针最大为%d,指针偏移失败 !\n",char4TOint(record_inode[index].file_size));
}
else
{
OpenFile_table[i].pointer1 = pos/1024;
OpenFile_table[i].pointer2 = pos%1024;
}
}
break;
}
}
if(i==OpenFileNum)
{
printf(" 索引号所对应的文件没有被打开,请先打开该文件!\n");
}
return 0;
}
读取文件函数:
int read_file(int index, int number)//从指定文件顺序读入number个字节到读写缓冲区buffer。读操作从文件的读写指针指示的位置开始
{
int i=0,j=0,x=0,y=0;
char use[8][512];
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
if(char4TOint(record_inode[index].file_size) == 0)
{
printf(" 该文件为空!\n");
}
else
{
read_block(char4TOint(record_inode[index].blk_identifier[0])*2, use[0],512);
read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2, use[2],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2, use[4],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2, use[6],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
x = OpenFile_table[i].pointer1*2;
if(OpenFile_table[i].pointer2>512)
{
x++;
y = OpenFile_table[i].pointer2 - 512;
}
else
{
y = OpenFile_table[i].pointer2;
}
if((char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
{
for(j=0; j<=(char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
{
buffer[j] = use[x][y];
y++;
if(y==512)
{
x++;
y=0;
}
}
printf(" 文件内容已读入到末尾,共读取%d个字节!\n",j);
buffer[j++]='\0';
}
else
{
for(j=0; j<=number; j++)
{
buffer[j] = use[x][y];
y++;
if(y==512)
{
x++;
y=0;
}
}
buffer[j++]='\0';
}
printf(" 文件内容已读入到读写缓冲区buffer中!内容为:\n\t\t%s\n",&buffer);
lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
}
break;
}
}
if(i==OpenFileNum)
{
printf(" 索引号所对应的文件没有被打开,请先打开该文件!\n");
}
return 0;
}
写入文件函数:
int write_file(int index, int number)//把读写缓冲区buffer的number个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始
{
int i=0,j=0,k=0,x=0,y=0,z=0,w;
char use[8][512];
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
printf(" 请输入你想写入该文件的内容:\n\t");
for(j=0; j<=number; j++)
{
scanf("%c",&buffer[j]);
}
if(char4TOint(record_inode[index].blk_num)==0)
{
intTOchar4(4,record_inode[index].blk_num);
for(z=0; z<4; z++)
{
for(k=0; k<BlkNum; k++)
{
if(super_blk.blk_map[k]=='0')
{
intTOchar4(k,record_inode[index].blk_identifier[z]);
super_blk.blk_map[k]='1';
break;
}
}
}
w=char4TOint(super_blk.blk_used)+4;
intTOchar4(w,super_blk.blk_used);
}
read_block(char4TOint(record_inode[index].blk_identifier[0])*2, use[0],512);
read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2, use[2],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2, use[4],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2, use[6],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
x = OpenFile_table[i].pointer1*2;
if(OpenFile_table[i].pointer2>512)
{
x++;
y = OpenFile_table[i].pointer2 - 512;
}
else
{
y = OpenFile_table[i].pointer2;
}
if((4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
{
for(j=0; j<=(4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
{
use[x][y] = buffer[j];
y++;
if(y==512)
{
x++;
y=0;
}
}
printf(" 文件内容未全部写入指定文件中,文件内容已达到最大值,写入%d个字节!\n",j);
}
else
{
for(j=0; j<=number; j++)
{
use[x][y] = buffer[j];
y++;
if(y==512)
{
x++;
y=0;
}
//printf("%c",use[x][y]);
}
printf(" 文件内容已全部写入指定文件中!\n");
}
//printf("%d\n",j);
w = char4TOint(record_inode[index].file_size)+j;
intTOchar4(w,record_inode[index].file_size);
write_block(char4TOint(record_inode[index].blk_identifier[0])*2, use[0],512);
write_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
write_block(char4TOint(record_inode[index].blk_identifier[1])*2, use[2],512);
write_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
write_block(char4TOint(record_inode[index].blk_identifier[2])*2, use[4],512);
write_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
write_block(char4TOint(record_inode[index].blk_identifier[3])*2, use[6],512);
write_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
}
break;
}
if(i==OpenFileNum)
{
printf(" 索引号所对应的文件没有被打开,请先打开该文件!\n");
}
return 0;
}
3.3.用户接口设计
简单清晰的操作方式是用户喜欢一个程序或软件的必要条件,特此编写以下函数,使程序操作起来更加方便快捷。
用户指令设计及路径:
/*指令集合*/
char* command[]= {"format","quit","directory","create","destroy","open","close","lseek","read","write","help","sbm","sim","sOF"};
/*路径名*/
char path[20]="file_system(yss)$ ";//文件系统(yss 袁少随)
辅助功能函数:
int format_fs()//格式化文件系统
{
init_Dick();初始化磁盘数组
char use[512];
int i=0;
memset(&super_blk.blk_map, '0', BlkNum);//初始化超级块
memset(&super_blk.inode_map, '0', InodeNum);
super_blk.blk_map[0]='1';
super_blk.blk_map[1]='1';
super_blk.blk_map[2]='1';
super_blk.blk_map[3]='1';
super_blk.blk_map[4]='1';
super_blk.blk_map[5]='1';
super_blk.blk_map[6]='1';
super_blk.blk_map[7]='1';
intTOchar4(8,super_blk.blk_used);
super_blk.inode_map[0]='1';
intTOchar4(1,super_blk.inode_used);
for(i=0; i<InodeNum; i++)//初始化文件描述符使用情况
{
intTOchar4(BlkNum,record_inode[i].blk_identifier[0]);
intTOchar4(BlkNum,record_inode[i].blk_identifier[1]);
intTOchar4(BlkNum,record_inode[i].blk_identifier[2]);
intTOchar4(BlkNum,record_inode[i].blk_identifier[3]);
intTOchar4(0,record_inode[i].blk_num);
intTOchar4(0,record_inode[i].file_size);
}
strncpy(dir_table[0].name,"yss_contents########",sizeof("yss_contents########")-1);//创建目录文件
intTOchar4(0,dir_table[0].inode_num);
intTOchar4(0,record_inode[0].blk_num);
intTOchar4(0,record_inode[0].file_size);
super_blk.inode_map[0]='1';
for(i=1; i<MaxDirNum; i++)//初始化目录使用情况
{
intTOchar4(InodeNum,dir_table[i].inode_num);
strncpy(dir_table[i].name,"!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
}
write_block(0,&super_blk,632);
write_block(2,&record_inode,2688);
write_block(8,&dir_table,2688);
memset(&use, ' ', 512);
for(i=16; i<L; i++)
{
write_block(i,use,512);
}
//printf("%d\n",sizeof(super_blk));
//printf("%d\n",sizeof(record_inode));
//printf("%d\n",sizeof(dir_table));
ArrayToFile();
printf(" 格式化文件系统成功!\n");
return 0;
}
void help()//求助函数
{
printf("***********************************************************************************\n");
printf("* 下面是本文件系统所支持的命令: *\n");
printf("* 格式化文件系统: format *\n");
printf("* 退出文件系统: quit *\n");
printf("* 显示目录内容: directory *\n");
printf("* 创建文件: create *\n");
printf("* 删除文件: destroy *\n");
printf("* 打开文件: open *\n");
printf("* 关闭文件: close *\n");
printf("* 文件指针偏移: lseek *\n");
printf("* 读文件: read *\n");
printf("* 写文件: write *\n");
printf("* 请求帮助: help *\n");
printf("* 磁盘块使用情况: sbm *\n");
printf("* 文件描述符使用情况: sim *\n");
printf("* 已打开文件列表: sOF *\n");
printf("***********************************************************************************\n");
}
主函数:
int main()
{
printf("***********************************************************************************\n");
printf("* 欢迎来到yss的文件系统!!! *\n");
printf("* 介绍:此文件系统是模拟Linux系统所制作,在这里你将体验到命令行的乐趣! *\n");
printf("* 格式化文件系统: format *\n");
printf("* 退出文件系统: quit *\n");
printf("* 显示目录内容: directory *\n");
printf("* 创建文件: create *\n");
printf("* 删除文件: destroy *\n");
printf("* 打开文件: open *\n");
printf("* 关闭文件: close *\n");
printf("* 文件指针偏移: lseek *\n");
printf("* 读文件: read *\n");
printf("* 写文件: write *\n");
printf("* 请求帮助: help *\n");
printf("* 磁盘块使用情况: sbm *\n");
printf("* 文件描述符使用情况: sim *\n");
printf("* 已打开文件列表: sOF *\n");
printf("* 好了!现在请开始你的表演!!! *\n");
printf("***********************************************************************************\n");
char comm[30],filename[20];
int i,quit=0,choice,index,number;
Disk = fopen(DISK,"r+");//打开磁盘文件
if(Disk == NULL)
{
printf("打开磁盘文件失败,请查看是否已创建disk.txt!\n");
}
init_fs();//初始化文件系统
while(1)
{
printf("%s ",path);
scanf("%s",comm);
choice=-1;
for(i=0; i<CommanNum; ++i)
{
if(strcmp(comm,command[i])==0)
{
choice=i;
break;
}
}
switch(choice)
{
/*格式化文件系统*/
case 0:
format_fs();
printf("\n");
break;
/*退出文件系统*/
case 1:
quit=1;
break;
/*显示目录内容*/
case 2:
directory();
printf("\n");
break;
/*创建文件*/
case 3:
printf("\t请输入文件名:");
scanf("%s",filename);
create(filename);
printf("\n");
break;
/*删除文件*/
case 4:
printf("\t请输入文件名:");
scanf("%s",filename);
destroy(filename);
printf("\n");
break;
/*打开文件*/
case 5:
printf("\t请输入文件名:");
scanf("%s",filename);
open_file(filename);
printf("\n");
break;
/*关闭文件*/
case 6:
printf("\t请输入文件索引号:");
scanf("%d",&index);
close_file(index);
printf("\n");
break;
/*关闭文件*/
case 7:
printf("\t请输入文件索引号:");
scanf("%d",&index);
printf("\t请输入指针偏移量:");
scanf("%d",&number);
lseek_file(index,number);
printf("\n");
break;
/*读文件*/
case 8:
printf("\t请输入文件索引号:");
scanf("%d",&index);
printf("\t请输入读取文件字节数目:");
scanf("%d",&number);
read_file(index,number);//将数据从文件写入BUFF
printf("\n");
break;
/*写文件*/
case 9:
printf("\t请输入文件索引号:");
scanf("%d",&index);
printf("\t请输入写入文件字节数目:");
scanf("%d",&number);
write_file(index,number);//将数据从BUFF写入文件
printf("\n");
break;
/*请求帮助*/
case 10:
help();
printf("\n");
break;
case 11:
show_blk_map();
printf("\n");
break;
case 12:
show_inode_map();
printf("\n");
break;
case 13:
show_OpenFile();
printf("\n");
break;
default:
printf("%s command not found\n",comm);
}
if(quit) break;
}
close_fs();//关闭文件系统
fclose(Disk);//关闭磁盘文件
return 0;
}
四、程序总代码
IO.h
#ifndef IO_H_INCLUDED
#define IO_H_INCLUDED
#include <stdio.h>
/*自定义常量*/
#define C 8//柱面总数
#define H 8//磁头总数
#define B 16//一个磁道的扇区数
#define L 1024//扇区总数;L=C*H*B
#define DISK "disk.txt"//磁盘文件
/*文件指针*/
FILE* Disk;
/*结构体*/
typedef struct
{
char record[512];//每个扇区大小为512字节
} Sector; //扇区
/*模拟磁盘数组*/
Sector ldisk[C][H][B];//CHB 分别表示柱面号,磁头号和扇区号
/*IO函数*/
int FileToArray(void);//把文件内容恢复到数组
int ArrayToFile(void);//把数组ldisk 存储到文件
int read_block(int x, char *p, int strlen);//把逻辑块i的内容读入到指针p指向的内存位置,拷贝的字符个数为strlen
int write_block(int i, char *p, int strlen);//把指针p指向的内容写入逻辑块i,拷贝的字符个数为strlen
void intTOchar4(int x,char p[4]);//int类型转换为char[4]
int char4TOint(char p[4]);//char[4]转换为int
int FileToArray()
{
int i,j,k;
fseek(Disk,0,SEEK_SET);
for(i=0; i<C; i++)
{
for(j=0; j<H; j++)
{
for(k=0; k<B; k++)
{
if(fread(&ldisk[i][j][k],512,1,Disk)!=1)
{
printf("文件内容恢复到数组失败!\n");
k=B;
j=H;
i=C;//退出
}
}
}
}
return 1;
}
int ArrayToFile()
{
int i,j,k;
fseek(Disk,0,SEEK_SET);
for(i=0; i<C; i++)
{
for(j=0; j<H; j++)
{
for(k=0; k<B; k++)
{
if(fwrite(&ldisk[i][j][k],512,1,Disk)!=1)
{
printf("数组存储到文件失败!\n");
k=B;
j=H;
i=C;//退出
}
}
}
}
return 1;
}
int read_block(int x, char *p, int strlen)
{
int i,j,k;
i=x/(H*B);
j=(x-i*H*B)/B;
k=(x-i*H*B-j*B);
strncpy(p, &ldisk[i][j][k], strlen);
return 0;
}
int write_block(int x, char *p, int strlen)
{
int i,j,k;
i=x/(H*B);
j=(x-i*H*B)/B;
k=(x-i*H*B-j*B);
strncpy(&ldisk[i][j][k], p, strlen);
return 0;
}
void intTOchar4(int x,char p[4])
{
int i=0;
i=x%10;
switch(i)
{
case 0:
p[0]='0';
break;
case 1:
p[0]='1';
break;
case 2:
p[0]='2';
break;
case 3:
p[0]='3';
break;
case 4:
p[0]='4';
break;
case 5:
p[0]='5';
break;
case 6:
p[0]='6';
break;
case 7:
p[0]='7';
break;
case 8:
p[0]='8';
break;
case 9:
p[0]='9';
break;
default:
break;
}
x/=10;
i=x%10;
switch(i)
{
case 0:
p[1]='0';
break;
case 1:
p[1]='1';
break;
case 2:
p[1]='2';
break;
case 3:
p[1]='3';
break;
case 4:
p[1]='4';
break;
case 5:
p[1]='5';
break;
case 6:
p[1]='6';
break;
case 7:
p[1]='7';
break;
case 8:
p[1]='8';
break;
case 9:
p[1]='9';
break;
default:
break;
}
x/=10;
i=x%10;
switch(i)
{
case 0:
p[2]='0';
break;
case 1:
p[2]='1';
break;
case 2:
p[2]='2';
break;
case 3:
p[2]='3';
break;
case 4:
p[2]='4';
break;
case 5:
p[2]='5';
break;
case 6:
p[2]='6';
break;
case 7:
p[2]='7';
break;
case 8:
p[2]='8';
break;
case 9:
p[2]='9';
break;
default:
break;
}
x/=10;
i=x%10;
switch(i)
{
case 0:
p[3]='0';
break;
case 1:
p[3]='1';
break;
case 2:
p[3]='2';
break;
case 3:
p[3]='3';
break;
case 4:
p[3]='4';
break;
case 5:
p[3]='5';
break;
case 6:
p[3]='6';
break;
case 7:
p[3]='7';
break;
case 8:
p[3]='8';
break;
case 9:
p[3]='9';
break;
default:
break;
}
}
int char4TOint(char p[4])
{
int x=0;
x=(((p[3]-48)*10+(p[2]-48))*10+(p[1]-48))*10+p[0]-48;
return x;
}
#endif // IO_H_INCLUDED
File.h
#ifndef FILE_H_INCLUDED
#define FILE_H_INCLUDED
#include "IO.h"
/*自定义常量*/
#define BlkNum 512//磁盘块的数目(编号从0开始)
#define BlkSize 1024//磁盘块大小为1K
#define InodeNum 112//文件描述符数目
#define BlkPerNode 4//每个文件包含的最大的磁盘块数目
#define K 4//超级块占磁盘块数目(0\1\2\3)
#define SuperBlkBeg 0//超级块起始磁盘块(0)
#define InodeBeg 1//文件描述符起始磁盘块(1\2\3)
#define BlockDirBeg 4//目录区起始磁盘块(4/5/6/7)
#define BlockFileBeg 8//文件区起始磁盘块
#define MaxDirNum 112//目录所支持的最大的文件数
#define CommanNum (sizeof(command)/sizeof(char*))//指令数目
#define OpenFileMaximumNum 10//文件系统同时打开文件最大数目
/*指令集合*/
char* command[]= {"format","quit","directory","create","destroy","open","close","lseek","read","write","help","sbm","sim","sOF"};
/*路径名*/
char path[20]="file_system(yss)$ ";//文件系统(yss 袁少随)
/*读写缓冲区*/
char buffer[5000];
/*结构体*/
typedef struct
{
char blk_map[BlkNum];//磁盘块位图
char inode_map[InodeNum];//文件描述符位图
char blk_used[4];//已被使用的磁盘块数目
char inode_used[4];//已被使用的文件描述符数目
} SuperBlk;//超级块(保留区)
typedef struct
{
char blk_identifier[BlkPerNode][4];//占用的磁盘块编号
char blk_num[4];//占用的磁盘块数目
char file_size[4];//文件的大小
} Inode;//文件描述符
typedef struct
{
char name[20];//文件名
char inode_num[4];//文件描述符序号
} Dir;//目录
typedef struct
{
int pointer1;//读写指针(选择盘块)
int pointer2;//读写指针(盘块内偏移)
char name[30];//文件名
int inode_num;//文件描述符序号
} OpenFile;//已打开文件
/*自定义变量*/
SuperBlk super_blk;//文件系统的超级块
Inode record_inode[InodeNum];//文件描述符使用情况
Dir dir_table[MaxDirNum];//目录使用情况
OpenFile OpenFile_table[OpenFileMaximumNum];//已打开文件
int OpenFileNum=0;//已打开文件数目
/*子函数*/
void init_Dick();//初始化磁盘
int init_fs();//初始化文件系统
int close_fs();//关闭文件系统
int format_fs();//格式化文件系统
int create(char *filename);//根据指定的文件名创建新文件
int destroy(char *filename);//删除指定文件
int open_file(char *filename);//打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作
int close_file(int index);//关闭指定文件
int read_file(int index, int number);//从指定文件顺序读入number个字节到读写缓冲区buffer。读操作从文件的读写指针指示的位置开始
int write_file(int index, int number);//把读写缓冲区buffer的number个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始
/*把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,
它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置*/
int lseek_file(int index, int pos);
int directory();//列表显示所有文件及其长度
void help();//求助函数
void show_blk_map();//显示磁盘块使用情况,0代表未被使用,1代表已使用
void show_inode_map();//显示文件描述符使用情况,0代表未被使用,1代表已使用
void show_OpenFile();//显示已打开文件
/*File函数*/
void init_Dick()
{
int i,j,k;
for(i=0; i<C; i++)
{
for(j=0; j<H; j++)
{
for(k=0; k<B; k++)
{
memset(&ldisk[i][j][k], '#', 512);
}
}
}
}
int init_fs()
{
char judge;
printf(" 如果你是第一次使用此文件系统,请输入1!否则输入其它任意键!\n");
scanf("%c",&judge);
if(judge=='1')
{
format_fs();
printf("\n");
}
FileToArray();//把文件内容恢复到数组
//把数组内容恢复到程序内存中
read_block(0,&super_blk,632);
read_block(2,&record_inode,2688);
read_block(8,&dir_table,4032);
printf("\n");
return 0;
}
int close_fs()
{
//把程序内存中内容写入模拟磁盘数组
write_block(0,&super_blk,632);
write_block(2,&record_inode,2688);
write_block(8,&dir_table,4032);
ArrayToFile();//把数组ldisk 存储到文件
return 0;
}
int format_fs()//格式化文件系统
{
init_Dick();初始化磁盘数组
char use[512];
int i=0;
memset(&super_blk.blk_map, '0', BlkNum);//初始化超级块
memset(&super_blk.inode_map, '0', InodeNum);
super_blk.blk_map[0]='1';
super_blk.blk_map[1]='1';
super_blk.blk_map[2]='1';
super_blk.blk_map[3]='1';
super_blk.blk_map[4]='1';
super_blk.blk_map[5]='1';
super_blk.blk_map[6]='1';
super_blk.blk_map[7]='1';
intTOchar4(8,super_blk.blk_used);
super_blk.inode_map[0]='1';
intTOchar4(1,super_blk.inode_used);
for(i=0; i<InodeNum; i++)//初始化文件描述符使用情况
{
intTOchar4(BlkNum,record_inode[i].blk_identifier[0]);
intTOchar4(BlkNum,record_inode[i].blk_identifier[1]);
intTOchar4(BlkNum,record_inode[i].blk_identifier[2]);
intTOchar4(BlkNum,record_inode[i].blk_identifier[3]);
intTOchar4(0,record_inode[i].blk_num);
intTOchar4(0,record_inode[i].file_size);
}
strncpy(dir_table[0].name,"yss_contents########",sizeof("yss_contents########")-1);//创建目录文件
intTOchar4(0,dir_table[0].inode_num);
intTOchar4(0,record_inode[0].blk_num);
intTOchar4(0,record_inode[0].file_size);
super_blk.inode_map[0]='1';
for(i=1; i<MaxDirNum; i++)//初始化目录使用情况
{
intTOchar4(InodeNum,dir_table[i].inode_num);
strncpy(dir_table[i].name,"!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
}
write_block(0,&super_blk,632);
write_block(2,&record_inode,2688);
write_block(8,&dir_table,2688);
memset(&use, ' ', 512);
for(i=16; i<L; i++)
{
write_block(i,use,512);
}
//printf("%d\n",sizeof(super_blk));
//printf("%d\n",sizeof(record_inode));
//printf("%d\n",sizeof(dir_table));
ArrayToFile();
printf(" 格式化文件系统成功!\n");
return 0;
}
int create(char *filename)//根据指定的文件名创建新文件
{
int i;
//printf("%d\n",strlen(filename));
if(strlen(filename)>=20)
{
printf(" 文件名过长!\n");
return -1;
}
for(i=0; i<MaxDirNum; i++)
{
if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
{
printf(" 文件系统中已存在该文件,请更换文件名或将已存在文件删除!\n");
return -1;
}
}
if(char4TOint(super_blk.inode_used)>=InodeNum)
{
printf(" 文件系统中存储文件已达上限,请先删除一些不必要的文件后再创建新文件!\n");
return -1;
}
strncpy(dir_table[char4TOint(super_blk.inode_used)].name,filename,strlen(filename));
for(i=1; i<InodeNum; i++)
{
if(super_blk.inode_map[i]=='0')
{
intTOchar4(i,dir_table[char4TOint(super_blk.inode_used)].inode_num);
intTOchar4(0,record_inode[i].blk_num);
intTOchar4(0,record_inode[i].file_size);
super_blk.inode_map[i]='1';
break;
}
}
i=char4TOint(super_blk.inode_used)+1;
intTOchar4(i,super_blk.inode_used);
printf(" 文件%s创建成功!\n",filename);
return 0;
}
int destroy(char *filename)//删除指定文件
{
int i,j,k;
char use[512];
for(i=0; i<OpenFileNum; i++)
{
if(strcmp(OpenFile_table[i].name, filename)==0)
{
printf(" %s文件已打开,请先关闭文件后再进行删除。\n",filename);
return -1;
}
}
for(i=1; i<MaxDirNum; i++)
{
if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
{
strncpy(dir_table[i].name, "!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].file_size);
if(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num)!=0)
{
memset(&use, ' ', 512);
//printf("%d\n",char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0]));
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2+1,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2+1,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2+1,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2,use,512);
write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2+1,use,512);
k = char4TOint(super_blk.blk_used)-4;
intTOchar4(k,super_blk.blk_used);
}
for(j=0; j<char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num); j++)
{
super_blk.blk_map[char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j])]='0';
intTOchar4(BlkNum,record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j]);
}
intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].blk_num);
super_blk.inode_map[char4TOint(dir_table[i].inode_num)]='0';
intTOchar4(InodeNum,dir_table[i].inode_num);
i=char4TOint(super_blk.inode_used)-1;
intTOchar4(i,super_blk.inode_used);
printf(" %s文件已删除!\n",filename);
break;
}
}
if(i==MaxDirNum)
{
printf(" 没有在目录中找到该文件,请确保输入的文件名正确!\n");
}
return 0;
}
int open_file(char *filename)//打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作
{
int i;
if(OpenFileNum>OpenFileMaximumNum)
{
printf(" 此时已打开文件数目达到文件系统最大要求,如要继续打开此文件,请先关闭一些不再使用的文件!\n");
return -1;
}
for(i=0; i<MaxDirNum; i++)
{
if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
{
strcpy(OpenFile_table[OpenFileNum].name, filename);
OpenFile_table[OpenFileNum].inode_num = char4TOint(dir_table[i].inode_num);
OpenFileNum++;
printf(" %s文件已打开,文件索引号为%d。\n",filename,char4TOint(dir_table[i].inode_num));
break;
}
}
if(i==MaxDirNum)
{
printf(" 没有在目录中找到该文件,请确保输入的文件名正确!\n");
}
return char4TOint(dir_table[i].inode_num);
}
int close_file(int index)//关闭指定文件
{
int i=0,j=0,judge=0;
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
printf(" %s文件已关闭。\n",OpenFile_table[i].name);
for(j=i; j<OpenFileNum-1; j++)
{
OpenFile_table[j].inode_num = OpenFile_table[j+1].inode_num;
strcpy(OpenFile_table[j].name, OpenFile_table[j+1].name);
OpenFile_table[j].pointer1 = OpenFile_table[j+1].pointer1;
OpenFile_table[j].pointer2 = OpenFile_table[j+1].pointer2;
}
OpenFile_table[j].inode_num = InodeNum;
strcpy(OpenFile_table[j].name, "\0");
OpenFile_table[j].pointer1 = 0;
OpenFile_table[j].pointer2 = 0;
OpenFileNum--;
judge = 1;
break;
}
}
if(judge==0)
{
printf(" 没有在已打开文件中找到该文件,请确保输入的索引号正确!\n");
}
return 0;
}
/*把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,
它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置*/
int lseek_file(int index, int pos)
{
int i=0;
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
if(char4TOint(record_inode[index].file_size) == 0)
{
printf(" 该文件尚未存储任何内容,不允许偏移读写指针!\n");
}
else
{
if(char4TOint(record_inode[index].file_size) < pos)
{
printf(" 该文件允许偏移读写指针最大为%d,指针偏移失败 !\n",char4TOint(record_inode[index].file_size));
}
else
{
OpenFile_table[i].pointer1 = pos/1024;
OpenFile_table[i].pointer2 = pos%1024;
}
}
break;
}
}
if(i==OpenFileNum)
{
printf(" 索引号所对应的文件没有被打开,请先打开该文件!\n");
}
return 0;
}
int read_file(int index, int number)//从指定文件顺序读入number个字节到读写缓冲区buffer。读操作从文件的读写指针指示的位置开始
{
int i=0,j=0,x=0,y=0;
char use[8][512];
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
if(char4TOint(record_inode[index].file_size) == 0)
{
printf(" 该文件为空!\n");
}
else
{
read_block(char4TOint(record_inode[index].blk_identifier[0])*2, use[0],512);
read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2, use[2],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2, use[4],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2, use[6],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
x = OpenFile_table[i].pointer1*2;
if(OpenFile_table[i].pointer2>512)
{
x++;
y = OpenFile_table[i].pointer2 - 512;
}
else
{
y = OpenFile_table[i].pointer2;
}
if((char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
{
for(j=0; j<=(char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
{
buffer[j] = use[x][y];
y++;
if(y==512)
{
x++;
y=0;
}
}
printf(" 文件内容已读入到末尾,共读取%d个字节!\n",j);
buffer[j++]='\0';
}
else
{
for(j=0; j<=number; j++)
{
buffer[j] = use[x][y];
y++;
if(y==512)
{
x++;
y=0;
}
}
buffer[j++]='\0';
}
printf(" 文件内容已读入到读写缓冲区buffer中!内容为:\n\t\t%s\n",&buffer);
lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
}
break;
}
}
if(i==OpenFileNum)
{
printf(" 索引号所对应的文件没有被打开,请先打开该文件!\n");
}
return 0;
}
int write_file(int index, int number)//把读写缓冲区buffer的number个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始
{
int i=0,j=0,k=0,x=0,y=0,z=0,w;
char use[8][512];
for(i=0; i<OpenFileNum; i++)
{
if(OpenFile_table[i].inode_num == index)
{
printf(" 请输入你想写入该文件的内容:\n\t");
for(j=0; j<=number; j++)
{
scanf("%c",&buffer[j]);
}
if(char4TOint(record_inode[index].blk_num)==0)
{
intTOchar4(4,record_inode[index].blk_num);
for(z=0; z<4; z++)
{
for(k=0; k<BlkNum; k++)
{
if(super_blk.blk_map[k]=='0')
{
intTOchar4(k,record_inode[index].blk_identifier[z]);
super_blk.blk_map[k]='1';
break;
}
}
}
w=char4TOint(super_blk.blk_used)+4;
intTOchar4(w,super_blk.blk_used);
}
read_block(char4TOint(record_inode[index].blk_identifier[0])*2, use[0],512);
read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2, use[2],512);
read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2, use[4],512);
read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2, use[6],512);
read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
x = OpenFile_table[i].pointer1*2;
if(OpenFile_table[i].pointer2>512)
{
x++;
y = OpenFile_table[i].pointer2 - 512;
}
else
{
y = OpenFile_table[i].pointer2;
}
if((4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
{
for(j=0; j<=(4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
{
use[x][y] = buffer[j];
y++;
if(y==512)
{
x++;
y=0;
}
}
printf(" 文件内容未全部写入指定文件中,文件内容已达到最大值,写入%d个字节!\n",j);
}
else
{
for(j=0; j<=number; j++)
{
use[x][y] = buffer[j];
y++;
if(y==512)
{
x++;
y=0;
}
//printf("%c",use[x][y]);
}
printf(" 文件内容已全部写入指定文件中!\n");
}
//printf("%d\n",j);
w = char4TOint(record_inode[index].file_size)+j;
intTOchar4(w,record_inode[index].file_size);
write_block(char4TOint(record_inode[index].blk_identifier[0])*2, use[0],512);
write_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
write_block(char4TOint(record_inode[index].blk_identifier[1])*2, use[2],512);
write_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
write_block(char4TOint(record_inode[index].blk_identifier[2])*2, use[4],512);
write_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
write_block(char4TOint(record_inode[index].blk_identifier[3])*2, use[6],512);
write_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
}
break;
}
if(i==OpenFileNum)
{
printf(" 索引号所对应的文件没有被打开,请先打开该文件!\n");
}
return 0;
}
int directory()//显示所有文件及其长度,以及占用磁盘号
{
int i=0,j=0,k=0,x=0;
if(char4TOint(super_blk.inode_used)==1)
{
printf(" 文件系统未含有文件!\n");
}
else
{
for(i=1; i<InodeNum; i++)
{
if(super_blk.inode_map[i]=='1')
{
for(j=0; j<MaxDirNum; j++)
{
if(char4TOint(dir_table[j].inode_num)==i)
break;
}
printf(" 文件名为:");
for(x=0; x<20; x++)
{
if(dir_table[j].name[x]!='!')
printf("%c",dir_table[j].name[x]);
}
printf(" 文件大小为:%d字节\n",char4TOint(record_inode[i].file_size));
if(char4TOint(record_inode[i].blk_num)==0)
{
printf(" 文件未占用磁盘块!");
}
else
{
printf(" 文件占用的磁盘块编号为: ");
for(k=0; k<char4TOint(record_inode[i].blk_num); k++)
printf("%d ",char4TOint(record_inode[i].blk_identifier[k]));
}
printf("\n\n");
}
}
}
return 0;
}
void help()
{
printf("***********************************************************************************\n");
printf("* 下面是本文件系统所支持的命令: *\n");
printf("* 格式化文件系统: format *\n");
printf("* 退出文件系统: quit *\n");
printf("* 显示目录内容: directory *\n");
printf("* 创建文件: create *\n");
printf("* 删除文件: destroy *\n");
printf("* 打开文件: open *\n");
printf("* 关闭文件: close *\n");
printf("* 文件指针偏移: lseek *\n");
printf("* 读文件: read *\n");
printf("* 写文件: write *\n");
printf("* 请求帮助: help *\n");
printf("* 磁盘块使用情况: sbm *\n");
printf("* 文件描述符使用情况: sim *\n");
printf("* 已打开文件列表: sOF *\n");
printf("***********************************************************************************\n");
}
void show_blk_map()//显示磁盘块使用情况,0代表未被使用,1代表已使用
{
int i=0;
for(i=0; i<BlkNum; i++)
{
printf("%c ",super_blk.blk_map[i]);
if((i+1)%24==0)
printf("\n");
}
printf("\n\t已被使用的磁盘块数目为:%d\n",char4TOint(super_blk.blk_used));
}
void show_inode_map()//显示文件描述符使用情况,0代表未被使用,1代表已使用
{
int i=0;
for(i=0; i<InodeNum; i++)
{
printf("%c ",super_blk.inode_map[i]);
if((i+1)%24==0)
printf("\n");
}
printf("\n\t已被使用的文件描述符数目为:%d\n",char4TOint(super_blk.inode_used));
}
void show_OpenFile()//显示已打开文件
{
int i=0;
if(OpenFileNum == 0)
{
printf("\t未打开任何文件!\n");
}
else
{
printf("\t已打开%d个文件,分别是:\n",OpenFileNum);
for(i=0; i<OpenFileNum; i++)
{
printf("\t\t文件名为%s,该文件索引号为%d.",OpenFile_table[i].name,OpenFile_table[i].inode_num);
}
}
}
#endif // FILE_H_INCLUDED
main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "file.h"
#include "IO.h"
/*主函数*/
int main()
{
printf("***********************************************************************************\n");
printf("* 欢迎来到yss的文件系统!!! *\n");
printf("* 介绍:此文件系统是模拟Linux系统所制作,在这里你将体验到命令行的乐趣! *\n");
printf("* 格式化文件系统: format *\n");
printf("* 退出文件系统: quit *\n");
printf("* 显示目录内容: directory *\n");
printf("* 创建文件: create *\n");
printf("* 删除文件: destroy *\n");
printf("* 打开文件: open *\n");
printf("* 关闭文件: close *\n");
printf("* 文件指针偏移: lseek *\n");
printf("* 读文件: read *\n");
printf("* 写文件: write *\n");
printf("* 请求帮助: help *\n");
printf("* 磁盘块使用情况: sbm *\n");
printf("* 文件描述符使用情况: sim *\n");
printf("* 已打开文件列表: sOF *\n");
printf("* 好了!现在请开始你的表演!!! *\n");
printf("***********************************************************************************\n");
char comm[30],filename[20];
int i,quit=0,choice,index,number;
Disk = fopen(DISK,"r+");//打开磁盘文件
if(Disk == NULL)
{
printf("打开磁盘文件失败,请查看是否已创建disk.txt!\n");
}
init_fs();//初始化文件系统
while(1)
{
printf("%s ",path);
scanf("%s",comm);
choice=-1;
for(i=0; i<CommanNum; ++i)
{
if(strcmp(comm,command[i])==0)
{
choice=i;
break;
}
}
switch(choice)
{
/*格式化文件系统*/
case 0:
format_fs();
printf("\n");
break;
/*退出文件系统*/
case 1:
quit=1;
break;
/*显示目录内容*/
case 2:
directory();
printf("\n");
break;
/*创建文件*/
case 3:
printf("\t请输入文件名:");
scanf("%s",filename);
create(filename);
printf("\n");
break;
/*删除文件*/
case 4:
printf("\t请输入文件名:");
scanf("%s",filename);
destroy(filename);
printf("\n");
break;
/*打开文件*/
case 5:
printf("\t请输入文件名:");
scanf("%s",filename);
open_file(filename);
printf("\n");
break;
/*关闭文件*/
case 6:
printf("\t请输入文件索引号:");
scanf("%d",&index);
close_file(index);
printf("\n");
break;
/*关闭文件*/
case 7:
printf("\t请输入文件索引号:");
scanf("%d",&index);
printf("\t请输入指针偏移量:");
scanf("%d",&number);
lseek_file(index,number);
printf("\n");
break;
/*读文件*/
case 8:
printf("\t请输入文件索引号:");
scanf("%d",&index);
printf("\t请输入读取文件字节数目:");
scanf("%d",&number);
read_file(index,number);//将数据从文件写入BUFF
printf("\n");
break;
/*写文件*/
case 9:
printf("\t请输入文件索引号:");
scanf("%d",&index);
printf("\t请输入写入文件字节数目:");
scanf("%d",&number);
write_file(index,number);//将数据从BUFF写入文件
printf("\n");
break;
/*请求帮助*/
case 10:
help();
printf("\n");
break;
case 11:
show_blk_map();
printf("\n");
break;
case 12:
show_inode_map();
printf("\n");
break;
case 13:
show_OpenFile();
printf("\n");
break;
default:
printf("%s command not found\n",comm);
}
if(quit) break;
}
close_fs();//关闭文件系统
fclose(Disk);//关闭磁盘文件
return 0;
}
五、实验结果
格式化文件系统:
显示磁盘块使用情况:
显示文件描述符使用情况:
帮助界面:
创建文件:
打开文件:
写文件:
读文件:
关闭文件:
删除文件:
六、实验体会
历时12天,终于完工。为自己点赞!
本次实验代码完全由本人(yss)一键一键所敲,程序运行起来指令十分简单,但或许还有一些不足之处,请各位在博客下多多批评指正,感谢!
通过本次模拟操作系统实验,我熟悉并掌握了真实情况下文件系统的运作方式,可能不同系统或不同版本的文件系统存在细节上的差异,但大体规律还是类似的。在真实磁盘上只有0和1,而我使用一个文件(Disk.txt,大小512KB)模拟真实磁盘,使用ASCII码来代替0和1,操作起来会相对简单一些(但其实还是比较难的,可能是自己太菜)。本次实验使我了解了文件系统的结构以及它的工作原理,了解文件系统的read,write等函数的实现,对操作系统有了更深一步的理解,获益匪浅。
如有感兴趣或想要了解更多的同学,请点击(里面有程序演示视频):
https://github.com/yuanshaosui/OS/tree/master/文件系统
欢迎各位同学的留言.