《簡單文件系統(tǒng)的實現(xiàn).doc》由會員分享,可在線閱讀,更多相關(guān)《簡單文件系統(tǒng)的實現(xiàn).doc(16頁珍藏版)》請在裝配圖網(wǎng)上搜索。
第三章 簡單文件系統(tǒng)的實現(xiàn)
3.1 設(shè)計目的和內(nèi)容要求
1. 設(shè)計目的
通過具體的文件存儲空間的管理、文件的物理結(jié)構(gòu)、目錄結(jié)構(gòu)和文件操作的實現(xiàn),加深對文件系統(tǒng)內(nèi)部數(shù)據(jù)結(jié)構(gòu)、功能以及實現(xiàn)過程的理解。
2.內(nèi)容要求
(1) 在內(nèi)存中開辟一個虛擬磁盤空間作為文件存儲分區(qū),在其上實現(xiàn)一個簡單的基于多級目錄的單用戶單任務(wù)系統(tǒng)中的文件系統(tǒng)。在退出該文件系統(tǒng)的使用時,應(yīng)將該虛擬文件系統(tǒng)以一個Windows 文件的方式保存到磁盤上,以便下次可以再將它恢復(fù)到內(nèi)存的虛擬磁盤空間中。
(2) 文件存儲空間的分配可采用顯式鏈接分配或其他的辦法。
(3) 空閑磁盤空間的管理可選擇位示圖或其他的辦法。如果采用位示圖來管理文件存儲空間,并采用顯式鏈接分配方式,那么可以將位示圖合并到FAT中。
(4) 文件目錄結(jié)構(gòu)采用多級目錄結(jié)構(gòu)。為了簡單起見,可以不使用索引結(jié)點,其中的每個目錄項應(yīng)包含文件名、物理地址、長度等信息,還可以通過目錄項實現(xiàn)對文件的讀和寫的保護。
(5) 要求提供以下操作命令:
l my_format:對文件存儲器進行格式化,即按照文件系統(tǒng)的結(jié)構(gòu)對虛擬磁盤空間進行布局,并在其上創(chuàng)建根目錄以及用于管理文件存儲空間等的數(shù)據(jù)結(jié)構(gòu)。
l my_mkdir:用于創(chuàng)建子目錄。
l my_rmdir:用于刪除子目錄。
l my_ls:用于顯示目錄中的內(nèi)容。
l my_cd:用于更改當(dāng)前目錄。
l my_create:用于創(chuàng)建文件。
l my_open:用于打開文件。
l my_close:用于關(guān)閉文件。
l my_write:用于寫文件。
l my_read:用于讀文件。
l my_rm:用于刪除文件。
l my_exitsys:用于退出文件系統(tǒng)。
3.學(xué)時安排
授課2學(xué)時,上機9學(xué)時。
4. 開發(fā)平臺
C或C++均可。
5.思考
(1) 我們的數(shù)據(jù)結(jié)構(gòu)中的文件物理地址信息是使用C語言的指針類型、還是整型,為什么?
(2) 如果引入磁盤索引結(jié)點,上述實現(xiàn)過程需要作哪些修改?
(3) 如果設(shè)計的是一個單用戶多任務(wù)文件系統(tǒng),則系統(tǒng)需要進行哪些擴充(尤其要考慮讀寫指針問題)?如果設(shè)計的是一個多用戶文件系統(tǒng),則又要進行哪些擴充?
3.2 預(yù)備知識
3.2.1 FAT文件系統(tǒng)介紹
1.概述
FAT文件系統(tǒng)是微軟公司在其早期的操作系統(tǒng)MS-DOS及Windows9x中采用的文件系統(tǒng),它被設(shè)計用來管理小容量的磁盤空間。FAT文件系統(tǒng)是以他的文件組織方式——文件分配表(file allocation table,F(xiàn)AT)命名的,文件分配表的每個表項中存放某文件的下一個盤塊號,而該文件的起始盤塊號則保存在它的文件控制塊FCB中。在文件分配表中,一般用FFFF來標(biāo)識文件的結(jié)束;用0000來標(biāo)識某個邏輯塊未被分配,即是空閑塊。為了提高文件系統(tǒng)的可靠性,在邏輯磁盤上通常設(shè)置兩張文件分配表,它們互為備份。此外,文件分配表必須存放在邏輯磁盤上的固定位置,而根目錄區(qū)通常位于FAT2之后,以便操作系統(tǒng)在啟動時能夠定位所需的文件,其磁盤布局如圖3-1所示:
圖3-1 FAT文件系統(tǒng)磁盤布局
上述磁盤布局中,引導(dǎo)塊中主要存放了用于描述分區(qū)的各種信息,包括邏輯塊的大小、文件分配表的大小及位置、根目錄的大小及位置等。除此之外,用于加載操作系統(tǒng)內(nèi)核的引導(dǎo)程序也存儲在引導(dǎo)塊中。
FAT文件系統(tǒng)家族又分為FAT12、FAT16、FAT32三種類型,這里的數(shù)字表示文件分配表中每個表項(即簇號)所占的位數(shù),即FAT12中每個表項占1.5個字節(jié)(12位),F(xiàn)AT16中每個表項占2個字節(jié)(16位),F(xiàn)AT32中每個表項占4個字節(jié)(32位)。由于FAT文件系統(tǒng)是以簇為單位為文件分配磁盤空間的(一個簇是一組連續(xù)的扇區(qū),通常包含2n個扇區(qū)),因此,F(xiàn)AT32比FAT12和FAT16支持更多的簇數(shù)、更小的簇大小和更大的磁盤容量,從而大大提高磁盤空間的利用率。通常,F(xiàn)AT12適用于小容量磁盤,如軟盤;FAT16是MS-DOS的文件系統(tǒng);FAT32是Windows9x中的主要文件系統(tǒng),開始支持大容量磁盤。
2.文件控制塊FCB
為了正確、方便地操作文件,必須設(shè)置相應(yīng)的數(shù)據(jù)結(jié)構(gòu)用于存放文件的描述和控制信息,常用的數(shù)據(jù)結(jié)構(gòu)有文件控制塊(簡稱FCB)和索引節(jié)點(簡稱i節(jié)點)。在FAT文件系統(tǒng)中使用文件控制塊。文件與文件控制塊一一對應(yīng),而文件控制塊的有序集合就稱為文件目錄,即一個文件控制塊就是一個文件目錄項。
雖然不同文件系統(tǒng)的文件控制塊的內(nèi)容和格式不完全相同,但通常都包括以下三類信息:基本信息、存取控制信息和使用信息。
(1)基本信息。包括文件名、用戶名、文件類型、文件的物理地址、文件長度、文件的邏輯結(jié)構(gòu)和物理結(jié)構(gòu)等。
(2)存取控制信息。一般分別給出文件主、伙伴用戶、一般用戶的存取權(quán)限。
(3)使用信息。包括文件的建立日期及時間、上次存取文件的日期及時間、當(dāng)前的使用信息等。
以MS-DOS(使用FAT16文件系統(tǒng))為例,它的每個文件控制塊包括32個字節(jié),其字節(jié)分配情況如圖3-2所示:
圖3-2 MS-DOS的文件控制塊
其中屬性字段占一個字節(jié),它的每一位用來表示該文件是否具有某種屬性,如果某一位的值為1,則表示該文件具有該屬性。各位所表示的屬性如表3-1所示:
表3-1 文件屬性對照表
位
7
6
5
4
3
2
1
0
屬性
保留
保留
存檔
子目錄
卷標(biāo)
系統(tǒng)文件
隱藏
只讀
3.根目錄區(qū)
FAT12、FAT16的根目錄區(qū)是固定區(qū)域、固定大小的,位于第二個FAT之后,如圖3-1所示,且占據(jù)若干連續(xù)扇區(qū),其中FAT12占14個扇區(qū),一共224個根目錄項;而FAT16占32個扇區(qū),最多保存512個目錄項,作為系統(tǒng)區(qū)的一部分。FAT32的根目錄是作為文件處理的,采用與子目錄文件相同的管理方式,其位置不是固定的,不過一般情況也是位于第二個FAT之后的,其大小可視需要增加,因此根目錄下的文件數(shù)目不再受最多512個的限制。
3.2.2 幾個C語言庫函數(shù)介紹
由于我們的文件系統(tǒng)是建立在內(nèi)存的虛擬磁盤上的,在退出文件系統(tǒng)的時候必須以一個文件的形式保存到磁盤上;而在啟動文件系統(tǒng)的時候必須從磁盤上將該文件讀入到內(nèi)存的虛擬磁盤中。下面介紹幾個可能會用到的C庫函數(shù),在使用這些庫函數(shù)之前必須包含頭文件“stdio.h”。
1.打開文件函數(shù)fopen()
(1)格式:FILE *fopen(const char *filename,const char *mode)
(2)功能:按照指定打開方式打開指定文件。
(3)輸入?yún)?shù)說明:
filename:待打開的文件名,如果不存在就創(chuàng)建該文件。
mode: 文件打開方式,常用的有:
l "r":為讀而打開文本文件(不存在則出錯)。
l "w":為寫而打開文本文件(若不存在則創(chuàng)建該文件;反之,則從文件起始位置寫,原內(nèi)容將被覆蓋)。
l "a":為在文件末尾添加數(shù)據(jù)而打開文本文件。(若不存在則創(chuàng)建該文件;反之,在原文件末尾追加)。
l "r+":為讀和寫而打開文本文件。(讀時,從頭開始;在寫數(shù)據(jù)時,新數(shù)據(jù)只覆蓋所占的空間,其后不變) 。
l "w+":首先建立一個新文件,進行寫操作,隨后可以從頭開始讀。(若文件存在,原內(nèi)容將全部消失) 。
l "a+":功能與"a"相同;只是在文件末尾添加新的數(shù)據(jù)后,可以從頭開始讀。
另外,上述模式字符串中都可以加一個“b”字符,如rb、wb、ab、rb+、wb+、ab+等組合,字符“b”表示fopen() 函數(shù)打開的文件為二進制文件,而非純文字文件。
(4)輸出:一個指向FILE類型的指針。
2.關(guān)閉文件函數(shù)fclose()
(1)格式:int fclose(FILE * stream);
(2)功能:用來關(guān)閉先前fopen()打開的一個文件。此動作會讓緩沖區(qū)內(nèi)的數(shù)據(jù)寫入文件中,并釋放系統(tǒng)所提供的文件資源。
(3)輸入?yún)?shù)說明:
stream:指向要關(guān)閉文件的指針,它是先前執(zhí)行fopen()函數(shù)的返回值。
(4)輸出:若關(guān)閉文件成功則返回0;有錯誤發(fā)生時則返回EOF并把錯誤代碼存到errno。
3.讀文件函數(shù)fread()
(1)格式:size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
(2)功能:讀二進制文件到內(nèi)存。
(3)輸入?yún)?shù)說明:
buffer:用于存放輸入數(shù)據(jù)的緩沖區(qū)的首地址;
stream:使用fopen()打開的文件的指針,用于指示要讀取的文件;
size: 每個數(shù)據(jù)塊的字節(jié)數(shù);
count: 要讀入的數(shù)據(jù)塊的個數(shù);
size*count:表示要求讀取的字節(jié)數(shù)。
(4)輸出:實際讀取的數(shù)據(jù)塊的個數(shù)。
4.寫文件函數(shù)fwrite()
(1)格式:size_t fwite(const void *buffer,size_t size,size_t count,FILE *stream);
(2)功能:將數(shù)據(jù)寫到二進制文件中。
(3)輸入?yún)?shù)說明:
buffer:用于存放輸出數(shù)據(jù)的緩沖區(qū)的首地址;
stream:使用fopen()打開的文件的指針,用于指示要寫出的文件;
size: 每個數(shù)據(jù)塊的字節(jié)數(shù);
count: 要寫出的數(shù)據(jù)塊的個數(shù);
size*count:表示要求寫出的字符數(shù)。
(4)輸出:實際寫出的數(shù)據(jù)塊的個數(shù)。
5.判斷文件結(jié)束函數(shù)feof ()
(1)格式:int feof(FILE * stream)
(2)功能:用來判斷是否已讀取到文件末尾。
(3)輸入?yún)?shù)說明:
stream:使用fopen()打開的文件的指針,用于指示要判斷的文件。
(4)輸出:如果已讀到文件尾則返回非零值,其他情況返回0。
6.定位文件函數(shù)fseek()
(1)格式:int fseek( FILE *stream, long offset, int origin );
(2)功能: 移動文件讀寫指針在文件中的位置。
(3)輸入?yún)?shù)說明:
stream:使用fopen()打開的文件的指針,用于指示要定位讀寫指針的文件;
offset:位移量,以字節(jié)為單位;
origin:初始位置,有三個常量:
SEEK_CUR:讀寫指針當(dāng)前位置;
SEEK_SET:文件開頭;
SEEK_END:文件末尾。
當(dāng)origin值為SEEK_CUR 或SEEK_END時,參數(shù)offset可以為負值。
3.3實例系統(tǒng)的設(shè)計與實現(xiàn)
本實例系統(tǒng)是仿照FAT16文件系統(tǒng)來設(shè)計實現(xiàn)的,但根目錄沒有采用FAT16的固定位置、固定大小的根目錄區(qū),而是以根目錄文件的形式來實現(xiàn)的,這也是目前主流文件系統(tǒng)對根目錄的處理方式。
3.3.1 數(shù)據(jù)結(jié)構(gòu)設(shè)計
1.需要包含的頭文件
(1)#include
(2)#include
(3)#include
(4)#include
2.定義的常量
(1)#define BLOCKSIZE 1024 磁盤塊大小
(2)#define SIZE 1024000 虛擬磁盤空間大小
(3)#define END 65535 FAT中的文件結(jié)束標(biāo)志
(4)#define FREE 0 FAT中盤塊空閑標(biāo)志
(5)#define ROOTBLOCKNUM 2 根目錄區(qū)所占盤塊總數(shù)
(6)#define MAXOPENFILE 10 最多同時打開文件個數(shù)
3.?dāng)?shù)據(jù)結(jié)構(gòu)
(1)文件控制塊FCB
用于記錄文件的描述和控制信息,每個文件設(shè)置一個FCB,它也是文件的目錄項的內(nèi)容。
typedef struct FCB //仿照FAT16設(shè)置的
{
char filename[8]; //文件名
char exname[3];//文件擴展名
unsigned char attribute;//文件屬性字段:為簡單起見,我們只為文件設(shè)置了兩種屬性:
//值為0時表示目錄文件,值為1時表示數(shù)據(jù)文件
unsigned short time;//文件創(chuàng)建時間
unsigned short data;//文件創(chuàng)建日期
unsigned short first;//文件起始盤塊號
unsigned long length;//文件長度(字節(jié)數(shù))
char free;//表示目錄項是否為空,若值為0,表示空,值為1,表示已分配
}fcb;
(2)文件分配表FAT
在本實例中,文件分配表有兩個作用:一是記錄磁盤上每個文件所占據(jù)的磁盤塊的塊號;二是記錄磁盤上哪些塊已經(jīng)分配出去了,哪些塊是空閑的,即起到了位示圖的作用。若FAT中某個表項的值為FREE,則表示該表項所對應(yīng)的磁盤塊是空閑的;若某個表項的值為END,則表示所對應(yīng)的磁盤塊是某文件的最后一個磁盤塊;若某個表項的值是其他值,則該值表示某文件的下一個磁盤塊的塊號。為了提高系統(tǒng)的可靠性,本實例中設(shè)置了兩張FAT表,它們互為備份,每個FAT占據(jù)兩個磁盤塊。
typedef struct FAT
{
unsigned short id;
}fat;
(3)用戶打開文件表USEROPEN
當(dāng)打開一個文件時,必須將文件的目錄項中的所有內(nèi)容全部復(fù)制到內(nèi)存中,同時還要記錄有關(guān)文件操作的動態(tài)信息,如讀寫指針的值等。在本實例中實現(xiàn)的是一個用于單用戶單任務(wù)系統(tǒng)的文件系統(tǒng),為簡單起見,我們把用戶文件描述符表和內(nèi)存FCB表合在一起,稱為用戶打開文件表,表項數(shù)目為10,即一個用戶最多可同時打開10個文件。然后用一個數(shù)組來描述,則數(shù)組下標(biāo)即某個打開文件的描述符。另外,我們在用戶打開文件表中還設(shè)置了一個字段“char dir[80]”,用來記錄每個打開文件所在的目錄名,以方便用戶打開不同目錄下具有相同文件名的不同文件。
typedef struct USEROPEN
{
char filename[8]; //文件名
char exname[3];//文件擴展名
unsigned char attribute;//文件屬性:值為0時表示目錄文件,值為1時表示數(shù)據(jù)文件
unsigned short time;//文件創(chuàng)建時間
unsigned short data;//文件創(chuàng)建日期
unsigned short first;//文件起始盤塊號
unsigned long length;//文件長度(對數(shù)據(jù)文件是字節(jié)數(shù),對目錄文件可以是目錄項個數(shù))
char free;//表示目錄項是否為空,若值為0,表示空,值為1,表示已分配
//前面內(nèi)容是文件的FCB中的內(nèi)容。
// 下面設(shè)置的dirno和diroff記錄了相應(yīng)打開文件的目錄項在父目錄文件中的位置,//這樣如果該文件的fcb被修改了,則要寫回父目錄文件時比較方便
int dirno; //相應(yīng)打開文件的目錄項在父目錄文件中的盤塊號
int diroff;// 相應(yīng)打開文件的目錄項在父目錄文件的dirno盤塊中的目錄項序號
char dir[MAXOPENFILE][80]; //相應(yīng)打開文件所在的目錄名,這樣方便快速檢查出
//指定文件是否已經(jīng)打開
int count; //讀寫指針在文件中的位置
char fcbstate; //是否修改了文件的FCB的內(nèi)容,如果修改了置為1,否則為0
char topenfile; //表示該用戶打開表項是否為空,若值為0,表示為空,否則表示已
//被某打開文件占據(jù)
}useropen;
(4)引導(dǎo)塊BLOCK0
在引導(dǎo)塊中主要存放邏輯磁盤的相關(guān)描述信息,比如磁盤塊大小、磁盤塊數(shù)量、文件分配表、根目錄區(qū)、數(shù)據(jù)區(qū)在磁盤上的起始位置等。如果是引導(dǎo)盤,還要存放操作系統(tǒng)的引導(dǎo)信息。本實例是在內(nèi)存的虛擬磁盤中創(chuàng)建一個文件系統(tǒng),因此所包含的內(nèi)容比較少,只有磁盤塊大小、磁盤塊數(shù)量、數(shù)據(jù)區(qū)開始位置、根目錄文件開始位置等。
typedef struct BLOCK0 //引導(dǎo)塊內(nèi)容
{
//存儲一些描述信息,如磁盤塊大小、磁盤塊數(shù)量、最多打開文件數(shù)等、
char information[200];
unsigned short root; //根目錄文件的起始盤塊號
unsigned char *startblock; //虛擬磁盤上數(shù)據(jù)區(qū)開始位置
}block0;
4.全局變量定義
(1)unsigned char *myvhard: 指向虛擬磁盤的起始地址
(2)useropen openfilelist[MAXOPENFILE]: 用戶打開文件表數(shù)組
(3)useropen *ptrcurdir: 指向用戶打開文件表中的當(dāng)前目錄所在打開文件表項的位置;
(4)char currentdir[80]: 記錄當(dāng)前目錄的目錄名(包括目錄的路徑)
(5)unsigned char* startp: 記錄虛擬磁盤上數(shù)據(jù)區(qū)開始位置
5.虛擬磁盤空間布局
由于真正的磁盤操作需要涉及到設(shè)備的驅(qū)動程序,所以本實例是在內(nèi)存中申請一塊空間作為虛擬磁盤使用,我們的文件系統(tǒng)就建立在這個虛擬磁盤上。虛擬磁盤一共劃分成1000個磁盤塊,每個塊1024個字節(jié),其布局格式是模仿FAT文件系統(tǒng)設(shè)計的,其中引導(dǎo)塊占一個盤塊,兩張FAT各占2個盤塊,剩下的空間全部是數(shù)據(jù)區(qū),在對虛擬磁盤進行格式化的時候,將把數(shù)據(jù)區(qū)第1塊(即虛擬磁盤的第6塊)分配給根目錄文件,如圖3-3所示:
圖3-3 虛擬磁盤空間布局
當(dāng)然,也可以仿照FAT16文件系統(tǒng),設(shè)置根目錄區(qū),其位置緊跟第2張FAT后面,大小也是固定的,這個思路相對要簡單一點,請同學(xué)們自己去實現(xiàn)。
3.3.2 實例主要命令及函數(shù)設(shè)計
1.系統(tǒng)主函數(shù)main()
(1)對應(yīng)命令:無
(2)命令調(diào)用格式:無
(3)函數(shù)設(shè)計格式:void main()
(4)功能:系統(tǒng)主函數(shù)
(5)輸入:無
(6)輸出:無
(7)函數(shù)需完成的工作:
① 對前面定義的全局變量進行初始化;
② 調(diào)用startsys()進入文件系統(tǒng);
③ 列出文件系統(tǒng)提供的各項功能及命令調(diào)用格式;
④ 顯示命令行提示符,等待用戶輸入命令;
⑤ 將用戶輸入的命令保存到一個buf中;
⑥ 對buf中的內(nèi)容進行命令解析,并調(diào)用相應(yīng)的函數(shù)執(zhí)行用戶鍵入的命令;
⑦ 如果命令不是“my_exitsys”,則命令執(zhí)行完畢后轉(zhuǎn)④。
2. 進入文件系統(tǒng)函數(shù)startsys()
(1)對應(yīng)命令:無
(2)命令調(diào)用格式:無
(3)函數(shù)設(shè)計格式:void startsys()
(4)功能:由main()函數(shù)調(diào)用,進入并初始化我們所建立的文件系統(tǒng),以供用戶使用。
(5)輸入:無
(6)輸出:無。
(7)函數(shù)需完成的工作:
① 申請?zhí)摂M磁盤空間;
② 使用c語言的庫函數(shù)fopen()打開myfsys文件:若文件存在,則轉(zhuǎn)③;若文件不存在,則創(chuàng)建之,轉(zhuǎn)⑤
③ 使用c語言的庫函數(shù)fread()讀入myfsys文件內(nèi)容到用戶空間中的一個緩沖區(qū)中,并判斷其開始的8個字節(jié)內(nèi)容是否為“10101010”(文件系統(tǒng)魔數(shù)),如果是,則轉(zhuǎn)④;否則轉(zhuǎn)⑤;
④ 將上述緩沖區(qū)中的內(nèi)容復(fù)制到內(nèi)存中的虛擬磁盤空間中;轉(zhuǎn)⑦
⑤ 在屏幕上顯示“myfsys文件系統(tǒng)不存在,現(xiàn)在開始創(chuàng)建文件系統(tǒng)”信息,并調(diào)用my_format()對①中申請到的虛擬磁盤空間進行格式化操作。轉(zhuǎn)⑥;
⑥ 將虛擬磁盤中的內(nèi)容保存到myfsys文件中;轉(zhuǎn)⑦
⑦ 使用c語言的庫函數(shù)fclose()關(guān)閉myfsys文件;
⑧ 初始化用戶打開文件表,將表項0分配給根目錄文件使用,并填寫根目錄文件的相關(guān)信息,由于根目錄沒有上級目錄,所以表項中的dirno和diroff分別置為5(根目錄所在起始塊號)和0;并將ptrcurdir指針指向該用戶打開文件表項。
⑨ 將當(dāng)前目錄設(shè)置為根目錄。
3.磁盤格式化函數(shù)my_format()
(1)對應(yīng)命令:my_format
(2)命令調(diào)用格式:my_format
(3)函數(shù)設(shè)計格式:void my_format()
(4)功能:對虛擬磁盤進行格式化,布局虛擬磁盤,建立根目錄文件(或根目錄區(qū))。
(5)輸入:無
(6)輸出:無。
(7)函數(shù)需完成的工作:
① 將虛擬磁盤第一個塊作為引導(dǎo)塊,開始的8個字節(jié)是文件系統(tǒng)的魔數(shù),記為“10101010”;在之后寫入文件系統(tǒng)的描述信息,如FAT表大小及位置、根目錄大小及位置、盤塊大小、盤塊數(shù)量、數(shù)據(jù)區(qū)開始位置等信息;
② 在引導(dǎo)塊后建立兩張完全一樣的FAT表,用于記錄文件所占據(jù)的磁盤塊及管理虛擬磁盤塊的分配,每個FAT占據(jù)兩個磁盤塊;對于每個FAT中,前面5個塊設(shè)置為已分配,后面995個塊設(shè)置為空閑;
③ 在第二張FAT后創(chuàng)建根目錄文件root,將數(shù)據(jù)區(qū)的第1塊(即虛擬磁盤的第6塊)分配給根目錄文件,在該磁盤上創(chuàng)建兩個特殊的目錄項:“.”和“..”,其內(nèi)容除了文件名不同之外,其他字段完全相同。
4.更改當(dāng)前目錄函數(shù)my_cd()
(1)對應(yīng)命令:my_cd
(2)命令調(diào)用格式:my_cd dirname
(3)函數(shù)設(shè)計格式:void my_cd(char *dirname)
(4)功能:改變當(dāng)前目錄到指定的名為dirname的目錄。
(5)輸入:
dirname:新的當(dāng)前目錄的目錄名;
(6)輸出:無
(7)函數(shù)需完成的工作:
① 調(diào)用my_open()打開指定目錄名的父目錄文件,并調(diào)用do_read()讀入該父目錄文件內(nèi)容到內(nèi)存中;
② 在父目錄文件中檢查新的當(dāng)前目錄名是否存在,如果存在則轉(zhuǎn)③,否則返回,并顯示出錯信息;
③ 調(diào)用my_close()關(guān)閉①中打開的父目錄文件;
④ 調(diào)用my_close()關(guān)閉原當(dāng)前目錄文件;
⑤ 如果新的當(dāng)前目錄文件沒有打開,則打開該目錄文件;并將ptrcurdir指向該打開文件表項;
⑥ 設(shè)置當(dāng)前目錄為該目錄。
5.創(chuàng)建子目錄函數(shù)my_mkdir()
(1)對應(yīng)命令:my_mkdir
(2)命令調(diào)用格式:my_ mkdir dirname
(3)函數(shù)設(shè)計格式:void my_mkdir(char *dirname)
(4)功能:在當(dāng)前目錄下創(chuàng)建名為dirname的子目錄。
(5)輸入:
dirname:新建目錄的目錄名。
(6)輸出:無。
(7)函數(shù)需完成的工作:
① 調(diào)用do_read()讀入當(dāng)前目錄文件內(nèi)容到內(nèi)存,檢查當(dāng)前目錄下新建目錄文件是否重名,若重名則返回,并顯示錯誤信息;
② 為新建子目錄文件分配一個空閑打開文件表項,如果沒有空閑表項則返回-1,并顯示錯誤信息;
③ 檢查FAT是否有空閑的盤塊,如有則為新建目錄文件分配一個盤塊,否則釋放①中分配的打開文件表項,返回,并顯示錯誤信息;
④ 在當(dāng)前目錄中為新建目錄文件尋找一個空閑的目錄項或為其追加一個新的目錄項;需修改當(dāng)前目錄文件的長度信息,并將當(dāng)前目錄文件的用戶打開文件表項中的fcbstate置為1;
⑤ 準(zhǔn)備好新建目錄文件的FCB的內(nèi)容,文件的屬性為目錄文件,以覆蓋寫方式調(diào)用do_write()將其填寫到對應(yīng)的空目錄項中;
⑥ 在新建目錄文件所分配到的磁盤塊中建立兩個特殊的目錄項“.”和“..”目錄項,方法是:首先在用戶空間中準(zhǔn)備好內(nèi)容,然后以截斷寫或者覆蓋寫方式調(diào)用do_write()將其寫到③中分配到的磁盤塊中;
⑦ 返回。
6.刪除子目錄函數(shù)rmdir()
(1)對應(yīng)命令:my_ rmdir
(2)命令調(diào)用格式:my_ rmdir dirname
(1)函數(shù)設(shè)計格式:void my_rmdir(char *dirname)
(2)功能:在當(dāng)前目錄下刪除名為dirname的子目錄。
(3)輸入:
dirname:欲刪除目錄的目錄名。
(4)輸出:無。
(5)函數(shù)需完成的工作:
① 調(diào)用do_read()讀入當(dāng)前目錄文件內(nèi)容到內(nèi)存,檢查當(dāng)前目錄下欲刪除目錄文件是否存在,若不存在則返回,并顯示錯誤信息;
② 檢查欲刪除目錄文件是否為空(除了“.”和“..”外沒有其他子目錄和文件),可根據(jù)其目錄項中記錄的文件長度來判斷,若不為空則返回,并顯示錯誤信息;
③ 檢查該目錄文件是否已經(jīng)打開,若已打開則調(diào)用my_close()關(guān)閉掉;
④ 回收該目錄文件所占據(jù)的磁盤塊,修改FAT;
⑤ 從當(dāng)前目錄文件中清空該目錄文件的目錄項,且free字段置為0:以覆蓋寫方式調(diào)用do_write()來實現(xiàn);
⑥ 修改當(dāng)前目錄文件的用戶打開表項中的長度信息,并將表項中的fcbstate置為1;
⑦ 返回。
7.顯示目錄函數(shù)my_ls()
(1)對應(yīng)命令:my_ls
(2)命令調(diào)用格式:my_ls
(3)函數(shù)設(shè)計格式:void my_ls(void)
(4)功能:顯示當(dāng)前目錄的內(nèi)容(子目錄和文件信息)。
(5)輸入:無
(6)輸出:無
(7)函數(shù)需完成的工作:
① 調(diào)用do_read()讀出當(dāng)前目錄文件內(nèi)容到內(nèi)存;
② 將讀出的目錄文件的信息按照一定的格式顯示到屏幕上;
③ 返回。
8.創(chuàng)建文件函數(shù)my_create()
(1)對應(yīng)命令:my_create
(2)命令調(diào)用格式:my_create filename
(3)函數(shù)設(shè)計格式:int my_create (char *filename)
(4)功能:創(chuàng)建名為filename的新文件。
(5)輸入:
filename:新建文件的文件名,可能包含路徑。
(6)輸出:若創(chuàng)建成功,返回該文件的文件描述符(文件打開表中的數(shù)組下標(biāo));否則返回-1。
(7)函數(shù)需完成的工作:
① 為新文件分配一個空閑打開文件表項,如果沒有空閑表項則返回-1,并顯示錯誤信息;
② 若新文件的父目錄文件還沒有打開,則調(diào)用my_open()打開;若打開失敗,則釋放①中為新建文件分配的空閑文件打開表項,返回-1,并顯示錯誤信息;
③ 調(diào)用do_read()讀出該父目錄文件內(nèi)容到內(nèi)存,檢查該目錄下新文件是否重名,若重名則釋放①中分配的打開文件表項,并調(diào)用my_close()關(guān)閉②中打開的目錄文件;然后返回-1,并顯示錯誤信息;
④ 檢查FAT是否有空閑的盤塊,如有則為新文件分配一個盤塊,否則釋放①中分配的打開文件表項,并調(diào)用my_close()關(guān)閉②中打開的目錄文件;返回-1,并顯示錯誤信息;
⑤ 在父目錄中為新文件尋找一個空閑的目錄項或為其追加一個新的目錄項;需修改該目錄文件的長度信息,并將該目錄文件的用戶打開文件表項中的fcbstate置為1;
⑥ 準(zhǔn)備好新文件的FCB的內(nèi)容,文件的屬性為數(shù)據(jù)文件,長度為0,以覆蓋寫方式調(diào)用do_write()將其填寫到⑤中分配到的空目錄項中;
⑦ 為新文件填寫①中分配到的空閑打開文件表項,fcbstate字段值為0,讀寫指針值為0;
⑧ 調(diào)用my_close()關(guān)閉②中打開的父目錄文件;
⑨ 將新文件的打開文件表項序號作為其文件描述符返回。
9.刪除文件函數(shù)my_rm()
(1)對應(yīng)命令:my_rm
(2)命令調(diào)用格式:my_rm filename
(3)函數(shù)設(shè)計格式:void my_rm(char *filename)
(4)功能:刪除名為filename的文件。
(5)輸入:
filename:欲刪除文件的文件名,可能還包含路徑。
(6)輸出:無。
(7)函數(shù)需完成的工作:
① 若欲刪除文件的父目錄文件還沒有打開,則調(diào)用my_open()打開;若打開失敗,則返回,并顯示錯誤信息;
② 調(diào)用do_read()讀出該父目錄文件內(nèi)容到內(nèi)存,檢查該目錄下欲刪除文件是否存在,若不存在則返回,并顯示錯誤信息;
③ 檢查該文件是否已經(jīng)打開,若已打開則關(guān)閉掉;
④ 回收該文件所占據(jù)的磁盤塊,修改FAT;
⑤ 從文件的父目錄文件中清空該文件的目錄項,且free字段置為0:以覆蓋寫方式調(diào)用do_write()來實現(xiàn);;
⑥ 修改該父目錄文件的用戶打開文件表項中的長度信息,并將該表項中的fcbstate置為1;
⑦ 返回。
10.打開文件函數(shù)my_open()
(1)對應(yīng)命令:my_open
(2)命令調(diào)用格式:my_open filename
(3)函數(shù)設(shè)計格式:int my_open(char *filename)
(4)功能:打開當(dāng)前目錄下名為filename的文件。
(5)輸入:
filename:欲打開文件的文件名
(6)輸出:若打開成功,返回該文件的描述符(在用戶打開文件表中表項序號);否則返回-1。
(7)函數(shù)需完成的工作:
① 檢查該文件是否已經(jīng)打開,若已打開則返回-1,并顯示錯誤信息;
② 調(diào)用do_read()讀出父目錄文件的內(nèi)容到內(nèi)存,檢查該目錄下欲打開文件是否存在,若不存在則返回-1,并顯示錯誤信息;
③ 檢查用戶打開文件表中是否有空表項,若有則為欲打開文件分配一個空表項,若沒有則返回-1,并顯示錯誤信息;
④ 為該文件填寫空白用戶打開文件表表項內(nèi)容,讀寫指針置為0;
⑤ 將該文件所分配到的空白用戶打開文件表表項序號(數(shù)組下標(biāo))作為文件描述符fd返回。
11.關(guān)閉文件函數(shù)my_close()
(1)對應(yīng)命令:my_close
(2)命令調(diào)用格式:my_close fd
(3)函數(shù)設(shè)計格式:void my_close(int fd)
(4)功能:關(guān)閉前面由my_open()打開的文件描述符為fd的文件。
(5)輸入:
fd:文件描述符。
(6)輸出:無。
(7)函數(shù)需完成的工作:
① 檢查fd的有效性(fd不能超出用戶打開文件表所在數(shù)組的最大下標(biāo)),如果無效則返回-1;
② 檢查用戶打開文件表表項中的fcbstate字段的值,如果為1則需要將該文件的FCB的內(nèi)容保存到虛擬磁盤上該文件的目錄項中,方法是:打開該文件的父目錄文件,以覆蓋寫方式調(diào)用do_write()將欲關(guān)閉文件的FCB寫入父目錄文件的相應(yīng)盤塊中;
③ 回收該文件占據(jù)的用戶打開文件表表項(進行清空操作),并將topenfile字段置為0;
④ 返回。
12.寫文件函數(shù)my_write()
(1)對應(yīng)命令:my_write
(2)命令調(diào)用格式:my_write fd
(3)函數(shù)設(shè)計格式:int my_write(int fd)
(4)功能:將用戶通過鍵盤輸入的內(nèi)容寫到fd所指定的文件中。磁盤文件的讀寫操作都必須以完整的數(shù)據(jù)塊為單位進行,在寫操作時,先將數(shù)據(jù)寫在緩沖區(qū)中,緩沖區(qū)的大小與磁盤塊的大小相同,然后再將緩沖區(qū)中的數(shù)據(jù)一次性寫到磁盤塊中;讀出時先將一個磁盤塊中的內(nèi)容讀到緩沖區(qū)中,然后再傳送到用戶區(qū)。本實例為了簡便起見,沒有設(shè)置緩沖區(qū)管理,只是在讀寫文件時由用戶使用malloc()申請一塊空間作為緩沖區(qū),讀寫操作結(jié)束后使用free()釋放掉。
寫操作常有三種方式:截斷寫、覆蓋寫和追加寫。截斷寫是放棄原來文件的內(nèi)容,重新寫文件;覆蓋寫是修改文件在當(dāng)前讀寫指針?biāo)傅奈恢瞄_始的部分內(nèi)容;追加寫是在原文件的最后添加新的內(nèi)容。在本實例中,輸入寫文件命令后,系統(tǒng)會出現(xiàn)提示讓用戶選擇其中的一種寫方式,并將隨后鍵盤輸入的內(nèi)容按照所選的方式寫到文件中,鍵盤輸入內(nèi)容通過CTR+Z鍵(或其他設(shè)定的鍵)結(jié)束。
(5)輸入:
fd: open()函數(shù)的返回值,文件的描述符;
(6)輸出:實際寫入的字節(jié)數(shù)。
(7)函數(shù)需完成的工作:
① 檢查fd的有效性(fd不能超出用戶打開文件表所在數(shù)組的最大下標(biāo)),如果無效則返回-1,并顯示出錯信息;
② 提示并等待用戶輸入寫方式:(1:截斷寫;2:覆蓋寫;3:追加寫)
③ 如果用戶要求的寫方式是截斷寫,則釋放文件除第一塊外的其他磁盤空間內(nèi)容(查找并修改FAT表),將內(nèi)存用戶打開文件表項中文件長度修改為0,將讀寫指針置為0并轉(zhuǎn)④;如果用戶要求的寫方式是追加寫,則修改文件的當(dāng)前讀寫指針位置到文件的末尾,并轉(zhuǎn)④;如果寫方式是覆蓋寫,則直接轉(zhuǎn)④;
④ 提示用戶:整個輸入內(nèi)容通過CTR+Z鍵(或其他設(shè)定的鍵)結(jié)束;用戶可分多次輸入寫入內(nèi)容,每次用回車結(jié)束;
⑤ 等待用戶從鍵盤輸入文件內(nèi)容,并將用戶的本次輸入內(nèi)容保存到一臨時變量text[]中,要求每次輸入以回車結(jié)束,全部結(jié)束用CTR+Z鍵(或其他設(shè)定的鍵);
⑥ 調(diào)用do_write()函數(shù)將通過鍵盤鍵入的內(nèi)容寫到文件中。
⑦ 如果do_write()函數(shù)的返回值為非負值,則將實際寫入字節(jié)數(shù)增加do_write()函數(shù)返回值,否則顯示出錯信息,并轉(zhuǎn)⑨;
⑧ 如果text[]中最后一個字符不是結(jié)束字符CTR+Z,則轉(zhuǎn)⑦繼續(xù)進行寫操作;否則轉(zhuǎn)⑨;
⑨ 如果當(dāng)前讀寫指針位置大于用戶打開文件表項中的文件長度,則修改打開文件表項中的文件長度信息,并將fcbstate置1;
⑩ 返回實際寫入的字節(jié)數(shù)。
13.實際寫文件函數(shù)do_write()
(1)對應(yīng)命令:無
(2)命令調(diào)用格式:無
(3)函數(shù)設(shè)計格式:int my_write(int fd,char *text,int len,char wstyle)
(4)功能:被寫文件函數(shù)my_write()調(diào)用,用來將鍵盤輸入的內(nèi)容寫到相應(yīng)的文件中去。
(5)輸入:
fd: open()函數(shù)的返回值,文件的描述符;
text:指向要寫入的內(nèi)容的指針;
len:本次要求寫入字節(jié)數(shù)
wstyle:寫方式
(6)輸出:實際寫入的字節(jié)數(shù)。
(7)函數(shù)需完成的工作:
① 用malloc()申請1024B的內(nèi)存空間作為讀寫磁盤的緩沖區(qū)buf,申請失敗則返回-1,并顯示出錯信息;
② 將讀寫指針轉(zhuǎn)化為邏輯塊塊號和塊內(nèi)偏移off,并利用打開文件表表項中的首塊號及FAT表的相關(guān)內(nèi)容將邏輯塊塊號轉(zhuǎn)換成對應(yīng)的磁盤塊塊號blkno;如果找不到對應(yīng)的磁盤塊,則需要檢索FAT為該邏輯塊分配一新的磁盤塊,并將對應(yīng)的磁盤塊塊號blkno登記到FAT中,若分配失敗,則返回-1,并顯示出錯信息;
③ 如果是覆蓋寫,或者如果當(dāng)前讀寫指針?biāo)鶎?yīng)的塊內(nèi)偏移off不等于0,則將塊號為blkno的虛擬磁盤塊全部1024B的內(nèi)容讀到緩沖區(qū)buf中;否則便用ASCII碼0清空buf;
④ 將text中未寫入的內(nèi)容暫存到緩沖區(qū)buff的第off字節(jié)開始的位置,直到緩沖區(qū)滿,或者接收到結(jié)束字符CTR+Z為止;將本次寫入字節(jié)數(shù)記錄到tmplen中;
⑤ 將buf中1024B的內(nèi)容寫入到塊號為blkno的虛擬磁盤塊中;
⑥將當(dāng)前讀寫指針修改為原來的值加上tmplen;并將本次實際寫入的字節(jié)數(shù)增加tmplen;
⑦ 如果tmplen小于len,則轉(zhuǎn)②繼續(xù)寫入;否則轉(zhuǎn)⑧;
⑧ 返回本次實際寫入的字節(jié)數(shù)。
14.讀文件函數(shù)my_read()
(1)對應(yīng)命令:my_read
(2)命令調(diào)用格式:my_read fd len
(3)函數(shù)設(shè)計格式:int myread (int fd, int len)
(4)功能:讀出指定文件中從讀寫指針開始的長度為len的內(nèi)容到用戶空間中。
(5)輸入:
fd: open()函數(shù)的返回值,文件的描述符;
len: 要從文件中讀出的字節(jié)數(shù)。
(6)輸出:實際讀出的字節(jié)數(shù)。
(7)函數(shù)需完成的工作:
① 定義一個字符型數(shù)組text[len],用來接收用戶從文件中讀出的文件內(nèi)容;
② 檢查fd的有效性(fd不能超出用戶打開文件表所在數(shù)組的最大下標(biāo)),如果無效則返回-1,并顯示出錯信息;
③ 調(diào)用do_read()將指定文件中的len字節(jié)內(nèi)容讀出到text[]中;
④ 如果do_read()的返回值為負,則顯示出錯信息;否則將text[]中的內(nèi)容顯示到屏幕上;
⑤ 返回。
15.實際讀文件函數(shù)do_read()
(1)對應(yīng)命令:無
(2)命令調(diào)用格式:無
(3)函數(shù)設(shè)計格式:int do_read (int fd, int len,char *text)
(4)功能:被my_read()調(diào)用,讀出指定文件中從讀寫指針開始的長度為len的內(nèi)容到用戶空間的text中。
(5)輸入:
fd: open()函數(shù)的返回值,文件的描述符;
len: 要求從文件中讀出的字節(jié)數(shù)。
text:指向存放讀出數(shù)據(jù)的用戶區(qū)地址
(6)輸出:實際讀出的字節(jié)數(shù)。
(7)函數(shù)需完成的工作:
① 使用malloc()申請1024B空間作為緩沖區(qū)buf,申請失敗則返回-1,并顯示出錯信息;
② 將讀寫指針轉(zhuǎn)化為邏輯塊塊號及塊內(nèi)偏移量off,利用打開文件表表項中的首塊號查找FAT表,找到該邏輯塊所在的磁盤塊塊號;將該磁盤塊塊號轉(zhuǎn)化為虛擬磁盤上的內(nèi)存位置;
③ 將該內(nèi)存位置開始的1024B(一個磁盤塊)內(nèi)容讀入buf中;
④ 比較buf中從偏移量off開始的剩余字節(jié)數(shù)是否大于等于應(yīng)讀寫的字節(jié)數(shù)len,如果是,則將從off開始的buf中的len長度的內(nèi)容讀入到text[]中;否則,將從off開始的buf中的剩余內(nèi)容讀入到text[]中;
⑤ 將讀寫指針增加④中已讀字節(jié)數(shù),將應(yīng)讀寫的字節(jié)數(shù)len減去④中已讀字節(jié)數(shù),若len大于0,則轉(zhuǎn)②;否則轉(zhuǎn)⑥;
⑥ 使用free()釋放①中申請的buf。
⑦ 返回實際讀出的字節(jié)數(shù)。
16. 退出文件系統(tǒng)函數(shù)my_exitsys()
(1)對應(yīng)命令:my_exitsys
(2)命令調(diào)用格式:my_ exitsys
(1)函數(shù)設(shè)計格式:void my_exitsys()
(2)功能:退出文件系統(tǒng)。
(3)輸入:無
(4)輸出:無。
(5)函數(shù)需完成的工作:
① 使用C庫函數(shù)fopen()打開磁盤上的myfsys文件;
② 將虛擬磁盤空間中的所有內(nèi)容保存到磁盤上的myfsys文件中;
③ 使用c語言的庫函數(shù)fclose()關(guān)閉myfsys文件;
④ 撤銷用戶打開文件表,釋放其內(nèi)存空間
⑤ 釋放虛擬磁盤空間。
鏈接地址:http://m.appdesigncorp.com/p-6633329.html