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

歡迎訪問 生活随笔!

生活随笔

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

windows

模拟实现EXT2文件系统

發布時間:2023/12/15 windows 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模拟实现EXT2文件系统 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

設計EXT2文件系統

實驗目的

(1)掌握文件系統的工作原理

(2)理解文件系統的主要數據結構

(3)學習較為復雜的 Linux 下的編程

(4)了解 EXT2 文件系統的結構

實驗內容

設計并實現一個二級文件系統程序:

  • 提供以下操作:
    • 文件創建 / 刪除接口命令 touch / rm

    • 目錄創建 / 刪除接口命令 mkdir / rmdir

    • 顯示目錄內容命令 ls

    • 切換目錄命令 cd

    • 讀 / 寫文件命令 read / write

    • 更改文件權限命令 chmod

  • 創建的文件不要求格式和內容。

  • 具備提供用戶登錄的功能。

  • 文件、目錄要有權限。

  • 實驗步驟

    程序設計思想

    要求設計一個簡單的文件系統,它包含了格式化、顯示(文件)目錄、創建文件、登錄等幾個簡單命令的實現,而且能完成超級塊的讀寫、inode 的讀寫等過程,是一個比真正的文件系統簡單得多,而又能基本體現文件系統理論的程序。在超級塊的使用上,采用了操作系統關于這方面的經典理論;而在節點的使用上,主要是模仿 Linux 的 EXT2 文件系統。

    程序流程

    這是一個面向過程的程序,它的流程圖如下圖:

    文件系統的設計思想

    真正的文件系統,在涉及文件讀寫、文件創建等操作時,會用到內外存之間通信的語句。這些與底層硬件有關的編程一方面會給完整完成實驗的人員制造不小的麻煩,更為重要的是這些內容不屬于操作系統原理的范疇。因此本實驗所設計的文件系統程序與真正的文件系統在某些方面有著本質的不同。

    下表是一個大致的比較:

    實驗設計的文件系統真實文件系統
    二進制格式自定義系統文件格式
    依賴于其他操作系統不依賴于其他操作系統
    調用庫函數訪問外村調用中斷訪問外存

    實驗要求設計的文件系統使用一個二進制文件來模擬磁盤空間,該 “文件系統” 的所有用戶信息、inode 信息、超級塊信息、文件信息均以二進制方式保存在文件的特定地方,如下圖。

    設計文件系統的數據結構

    1)一些常量,根據上一步的圖設計

    #define VOLUME_NAME "EXT2FS" //卷名 #define BLOCK_SIZE 512 //塊大小 #define DISK_SIZE 4612 //磁盤總塊數#define DISK_START 0 //磁盤開始地址 #define SB_SIZE 32 //超級塊大小是32B#define GD_SIZE 32 //塊組描述符大小是32B #define GDT_START (0+512) //塊組描述符起始地址#define BLOCK_BITMAP (512+512) //塊位圖起始地址 2*512 #define INODE_BITMAP (1024+512) //inode 位圖起始地址 3*512#define INODE_TABLE (1536+512) //索引節點表起始地址 4*512 #define INODE_SIZE 64 //每個inode的大小是 64B #define INODE_TABLE_COUNTS 4096 //inode entry 數#define DATA_BLOCK 264192 //數據塊起始地址 4*512+4096*64 #define DATA_BLOCK_COUNTS 4096 //數據塊數#define BLOCKS_PER_GROUP 4612 //每組中的塊數#define USER_MAX 4 //用戶個數 #define FOPEN_TABLE_MAX 16 //文件打開表大小

    2)超級塊的數據結構

    struct super_block { // 32 Bchar sb_volume_name[16]; //文件系統名unsigned short sb_disk_size; //磁盤總大小unsigned short sb_blocks_per_group; // 每組中的塊數unsigned short sb_size_per_block; // 塊大小char sb_pad[10]; //填充 };

    3)組描述符的數據結構

    struct group_desc { // 32 Bchar bg_volume_name[16]; //文件系統名unsigned short bg_block_bitmap; //塊位圖的起始塊號unsigned short bg_inode_bitmap; //索引結點位圖的起始塊號unsigned short bg_inode_table; //索引結點表的起始塊號unsigned short bg_free_blocks_count; //本組空閑塊的個數unsigned short bg_free_inodes_count; //本組空閑索引結點的個數unsigned short bg_used_dirs_count; //組中分配給目錄的結點數char bg_pad[4]; //填充(0xff) };

    4)索引結點的數據結構

    struct inode { // 64 B = 6 * 2B + 5 * 4B + 16B + 16Bunsigned short i_mode; //文件類型及訪問權限unsigned short i_blocks; //文件所占的數據塊個數(0~7), 最大為7unsigned short i_uid; //文件擁有者標識號unsigned short i_gid; //文件的用戶組標識符unsigned short i_links_count; //文件的硬鏈接計數unsigned short i_flags; //打開文件的方式unsigned long i_size; //文件或目錄大小(單位 byte)unsigned long i_atime; //訪問時間unsigned long i_ctime; //創建時間unsigned long i_mtime; //修改時間unsigned long i_dtime; //刪除時間unsigned short i_block[8]; //直接索引方式 指向數據塊號char i_pad[16]; //填充(0xff) };

    5)目錄項入口的數據結構

    struct dir_entry { // 16 Bunsigned short inode; //索引節點號unsigned short rec_len; //目錄項長度unsigned short name_len; //文件名長度char file_type; //文件類型(1 普通文件 2 目錄.. )char name[9]; //文件名 };

    6)用戶信息的數據結構

    struct user {char username[10];char password[10];unsigned short u_uid; //用戶標識號unsigned short u_gid; }User[USER_MAX];

    文件系統實現的功能函數

    extern void initialize_user(); //初始化用戶 extern int login(char username[10], char password[10]); //用戶登錄 extern void initialize_memory(); //初始化內存 extern void format(); //格式化文件系統 extern void cd(char tmp[100]); //進入某個目錄,實際上是改變當前路徑 extern void mkdir(char tmp[100], int type); //創建目錄 extern void cat(char tmp[100], int type); //創建文件 extern void rmdir(char tmp[100]); //刪除一個空目錄 extern void del(char tmp[100]); //刪除文件 extern void open_file(char tmp[100]); //打開文件 extern void close_file(char tmp[100]); //關閉文件 extern void read_file(char tmp[100]); //讀文件內容 extern void write_file(char tmp[100]); //文件以覆蓋方式寫入 extern void ls(); //查看目錄下的內容 extern void check_disk(); //檢查磁盤狀態 extern void help(); //查看指令 extern void chmod(char tmp[100], unsigned short mode); //修改文件權限

    一些讀寫方法的處理

    進行超級塊、組描述符、位圖、inode 節點、數據塊的讀寫時,需要用到一些緩沖區,定義如下:

    static struct super_block sb_block[1]; // 超級塊緩沖區 static struct group_desc gdt[1]; // 組描述符緩沖區 static struct inode inode_area[1]; // inode緩沖區 static unsigned char bitbuf[512] = {0}; // block位圖緩沖區 static unsigned char ibuf[512] = {0}; // inode位圖緩沖區 static struct dir_entry dir[32]; // 目錄項緩沖區 32*16=512 static char Buffer[BLOCK_SIZE]; // 針對數據塊的緩沖區

    1)讀寫超級塊

    // 寫超級塊 static void update_super_block() {fp = fopen("./Ext2", "rb+");fseek(fp, DISK_START, SEEK_SET);fwrite(sb_block, SB_SIZE, 1, fp);fflush(fp); //立刻將緩沖區的內容輸出,保證磁盤內存數據的一致性 }// 讀超級塊 static void reload_super_block() {fseek(fp, DISK_START, SEEK_SET);fread(sb_block, SB_SIZE, 1, fp);//讀取內容到超級塊緩沖區中 }

    先定位文件內部位置指針的位置,超級塊的起始位置在前面步驟的分析圖中已給出,再進行塊的讀寫,其中定位文件內部位置指針用到的庫函數為 int fseek(FILE *stream, long offset, int fromwhere)。同時在寫完后用庫函數 int fflush(FILE *stream) 清除讀寫緩沖區。

    2)讀寫組描述符

    // 寫組描述符 static void update_group_desc() {fp = fopen("./Ext2", "rb+");fseek(fp, GDT_START, SEEK_SET);fwrite(gdt, GD_SIZE, 1, fp);fflush(fp); }// 讀組描述符 static void reload_group_desc() {fseek(fp, GDT_START, SEEK_SET);fread(gdt, GD_SIZE, 1, fp); }

    組描述符的起始位置同樣在前面步驟的分析圖中已給出。

    3)讀寫塊位圖

    // 寫 block 位圖 static void update_block_bitmap() {fp = fopen("./Ext2", "rb+");fseek(fp, BLOCK_BITMAP, SEEK_SET);fwrite(bitbuf, BLOCK_SIZE, 1, fp);fflush(fp); }// 讀 block 位圖 static void reload_block_bitmap() {fseek(fp, BLOCK_BITMAP, SEEK_SET);fread(bitbuf, BLOCK_SIZE, 1, fp); }

    4)讀寫 inode 位圖

    // 寫 inode 位圖 static void update_inode_bitmap() {fp = fopen("./Ext2", "rb+");fseek(fp, INODE_BITMAP, SEEK_SET);fwrite(ibuf, BLOCK_SIZE, 1, fp);fflush(fp); }// 讀 inode 位圖 static void reload_inode_bitmap() {fseek(fp, INODE_BITMAP, SEEK_SET);fread(ibuf, BLOCK_SIZE, 1, fp); }

    5)讀寫第 i 個 inode

    // 寫第 i 個 inode static void update_inode_entry(unsigned short i) {fp = fopen("./Ext2", "rb+");fseek(fp, INODE_TABLE + (i - 1) * INODE_SIZE, SEEK_SET);fwrite(inode_area, INODE_SIZE, 1, fp);fflush(fp); }// 讀第 i 個 inode static void reload_inode_entry(unsigned short i) {fseek(fp, INODE_TABLE + (i - 1) * INODE_SIZE, SEEK_SET);fread(inode_area, INODE_SIZE, 1, fp); }

    6)讀寫第 i 個數據塊

    // 寫第 i 個數據塊 static void update_dir(unsigned short i) {fp = fopen("./Ext2", "rb+");fseek(fp, DATA_BLOCK + i * BLOCK_SIZE, SEEK_SET);fwrite(dir, BLOCK_SIZE, 1, fp);fflush(fp); }// 讀第 i 個數據塊 static void reload_dir(unsigned short i) {fseek(fp, DATA_BLOCK + i * BLOCK_SIZE, SEEK_SET);fread(dir, BLOCK_SIZE, 1, fp); }

    內存的查找、分配、刪除等方法

    1)分配數據塊

    // 分配一個數據塊,返回數據塊號 static int alloc_block() {//bitbuf共有512個字節,表示4096個數據塊。根據last_alloc_block/8計算它在bitbuf的哪一個字節unsigned short cur = last_alloc_block;unsigned char con = 128; // 1000 0000bint flag = 0;if (gdt[0].bg_free_blocks_count == 0) {printf("There is no block to be allocated!\n");return (0);}reload_block_bitmap();cur /= 8;while (bitbuf[cur] == 255) { //該字節的8個bit都已有數據if (cur == 511)cur = 0; //最后一個字節也已經滿,從頭開始尋找elsecur++;}while (bitbuf[cur] & con) { //在一個字節中找具體的某一個bitcon = con / 2;flag++;}bitbuf[cur] = bitbuf[cur] + con;last_alloc_block = cur * 8 + flag;update_block_bitmap();gdt[0].bg_free_blocks_count--;update_group_desc();return last_alloc_block; }

    2)分配 inode

    // 分配一個 inode static int get_inode() {unsigned short cur = last_alloc_inode;unsigned char con = 128;int flag = 0;if (gdt[0].bg_free_inodes_count == 0) {printf("There is no Inode to be allocated!\n");return 0;}reload_inode_bitmap();cur = (cur - 1) / 8; //第一個標號是1,但是存儲是從0開始的while (ibuf[cur] == 255) { //先看該字節的8個位是否已經填滿if (cur == 511)cur = 0;elsecur++;}while (ibuf[cur] & con) { //再看某個字節的具體哪一位沒有被占用con = con / 2;flag++;}ibuf[cur] = ibuf[cur] + con;last_alloc_inode = cur * 8 + flag + 1;update_inode_bitmap();gdt[0].bg_free_inodes_count--;update_group_desc();return last_alloc_inode; }

    3)查找文件或目錄

    // 查找當前目錄中名為tmp的文件或目錄,并得到該文件的inode號,它在上級目錄中的數據塊號以及數據塊中目錄的項號 static unsigned short research_file(char tmp[100], int file_type, unsigned short *inode_num,unsigned short *block_num, unsigned short *dir_num) {unsigned short j, k;reload_inode_entry(current_dir); //進入當前目錄j = 0;while (j < inode_area[0].i_blocks) {reload_dir(inode_area[0].i_block[j]);k = 0;while (k < 32) {if (!dir[k].inode || dir[k].file_type != file_type || strcmp(dir[k].name, tmp)) {k++;}else {*inode_num = dir[k].inode;*block_num = j;*dir_num = k;return 1;}}j++;}return 0; }

    4)為新增目錄或文件分配 dir_entry

    // 為新增目錄或文件分配 dir_entry // 對于新增文件,只需分配一個 inode 號 // 對于新增目錄,除了 inode 號外,還需要分配數據區存儲.和..兩個目錄項 static void dir_prepare(unsigned short tmp, unsigned short len, int type) {reload_inode_entry(tmp);if (type == 2) { // 目錄inode_area[0].i_size = 32;inode_area[0].i_blocks = 1;inode_area[0].i_block[0] = alloc_block();dir[0].inode = tmp;dir[1].inode = current_dir;dir[0].name_len = len;dir[1].name_len = current_dirlen;dir[0].file_type = dir[1].file_type = 2;for (type = 2; type < 32; type++)dir[type].inode = 0;strcpy(dir[0].name, ".");strcpy(dir[1].name, "..");update_dir(inode_area[0].i_block[0]);inode_area[0].i_mode = 01006;}else {inode_area[0].i_size = 0;inode_area[0].i_blocks = 0;inode_area[0].i_mode = 0407;}update_inode_entry(tmp); }

    5)刪除一個塊

    // 刪除一個塊 static void remove_block(unsigned short del_num) {unsigned short tmp;tmp = del_num / 8;reload_block_bitmap();switch (del_num % 8) { // 更新block位圖 將具體的位置為0case 0:bitbuf[tmp] = bitbuf[tmp] & 127;break; // bitbuf[tmp] & 0111 1111bcase 1:bitbuf[tmp] = bitbuf[tmp] & 191;break; //bitbuf[tmp] & 1011 1111bcase 2:bitbuf[tmp] = bitbuf[tmp] & 223;break; //bitbuf[tmp] & 1101 1111bcase 3:bitbuf[tmp] = bitbuf[tmp] & 239;break; //bitbuf[tmp] & 1110 1111bcase 4:bitbuf[tmp] = bitbuf[tmp] & 247;break; //bitbuf[tmp] & 1111 0111bcase 5:bitbuf[tmp] = bitbuf[tmp] & 251;break; //bitbuf[tmp] & 1111 1011bcase 6:bitbuf[tmp] = bitbuf[tmp] & 253;break; //bitbuf[tmp] & 1111 1101bcase 7:bitbuf[tmp] = bitbuf[tmp] & 254;break; // bitbuf[tmp] & 1111 1110b}update_block_bitmap();gdt[0].bg_free_blocks_count++;update_group_desc(); }

    6)刪除一個 inode

    // 刪除一個 inode static void remove_inode(unsigned short del_num) {unsigned short tmp;tmp = (del_num - 1) / 8;reload_inode_bitmap();switch ((del_num - 1) % 8) { //更改block位圖case 0:bitbuf[tmp] = bitbuf[tmp] & 127;break;case 1:bitbuf[tmp] = bitbuf[tmp] & 191;break;case 2:bitbuf[tmp] = bitbuf[tmp] & 223;break;case 3:bitbuf[tmp] = bitbuf[tmp] & 239;break;case 4:bitbuf[tmp] = bitbuf[tmp] & 247;break;case 5:bitbuf[tmp] = bitbuf[tmp] & 251;break;case 6:bitbuf[tmp] = bitbuf[tmp] & 253;break;case 7:bitbuf[tmp] = bitbuf[tmp] & 254;break;}update_inode_bitmap();gdt[0].bg_free_inodes_count++;update_group_desc(); }

    7)在打開文件表中查找是否已打開某個文件

    // 在打開文件表中查找是否已打開文件 static unsigned short search_file(unsigned short Inode) {unsigned short fopen_table_point = 0;while (fopen_table_point < 16 && fopen_table[fopen_table_point++] != Inode);if (fopen_table_point == 16) {return 0;}return 1; }

    程序編譯運行

    代碼編寫完成后,共有4個文件,源碼見附件。

    把代碼文件上傳到 openEuler 操作系統(本實驗采用 openEuler,當然其他操作系統也可以)中,使用命令 gcc main.c init.c –o ext2 進行編譯鏈接:

    編譯鏈接成功,得到可執行文件 ext2,下面開始進行運行測試:

    鍵入 ./ext2 運行可執行文件,效果圖如下:

    這是簡易的登錄界面,輸入內置的用戶名 test 和密碼 test,登錄成功,程序開始安裝文件系統并執行初始化:

    這時我們使用 quit 命令退出程序,然后查看當前目錄,發現多了一個 Ext2 文件,這是被程序創建出來的二進制文件,用于模擬磁盤空間。

    然后再次進入文件系統,登錄,我們發現這次程序沒有再進行文件系統的安裝和初始化等工作,這是因為每次進入文件系統時,程序會檢查文件系統是否存在,不存在時才會創建。

    下面我們開始測試程序功能:

    1)ls 功能,成功

    2)mkdir 創建目錄,成功

    3)touch 創建文件,成功

    4)cd 功能進入目錄 dir,創建文件,也成功

    可以發現使用 cd 切換目錄時,目錄的變化在 @ 字符后顯示了。

    5)rm 刪除 dir 目錄下的文件 file,成功

    6)返回主目錄中,刪除 dir 文件夾,成功

    7)輸入 help 顯示指令幫助信息,或輸入一個錯誤指令,文件系統自動輸出指令幫助,成功

    8)write 向file文件中寫一些信息,系統會提示還未打開文件

    打開文件 file 后,再次執行寫命令向 file 寫入信息,以 # 結束,成功,我們發現向 file 文件寫入信息后,file 文件的大小變為了 33bytes

    9)read ,下面讀取 file 文件中的信息,上一步寫入的信息都被讀出來了,然后關閉 file 文件,成功

    10)改變 file 文件的權限,權限的表示方式為二進制 111b,最高位表示讀權限,第二位表示寫權限,最低位表示執行權限,1 表示有權限,0 表示無權限。先查看當前 file 文件的權限,為 111b

    然后我們把 file 的權限改為 011b(十進制為3),即沒有讀權限

    可以看到現在 file 文件已經沒有讀權限了,再次嘗試讀取 file 文件中的內容,被文件系統阻止,并提示 file 文件不能讀。

    11)測試檢查磁盤狀態功能,成功

    12)測試格式化文件系統功能,發現文件系統中所有文件已被格式化,成功

    13)退出文件系統,成功

    心得體會

    通過本次設計并實現 ext2 文件系統,我對 ext2 文件系統的思想、結構、設計方式有了深入的了解,在實現的過程中,也對一些用到的函數掌握程度更深入,比如 fopen,fseek,fwrite,fread,fflush 等函數,總的來說,這次實驗讓我收獲頗豐。

    文中代碼不完整,想要完整代碼可自行下載。
    https://download.csdn.net/download/qq_43791817/19571431

    總結

    以上是生活随笔為你收集整理的模拟实现EXT2文件系统的全部內容,希望文章能夠幫你解決所遇到的問題。

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