操作系统实验——简易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 = &currentdirtable->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;}}
}

操作系统实验——简易FAT16文件系统的实现相关推荐

  1. 广州大学2020操作系统实验四:文件系统

    相关资料 广州大学2020操作系统实验一:进程管理与进程通信 广州大学2020操作系统实验二:银行家算法 广州大学2020操作系统实验三:内存管理 广州大学2020操作系统实验四:文件系统 广州大学2 ...

  2. 哈工大操作系统实验——实现proc文件系统

    哈工大操作系统实验--实现proc文件系统 参考文章: 操作系统实验08-proc文件系统的实现 在 Linux 0.11 上实现 procfs(proc 文件系统)内的 psinfo 结点.当读取此 ...

  3. 操作系统实验四:文件系统

    一.实验目的 1.熟悉Linux文件系统的文件和目录结构,掌握Linux文件系统的基本特征: 2.模拟实现Linux文件系统的简单I/O流操作:备份文件. 二.实验环境 Linux系统 三.实验内容 ...

  4. 广州大学2020操作系统实验二:银行家算法

    相关资料 广州大学2020操作系统实验一:进程管理与进程通信 广州大学2020操作系统实验二:银行家算法 广州大学2020操作系统实验三:内存管理 广州大学2020操作系统实验四:文件系统 广州大学2 ...

  5. 广州大学2020操作系统实验一:进程管理与进程通信

    相关资料 广州大学2020操作系统实验一:进程管理与进程通信 广州大学2020操作系统实验二:银行家算法 广州大学2020操作系统实验三:内存管理 广州大学2020操作系统实验四:文件系统 广州大学2 ...

  6. 操作系统实验 C语言实现仿写简易文件系统 北XX大 NXXT

    操作系统实验 C语言实现 北XX大 懂得都懂 实验题目 结果展示 实现代码 实验题目 实验目的 通过一个简单多用户文件系统设计,加深理解文件系统的内部功能及实现. 实验内容 为Unix/Linux 系 ...

  7. 吉林大学操作系统上机(实验四:文件系统——Hash结构文件)

    实验四:文件系统--Hash结构文件 实验目的 1.理解Linux文件系统的内部技术,掌握Linux与文件有关的系统调用命令,并在此基础上建立面向随机检索的hash结构文件. 2.Linux系统保持U ...

  8. 【操作系统】简易文件系统设计

    [操作系统] 简易文件系统 这个是本学期最后一次的操作系统实验,个人觉得做得还行,故写篇博客分享一下. 实验要求 创建一个100M的文件或者创建一个100M的共享内存 尝试自行设计一个C语言小程序,使 ...

  9. java 动态分区 链表_大二作业——操作系统实验——C语言用双向链表,模拟实现动态分区式存储管理...

    实验:动态分区式存储管理 实验内容: 编写程序模拟完成动态分区存储管理方式的内存分配和回收.实验具体包括:首先确定内存空闲分配表:然后采用最佳适应算法完成内存空间的分配和回收:最后编写主函数对所做工作 ...

最新文章

  1. SQL Server 2012笔记分享-29:日志文件的工作方式
  2. 使用Docker运行SQL Server
  3. main.js中的Vue.config.productionTip = false
  4. Python 编程问题集
  5. rabbitMQ 常用api翻译
  6. 反射 字段_java核心基础之反射
  7. Android 系统(193)----图解从URL到网页通信原理
  8. SQL Server中的数据层应用程序简介
  9. redis同步到磁盘
  10. SQL Server 数据库的创建
  11. Vim命令大全(linux)
  12. c语言合数的分解编程,C语言 · 分解质因数
  13. 洞悉物联网发展1000问之透过华为山海经看如何突破物联网关键技术?
  14. c语言测序,Hi-C测序
  15. Android测试——(下篇)
  16. 51nod 3199 操作栈
  17. codeforces 1000A,T-sthirt
  18. P3380 【模板】二逼平衡树(树套树)
  19. Linux杀不死木马,杀不死进程,自启动进程
  20. 读研攻略(10)—三千字总结,要不要读博?

热门文章

  1. java svn安装地址_SVN的安装和配置
  2. docker 容器restarting_FATE联邦学习docker-compose部署中的坑
  3. python怎么输入列表元素每个元素占一行_如何对列表的每个元素执行操作并将结果放在Python的新列表中?...
  4. linux内核4.0,新闻|Linux内核4.0功能:实时内核补丁,支持PS3
  5. 你以为没有CAD的前辈们画不出复杂的图纸?
  6. php autoload静态,Composer 中自动加载 autoload_static 问题
  7. java创建集合有的不用泛型_为什么在Java泛型右手边的集合类型没有任何影响?...
  8. C++:C++语言入门级基础知识考察点回顾之函数、结构体和类
  9. DL之Keras: Keras深度学习框架的注意事项(默认下载存放路径等)、使用方法之详细攻略
  10. Hadoop中任务提交运行流程