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