实验五: 文件系统
一、实验目的
本实验要求在模拟的I/O系统之上开发一个简单的文件系统。用户通过create, open, read等命令与文件系统交互。文件系统把磁盘视为顺序编号的逻辑块序列,逻辑块的编号为0至L−1。I/O系统利用内存中的数组模拟磁盘。
二、概要设计
文件系统提供如下函数;create, destroy, open, read, write。
• int create(filename): 根据指定的文件名创建新文件。
找到一个空闲的文件描述符。
在文件目录中为新创建的文件分配一个目录项(可能需要为目录文件分配新的磁盘块)。
在分配的目录项中记录文件名以及描述符编号。
返回状态信息(如有无错误发生等)。
• int destroy(filename): 删除指定文件。
在目录中搜索该文件的描述符编号。
删除该文件对应的目录项并更新位图。
释放文件描述符。
返回状态信息。
•int open(filename): 打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作。
搜索目录找到文件对应的描述符编号。
在打开文件表中分配一个表目。
在分配到的表目中把读写指针置为0,并记录描述符编号。
读入文件的第一块到读写缓冲区中。
返回分配到的表目在打开文件表中的索引号。
•int close(index): 关闭指定文件。
把缓冲区的内容写入磁盘。
释放该文件在打开文件表中对应的表目。
返回状态信息。
•int read(index, mem_area, count): 从指定文件顺序读入count个字节memarea指定的内存位置。读操作从文件的读写指针指示的位置开始。
计算读写指针对应的位置在读写缓冲区中的偏移。
把缓冲区中的内容拷贝到指定的内存位置,直到发生下列事件之一。
到达文件尾或者已经拷贝了指定的字节数。这时,更新读写指针并返回相应信息。
到达缓冲区末尾。这时,把缓冲区内容写入磁盘,然后把文件下一块的内容读入磁盘。最后返回第2步。
•int write(index, mem_area, count): 把mem_area指定的内存位置开始的count个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始。
写的内容若小于缓冲区内容,则直接写入缓冲区,完成写操作。
写入的内容,缓冲区若无法一次装完,则需要填满缓冲区,然后将缓冲区写入文件,腾出缓冲区。
然后再写入缓冲区,碰到缓冲区满的情况便写入文件,腾出缓冲区,以便文件的写入,完成写操作。
返回状态信息。
•int lseek(index, pos): pos是一个整数,表示从文件开始位置的偏移量。
把文件的读写指针移动到pos指定的位置。
文件打开时,读写指针自动设置为0。
每次读写操作之后,它指向最后被访问的字节的下一个位置。
lseek能够在不进行读写操作的情况下改变读写指针能位置。
三、详细设计及测试结果
创建文件:
int create(char filename[])
{
int i;
int frees;
int freed;
int freed2;
char temps[B];
char tempc[B];
char temp[B];
for(i = K ; i < K+FILE_NUM ; i++)
{
read_block((i-K)/B,temp);
if(temp[(i-K)%B] == BUSY)
{
read_block(i,temp);
if(strncmp(temp+1,filename,FILE_NAME_LENGTH) == 0)
{
printf("该目录已经存在文件名为%s的文件\n",filename);
return ERROR;
}
}
}
for(i = FILE_SIGN_AREA ; i < K; i ++)
{
read_block(i,temp);
if(temp[0] == FREE)
{
frees = i;
break;
}
}
if(i == K)
{
printf("没有空闲的文件描述符\n");
return ERROR;
}
for(i = K ; i < K+FILE_NUM ; i++)
{
read_block((i-K)/B,temp);
if(temp[(i-K)%B] == FREE)
{
freed = i;
break;
}
}
if(i == K+FILE_NUM)
{
printf("文件个数已达上限\n");
return ERROR;
}
for(i = K + FILE_NUM; i < L ; i++)
{
read_block((i-K)/B,temp);
if(temp[(i-K)%B] == FREE)
{
freed2 = i;
break;
}
}
if(i == L)
{
printf("磁盘已满,分配失败\n");
return ERROR;
}
filesign temp_filesign;
contents temp_contents;
temp_filesign.filesign_flag = 1;
temp_filesign.file_length = 0;
temp_filesign.file_block = 1;
Init_block(temps,B);
temps[0] = temp_filesign.filesign_flag;
temps[1] = temp_filesign.file_length;
temps[2] = temp_filesign.file_block;
temps[3] = freed2;
for(i = 4 ; i < FILE_BLOCK_LENGTH ; i++)
{
temps[i] = '\0';
}
write_block(frees,temps);
temp_contents.filesignnum = frees - FILE_SIGN_AREA;
strncpy(temp_contents.filename,filename,FILE_NAME_LENGTH);
Init_block(tempc,B);
tempc[0] = temp_contents.filesignnum;
tempc[1] = '\0';
strcat(tempc,temp_contents.filename);
write_block(freed,tempc);
read_block((freed-K)/B,temp);
temp[(freed-K)%B] = BUSY;
write_block((freed-K)/B,temp);
read_block((freed2-K)/B,temp);
temp[(freed2-K)%B] = BUSY;
write_block((freed2-K)/B,temp);
read_block(FILE_SIGN_AREA,temp);
temp[1]++;
write_block(FILE_SIGN_AREA,temp);
return OK;
}
删除文件:
int destroy(char * filename)
{
int i;
int dtys;
int dtyd;
int use_block;
int index;
char temp[B];
char tempd[B];
for(i = K ; i < K+FILE_NUM ; i++)
{
read_block((i-K)/B,temp);
if(temp[(i-K)%B] == BUSY)
{
read_block(i,temp);
if(strncmp(temp+1,filename,FILE_NAME_LENGTH) == 0)
{
dtyd = i;
dtys = temp[0] + FILE_SIGN_AREA;
index = temp[0];
break;
}
}
}
if(i == K+FILE_NUM)
{
printf("没有找到该文件\n");
return ERROR;
}
int list = -1;
for(i = 0; i < FILE_NUM ; i++)
{
if(open_list[i].filesignnum == index)
{
list = i;
break;
}
}
if(open_list[list].flag == BUSY && list != -1)
{
printf("该文件已经被打开,需要关闭才能删除\n");
return ERROR;
}
read_block(dtys,temp);
use_block = temp[2];
for(i = 0 ; i < use_block ; i++)
{
read_block((temp[i+3]-K)/B,tempd);
tempd[(temp[i+3]-K)%B] = FREE;
write_block((temp[i+3]-K)/B,tempd);
}
Init_block(temp,B);
write_block(dtys,temp);
Init_block(temp,B);
write_block(dtyd,temp);
read_block((dtyd-K)/B,temp);
temp[(dtyd-K)%B] = FREE;
write_block((dtyd-K)/B,temp);
read_block(FILE_SIGN_AREA,temp);
temp[1]--;
write_block(FILE_SIGN_AREA,temp);
return OK;
}
打开文件:
int open(char * filename)
{
int i;
int opd;
int ops;
int list;
char temp[B];
int index;
for(i = K ; i < K+FILE_NUM ; i++)
{
read_block((i-K)/B,temp);
if(temp[(i-K)%B] == BUSY)
{
read_block(i,temp);
if(strncmp(temp+1,filename,FILE_NAME_LENGTH) == 0)
{
opd = i;
ops = temp[0] ;
// printf("opd: %d,ops: %d\n",opd,ops);
break;
}
}
}
if(i == K+FILE_NUM)
{
printf("没有找到该文件\n");
return ERROR;
}
for(i = 0 ; i < FILE_NUM ; i++)
{
if(open_list[i].filesignnum == ops && open_list[i].flag == BUSY)
{
printf("该文件已经被打开\n");
return ERROR;
}
}
for(i = 0 ; i < FILE_NUM ; i++)
{
if(open_list[i].flag != BUSY)
{
list = i;
break;
}
}
open_list[list].filesignnum = ops;
open_list[list].flag = BUSY;
index = open_list[list].filesignnum;
lseek(index,0);
Init_block(open_list[list].buffer,BUFFER_LENGTH);
read_block(open_list[list].pointer[0],temp);
strncpy(open_list[list].buffer,temp,BUFFER_LENGTH);
return OK;
}
关闭文件:
int close(int index)
{
int i;
int list = -1;
char temp[B];
for(i = 0; i < FILE_NUM ; i++)
{
if(open_list[i].filesignnum == index)
{
list = i;
break;
}
}
if(list == -1)
{
printf("没找到当前索引号文件,操作失败\n");
return ERROR;
}
if(open_list[list].flag != BUSY)
{
printf("输入的索引号有误,操作失败\n");
return ERROR;
}
write_buffer(index,list);
Init_block(open_list[list].buffer,BUFFER_LENGTH);
open_list[list].filesignnum = FREE;
open_list[list].flag = FREE;
open_list[list].pointer[0] = NULL;
open_list[list].pointer[1] = NULL;
return OK;
}
文件的读操作:
int read(int index, int mem_area, int count)
{
int i;
int list = -1;
char temp[B];
for(i = 0; i < FILE_NUM ; i++)
{
if(open_list[i].filesignnum == index)
{
list = i;
break;
}
}
if(list == -1)
{
printf("没找到当前索引号文件,操作失败\n");
return ERROR;
}
if(open_list[list].flag != BUSY)
{
printf("输入的索引号有误,操作失败\n");
return ERROR;
}
char temp_output[OUTPUT_LENGTH];
Init_block(temp_output,OUTPUT_LENGTH);
char output[OUTPUT_LENGTH];
Init_block(output,OUTPUT_LENGTH);
read_block(FILE_SIGN_AREA+index,temp);
int file_length = temp[1];
int file_block = temp[2];
int file_area;
for(i = 0; i < file_block - 1 ; i++)
{
read_block(FILE_SIGN_AREA+index,temp);
read_block(temp[3+i],temp);
strncpy(temp_output+i*B,temp,B);
}
read_block(FILE_SIGN_AREA+index,temp);
read_block(temp[3+i],temp);
strncpy(temp_output+i*B,temp,B);
int x = open_list[list].pointer[0];
int y = open_list[list].pointer[1];
for(i = 0 ; i < file_block ; i++)
{
read_block(FILE_SIGN_AREA+index,temp);
if(temp[3+i] == x)
{
break;
}
}
file_area = i * B + y;
for(i = 0 ; i < count ; i++)
{
output[i+mem_area] = temp_output[i+file_area];
}
printf("%s\n",output+mem_area);
return OK;
}
文件的写操作:
int write(int index,int mem_area,int count)
{
int i;
int list = -1;
int input_length;
char temp[B];
for(i = 0; i < FILE_NUM ; i++)
{
if(open_list[i].filesignnum == index)
{
list = i;
break;
}
}
if(list == -1)
{
printf("没找到当前索引号文件,操作失败\n");
return ERROR;
}
if(open_list[list].flag != BUSY)
{
printf("输入的索引号有误,操作失败\n");
return ERROR;
}
char input[INPUT_LENGTH];
Init_block(input,INPUT_LENGTH);
i = 0;
fflush(stdin);
while(scanf("%c",&input[i]))
{
if(input[i] == '\n')
{
input[i] == '\0';
break;
}
i++;
}
input_length = i;
if(count <= BUFFER_LENGTH )
{
strncat(open_list[list].buffer,input+mem_area,count);
}
else
{
int rest;
for(i = 0; i < BUFFER_LENGTH ; i++)
{
if(open_list[list].buffer[i] == FREE)
{
rest = BUFFER_LENGTH - i;
break;
}
}
strncat(open_list[list].buffer+BUFFER_LENGTH-rest,input + mem_area,rest);
write_buffer(index,list);
Init_block(open_list[list].buffer,BUFFER_LENGTH);
for(i = 0; i < (count/BUFFER_LENGTH)-1 ; i++)
{
strncpy(open_list[list].buffer,(input+mem_area)+rest+i*BUFFER_LENGTH,BUFFER_LENGTH);
write_buffer(index,list);
Init_block(open_list[list].buffer,BUFFER_LENGTH);
}
Init_block(open_list[list].buffer,BUFFER_LENGTH);
strncpy(open_list[list].buffer,(input+mem_area)+rest+i*BUFFER_LENGTH,count%BUFFER_LENGTH);
int buffer_start;
}
return OK;
}
目录:
新建文件并查看:
删除文件并查看:
打开文件:
写操作:
关闭文件:
后台查看磁盘数组的内容,可以查看实时情况命令(ldisk)
GitHub源码:https://github.com/wwyw/lab5