操作系统实验——简易FAT16文件系统的实现
操作系統(tǒng)實(shí)驗(yàn)——簡(jiǎn)易FAT16文件系統(tǒng)的實(shí)現(xiàn)
- 前言
- 實(shí)驗(yàn)要求
- FAT16基礎(chǔ)知識(shí)
- 磁盤組成部分
- 分區(qū)原理
- 思路
- 完整代碼
前言
暑假啦!呼,所有的補(bǔ)課終于也都結(jié)束了,雖然績(jī)點(diǎn)還是一如既往的拉跨,但是很慶幸自己還是熬過來了,唯一有點(diǎn)小遺憾的是信安大賽沒能進(jìn)入到?jīng)Q賽,有點(diǎn)小可惜吧但也在意料之中,雖然盡力了但一個(gè)月準(zhǔn)備的作品哪能有別人準(zhǔn)備了那么久的作品成熟呢。好了回到正題,這是一個(gè)非常非常簡(jiǎn)陋的文件系統(tǒng),也是在考試月最后的一個(gè)大實(shí)驗(yàn),所以也是緊趕慢趕。接下來介紹一下代碼思路,最后也會(huì)給出完整代碼。
實(shí)驗(yàn)要求
實(shí)現(xiàn)一個(gè)簡(jiǎn)單的類 FAT-16 文件系統(tǒng),具有以下功能(不要求全
部完成):mkdir,ls,delete,open,read,write,close 系統(tǒng)是基于內(nèi)存的:
建立一個(gè)數(shù)組:
#define DISK_MAXLEN 2560
char Disk[DISK_MAXLEN];
把這個(gè)數(shù)組當(dāng)成硬盤,實(shí)現(xiàn)文件系統(tǒng)。假設(shè)只有一個(gè)進(jìn)程使用。
FAT16基礎(chǔ)知識(shí)
磁盤組成部分
MBR(master boot record)位于硬盤的第一個(gè)扇區(qū),bios 在執(zhí)行自
己固有的程序以后就會(huì)進(jìn)入到 mbr 中的第一條指令,MBR 分為兩部
分:引導(dǎo)代碼和 DPT(硬盤分區(qū)表)。在 DPT 共 64 個(gè)字節(jié)中,以 16
個(gè)字節(jié)為分區(qū)表項(xiàng)單位描述一個(gè)分區(qū)的屬性。第一個(gè)分區(qū)表項(xiàng)描述一
個(gè)分區(qū)的屬性,一般為基本分區(qū)。第二個(gè)分區(qū)表項(xiàng)描述除基本分區(qū)外
的其余空間,一般而言,是擴(kuò)展分區(qū)。總的來說 MBR 的功能是描述
分區(qū)屬性的,本次實(shí)驗(yàn)之劃分為一個(gè)分區(qū),所以這部分不做考慮。
其余還有保留扇區(qū),一般為 62 個(gè)。第一個(gè)分區(qū),一般為活動(dòng)分區(qū)。
如果磁盤分了多個(gè)分區(qū),則有第二個(gè)分區(qū) DPT 和保留扇區(qū)等。
分區(qū)原理
1)DBR 區(qū)(DOS BOOT RECORD)即操作系統(tǒng)引導(dǎo)記錄區(qū)
通常占用 512 字節(jié),由跳轉(zhuǎn)指令、廠商標(biāo)志、操作系統(tǒng)版本號(hào)、
BPB(BIOS Parameter Block)、擴(kuò)展 BPB、os 引導(dǎo)程序、結(jié)束標(biāo)志幾部
分組成。下如下圖所示,前三個(gè)字節(jié)為跳轉(zhuǎn)指令,之后 8 個(gè)字節(jié)為廠
商標(biāo)志和操作系統(tǒng)版本號(hào),之后被選中的 53 個(gè)字節(jié)為 BPB,之后的
代碼為擴(kuò)展 BPB,引導(dǎo)程序代碼,結(jié)束標(biāo)志(55AA)。
其中 BPB 部分存放了許多重要信息,本次實(shí)驗(yàn)中的 DBR 區(qū)也簡(jiǎn)化
成了只有 BPB 的部分信息,通常存放扇區(qū)字節(jié)數(shù)、一個(gè)字節(jié)為每個(gè)
簇的扇區(qū)數(shù)、保留扇區(qū)數(shù)、FAT 數(shù)、根目錄項(xiàng)數(shù)、每個(gè) FAT 表的扇區(qū)
數(shù)、每道扇區(qū)數(shù)、磁頭數(shù)、隱藏扇區(qū)數(shù)等
2)FAT
為了解決鏈表的不足,在鏈表的基礎(chǔ)上取出每個(gè)磁盤塊的指針字,
把它們放在內(nèi)存的一個(gè)表中,相應(yīng)的表格稱為文件分配表。每個(gè)目錄
項(xiàng)通常存放的是磁盤塊的信息,如空閑、下一個(gè)和最后。
3)目錄
目錄區(qū)中的記錄項(xiàng)以32字節(jié)為單位,這32個(gè)字節(jié)的內(nèi)容如下表所示,
根據(jù)文件的首簇號(hào)去 FAT 表中尋找文件的下一個(gè)部分,以此類推,以
鏈表的形式將文件不連續(xù)存儲(chǔ)。
思路
根據(jù)實(shí)驗(yàn)要求虛擬磁盤空間為一個(gè) char 數(shù)組 Disk,最大值為2560。考慮磁盤空間和文件數(shù),選取了 32B 為一個(gè)簇,則 fat 表項(xiàng)最多有 80 個(gè)(其實(shí)達(dá)不到,因?yàn)橛幸徊糠忠纸o DBR 等)。定義結(jié)構(gòu)體 fcb,主要去存儲(chǔ)當(dāng)前文件在磁盤塊中開始存儲(chǔ)的盤塊號(hào)。定義結(jié)構(gòu)體目錄項(xiàng),去存儲(chǔ)文件名、類型、fat 開始的索引號(hào)、fcb開始的索引號(hào)、目錄項(xiàng)列表開始的索引號(hào),這體現(xiàn)了本次實(shí)驗(yàn)最重要的思想就是通過文件名找到目錄項(xiàng),再通過目錄項(xiàng)找到 fat,fcb 和目錄項(xiàng)列表所在的位置。定義結(jié)構(gòu)體目錄項(xiàng)列表,去存儲(chǔ)目錄個(gè)數(shù),以及維護(hù)一個(gè)目錄結(jié)構(gòu)體數(shù)組。定義全局變量根目錄、當(dāng)前目錄和絕對(duì)路徑。
創(chuàng)建文件。本實(shí)驗(yàn)思想是將文件和目錄均當(dāng)成文件,所以在創(chuàng)建中只使用一個(gè)函數(shù),除了類型名不同以外,目錄還需要維護(hù)一個(gè)目錄項(xiàng)列表。創(chuàng)建過程中需要添加目錄項(xiàng)、創(chuàng)建 fcb、創(chuàng)建 fat 等。
刪除文件。刪除文件前需要先判斷是否存在這一個(gè)文件,然后刪除目錄、釋放 fat 即可、清空磁盤數(shù)據(jù)。
展示目錄下的文件。因?yàn)槊總€(gè)目錄都維護(hù)了一個(gè)目錄項(xiàng)列表,所以可以直接遍歷目錄項(xiàng)列表數(shù)組找到每一個(gè)文件,輸出文件名。進(jìn)入下一級(jí)目錄。遍歷所在的目錄下的文件找到對(duì)應(yīng)的下一級(jí)目錄,修改當(dāng)前目錄。
讀文件。得到用戶輸入的文件名和讀取數(shù)據(jù)的長(zhǎng)度,找到對(duì)應(yīng)的fcb 索引,通過 fcb 找到開始的磁盤塊輸出即可。
寫文件。與讀文件操作類似,但需要根據(jù)讀入的數(shù)據(jù)修改 fat 和更新 filesize。有些模擬的文件系統(tǒng)選擇一開始就分配好固定的簇,但是我選擇了一種動(dòng)態(tài)分配的策略。
完整代碼
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> using namespace std;const int DISK_MAXLEN = 2560; const int dirtable_max_size = 80; const int fatnum = 80; char Disk[DISK_MAXLEN]; int dbr[2]; int startindex;void init(); void createfile(char filename[], int filesize, int type); void adddirunit(char fileName[], int type); int findunit(char filename[]); void ls(); void deletefile(char filename[]); void deleteunit(int unitindex); short findfreefat(); void freefat(char filename[]); void changedir(char dirname[]); void read(char filename[], int length); void write(char filename[], char content[]); void adjustfat(short num, int unitindex);struct fcb {short blockindex;//which is blockshort filesize;short datasize; };struct dirunit {char filename[80];char type;short startfat;short startfcb;short startdir; };struct dirtable {int dirunitnum;dirunit dirs[dirtable_max_size]; };short fat[fatnum]; //free:0 last:-1 next:id dirtable* table[10]; fcb* FCB[fatnum];dirtable rootdirtable; dirtable* currentdirtable; char path[100] = "C:\\root\\";void init() {rootdirtable.dirunitnum = 0;currentdirtable = &rootdirtable;//8B has been allocateddbr[0] = fatnum;dbr[1] = dirtable_max_size;//B_num that allocated to fat tableint fat_B = fatnum * sizeof(short);//calculate startindex of datastartindex = 8 + fatnum; }/* struct fcb{int blockindex;int filesize;int datasize; };*/int FCBrecord = 0; //record current index of fcb when creating int TABrecord = 0; //record current index of dir table when creating void createfile(char filename[], int filesize, int type) {if (strlen(filename) > 80) {cout << "file name is too long" << endl;return;}//add diradddirunit(filename, type);int index = findunit(filename);//create fcbfcb* curfcb = (fcb*)new fcb();curfcb->blockindex = startindex++;curfcb->filesize = filesize;curfcb->datasize = 0;//nothing is writedFCB[FCBrecord] = curfcb;currentdirtable->dirs[index].startfcb = FCBrecord;//create fatint i = findfreefat();currentdirtable->dirs[index].startfat = i;fat[i] = -1;//create dirif (type == 0) {dirtable* curdirtable = (dirtable*)new dirtable();table[TABrecord] = curdirtable;curdirtable->dirunitnum = 0;currentdirtable->dirs[index].startdir = TABrecord;} }/* struct dirunit{char filename[80];char type;int startfat; };struct dirtable{int dirunitnum;dirunit dirs[dirtable_max_size]; };*/void adddirunit(char filename[], int type) {int dirunitnum = currentdirtable->dirunitnum;//whether is fullif (dirunitnum == dirtable_max_size){cout << "dirTables is full, try to delete some file\n";return;}//whether is existedif (findunit(filename) != -1){printf("file already exist\n");return;}//creater new dirunitdirunit* newdirunit = ¤tdirtable->dirs[dirunitnum];currentdirtable->dirunitnum++;int i = strlen(filename);while (i--)newdirunit->filename[i] = filename[i];newdirunit->type = type;return; }int findunit(char filename[]) {//look up in orderint dirunitnum = currentdirtable->dirunitnum;int unitIndex = -1;for (int i = 0; i < dirunitnum; i++)if (strcmp(filename, currentdirtable->dirs[i].filename) == 0)unitIndex = i;return unitIndex; }void ls() {int uninum = currentdirtable->dirunitnum;for (int i = 0; i < uninum; i++) {dirunit curunit = currentdirtable->dirs[i];cout << curunit.filename << " ";}cout << endl; }void deletefile(char filename[]) {int unitindex = findunit(filename);if (unitindex == -1) {cout << "sorry,not found" << endl;return;}//delete unit in the tabledeleteunit(unitindex);freefat(filename); }void deleteunit(int unitindex) {//let the next item covers int dirunitnum = currentdirtable->dirunitnum;for (int i = unitindex; i < dirunitnum - 1; i++) {currentdirtable->dirs[i] = currentdirtable->dirs[i + 1];}currentdirtable->dirunitnum--; }short findfreefat() {for (short i = 0; i < fatnum; i++) {if (fat[i] == 0)return i;} }void freefat(char filename[]) {//find the link in fat and free each of itint i = currentdirtable->dirs[findunit(filename)].startfat;if (i == -1) {fat[i] = 0;return;}while (i == -1) {int temp = i;i = fat[i];fat[temp] = 0;}if (i == -1) {fat[i] = 0;return;} }void changedir(char dirname[]) {//see whether the name is validint unitindex = findunit(dirname);if (unitindex == -1) {cout << "sorry,not found" << endl;return;}if (currentdirtable->dirs[unitindex].type == 1) {cout << "not a dir" << endl;return;}//change currentdirint i = currentdirtable->dirs[unitindex].startdir;currentdirtable = table[i];//change pathif (strcmp(dirname, "..") == 0) {//rebackint length = strlen(path);for (int i = length - 2; i >= 0; i--) {if (path[i] == '\\') {path[i + 1] = '\0';break;}}}else {strcat_s(path, dirname);strcat_s(path, "\\");} }void read(char filename[], int length) {int unitindex = findunit(filename);if (unitindex == -1) {cout << "sorry,not found" << endl;return;}//read the data of given length int index = currentdirtable->dirs[unitindex].startfcb;fcb* myfcb = FCB[index];for (int i = 0; i < length; i++) {cout << Disk[i + myfcb->blockindex];}cout << endl; }void write(char filename[], char content[]) {int unitindex = findunit(filename);if (unitindex == -1) {cout << "sorry,not found" << endl;return;}int length = sizeof(content);//how many clusters needint num = (length % 32 == 0) ? length / 32 : length / 32 + 1;adjustfat(num, unitindex);//renew the filesizeFCB[currentdirtable->dirs[unitindex].startfcb]->filesize = num;//get the start index and write the content in orderint index = currentdirtable->dirs[unitindex].startfcb;fcb* myfcb = FCB[index];for (int i = 0; i < length; i++) {Disk[i + myfcb->blockindex] = content[i];}cout << endl;}void adjustfat(short num, int unitindex) {int index = currentdirtable->dirs[unitindex].startfat;for (int i = 0; i < num - 1; i++) {short j = findfreefat();fat[index] = j;index = j;}fat[index] = -1; }int main() {init();string s;char name[80] = { 0 };char content[100] = { 0 };int length = 0;for (int i = 0; i < 35; i++)cout << '*';cout << endl;cout << "you can do the operation as follows" << endl;cout << "1.mkdir+dirname\n2.vi+filename\n3.ls\n4.cd+dirname\n5.read+filename+length\n6.write+filename+data\n7.delete+filename\n8.quit" << endl;for (int i = 0; i < 35; i++)cout << '*';cout << endl;while (1) {int i = strlen(path);int j = 0;while (j < i) {cout << path[j];j++;}cout << '>';char operation[5];char op = getchar();if (op == '\n')continue;cin >> s;memcpy(operation, s.c_str(), s.length());switch (op) {case 'q':return 0;case 'm':cin >> s;memcpy(name, s.c_str(), s.length());createfile(name, 1, 0);getchar();break;case 'v':cin >> s;memcpy(name, s.c_str(), s.length());createfile(name, 1, 1);getchar();break;case 'l':ls(); getchar(); break;case 'c':cin >> s;memcpy(name, s.c_str(), s.length());changedir(name);getchar();break;case 'r':cin >> s;memcpy(name, s.c_str(), s.length());scanf_s("%d", &length);read(name, length);getchar();break;case 'w':cin >> s;memcpy(name, s.c_str(), s.length());cin >> s;memcpy(content, s.c_str(), s.length());write(name, content);getchar();break;case 'd':cin >> s;memcpy(name, s.c_str(), s.length());deletefile(name);getchar();break;}} } 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的操作系统实验——简易FAT16文件系统的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STL体系结构
- 下一篇: [力扣leetcode39]组合总和及回