操作系統(tǒng)——實(shí)驗(yàn)五

一、實(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ù)定義:

  1. read_block(int i, char *p);
    該函數(shù)把邏輯塊i的內(nèi)容讀入到指針p指向的內(nèi)存位置,拷貝的字符個(gè)數(shù)為存儲(chǔ)塊的長(zhǎng)度B。
  2. 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ù)組。

  1. int backup_disk(FILE *filepath);
    該函數(shù)將內(nèi)存中現(xiàn)有的ldisk[C][H][B]保存到文件句柄FILE *filepath對(duì)應(yīng)的二進(jìn)制文件中。
  2. 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)組成為:

  1. iosystem.h用來(lái)聲明全局變量與函數(shù)接口。
  2. 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)流程圖

文件系統(tǒng)位于I/O系統(tǒng)之上。
文件系統(tǒng)的組織結(jié)構(gòu)如下:

  1. filesystem.h用來(lái)聲明全局變量與函數(shù)接口。
  2. 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
我們只需要將1001001111111110進(jìn)行按位與&操作,這樣我們就可以得到正確結(jié)果。

兩個(gè)switch-case語(yǔ)句分別對(duì)應(yīng)了修改為01的情況下的位運(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ù)如下:

  1. 計(jì)算讀寫(xiě)指針對(duì)應(yīng)的位置在讀寫(xiě)緩沖區(qū)中的偏移
  2. 把緩沖區(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)建文件

image.png

image.png

2.刪除文件

image.png

image.png

3.打開(kāi)文件

已經(jīng)嵌入到上述展示之中。

4.關(guān)閉文件

同上。

5.讀取文件

image.png

image.png

6.寫(xiě)入文件

image.png

image.png

7.目錄打印

image.png

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;
    
}
image.png

查看目錄,發(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;
    
}
image.png

可以看到,我們成功把磁盤(pán)內(nèi)容恢復(fù)了。

9.位圖打印

int main()
{
    init();
    bitMapOutput();
    create("5555"); 
    bitMapOutput();
}
image.png

image.png

可以看到,位圖如我們預(yù)期更改了。

代碼詳見(jiàn):https://github.com/Jerlllly/BJTU_operating-system-lesson/tree/master/Lab5

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容