操作系统实验——简易FAT16文件系统的实现
操作系統實驗——簡易FAT16文件系統的實現
- 前言
- 實驗要求
- FAT16基礎知識
- 磁盤組成部分
- 分區原理
- 思路
- 完整代碼
前言
暑假啦!呼,所有的補課終于也都結束了,雖然績點還是一如既往的拉跨,但是很慶幸自己還是熬過來了,唯一有點小遺憾的是信安大賽沒能進入到決賽,有點小可惜吧但也在意料之中,雖然盡力了但一個月準備的作品哪能有別人準備了那么久的作品成熟呢。好了回到正題,這是一個非常非常簡陋的文件系統,也是在考試月最后的一個大實驗,所以也是緊趕慢趕。接下來介紹一下代碼思路,最后也會給出完整代碼。
實驗要求
實現一個簡單的類 FAT-16 文件系統,具有以下功能(不要求全
部完成):mkdir,ls,delete,open,read,write,close 系統是基于內存的:
建立一個數組:
#define DISK_MAXLEN 2560
char Disk[DISK_MAXLEN];
把這個數組當成硬盤,實現文件系統。假設只有一個進程使用。
FAT16基礎知識
磁盤組成部分
MBR(master boot record)位于硬盤的第一個扇區,bios 在執行自
己固有的程序以后就會進入到 mbr 中的第一條指令,MBR 分為兩部
分:引導代碼和 DPT(硬盤分區表)。在 DPT 共 64 個字節中,以 16
個字節為分區表項單位描述一個分區的屬性。第一個分區表項描述一
個分區的屬性,一般為基本分區。第二個分區表項描述除基本分區外
的其余空間,一般而言,是擴展分區。總的來說 MBR 的功能是描述
分區屬性的,本次實驗之劃分為一個分區,所以這部分不做考慮。
其余還有保留扇區,一般為 62 個。第一個分區,一般為活動分區。
如果磁盤分了多個分區,則有第二個分區 DPT 和保留扇區等。
分區原理
1)DBR 區(DOS BOOT RECORD)即操作系統引導記錄區
通常占用 512 字節,由跳轉指令、廠商標志、操作系統版本號、
BPB(BIOS Parameter Block)、擴展 BPB、os 引導程序、結束標志幾部
分組成。下如下圖所示,前三個字節為跳轉指令,之后 8 個字節為廠
商標志和操作系統版本號,之后被選中的 53 個字節為 BPB,之后的
代碼為擴展 BPB,引導程序代碼,結束標志(55AA)。
其中 BPB 部分存放了許多重要信息,本次實驗中的 DBR 區也簡化
成了只有 BPB 的部分信息,通常存放扇區字節數、一個字節為每個
簇的扇區數、保留扇區數、FAT 數、根目錄項數、每個 FAT 表的扇區
數、每道扇區數、磁頭數、隱藏扇區數等
2)FAT
為了解決鏈表的不足,在鏈表的基礎上取出每個磁盤塊的指針字,
把它們放在內存的一個表中,相應的表格稱為文件分配表。每個目錄
項通常存放的是磁盤塊的信息,如空閑、下一個和最后。
3)目錄
目錄區中的記錄項以32字節為單位,這32個字節的內容如下表所示,
根據文件的首簇號去 FAT 表中尋找文件的下一個部分,以此類推,以
鏈表的形式將文件不連續存儲。
思路
根據實驗要求虛擬磁盤空間為一個 char 數組 Disk,最大值為2560。考慮磁盤空間和文件數,選取了 32B 為一個簇,則 fat 表項最多有 80 個(其實達不到,因為有一部分要分給 DBR 等)。定義結構體 fcb,主要去存儲當前文件在磁盤塊中開始存儲的盤塊號。定義結構體目錄項,去存儲文件名、類型、fat 開始的索引號、fcb開始的索引號、目錄項列表開始的索引號,這體現了本次實驗最重要的思想就是通過文件名找到目錄項,再通過目錄項找到 fat,fcb 和目錄項列表所在的位置。定義結構體目錄項列表,去存儲目錄個數,以及維護一個目錄結構體數組。定義全局變量根目錄、當前目錄和絕對路徑。
創建文件。本實驗思想是將文件和目錄均當成文件,所以在創建中只使用一個函數,除了類型名不同以外,目錄還需要維護一個目錄項列表。創建過程中需要添加目錄項、創建 fcb、創建 fat 等。
刪除文件。刪除文件前需要先判斷是否存在這一個文件,然后刪除目錄、釋放 fat 即可、清空磁盤數據。
展示目錄下的文件。因為每個目錄都維護了一個目錄項列表,所以可以直接遍歷目錄項列表數組找到每一個文件,輸出文件名。進入下一級目錄。遍歷所在的目錄下的文件找到對應的下一級目錄,修改當前目錄。
讀文件。得到用戶輸入的文件名和讀取數據的長度,找到對應的fcb 索引,通過 fcb 找到開始的磁盤塊輸出即可。
寫文件。與讀文件操作類似,但需要根據讀入的數據修改 fat 和更新 filesize。有些模擬的文件系統選擇一開始就分配好固定的簇,但是我選擇了一種動態分配的策略。
完整代碼
#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;}} } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的操作系统实验——简易FAT16文件系统的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STL体系结构
- 下一篇: [力扣leetcode39]组合总和及回