一、實(shí)驗(yàn)簡(jiǎn)介
本實(shí)驗(yàn)要求在模擬的I/O系統(tǒng)之上開(kāi)發(fā)一個(gè)簡(jiǎn)單的文件系統(tǒng)。用戶通過(guò)create, open, read等命令與文件系統(tǒng)交互。文件系統(tǒng)把磁盤(pán)視為順序編號(hào)的邏輯塊序列,邏輯塊的編號(hào)為0至L ? 1。I/O系統(tǒng)利用內(nèi)存中的數(shù)組模擬磁盤(pán)。
二、I/O系統(tǒng)
實(shí)際物理磁盤(pán)的結(jié)構(gòu)是多維的:有柱面、磁頭、扇區(qū)等概念。I/O系統(tǒng)的任務(wù)是隱藏磁盤(pán)的結(jié)構(gòu)細(xì)節(jié),把磁盤(pán)以邏輯塊的面目呈現(xiàn)給文件系統(tǒng)。邏輯塊順序編號(hào),編號(hào)取值范圍為0至L?1,其中L表示磁盤(pán)的存儲(chǔ)塊總數(shù)。實(shí)驗(yàn)中,我們可以利用數(shù)組ldisk[C][H][B]構(gòu)建磁盤(pán)模型,其中CHB 分別表示柱面號(hào),磁頭號(hào)和扇區(qū)號(hào)。每個(gè)扇區(qū)大小為512字節(jié)。I/O系統(tǒng)從文件系統(tǒng)接收命令,根據(jù)命令指定的邏輯塊號(hào)把磁盤(pán)塊的內(nèi)容讀入命令指定的內(nèi)存區(qū)域,或者把命令指定的內(nèi)存區(qū)域內(nèi)容寫(xiě)入磁盤(pán)塊。文件系統(tǒng)和I/O系統(tǒng)之間的接口由如下兩個(gè)函數(shù)定義:
-
read_block(int i, char *p);
該函數(shù)把邏輯塊i的內(nèi)容讀入到指針p指向的內(nèi)存位置,拷貝的字符個(gè)數(shù)為存儲(chǔ)塊的長(zhǎng)度B。 -
write block(int i, char *p);
該函數(shù)把指針p指向的內(nèi)容寫(xiě)入邏輯塊i,拷貝的字符個(gè)數(shù)為存儲(chǔ)塊的長(zhǎng)度B。
此外,為了方便測(cè)試,我們還需要實(shí)現(xiàn)另外兩個(gè)函數(shù):一個(gè)用來(lái)把數(shù)組ldisk 存儲(chǔ)到文件;另一個(gè)用來(lái)把文件內(nèi)容恢復(fù)到數(shù)組。
-
int backup_disk(FILE *filepath);
該函數(shù)將內(nèi)存中現(xiàn)有的ldisk[C][H][B]保存到文件句柄FILE *filepath對(duì)應(yīng)的二進(jìn)制文件中。 -
int restore_disk(FILE *filepath);
該函數(shù)將從二進(jìn)制文件句柄FILE *filepath中讀取硬盤(pán)數(shù)據(jù),并存儲(chǔ)到內(nèi)存數(shù)組ldisk[C][H][B]中。
在IO系統(tǒng)中,我們的文件結(jié)構(gòu)組成為:
-
iosystem.h用來(lái)聲明全局變量與函數(shù)接口。 -
iosystem.c用來(lái)定義函數(shù)與實(shí)現(xiàn)變量。
在iosystem.h中:
#define C 80
#define H 2
#define B 18
定義了我們物理硬盤(pán)的柱面號(hào),磁頭號(hào)和扇區(qū)號(hào)的最大值。
unsigned char *ldisk[C][H][B];
int init_ldisk();
int read_block(int i,unsigned char *p);
int write_block(int i,unsigned char *p);
int backup_disk(FILE *filepath);
int restore_disk(FILE *filepath);
聲明了我們IO系統(tǒng)對(duì)外的接口與物理硬盤(pán)ldisk的數(shù)組結(jié)構(gòu)。
unsigned char *ldisk[C][H][B]是一個(gè)unsigned char類型的指針數(shù)組。
在iosystem.c中,我們查看相關(guān)函數(shù)的實(shí)現(xiàn):
int init_ldisk()
{
for(int i=0;i<C;i++)
{
for(int j=0;j<H;j++)
{
for(int k=0;k<B;k++)
{
ldisk[i][j][k]=(unsigned char *)malloc(sizeof(unsigned char)*512);
}
}
}
printf("IO INFO,logic disk init successfuly.\n");
return 0;
}
這是初始化物理硬盤(pán)的函數(shù),通過(guò)一個(gè)三重循環(huán)來(lái)對(duì)指針數(shù)組申請(qǐng)內(nèi)存空間,根據(jù)題意,每個(gè)扇區(qū)我們申請(qǐng)了512B的大小。
int read_block(int i,unsigned char *p)
{
if (i >= C*H*B)
{
printf("IO ERROR,index out of range!\n");
return -1;
}
int CylinderIndex=i/(H*B);
int SectorIndex=i%B+1;
int HeadsIndex=(i/18)%2;
memcpy(p,ldisk[CylinderIndex][HeadsIndex][SectorIndex-1],512);
printf("IO INFO,read logic index is %d,physic index is %d,%d,%d,the content is %s.\n",i,CylinderIndex,HeadsIndex,SectorIndex,ldisk[CylinderIndex][HeadsIndex][SectorIndex-1]);
return 0;
}
這是讀取邏輯塊的函數(shù),其參數(shù)int i,unsigned char *p分別為需要讀取的邏輯塊號(hào)與返回結(jié)果的指針。在函數(shù)體中,我們通過(guò)模運(yùn)算與取整運(yùn)算將邏輯塊號(hào)轉(zhuǎn)化為物理三維塊號(hào),并使用memcpy()函數(shù)將對(duì)應(yīng)內(nèi)存空間的數(shù)據(jù)拷貝給返回指針p。
int write_block(int i,unsigned char *p)
{
if (i >= C*H*B)
{
printf("IO ERROR,index out of range!\n");
return -1;
}
int CylinderIndex=i/(H*B);
int SectorIndex=i%B+1;
int HeadsIndex=(i/18)%2;
memcpy(ldisk[CylinderIndex][HeadsIndex][SectorIndex-1],p,512);
printf("IO INFO,write logic index is %d,physic index is %d,%d,%d,the content is %s.\n",i,CylinderIndex,HeadsIndex,SectorIndex,p);
return 0;
}
這是寫(xiě)入邏輯塊的函數(shù),其參數(shù)int i,unsigned char *p分別為需要寫(xiě)入的邏輯塊號(hào)與輸入數(shù)據(jù)的指針。在函數(shù)體中,我們通過(guò)模運(yùn)算與取整運(yùn)算將邏輯塊號(hào)轉(zhuǎn)化為物理三維塊號(hào),并使用memcpy()函數(shù)將對(duì)應(yīng)指針的數(shù)據(jù)拷貝給對(duì)應(yīng)內(nèi)存空間的指針。
int backup_disk(FILE *filepath)
{
if(filepath==NULL)
{
printf("IO ERROR,filepath open fail");
return -1;
}
for(int i=0;i<C;i++)
{
for(int j=0;j<H;j++)
{
for(int k=0;k<B;k++)
{
fwrite(ldisk[i][j][k],sizeof(unsigned char),512,filepath);
}
}
}
fclose(filepath);
printf("IO INFO,backup successfuly.\n");
return 0;
}
根據(jù)實(shí)驗(yàn)要求,我設(shè)計(jì)了備份函數(shù),可以將虛擬在內(nèi)存中的物理硬盤(pán)數(shù)據(jù)空間保存為文件,文件的儲(chǔ)存方式為二進(jìn)制儲(chǔ)存,這樣方便我們?cè)诨謴?fù)的時(shí)候直接讀取。
int restore_disk(FILE *filepath)
{
if(filepath==NULL)
{
printf("IO ERROR,filepath open fail");
return -1;
}
for(int i=0;i<C;i++)
{
for(int j=0;j<H;j++)
{
for(int k=0;k<B;k++)
{
fread(ldisk[i][j][k],sizeof(unsigned char),512,filepath);
}
}
}
fclose(filepath);
printf("IO INFO,restore backup successfuly.\n");
return 0;
}
根據(jù)實(shí)驗(yàn)要求,我設(shè)計(jì)了恢復(fù)備份函數(shù),可以讀取硬盤(pán)中的二進(jìn)制文件,并將其恢復(fù)到我們虛擬的內(nèi)存硬盤(pán)空間之中。
三、文件系統(tǒng)

文件系統(tǒng)位于I/O系統(tǒng)之上。
文件系統(tǒng)的組織結(jié)構(gòu)如下:
-
filesystem.h用來(lái)聲明全局變量與函數(shù)接口。 -
filesystem.c用來(lái)定義函數(shù)與實(shí)現(xiàn)變量。
typedef struct
{
int fileSize;
int blockList[3];
}fileDescriptorItem;
我們定義了名為fileDescriptorItem的文件描述符結(jié)構(gòu)體類型,其中fileSize為文件大小,blockList[3]為這個(gè)文件所分配的邏輯塊號(hào),最多每個(gè)文件可分配3塊。
typedef struct
{
unsigned char fileName[28];
int fileDescriptorIndex;
}dictionaryItem;
我們定義了名為dictionaryItem的目錄結(jié)構(gòu)體類型,其中fileName為文件名稱,fileDescriptorIndex為這個(gè)文件所分配的文件描述符的序號(hào),最多每個(gè)文件名最長(zhǎng)為28字節(jié)。
fileDescriptorItem *fileDescriptor[7];
unsigned char *bitMap;
dictionaryItem *dictionary;
在這里,我們定義了三個(gè)指針,分別為文件描述符指針數(shù)組、位圖指針、目錄指針,其中文件描述符指針數(shù)組大小為7。
int init()
{
printf("\nFILE INFO,file system will init.\n");
init_ldisk();
bitMap=(unsigned char*)calloc(512,sizeof(unsigned char));
for(int i=0;i<512;i++)
{bitMap[i]=0;}
bitMap[0]=0xff;
write_block(0,bitMap);
for(int i=0;i<7;i++)
{
fileDescriptor[i]=(fileDescriptorItem*)calloc(sizeof(unsigned char)*512/sizeof(fileDescriptorItem),sizeof(fileDescriptorItem));
write_block(i+1,(unsigned char*)fileDescriptor[i]);
}
printf("FILE INFO,file system init finished.\n");
return 0;
}
在這個(gè)函數(shù)中,我們對(duì)位圖、文件描述符進(jìn)行了初始化,對(duì)指針?lè)峙淞藘?nèi)存空間,并將所有更改寫(xiě)入到硬盤(pán)之中。
int bitMapUpdate(int flag,int index)
{
printf("\nFILE INFO,bitmap is updating.\n");
read_block(0,bitMap);
int temp=index%8;
if(flag==1){
switch(temp)
{
case 0:bitMap[index/8]=bitMap[index/8]|0x80;break;
case 1:bitMap[index/8]=bitMap[index/8]|0x40;break;
case 2:bitMap[index/8]=bitMap[index/8]|0x20;break;
case 3:bitMap[index/8]=bitMap[index/8]|0x10;break;
case 4:bitMap[index/8]=bitMap[index/8]|0x08;break;
case 5:bitMap[index/8]=bitMap[index/8]|0x04;break;
case 6:bitMap[index/8]=bitMap[index/8]|0x02;break;
case 7:bitMap[index/8]=bitMap[index/8]|0x01;break;
}}
else if(flag==0)
{
switch(temp)
{
case 0:bitMap[index/8]=bitMap[index/8]&0x7f;break;
case 1:bitMap[index/8]=bitMap[index/8]&0xbf;break;
case 2:bitMap[index/8]=bitMap[index/8]&0xdf;break;
case 3:bitMap[index/8]=bitMap[index/8]&0xef;break;
case 4:bitMap[index/8]=bitMap[index/8]&0xf7;break;
case 5:bitMap[index/8]=bitMap[index/8]&0xfb;break;
case 6:bitMap[index/8]=bitMap[index/8]&0xfd;break;
case 7:bitMap[index/8]=bitMap[index/8]&0xfe;break;
}
}
write_block(0,bitMap);
printf("FILE INFO,bitmap updated.\n");
}
這個(gè)函數(shù)是對(duì)位圖進(jìn)行更新操作的函數(shù),參數(shù)int flag,int index分別是指將位圖修改為0 or 1 與修改的位圖序號(hào)。在函數(shù)體中,我們先讀取了硬盤(pán)中對(duì)應(yīng)塊號(hào)的位圖,另外,由于C語(yǔ)言中沒(méi)有對(duì)二進(jìn)制的直接修改操作,所以在這里我們使用位運(yùn)算來(lái)代替,比如我們舉例如下:
位圖中一個(gè)字節(jié)
10010011
現(xiàn)在我們希望將其最后一位1修改為0
我們只需要將10010011與11111110進(jìn)行按位與&操作,這樣我們就可以得到正確結(jié)果。
兩個(gè)switch-case語(yǔ)句分別對(duì)應(yīng)了修改為0或1的情況下的位運(yùn)算類型。
int findFreeBitMap()
{
printf("\nFILE INFO,is finding free bitmap.\n");
read_block(0,bitMap);
for(int i=0;i<512;i++)
{
printf("%d",bitMap[i]);
if(bitMap[i]!=0xff)
{
for(int j=0;j<8;j++)
{
int a=bitMap[i];
if(a==0)
{
printf("\nFILE INFO,found free bitmap:%d.\n",i*8+j);
return i*8+j;
}
}
}
}
printf("\nFILE ERROR,can't find free bitmap.\n");
return -1;
}
這個(gè)函數(shù)用來(lái)尋找位圖中空閑的下一位,如果尋找成功返回序號(hào),尋找失敗返回-1。
int bitMapOutput()
{
printf("\nFILE INFO,bitmap output:\n");
for(int i=0;i<512;i++)
{
if(bitMap[i]==0)
printf("00000000");
else
{
for(int j=7;j>=0;j--)
{
int a=bitMap[i];
printf("%d",(a>>j)&0x01);
}
}
if((i+1)%16==0 && i!=0)
printf("\n");
}
printf("\nFILE INFO,bitmap output finished.\n");
}
這個(gè)函數(shù)可以將位圖按照一定格式打印出來(lái),在這里值得注意的是我們使用位運(yùn)算來(lái)實(shí)現(xiàn)讀取每一位。先右移,再與00000001進(jìn)行&操作,這樣便得到了每一位。
int fileDescriptorInsert(int fileSize,int blockList[3])
{
printf("\nFILE INFO,file descriptor is inserting.\n");
for(int i=0;i<7;i++)
{
read_block(i+1,(unsigned char*)fileDescriptor[i]);
}
for(int i=0;i<7;i++)
{
for(int j=0;j<sizeof(unsigned char)*512/sizeof(fileDescriptorItem);j++)
{
if (fileDescriptor[i][j].fileSize==0 && fileDescriptor[i][j].blockList[0]==0 && fileDescriptor[i][j].blockList[1]==0 && fileDescriptor[i][j].blockList[2]==0)
{
fileDescriptor[i][j].fileSize=fileSize;
fileDescriptor[i][j].blockList[0]= blockList[0];
fileDescriptor[i][j].blockList[1]= blockList[1];
fileDescriptor[i][j].blockList[2]= blockList[2];
for(int l=0;l<7;l++)
{
write_block(l+1,(unsigned char*)fileDescriptor[l]);
}
printf("FILE INFO,file descriptor inserted.\n");
return i*sizeof(unsigned char)*512/sizeof(fileDescriptorItem)+j;
}
}
}
printf("FILE ERROR,can't insertfile descriptor.\n");
return -1;
}
這個(gè)函數(shù)的功能是插入文件描述符。首先讀取文件描述符所對(duì)應(yīng)的邏輯塊到內(nèi)存中,之后尋找空的文件描述符位置,然后進(jìn)行相應(yīng)的修改操作,最后將所有修改寫(xiě)入物理硬盤(pán)中。
int fileDescriptorUpdate(int index,int fileSize,int blockList[3])
{
printf("\nFILE INFO,file descriptor is updating.\n");
for(int i=0;i<7;i++)
{
read_block(i+1,(unsigned char*)fileDescriptor[i]);
}
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].fileSize=fileSize;
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].blockList[0]= blockList[0];
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].blockList[1]= blockList[1];
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].blockList[2]= blockList[2];
for(int l=0;l<7;l++)
{
write_block(l+1,(unsigned char*)fileDescriptor[l]);
}
printf("FILE INFO,file descriptor updated.\n");
return 0;
}
這個(gè)函數(shù)是用來(lái)更新文件描述符,首先讀取文件描述符所對(duì)應(yīng)的邏輯塊到內(nèi)存中,然后進(jìn)行相應(yīng)的修改操作,最后將所有修改寫(xiě)入物理硬盤(pán)中。
int fileDescriptorDelete(int index)
{
printf("\nFILE INFO,file descriptor is deleting.\n");
for(int i=0;i<7;i++)
{
read_block(i+1,(unsigned char*)fileDescriptor[i]);
}
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].fileSize=0;
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].blockList[0]= 0;
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].blockList[1]= 0;
fileDescriptor[index/(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))][index%(sizeof(unsigned char)*512/sizeof(fileDescriptorItem))].blockList[2]= 0;
for(int l=0;l<7;l++)
{
write_block(l+1,(unsigned char*)fileDescriptor[l]);
}
printf("FILE INFO,file descriptor deleted.\n");
return 0;
}
這個(gè)函數(shù)的功能是用來(lái)刪除文件描述符,參數(shù)為刪除文件描述符的序號(hào),進(jìn)入函數(shù)體之后先從硬盤(pán)對(duì)應(yīng)邏輯塊讀取文件描述符,之后進(jìn)行對(duì)應(yīng)修改,最后將所有內(nèi)存中的文件描述符寫(xiě)會(huì)到硬盤(pán)中。
int initDic()
{
printf("FILE INFO,is initing dic.\n");
dictionary=(dictionaryItem*)calloc(sizeof(unsigned char)*512/sizeof(dictionaryItem),sizeof(dictionaryItem)) ;
int index=findFreeBitMap();
write_block(index,(unsigned char*)dictionary);
bitMapUpdate(1,index);
int blockList[3]={index};
int descriptorIndex=fileDescriptorInsert(1,blockList);
strncpy(dictionary[0].fileName,"Dictionary",strlen("Dictionary"));
dictionary[0].fileDescriptorIndex=descriptorIndex;
write_block(index,(unsigned char*)dictionary);
printf("FILE INFO,inited dic.\n");
return 0;
}
這個(gè)是用來(lái)初始化目錄的函數(shù),我們給目錄指針?lè)峙淞藘?nèi)存空間,并將其寫(xiě)入到硬盤(pán)之中,需要注意的是里面對(duì)于位圖的分配與文件描述符的建立。
int readDic()
{
for(int i=0;i<7;i++)
{
read_block(i+1,(unsigned char*)fileDescriptor[i]);
}
int i0=fileDescriptor[0][0].blockList[0];
int i1=fileDescriptor[0][0].blockList[1];
int i2=fileDescriptor[0][0].blockList[2];
if(i0!=0)
{
read_block(i0,(unsigned char*)dictionary);
}
if(i1!=0)
{
read_block(i0,(unsigned char*)dictionary+512);
}
if(i2!=0)
{
read_block(i0,(unsigned char*)dictionary+512);
}
return 0;
}
這個(gè)是用來(lái)將目錄從邏輯塊中讀取到內(nèi)存中,由于目錄最多可能有三塊,所以我們需要先找到目錄的文件描述符,然后根據(jù)blockList里面的參數(shù)情況來(lái)分別讀取。
int create(unsigned char *filename)
{
printf("\nFILE INFO,is creating file,filename is %s\n",filename);
int flag=0;
read_block(0,bitMap);
for(int i=1;i<512;i++)
{
if(bitMap[i]!=0)
{
flag=1;
break;
}
}
if(flag==0)
{
initDic();
}
/*Check dic is full or not*/
readDic();
CheckDic();
int FileDescriptorNum,MenuItemNum,DiskNum;
MenuItemNum = SearchMenuItem();
strcpy(menuitem[MenuItemNum].FileName,filename);
FileDescriptorNum = SearchFileDescriptor();
menuitem[MenuItemNum].FileDescriptorNum = FileDescriptorNum;
DiskNum = SearchBitMap();
filedescriptor[FileDescriptorNum].DiskNum[0] = DiskNum;
filedescriptor[FileDescriptorNum].IsFree = 'N';
return 0;
}
這個(gè)是建立文件函數(shù),參數(shù)為所建立的文件名稱,首先讀取位圖,并查找空閑的位,之后查看目錄書(shū)否建立,如果沒(méi)有建立執(zhí)行相關(guān)操作,讀取目錄與文件描述符,并尋找空的目錄項(xiàng)與文件描述符項(xiàng),寫(xiě)入修改,最后寫(xiě)入到硬盤(pán)上。
int destroy(char* filename)
{
int temp = 1;
int pos = 0;
for (int i = 0; i < B_MAX; i++)
{
if (ldisk[0][0][i].flag == '1')
{
if (strcmp(ldisk[0][0][i].data, filename)== 0)
{
pos = i;
break;
}
}
}
if (pos == 0)
{
cout << "FILE ERROR,can't delete.\n" << endl;
}
else {
ldisk[0][0][pos].flag = '0';
ldisk[0][0][pos].data[0] = '\0';
ldisk[0][0][pos].next = NULL;
cout << "FILE INFO,deleted." << endl;
}
return 0;
}
這個(gè)函數(shù)用來(lái)根據(jù)文件名刪除對(duì)應(yīng)文件,需要注意的是刪除時(shí)對(duì)文件描述符、邏輯塊、目錄項(xiàng)、位圖等的具體操作,并寫(xiě)入更改到硬盤(pán)之中。
int open(char* filename)
{
int pos = 0;
for (int i = 0; i < B_MAX; i++)
{
if (ldisk[0][0][i].flag == '1')
{
if (strcmp(ldisk[0][0][i].data, filename)==0)
{
pos = i;
break;
}
}
}
if (pos == 0)
{
cout << "FILE ERROR,can't open.\n" << endl;
}
else {
cout << "FILE INFO,opened." << endl;
for (int j = 0; j < C_MAX; j++)
{
if (item[j].index == 0)
{
item[j].index = 19706500 + j;
item[j].pos = 0;
item[j].data = ldisk[0][0][pos].next;
cout << "index: " << item[j].index << endl;
return item[j].index;
}
}
}
return 0;
}
文件系統(tǒng)維護(hù)一張打開(kāi)文件表.打開(kāi)文件表的長(zhǎng)度固定,其表目包含如下信息:
?讀寫(xiě)緩沖區(qū)
? 讀寫(xiě)指針
? 文件描述符號(hào)
文件被打開(kāi)時(shí),便在打開(kāi)文件表中為其分配一個(gè)表目;文件被關(guān)閉時(shí),其對(duì)應(yīng)的表目被釋放。讀寫(xiě)緩沖區(qū)的大小等于一個(gè)磁盤(pán)存儲(chǔ)塊。打開(kāi)文件時(shí)需要進(jìn)行的操作如下:
? 搜索目錄找到文件對(duì)應(yīng)的描述符編號(hào)
? 在打開(kāi)文件表中分配一個(gè)表目
? 在分配到的表目中把讀寫(xiě)指針置為0,并記錄描述符編號(hào)
? 讀入文件的第一塊到讀寫(xiě)緩沖區(qū)中
? 返回分配到的表目在打開(kāi)文件表中的索引號(hào)
int close(int index)
{
for (int j = 0; j < C_MAX; j++)
{
if (item[j].index == index)
{
item[j].index == 0;
item[j].pos = 0;
item[j].data = NULL;
}
}
cout << "FILE INFO,closed." << endl;
return 0;
}
關(guān)閉文件時(shí)需要進(jìn)行的操作如下:
? 把緩沖區(qū)的內(nèi)容寫(xiě)入磁盤(pán)
? 釋放該文件在打開(kāi)文件表中對(duì)應(yīng)的表目
? 返回狀態(tài)信息
int read(int index, string mem_area, int count)
{
for (int j = 0; j < C_MAX; j++)
{
if (item[j].index == index)
{
for (int i = 0; i < count; i++)
{
mem_area[i] = item[j].data->data[i + item[j].pos];
cout << mem_area[i];
}
cout << "FILE INFO,read." << endl;
return 0;
}
}
cout << "FILE ERROR,can't read.'" << endl;
return 0;
}
文件打開(kāi)之后才能進(jìn)行讀寫(xiě)操作.讀操作需要完成的任務(wù)如下:
- 計(jì)算讀寫(xiě)指針對(duì)應(yīng)的位置在讀寫(xiě)緩沖區(qū)中的偏移
- 把緩沖區(qū)中的內(nèi)容拷貝到指定的內(nèi)存位置,直到發(fā)生下列事件之一:
? 到達(dá)文件尾或者已經(jīng)拷貝了指定的字節(jié)數(shù)。這時(shí),更新讀寫(xiě)指針并返回相應(yīng)信息
? 到達(dá)緩沖區(qū)末尾。這時(shí),把緩沖區(qū)內(nèi)容寫(xiě)入磁盤(pán),然后把文件下一塊的內(nèi)容讀入磁盤(pán)。最后返回第2步。
int write(int index, string mem_area, int count)
{
for (int j = 0; j < C_MAX; j++)
{
if (item[j].index == index)
{
myblock* p = item[j].data;
for (int i = 0; i < count; i++)
{
if (i+1 % 512 == 0)
{
p->next = NULL;
p = p->next;
}
p->data[item[j].pos] = mem_area[i];
item[j].pos++;
}
cout << "FILE INFO,wirtten." << endl;
return 0;
}
}
cout << "FILE ERROR,can't write." << endl;
return 0;
}
寫(xiě)文件時(shí),須在相應(yīng)系統(tǒng)調(diào)用中給出文件名和其在內(nèi)存源地址。此時(shí),系統(tǒng)要查找目錄,找到指定目錄項(xiàng),從再利用目錄中的寫(xiě)指針進(jìn)行寫(xiě)操作。設(shè)置文件讀/寫(xiě)指針的位置,以便每次讀/寫(xiě)文件時(shí),不需要從始端開(kāi)始而是從所設(shè)置的位置開(kāi)始操作??梢愿捻樞虼嫒殡S機(jī)存取。
四、測(cè)試
在這部分,我們將利用命令行測(cè)試上述編寫(xiě)的文件系統(tǒng)。
1.創(chuàng)建文件


2.刪除文件


3.打開(kāi)文件
已經(jīng)嵌入到上述展示之中。
4.關(guān)閉文件
同上。
5.讀取文件


6.寫(xiě)入文件


7.目錄打印

8.備份與恢復(fù)
進(jìn)入程序的開(kāi)發(fā)者模式進(jìn)行以下操作:
我們先進(jìn)行備份測(cè)試:
int main()
{
init_ldisk();
write_block(2581,"55555555555555555");
FILE *fp=fopen("backupFile.bin","wb");
backup_disk(fp);
// init_ldisk();
// FILE *fp=fopen("backupFile.bin","rb");
// restore_disk(fp);
// char *p=(char*)malloc(sizeof(unsigned char)*512);
// read_block(2581,p);
// printf("%s\n",p);
// printf("\n");
system("pause");
return 0;
}

查看目錄,發(fā)現(xiàn)備份文件:

下面我們進(jìn)行恢復(fù)的測(cè)試:
int main()
{
// init_ldisk();
// write_block(2581,"55555555555555555");
// FILE *fp=fopen("backupFile.bin","wb");
// backup_disk(fp);
init_ldisk();
FILE *fp=fopen("backupFile.bin","rb");
restore_disk(fp);
char *p=(char*)malloc(sizeof(unsigned char)*512);
read_block(2581,p);
printf("%s\n",p);
printf("\n");
system("pause");
return 0;
}

可以看到,我們成功把磁盤(pán)內(nèi)容恢復(fù)了。
9.位圖打印
int main()
{
init();
bitMapOutput();
create("5555");
bitMapOutput();
}


可以看到,位圖如我們預(yù)期更改了。
代碼詳見(jiàn):https://github.com/Jerlllly/BJTU_operating-system-lesson/tree/master/Lab5