日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Nachos操作系统-文件系统添加多级目录

發布時間:2023/12/10 windows 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Nachos操作系统-文件系统添加多级目录 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

多級目錄設置

前面提到了,當前的文件系統中并沒有完成對于多級目錄的設置。

為了更好的了解Nachos,這里嘗試向當前的文件系統中添加代碼以完成多級目錄的設置。

總覽

對于多級目錄來說,與其相關的操作主要有這幾個:

  • 創建目錄
  • 刪除目錄
  • 向目錄中添加文件
  • 從目錄中刪除文件
  • 展示目錄及目錄中的文件內容

為了便于代碼的編寫,我定義一個宏CntDirectLevel代表最多擁有的目錄層級

接下來對各自的實現進行設計與分析:

通用函數

在這里創建一個通用函數bool ParseFileName(char* name,char** &dirs),并將其存儲在單獨的目錄ParseFN.h中。

函數功能即判斷檔期按輸入的文件名是否在一個目錄下。如果是,返回TRUE,并將各級目錄名存儲在dirs中。如果不是,返回FALSE。

具體實現如下:

bool ParseFileName(char* name,char**& dirs) {if(name[0]=='.' && name[1]=='/'){dirs=new char*[10];int DirLevInd=0;for(int i=1;name[i]!='\0';){ //check the '/'if(name[i]=='/'){cout<<i<<endl;i++;int index=0;dirs[DirLevInd]=new char[10];// get the name of directory[DirLevInd-1]for(;name[i]!='\0' && name[i]!='/';i++){cout<<name[i];dirs[DirLevInd][index++]=name[i];}cout<<"\t";dirs[DirLevInd][index]='\0';DirLevInd++;}}dirs[DirLevInd]=nullptr;// DirLevInd is cnt of FileLevelreturn true;}else{return false;} }

創建目錄及向目錄中添加文件

為了不破壞原本Nachos的參數系統,這里想要通過對添加文件時的文件名進行檢查,通過檢查來確定是否創建目錄

即:如果新生成/創建的文件的文件名形如./***/findName

那么應該首先檢查當前目錄下是否存在要生成的目錄,如果存在,即進入目錄下。如果不存在,就根據前者的名字創建目錄,然后再進入目錄下。

根據當前Nachos文件系統中創建文件的規則,可以發現它主要是在../lab5/ftest.cc中的函數Copy中調用了fileSystem->Create(to,fileLength)函數完成了對于文件的創建。


為了檢查是否需要創建目錄,需要在當前的目錄中進行檢查,來檢測目錄是否已經存在。

因此這里有一個目錄與文件的標識和區分問題,即我們檢測目錄名時,目錄名存在的條件為:同名且類型為目錄

根據實驗四中得知的目錄與文件的相關知識,可以知道目錄的目錄項中包含三個部分:bool inUse,int sector,char* fileName。注意到inUse變量的類型為bool,理論只占用一個bit,但是實際使用中會發現改位置占用了不止一個字節:

根據這個特點,如果我在結構中聲明inUse之后創建一個bool類型的變量direct,就可以做到基本不修改表目錄項的內容且可以保證目錄表的大小不會有什么變化,維護了原本Nachos 系統的健壯性。

嘗試結果如下:

其中前者代表inUse,后者代表direct。

數據結構確定后,就開始修改函數。對于創建目錄,所有需要修改的內容如下:

  • directory.h

    在類DirectoryEntry中添加成員變量bool direct用來標明當前記錄是否為目錄文件。

    在類Directory中添加成員函數

    • bool Add(char *name,int newSector,bool isDirect);

    對類Directory中成員函數的修改:

    • 使用默認形參的方式不會破壞原本的函數調用語法,并且還可以添加新的調用方式

    • int Find(char *name,bool isDirect=false)

    • int FindIndex(char *name,bool isDirect=false)

    • 構造函數的修改(置默認的direct為FALSE)

  • directory.cc

    添加的成員函數Add的實現:

    bool Directory::Add(char* name,int newSector,bool isDirect) {if(isDirect){// the directory existsif (FindIndex(name,isDirect) != -1)return FALSE;// create a new directoryfor (int i = 0; i < tableSize; i++)if (!table[i].inUse) {table[i].inUse = TRUE;table[i].direct=isDirect;strncpy(table[i].name, name, FileNameMaxLen); table[i].sector = newSector;return TRUE;}return FALSE; // no space. Fix when we have extensible files.}else{printf("Directory::Add : Unexpected Call of Function!\n");Abort();return FALSE;} }

    修改函數FindIndex結果:

修改函數Find:

int Directory::FindIndex(char *name,bool isDirect) {for (int i = 0; i < tableSize; i++)if (table[i].inUse && !strncmp(table[i].name, name, FileNameMaxLen) && (table[i].direct == isDirect))return i;return -1; // name not in directory }

構造函數修改:

  • filesys.h

    • 添加函數 bool CreateDir(char** dirs,int fileLength)

      其中dirs是存放著每一層目錄名的二維數組fileLength只代表最后的文件的文件大小。

      通過這個函數逐層創建目錄以及最后創建文件。

    • 添加成員函數Open(char **dirs)

    • 添加私有成員函數Directory* createDir(char* name,Directory* in)

      意味著在目錄in中創建一個名稱為name的目錄并返回創建的這個目錄。

    • 添加私有成員函數bool createFile(char* name,Directory* in,int fileLength,OpenFile* in_file)

  • filesys.cc

    • CreateDir函數的實現

      循環對每層目錄進行如下操作:

      • 調用函數createDir(dirs[i],pre,preFile),代表著在目錄pre中創建名稱為dirs[i]的目錄,對應的文件通過引用傳遞存儲在preFile中。

        為了進行傳遞,需要先查找當前目錄是否存在,如果存在就返回當前目錄的指針,但是如果下一級目錄不存在,還要用到當前目錄的存儲位置,因為通過創建目錄以后,當前目錄發生修改,需要進行寫回操作。

      • 檢查是否創建成功。

      到最后一層時應當進行文件的創建。

      因此直接調用私有成員函數createFile(dirs[i],pre,fileLength,preFile)

      即向目錄pre中寫入名稱為dirs[i],大小為fileLength的文件,然后將更改后的文件寫回preFile。

      最后代碼如下:

      bool FileSystem::CreateDir(char** dirs,int fileLength) {int i=0;Directory* pre=new Directory(NumDirEntries);pre->FetchFrom(directoryFile);OpenFile* preFile=directoryFile;for(;dirs[i+1]!=NULL;i++){pre=createDir(dirs[i],pre,preFile);if(pre==NULL){printf("CreateDir: Unable to create directory %s\n",dirs[i]);return false;}}// shoule chreate a filereturn createFile(dirs[i],pre,fileLength,preFile); }
    • Open的實現(實際上是對原有成員函數Open(char* name)的重載)

      傳入一串目錄和最終的文件名,返回最后的文件名對應文件的OpenFile類指針

      OpenFile * FileSystem::Open(char **dirs) { Directory *directory = new Directory(NumDirEntries);OpenFile *openFile = directoryFile;int sector,i;for(i=0;dirs[i+1]!=NULL;i++){DEBUG('f', "Opening directory %s\n", dirs[i]);directory->FetchFrom(openFile);sector=directory->Find(dirs[i],true);// printf("Find Directory %s Header in %d\n",dirs[i],sector);if(sector<0) return NULL;openFile=NULL;openFile=new OpenFile(sector); // get the openfile of next level directory}DEBUG('f', "Opening File %s\n", dirs[i]);directory->FetchFrom(openFile);sector = directory->Find(dirs[i]); // printf("Find File %s Header in %d\n",dirs[i],sector);if (sector < 0) openFile=NULL; else openFile = new OpenFile(sector); // name was found in directory delete directory;return openFile; // return NULL if not found }
    • 私有函數createDir 的實現

      首先檢查目錄in中是否已經存在想要創建的目錄了。

      • 如果存在,返回這個目錄。

      • 如果不存在,創建這個目錄,返回目錄。

        // make directory in the directory `in` // in_file means current dir `in`'s file,when return ,it means the storage file of return Directory Directory* FileSystem::createDir(char* name,Directory* in,OpenFile* &in_file) {BitMap *freeMap;FileHeader *hdr;int sector;bool success;int dirFileH=0;if((dirFileH=in->Find(name,true))!=-1){// the directory exists in current Direcotyin_file=new OpenFile(dirFileH);Directory* ret;ret=new Directory(NumDirEntries);ret->FetchFrom(in_file);return ret;}else{// we should create a fileDEBUG('f',"Creating Directory %s \n",name);Directory* ret;freeMap=new BitMap(NumSectors);freeMap->FetchFrom(freeMapFile);sector=freeMap->Find();if(sector==-1)ret=NULL;else if(!in->Add(name,sector,true))ret=NULL;else{hdr=new FileHeader;if(!hdr->Allocate(freeMap,DirectoryFileSize))ret=NULL;else{success=TRUE;hdr->WriteBack(sector);in->WriteBack(in_file);freeMap->WriteBack(freeMapFile);ret=new Directory(NumDirEntries);in_file=new OpenFile(sector);ret->FetchFrom(in_file);}delete hdr;}delete freeMap;return ret;} }
    • 私有成員函數createFile的實現

      總體上參考了函數Create。也就是先檢查文件是否存在,不存在則創建文件,對應修改目錄和位圖等等。

      bool FileSystem::createFile(char* name,Directory *in,int fileLength,OpenFile* in_file) {Directory *directory;BitMap *freeMap;FileHeader *hdr;int sector;bool success;DEBUG('f', "Creating file %s, size %d\n", name, fileLength);// make file in the directory `in`directory = in;if (directory->Find(name) != -1)success = FALSE; // file is already in directoryelse {freeMap = new BitMap(NumSectors);freeMap->FetchFrom(freeMapFile);sector = freeMap->Find(); // find a sector to hold the file headerif (sector == -1) success = FALSE; // no free block for file header else if (!directory->Add(name, sector))success = FALSE; // no space in directoryelse {hdr = new FileHeader;if (!hdr->Allocate(freeMap, fileLength))success = FALSE; // no space on disk for dataelse { success = TRUE;// everthing worked, flush all changes back to diskhdr->WriteBack(sector); directory->WriteBack(in_file);freeMap->WriteBack(freeMapFile);}delete hdr;}delete freeMap;}delete directory;return success; }
  • fstest.cc

    • 更改函數void Copy(char* from,char* to)

      當通過從Linux向Nachos復制文件時,需要檢查Nachos中的文件名是否為目錄下的文件。

      因此先調用ParseFileName函數。

      如果是普通文件,則正常進行,

      如果是目錄名,通過調用的函數就得到了多級目錄的各自名稱。

      然后直接調用上面提到的CreateDir進行創建:

      這里只給出關鍵的部分代碼:

      char** dirs; if(ParseFileName(to,dirs)) {if(!fileSystem->CreateDir(dirs,fileLength)){printf("Copy: couldn't create output file %s\n", to);fclose(fp);return;}openFile=fileSystem->Open(dirs); } else //normal files//...

刪除目錄及刪除目錄中文件

這里的文件刪除Nachos系統本身具有的刪除非常相似。通過將目錄項中的inUse項設置為False,同時修改位圖,就算刪除了文件。

但是這里還包括了對于目錄的刪除,為了加以區分,這里通過添加新的Nachos指令rd標識remove directory刪除目錄文件。

  • 刪除文件

    涉及到的函數修改主要是filesys.cc中的Remove函數

    要做到刪除目錄下的文件,就需要找到文件所在的最后一層目錄,將最后一層目錄的目錄項中對應文件的inUse設置為FALSE;

    程序修改如下:

    這里只給出關鍵部分代碼,后續代碼基本與原Remove函數一致

    char** dirs; if(ParseFileName(name,dirs)) {int i=0;for(i=0;dirs[i+1]!=NULL;i++){sector=directory->Find(dirs[i],true);if(sector==-1){delete dirFile;delete directory;return FALSE;}dirFile=new OpenFile(sector);directory->FetchFrom(dirFile);}// current directory is the last level of directory// and dirs[i] is the name of the filename=dirs[i]; }
  • 刪除目錄

    首先要明確一點,即刪除目錄時,目錄下的文件也要隨之刪除。

    因此可以采用遞歸的方式。刪除當前文件前,先刪除掉當前文件下的所有文件和目錄,再刪除當前目錄。

    首先進行查找,找到要刪除目錄的上一級目錄。然后調用函數dir->Clear()將該目錄下的所有文件和目錄清空,然后參考Remove函數將目錄dir從當前目錄中刪除。

    對于命令-rd的處理,采用如下方法:

    • 函數RemoveDir的實現:

      void FileSystem::RemoveDir(char* name) {// printf("Entry\n");char **dirs;OpenFile *dirFile=directoryFile;Directory *dir=new Directory(NumDirEntries);dir->FetchFrom(dirFile);int i=0;int sector=0;if(!ParseFileName(name,dirs)){printf("You Should give a directory but not a file name\n");return ;}for(i=0;dirs[i+1]!=NULL;i++){sector=dir->Find(dirs[i]);if(sector<0){printf("Cann't Find Directory %s\n",dirs[i]);return;}dirFile=new OpenFile(sector);dir->FetchFrom(dirFile);}// printf("Ready to CLear!\n");sector=dir->Find(dirs[i],true);if(sector<0){printf("RemoveDir: Unable to Find the directory %s\n",dirs[i]);}OpenFile* delFile=new OpenFile(sector);Directory* delDir=new Directory(NumDirEntries);delDir->FetchFrom(delFile);// clear the content of directory dirs[i]delDir->Clear(freeMapFile,delFile,NumDirEntries);FileHeader* fileHdr = new FileHeader;fileHdr->FetchFrom(sector);BitMap* freeMap = new BitMap(NumSectors);freeMap->FetchFrom(freeMapFile);fileHdr->Deallocate(freeMap); // remove data blocksfreeMap->Clear(sector); // remove header blockif(!dir->Remove(dirs[i],true))printf("RemoveDir: Unable to Remove directory %s\n",dirs[i]);freeMap->WriteBack(freeMapFile); // flush to diskdir->WriteBack(dirFile); // flush to diskdelete dir;delete fileHdr;delete freeMap;delete delDir;delete delFile;delete dirFile; }
    • 函數Clear的實現:

      bool Directory::Clear(OpenFile* freeMapFile,OpenFile* curFile,int n) {FileHeader* fileHdr=new FileHeader;BitMap* freeMap=new BitMap(NumSectors);freeMap->FetchFrom(freeMapFile);OpenFile* delFile;Directory* delDir=new Directory(n);for(int i=0;i<n;i++){if(table[i].inUse){if(table[i].sector<0) return FALSE;if(table[i].direct){//delete a directorydelFile=new OpenFile(table[i].sector);delDir->FetchFrom(delFile);delDir->Clear(freeMapFile,delFile,n);}fileHdr->FetchFrom(table[i].sector);fileHdr->Deallocate(freeMap);freeMap->Clear(table[i].sector);Remove(table[i].name);}}freeMap->WriteBack(freeMapFile);this->WriteBack(curFile);delete fileHdr;delete freeMap;return true; }

展示目錄以及目錄中的文件內容

這里以Nachos系統中的指令作為區分。

  • 首先是對于Nachos相關參數中的**-p參數。**

    調用了../fstest.cc中的Print(char *name)函數,輸出名稱為name的文件的內容。

    通過閱讀函數內部可以知道,這里是直接調用了FileSystem::open(char* name)用來獲取文件的文件句柄。

    為了滿足多層級目錄的設置,在這里調用通用函數ParseFileName進行判斷。

    • 如果只是單個文件,則直接輸出。
    • 如果在子目錄下,通過多級目錄的名稱找到文件后再輸出。

    實現如下:

    void Print(char *name) {OpenFile *openFile; int i, amountRead;char *buffer;char** dirs;if(ParseFileName(name,dirs)){if((openFile=fileSystem->Open(dirs))==NULL){printf("Print: unable to open file %s\n", name);return;}}else{if ((openFile = fileSystem->Open(name)) == NULL) {printf("Print: unable to open file %s\n", name);return;}}buffer = new char[TransferSize];while ((amountRead = openFile->Read(buffer, TransferSize)) > 0)for (i = 0; i < amountRead; i++)printf("%c", buffer[i]);delete [] buffer;delete openFile; // close the Nachos filereturn; }
  • 對于參數-l,這里對參數設置進行添加,即設置參數-ld,意為list directory。

    在處理參數的界面添加以下代碼:

    else if(!strcmp(*argv,"-ld")) {ASSERT(argc>1);fileSystem->ListDir(*(argv+1)); }
    • 對../lab5/filesys.h添加函數:

      void ListDir(char* name)

    • 對../lab5/filesys.cc

      函數ListDir的實現

      功能為傳入目錄名,然后找到最后一個目錄名對應的目錄,輸出目錄下的所有文件名和目錄名。首先解析文件名,得到一連串的目錄名。然后逐層尋找目錄中的下一級目錄文件。

      void FileSystem::ListDir(char* name) {char** dirs;if(ParseFileName(name,dirs)){OpenFile* curFile=directoryFile;Directory* dir=new Directory(NumDirEntries);dir->FetchFrom(curFile);int sector;for(int i=0;dirs[i]!=NULL;i++){if((sector=dir->Find(dirs[i],true))<0){printf("ListDir: Unable to find directory:%s\n",dirs[i]);return;}curFile=new OpenFile(sector);dir->FetchFrom(curFile);}dir->List();delete curFile;delete dir;return;}else{delete dirs;printf("Unable to List file \n");} }
    • 為了增加區分度,對List時調用的函數../lab5/directory.cc->Directory::List()進行修改:

      輸出目錄時顏色設置為藍色。

      為了將目錄下的子目錄內容和文件都進行輸出,這里對List函數進行改進,更改為遞歸輸出。

      為了輸出時可以比較明顯地看出層次結構,這里通過更改縮進地方式來完成對于縮進的改進。為了表現這一點,就需要確認產生的縮進層次,這一點通過更改List函數的傳入參數確定。即令其傳入參數為int類型數字n,代表輸出文件名前要輸出的\t的個數。

      為了不改變原有的函數功能,默認n=0

      void Directory::List(int cntTable) {// printf the table space to show the levelchar TableSpace[cntTable+1];for(int i=0;i<cntTable;i++)TableSpace[i]='\t';TableSpace[cntTable]='\0';for (int i = 0; i < tableSize; i++){if (table[i].inUse){if(table[i].direct){// DirectoryDirectory* dir=new Directory(10);OpenFile* dirFile=new OpenFile(table[i].sector);// printf("FetchBefore!\n");dir->FetchFrom(dirFile);printf("%s\033[34m\033[1m%s\033[0m\n",TableSpace,table[i].name);// printf("ListBefore!\n"); dir->List(cntTable+1);delete dir;delete dirFile;}else{// normal Filesprintf("%s%s\n",TableSpace,table[i].name);}}} }
  • 對于參數-D,注意到對于參數-D,產生調用時會調用根目錄的函數Print

    為了在輸出時更好地區分調用內容,這里采用對輸出內容進行著色的方式進行輸出。

    函數更改如下(只貼關鍵的代碼):

    for (int i = 0; i < tableSize; i++) {if (table[i].inUse && !table[i].direct) {printf("\033[0mName: %s, Sector: %d\n", table[i].name, table[i].sector);hdr->FetchFrom(table[i].sector);hdr->Print();}else if(table[i].inUse && table[i].direct) {printf("\033[34m\033[1mDirectory: %s, Sector: %d\n",table[i].name,table[i].sector);hdr->FetchFrom(table[i].sector);hdr->Print();printf("\033[0m");} }

多級目錄的測試

  • 首先make。

  • 然后通過./nachos -f生成DISK磁盤文件

  • 通過./nachos -cp ./test/small ./dir/ttt/small將Linux文件small復制到Nachos下的目錄./dir/ttt下。

  • 通過./nachos -ld ./dir/ttt查看ttt目錄下的內容


    通過./nachos -p ./dir/ttt/small嘗試輸出文件內容:

  • 通過./nachos -r ./dir/ttt/small嘗試刪除文件,可以看到此時的ttt目錄下已經沒有文件了

    再通過./nachos -D進一步查看內容,與刪除前相比,位圖中的第11,12塊被釋放,說明文件small已經成功刪除

  • 通過./nachos -rd ./dir刪除目錄及其子目錄,可以發現,目錄文件的inUse項被設置為了0。同時位圖也釋放了。刪除成功!

  • 類文件樹的輸出測試:

    重新創建一個DISK進行后續測試。

    通過幾個命令,使得整體目錄結構為:

    • 根目錄下包含文件small,目錄dir
    • 目錄dir下包含文件file,目錄ttt和ttt2
    • 目錄ttt下包含一個文件file
    • 目錄ttt2下包含一個文件file2

    命令如下:

    ./nachos -cp ./test/small small ./nachos -cp ./test/empty ./dir/file ./nachos -cp ./test/small ./dir/ttt/file ./nachos -cp ./test/empty ./dir/ttt2/file2

    然后通過以下命令分別進行輸出查看:

    ./nachos -l

    ./nachos -ld ./dir

感受

整個實驗相對復雜的地方在于對于文件系統的擴展。為了實現文件系統的擴展,需要對文件的創造和刪除非常熟悉,還需要對目錄文件和整個文件系統存儲的結構有比較深得了解。擴展文件系統的過程中對諸多函數都產生了更改,并且加入了新的Nachos參數和相關函數。函數之間的相互調用錯綜復雜,對于函數運行中可能出現的錯誤都要盡量考慮周到,例如創建OpenFile類對象的時候,一定要先檢查構造函數需要的參數sector的正負情況!編寫新的函數時一定要仔細考慮好將該函數添加到哪個類中,作為類的成員函數。函數添加到這個類中還有沒有復用性更高的方案?能否將這個函數獨立出來以供使用?一系列問題都是在構建大型項目時需要仔細考慮的。

雖然非常麻煩,但是程序成功運行時的快樂也是無與倫比的!

總結

以上是生活随笔為你收集整理的Nachos操作系统-文件系统添加多级目录的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。