一、实验内容

[问题描述]

在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的模拟UNIX文件系统 。

[基本要求]

1.在现有机器硬盘上开辟20M的硬盘空间,作为设定的硬盘空间。

2.编写一管理程序对此空间进行管理,以模拟UNIX文件系统,具体要求如下:

题目分析:

Unix文件系统结构:

0#: 引导块

1#   超级块

2#-19#号为目录区

20#-30#号为i结点索引区

(7)功能:1、初始化

2、建立文件(需给出文件名,文件长度)

3、建立子目录

4、打开文件(显示文件所占的盘块)

5、删除文件

6、删除目录

7、显示目录(即显示目录下的信息,包括文件、子目录等)

8、显示整个系统信息

题目分析:

Unix文件系统结构:

0#       引导区: 存放操作系统引导和启动代码

1#       超级块: 存放文件系统管理资源的描述信息。比如磁盘总数、空闲块数、块的大小等。其中有50byte的空闲盘块栈存放将要分配的空闲盘块。

2~21#    目录区: 存放根目录下文件和目录文件信息。目录项信息包括:文件名14byte,i结点号2byte。

22#~31#  索引区: 也叫i结点区,存放每个文件的描述信息,包括文件类型1 byte,物理地址(共13个表项,每个表项2 byte),文件长度4 byte,联结计数1 byte

32#~…   数据区: 普通文件数据及目录文件数据

20M的硬盘空间,盘块大小为1K(即1024 byte),共计20480个盘块;

目录区占10个盘块,一个目录项为16 byte,所以最多有640个目录项;

引导区占20个盘块,一个索引结点为32 byte,所以最多有640个索引结点

空闲盘块管理:

成组链接是将所有空闲盘块按50个块为一组,每组所有的盘块号记入其前一组的第一个盘块的s.free(0)~s.free(49)中。将第一组的盘块总数和所有盘块号记入超级块中的空闲盘块栈中。

最末一组只有49个空闲盘块,其盘块号分别计入s.free(1)~s.free(49)中,s.free(0)中存放0,表示空闲盘块链结束。

二级索引的实现:

i索引结点的物理地址(索引表):共有13个表项,每个表项2 byte,其中前10项分别存放文件的实际存储盘块的首地址。若文件大小不超过10240 byte,则一级索引就够用了。但是如果文件很大则需要二级或多级索引,i索引结点的物理地址的第11项会指向一个二级索引结点项,若一个地址占2 byte,则此二级索引结点中将存放着512个盘块的地址,文件最大可以达到(512+10)*1024 byte

实验分析:

数据结构设计

i节点:

struct INode

{

char fileSpec;  //文件类型0表示NORMAL 1表示DIR 1byte

short iaddr[13];   索引表26byte

int fileLength;  文件长度 4byte

char linkCount; //链接计数 1byte

};

目录项信息:

struct DirChild

{

char filename[14]; 文件名 14byte

short i_BNum;  i节点号 2byte

};

目录节点():

struct DirNode

{

DirChild childItem[64];   //目录下存放的文件

short DirCount;  //存放的文件数量

};

SS[51] 存放超级块前50byte

freeBlockNum 当前可用盘快所在组记录的盘快号

freeTotalB 当前所剩空闲块数

rootDirNum; 当前目录所在的磁盘号号

currentDirIndex ; 当前所在目录所在rootDir中的下标

rootDir[10]; 目录节点

DirFloorArr[10];  存放进入的目录节点下标

DirFloor = 0;  存放当前DirFloorArr的下标

DirName[10][14]; 存放进入过的目录的名称

INode iNode[640];  i节点

三、算法设计(总体设计及模块设计)

下面列出主要函数:

初始化函数initSystem():

空闲盘块栈进行初始化:

盘块总数为总盘块数20480,空闲盘块个数为每组盘块数50,栈中每个盘块初值置为盘块号,stcak中记录下一组盘块的盘块号。建立20MB的二进制,值全为0。

i结点信息初始化:

每个i结点的所有文件地址初值都置为-1,i结点文件长度置-1,文件类型默认-1。

成组链接:

完成成组链接的初始化,将对应盘快写入所连接的盘快号

根目录区信息初始化:

每个根目录文件名置为空,目录文件长度置为1,每个目录文件所在的目录名置为空。压入root节点。

存储空间初始化:

空闲盘块个数处置置为0,是否被占用标识置为0,每个空闲盘块的free空间置为-1,二级索引表项置为-1。空闲块的信息用成组链接的方法写进每组的第一块free(0)中。

读入信息函数readSystem( ):

将盘块中的信息,空闲盘块栈中的信息,i结点信息和目录项信息读入系统文件中。

读出信息函数savaFile(  )

将系统文件中的信息读出并存入相应的数据结构中。

内含:  WriteINode();

WriteRootDir();

WritePara();

节点回收CallBackDisk(INode& iNode):

内含:

CallBackDisk(INode& iNode) 回收iNode中对应的块

DelDirItem(DirNode& dir, short index) 删除一个文件信息

CleanINode(INode& iNode) 清空iNode信息

根据iNode节点中的索引节点,进行块的逐个回收。如果空闲盘块栈尚未满,将回收的盘块的是否被占用标识置为0,将该盘块放入空闲盘块栈中,空间盘块数目加一;如果在回收盘块时发现空闲盘块栈已满,则栈中的所有地址信息写入当前要回收的空闲盘块的free(0)~free(49)中,将空闲盘块栈清空,空闲盘块个数置为0,并将当前要回收的盘块放入空闲盘块栈中。

5.文件创建函数Mf(DirNode& dir, char fileName[14], short length)

判断是否重名,如果无重名,则分配dirChild节点,分配iNode节点,分配长度为length大小的磁盘块。

6. 目录创建函数Md(DirNode& dir, char fileName[14], short length)

判断是否重名,如果无重名,则分配dirChild节点,分配iNode节点,分配长度为4大小的磁盘块。类似于Mf,不同为长度默认,且须分配空DirNode节点。

7.文件删除函数Del(DirNode& dir, char fileName[14]):

首先把当前文件名与每一个目录项文件名作比较,找到要删除的该文件是否存在;存在则找到在dirChild中的下标index,  对应的iNode节点,调用:

CallBackDisk(INode& iNode) 回收iNode中对应的块

DelDirItem(DirNode& dir, short index) 删除一个文件信息

CleanINode(INode& iNode) 清空iNode信息

8.目录删除函数Rd(DirNode& dir, char fileName[14]):

内含:

CallBackDisk(INode& iNode) 回收iNode中对应的块

DelDirItem(DirNode& dir, short index) 删除一个文件信息

CleanINode(INode& iNode) 清空iNode信息

首先判断目录是否存在。存在则采用递归删除,对dirChild进行循环判断。如果为空,则直接删除该目录,从DirNode节点中删除。如果不为空,则:如果dirChild为文件,则进行文件删除操作,如果为目录,递归,重复入上操作。

9.打开文件/目录OpenFile(DirNode& dir, char fileName[14])

首先判断文件名是否存在,存在则显示文件名称 类型 并通过iNode节点中索引读出占用的块。

10.显示当前目录下的所有文件:Dir():

通过访问当前所在目录的dirChild,输出文件信息。

11.进入指定目录函数enterDir(DirNode dir, char fileName[14]):

在DirNode中找到该目录,将该目录的下标压入DirFloorArr,名称压入DirName,currentDirIndex置为DirFloorArr,转换目录。DirFloor++

12.退出目录函数: exitDir()

DirFloor--,即从DirFloorArr弹出当前目录,currentDirIndex置为DirFloorArr[DirFloor]。

即进入上一级目录

13.帮助函数help() :

显示帮助信息

删除文件函数 Del(DirNode& dir, char fileName[14])

内含:

CallBackDisk(INode& iNode) 回收iNode中对应的块

DelDirItem(DirNode& dir, short index) 删除一个文件信息

CleanINode(INode& iNode) 清空iNode信息

14.分配磁盘空间函数AssAnEmpty()( int length , int allo[]):

根据length计算需要分配的磁盘数目。每分配一个磁盘都需要进行以下操作:首先获得空闲盘块栈中当前可以分配的空闲块的地址;如果空闲盘块数目不为1,则将栈中相应盘块的地址写进文件地址缓冲区,然后检查当前分配的盘块是否超过了前十个直接地址访问区,如果超出则将第十一个一级索引地址分配,并为该索引分配一个块。如果一级索引不能满足,则为第十二个索引地址分配一个块,并且在该块中的每个占用的空间都分配一个块。

15. 主函数mian()

调用help函数显示界面,调用存命令表函数,读取系统文件system,如果不能打开,格式化磁盘。显示当前所在的目录,用户输入相应的操作,检验命令是否存在,不存在就报错,存在就调用相关的函数。退出文件模拟系统时,将磁盘利用信息写入系统文件,结束运行。

实验过程中出现的问题及解决方法

(1)如何存储一个目录其子目录所对应的DirNode的下标,因为磁盘的解构是固定的,20MB都有分配,所以如何不破坏磁盘整体结构去分配呢。本次实验对链接计数没有使用,所以我在其子目录对应的iNode节点的链接计数存放了其对应的下标。

(2)文件成组链接写入有误,这是困扰了我最长时间的地方。在开始,我采用文本格式创建、读写文件。但是在成组链接的链接节点写入中会存在错误的写入。解决方法为采用二进制打开。

(3)成组链接中对于栈底的盘块要特殊处理,它需要存放下一组空闲盘块的所有信息,在进行回收时要进行判断,如果回收栈满,就把它们目前在超级块中的信息放入到新回收的盘块中,作为新的空闲盘块组的栈底。

(4)目录的删除。如果目录不为空,必须先将该目录存在的文件或子目录先进行删除。需要递归进行。

如果运行指针出错,请先初始化。

代码:

#include <fstream>#include <iostream>#include <cstring>using namespace std;const char FileName[] = "os.txt";const char NullName[] = "00000000000000";const int DirLen = 1;const short SSNum = -1; //super block num//i节点结构信息struct INode
{char fileSpec; //0表示NORMAL 1表示DIRshort iaddr[13];int fileLength;char linkCount;
};struct DirChild
{char filename[14];short i_BNum;
};struct DirNode
{DirChild childItem[64];short DirCount;
};short SS[51]; //超级栈,指针为SS[0]short freeBlockNum = 0; //当前可用盘快所在组记录的盘快号short freeTotalB = 20450;short rootDirNum; //当前目录所在的磁盘号号short currentDirIndex = 0;
DirNode rootDir[10];int DirFloorArr[10];
int DirFloor = 0;
char DirName[10][14];INode iNode[640];//================================================================//函数描述:创建20M磁盘//入口参数:无//返回值: 无//===============================================================short assAnDirMy()
{for (int i = 0; i < 10; i++){if (rootDir[i].DirCount == -1){rootDir[i].DirCount = 0;return i;}}return -1;
}void Format()
{cout << "系统正在初始化......" << endl;// 打开文件FILE* f = fopen(FileName, "wb+");if (f == NULL){cout << "程序创建错误,请重新输入" << endl;return;}for (int i = 0; i < 20971520; i++) //20971520=20Mb,暂时20mbfprintf(f, "%c", '0');// 关闭文件fclose(f);
}//================================================================//函数描述:数组赋值//入口参数:无//返回值: 无//===============================================================void ArrarEqual(short arr[51], short begin, short end){for (short i = 0; i < end - begin + 1; i++)arr[50 - i] = begin + i;
}//================================================================//函数描述:重构BWrite,实现一个数组的写入//入口参数:无  BBVBVB//返回值: 无//===============================================================void BWrite(short arr[51], short diskNum)
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "写文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, 1024 * diskNum, 0))cout << "文件指针错误" << endl;fwrite(arr, sizeof(short), 51, f);fclose(f);
}void WriteINode()
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "写文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, 1024 * 11, 0))cout << "文件指针错误" << endl;fwrite(iNode, sizeof(INode), 640, f);fclose(f);
}void WriteRootDir()
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "写文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, 1024 * 1, 0))cout << "文件指针错误" << endl;for (int i = 0; i < 10; i++) {fwrite(rootDir[i].childItem, sizeof(DirChild), 64, f);}if (fseek(f, sizeof(short) * 53, 0))cout << "文件指针错误" << endl;for (int i = 0; i < 10; i++) {fwrite(&(rootDir[i].DirCount), sizeof(short), 1, f);}fclose(f);
}
//================================================================//函数描述:重构BWrite,实现一个数组的写入,数组长度不确定//入口参数:无//返回值: 无//===============================================================void BWriteArr(short arr[512], short diskNum)
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "写文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, 1024 * diskNum, 0))cout << "文件指针错误" << endl;fwrite(arr, sizeof(short), 512, f);fclose(f);
}//================================================================//函数描述:从磁盘中读出数组//入口参数:无//返回值: 无//===============================================================void BRead(short arr[51], short diskNum)
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "读文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, 1024 * diskNum, 0))cout << "文件指针错误" << endl;fread(arr, sizeof(short), 51, f);fclose(f);
}//================================================================//函数描述:从磁盘中读出数组, 放入到iNOde中//入口参数:无//返回值: 无//===============================================================void BReadArr(short arr[512], short diskNum)
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "读文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, 1024 * diskNum, 0))cout << "文件指针错误" << endl;fread(arr, sizeof(short), 512, f);fclose(f);
}//================================================================//函数描述:写入一个目录项//入口参数:无//返回值: 无//===============================================================void BWrite(short diskNum)
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "写文件处错误,请重新输入" << endl;return;}//设置文件指针if (fseek(f, long(1024 * diskNum), 0))cout << "文件指针错误" << endl;for (int i = 0; i < 64; i++){fprintf(f, "%hd", rootDir->childItem[i].i_BNum);fputs(rootDir->childItem[i].filename, f);}fclose(f);
}//================================================================//函数描述:分配一个空闲的普通快//入口参数:无//返回值: 分配的块号//===============================================================short AssAnEmpty()
{short temp;if (SS[0] > 1){SS[0]--;temp = SS[SS[0] + 1];//                               SS[SS[0]+1]=-1;freeTotalB--; //总剩余数-1return temp;}else{if (SS[1] == 0){cout << "盘片用尽" << endl;return -1;}//temp = freeBlockNum;freeBlockNum = SS[1]; //保存当前读入的块号temp = freeBlockNum;BRead(SS, SS[1]);/*if (temp == 0) {SS[0]--;temp = SS[SS[0] + 1];}*/freeTotalB--;return temp;}
}short AssAnNode()
{for (short i = 0; i < 640; i++){if (iNode[i].fileLength == -1){return i;}}printf("无节点可分配\n");return -1;
}//================================================================//函数描述:分配一个空闲的目录快//入口参数:无//返回值: 无//===============================================================short AssAnDir(DirNode& dir)
{if (dir.DirCount == 64){cout << "该目录已满" << endl;return -1;}else{for (short i = 0; i < 64; i++){if (dir.childItem[i].i_BNum == -1){dir.DirCount++;dir.childItem[i].i_BNum = AssAnNode();return i;}}}
}//================================================================//函数描述:创建一个文件节点,并分配INOde和磁盘空间//入口参数:无//返回值: 无//===============================================================void InitCreate(char fielSpec, short diskNum)
{//         int blockNum=AssertAnEmpty();if (fielSpec == '1'){WriteINode();WriteRootDir();}
}//================================================================//函数描述:初始化//入口参数:无//返回值: 无//===============================================================void Init(char fielSpec, short diskNum)
{InitCreate(fielSpec, diskNum);BRead(SS, 0);
}//================================================================//函数描述:初始化索引区//入口参数:无//返回值: 无//===============================================================void Init()
{for (int i = 0; i < 10; i++){rootDir[i].DirCount = -1;for (int j = 0; j < 64; j++){rootDir[i].childItem[j].i_BNum = -1;strncpy(rootDir[i].childItem[j].filename, NullName, 14);}}for (int i = 0; i < 640; i++){iNode[i].fileSpec = 2;iNode[i].linkCount = -1;iNode[i].fileLength = -1;for (short i = 0; i < 13; i++)iNode[i].iaddr[i] = -1;}rootDir[0].DirCount = 0;freeBlockNum = 0; //当前可用盘快所在组记录的盘快号freeTotalB = 20450;BRead(SS, 0);//根据文件长度非配文件磁盘节点//直接寻址
}//================================================================//函数描述:成组链接初始化//入口参数:无//返回值: 无//===============================================================void Linkdisk()
{//临时空闲栈SS[0] = 50;ArrarEqual(SS, 31, 80);BWrite(SS, 0);for (short i = 1; i < 408; i++){SS[0] = 50;ArrarEqual(SS, i * 50 + 31, i * 50 + 80);BWrite(SS, i * 50 + 30);}ArrarEqual(SS, 408 * 50 + 31, 408 * 50 + 79);SS[0] = 49;SS[1] = 0; //49BWrite(SS, 408 * 50 + 30);cout << "磁盘disk.txt完成创建,大小20MB" << endl;
}
//================================================================//函数描述:判断一个文件是一个普通文件//入口参数:无//返回值: -1,不存在,文件号//===============================================================bool IsFile(short diskNum)
{if (iNode[diskNum].fileSpec == '0')return true;elsereturn false;
}//================================================================//函数描述:判断一个文件是一个普通文件//入口参数:无//返回值: -1,不存在,文件号//===============================================================bool IsDir(short diskNum)
{if (iNode[diskNum].fileSpec == '1')return true;elsereturn false;
}
//================================================================//函数描述:判断一个文件是否存在//入口参数:无//返回值: -1,不存在,文件号//===============================================================short IsFileExist(DirNode dir, char fileName[14])
{for (int i = 0; i < 64; i++){if (strcmp(fileName, dir.childItem[i].filename) == 0 && IsFile(dir.childItem[i].i_BNum))return dir.childItem[i].i_BNum;}return -1;
}short IsDirExist(DirNode dir, char fileName[14])
{for (int i = 0; i < 64; i++){if (strcmp(fileName, dir.childItem[i].filename) == 0 && IsDir(dir.childItem[i].i_BNum))return dir.childItem[i].i_BNum;}return -1;
}//================================================================//函数描述:创建一个iNode,并分配磁盘空间//入口参数:无//返回值: 无  AssAnEmpty(),BWrite(dirChild,dir[512-i])未实现//===============================================================void CreateINode(short iNodeNum, char fileSpec, short linkCount, short length)
{iNode[iNodeNum].fileSpec = fileSpec;iNode[iNodeNum].linkCount = linkCount;iNode[iNodeNum].fileLength = length;//为目录磁盘,分配目录节点if (fileSpec == '1'){for (int i = 0; i < 4; i++){iNode[iNodeNum].iaddr[i] = AssAnEmpty();}return;}//根据文件长度分配文件磁盘节点//直接寻址short i;i = 10;short left = length;while (left && i){iNode[iNodeNum].iaddr[10 - i] = AssAnEmpty();left--;i--;}if (left > 0){ //一级索引i = 512;short dir[512];iNode[iNodeNum].iaddr[10] = AssAnEmpty();while (left && i){dir[512 - i] = AssAnEmpty();i--;left--;}BWriteArr(dir, iNode[iNodeNum].iaddr[10]);if (left > 0){ //二级索引short k = 512;short j = 512;short dirChild[512];iNode[iNodeNum].iaddr[11] = AssAnEmpty();while (left && k){ //二级索引1次寻址dir[512 - k] = AssAnEmpty();j = 512;while (left && j){ //二级索引二次寻址dirChild[512 - j] = AssAnEmpty();left--;j--;}BWriteArr(dirChild, dir[512 - k]);BWriteArr(dir, iNode[iNodeNum].iaddr[11]); //写二级索引一次寻址中盘快记录的一次寻的盘快号k--;}}}
}//================================================================//函数描述:清空iNode信息,并分配磁盘空间//入口参数:无//返回值: 无  AssAnEmpty(),BWrite(dirChild,dir[512-i])未实现//===============================================================void CleanINode(INode& iNode)
{iNode.fileSpec = '2';iNode.linkCount = -1;iNode.fileLength = -1;//根据文件长度非配文件磁盘节点//直接寻址for (short i = 0; i < 13; i++)iNode.iaddr[i] = -1;
}//================================================================//函数描述:创建一个iNode,并分配磁盘空间//入口参数:无//返回值: 无//===============================================================void InsertDir(char fileName[14], short blockNum)
{strcpy(rootDir->childItem[blockNum].filename, fileName);rootDir->childItem[rootDir->DirCount].i_BNum = blockNum;rootDir->DirCount++;return;
}//================================================================//函数描述:存在文件,并分配iNOde节点和磁盘空间//入口参数:无//返回值: 无//===============================================================void Create(DirNode& dir, char fileName[14], short length, char fileSpec)
{if (length > freeTotalB){cout << "当前文件超出长度" << endl;return;}short index = AssAnDir(dir);short iNodeNum = dir.childItem[index].i_BNum;if (index == -1){printf("目录区已满,无法继续创建文件或目录\n");return;}CreateINode(iNodeNum, fileSpec, 0, length);strcpy(dir.childItem[index].filename, fileName);if (fileSpec == '1'){iNode[iNodeNum].linkCount = assAnDirMy();}//InsertDir(rootDir, fileName, iNodeNum);//BWrite(rootDirNum);//此处
}//================================================================//函数描述:创建一个文件,//入口参数:无//返回值: 无//===============================================================void Mf(DirNode& dir, char fileName[14], short length)
{int iNodeNum = IsFileExist(dir, fileName);if (iNodeNum != -1){ //有重名名,进一步判断cout << "当前文件已经存在,请重新输入文件名" << endl;}else{ //存在文件,为索引文件,或者无重名现象,创建文件,并分配iNOde节点和磁盘空间Create(dir, fileName, length, '0');}
}//================================================================//函数描述:在当前目录创建一个子目录//入口参数:无//返回值: 无//===============================================================void Md(DirNode& dir, char fileName[14], short length)
{int iNodeNum = IsDirExist(dir, fileName);if (iNodeNum != -1){ //有重名名,进一步判断cout << "当前目录已经存在,请重新输入目录名" << endl;}else{Create(dir, fileName, length, '1');}} //================================================================//函数描述:打开一个文件,//入口参数:无//返回值: 无//===============================================================void ShowBlockInfo(INode iNode)
{short dir[512];short i;i = 10;short left = iNode.fileLength;while (left && i){cout << (iNode.fileLength - left) << ":" << iNode.iaddr[10 - i] << "  ";left--;i--;}if (left > 0){i = 512;short dir1[512];BReadArr(dir1, iNode.iaddr[10]);while (left && i){cout << (iNode.fileLength - left) << ":" << dir1[512 - i] << "  ";i--;left--;}}if (left > 0){ //二级索引short k = 512;short j = 512;short dirChild[512];BReadArr(dir, iNode.iaddr[11]);while (left && k){ //二级索引1次寻址BReadArr(dirChild, dir[512 - k]);j = 512;while (left && j){ //二级索引二次寻址cout << (iNode.fileLength - left) << ":" << dirChild[512 - j] << "  ";left--;j--;}k--;}}
}//================================================================//函数描述:打开一个文件,//入口参数:无//返回值: 无//================================================================void ShowFileInfo(INode iNode, char fileName[14])
{cout << "文件名        " << fileName;cout << "      文件类型  ";switch (iNode.fileSpec){case '0':cout << "< 文件 > ";break;case '1':cout << "< 目录 > ";break;default:cout << "错误";}cout << "         " << iNode.fileLength << "KB" << endl;
}//================================================================//函数描述:打开一个文件,//入口参数:无//返回值: 无//===============================================================void OpenFile(DirNode& dir, char fileName[14])
{int blockNum = IsFileExist(dir, fileName);if (blockNum == -1){ //不存在该文件,退出cout << "该文件按不存在" << endl;return;}else{ShowFileInfo(iNode[blockNum], fileName);ShowBlockInfo(iNode[blockNum]);cout << endl;}
}void OpenDir(DirNode& dir, char fileName[14])
{int blockNum = IsDirExist(dir, fileName);if (blockNum == -1){ //不存在该文件,退出cout << "该目录按不存在" << endl;return;}else{ShowFileInfo(iNode[blockNum], fileName);ShowBlockInfo(iNode[blockNum]);cout << endl;}
}
//================================================================//函数描述:回收一块空余磁盘片//入口参数:无//返回值: 无//===============================================================void CallBackOne(short diskNum)
{freeTotalB++;if (SS[0] < 49){SS[0]++;SS[SS[0]] = diskNum;}else if (SS[0] == 49 && SS[1] != 0){SS[0]++;SS[SS[0]] = diskNum;}else if (SS[0] == 49 && SS[1] == 0){BWrite(SS, diskNum); //将空白的一组回写到上一组记录空闲盘快号的磁盘freeBlockNum = diskNum; //将当前空白的一组第一个盘快作为下一个盘组的记录盘//修改超级栈SS[1] = diskNum;SS[0] = 1;}else{ //SS[0]==50BWrite(SS, diskNum); //将空白的一组回写到上一组记录空闲盘快号的磁盘freeBlockNum = diskNum; //将当前空白的一组第一个盘快作为下一个盘组的记录盘//修改超级栈SS[1] = diskNum;SS[0] = 1;}
}//================================================================//函数描述:回收文件占用的磁盘//入口参数:无//返回值: 无//===============================================================void CallBackDisk(INode& iNode)
{short i;i = 10;short left = iNode.fileLength;while (left && i){ //直接索引回收CallBackOne(iNode.iaddr[10 - i]);left--;i--;}if (left > 0){ //一级索引回收i = 512;short dir1[512];BReadArr(dir1, iNode.iaddr[10]);while (left && i){CallBackOne(dir1[512 - i]);i--;left--;}CallBackOne(iNode.iaddr[10]);}if (left > 0){ //二级索引short k = 512;short j = 512;short dir[512];short dirChild[512];BReadArr(dir, iNode.iaddr[11]); //二级索引1次寻址while (left && k){ //二级索引1次寻址BReadArr(dirChild, dir[512 - k]);j = 512;while (left && j){ //二级索引二次回收CallBackOne(dirChild[512 - j]);left--;j--;}CallBackOne(dir[512 - k]); //二级索引一次寻址k--;}CallBackOne(iNode.iaddr[11]);}
}//================================================================//函数描述:回收文件的iNOde节点//入口参数:无//返回值: 无//===============================================================void CallBackINode(short diskNum)
{CallBackOne(diskNum);
}//================================================================//函数描述:删除索引中一项//入口参数:无//返回值: -1,不存在,文件号//===============================================================void DelDirItem(DirNode& dir, short index)
{strcpy(dir.childItem[index].filename, NullName);dir.childItem[index].i_BNum = -1;
}//================================================================//函数描述:删除一个文件//入口参数:无//返回值: 无//===============================================================void Del(DirNode& dir, char fileName[14])
{short blockNum = IsFileExist(dir, fileName);int index = -1;if (blockNum == -1){ //不存在该文件,退出cout << "文件不存在,删除失败" << endl;}else{for (int i = 0; i < 64; i++){if (strcmp(fileName, dir.childItem[i].filename) == 0 && IsFile(dir.childItem[i].i_BNum)) {index = i;break;}}CallBackDisk(iNode[blockNum]);DelDirItem(dir, index);CleanINode(iNode[blockNum]);}
}//================================================================//函数描述:删除一个目录//入口参数:无//返回值: 无//===============================================================void recursionDel(DirNode& dir)
{if (dir.DirCount != 0){for (int i = 0; i < 64; i++){if (dir.childItem[i].i_BNum != -1) {if (iNode[dir.childItem[i].i_BNum].fileSpec == '0'){ //如果是文件CallBackDisk(iNode[dir.childItem[i].i_BNum]);DelDirItem(dir, i);CleanINode(iNode[dir.childItem[i].i_BNum]);}else{if (rootDir[iNode[dir.childItem[i].i_BNum].linkCount].DirCount != 0){recursionDel(rootDir[iNode[dir.childItem[i].i_BNum].linkCount]);CallBackDisk(iNode[dir.childItem[i].i_BNum]);DelDirItem(dir, i);CleanINode(iNode[dir.childItem[i].i_BNum]);dir.DirCount = -1;}else{CallBackDisk(iNode[dir.childItem[i].i_BNum]);DelDirItem(dir, i);CleanINode(iNode[dir.childItem[i].i_BNum]);dir.DirCount = -1;}}}}}}void Rd(DirNode& dir, char fileName[14])
{short blockNum = IsDirExist(dir, fileName);  //返回子节点所在的INODE下标int index = -1;if (blockNum == -1){ //不存在该文件,退出cout << "目录不存在,删除失败" << endl;}else{for (int i = 0; i < 64; i++){if (strcmp(fileName, dir.childItem[i].filename) == 0 && IsDir(dir.childItem[i].i_BNum)) {index = i;break;}}recursionDel(rootDir[iNode[blockNum].linkCount]);CallBackDisk(iNode[blockNum]);DelDirItem(dir, index);CleanINode(iNode[blockNum]);}
}//================================================================//函数描述:显示目录项的内容//入口参数:无//返回值: 无//===============================================================void Dir()
{for (int i = 0; i < 64; i++){if (rootDir[currentDirIndex].childItem[i].i_BNum != -1){//BRead(iNode[i], rootDir->childItem[i].i_BNum);ShowFileInfo(iNode[rootDir[currentDirIndex].childItem[i].i_BNum], rootDir[currentDirIndex].childItem[i].filename);}}
}//================================================================//函数描述:销毁资源//入口参数:无//返回值: 无//===============================================================void exit()
{delete[] iNode;delete rootDir;
}//================================================================//函数描述:打印版权信息//入口参数:无//返回值: 无//===============================================================void help() //打印命令及解释{cout << "==============================================================================\n"<< endl;printf("                              命令使用指南\n");printf("    1:     mf                                                                       新建文件\n");printf("    2:     mkdir                                                                    建立子目录\n");printf("    3:     cat                                                                      查看文件信息\n");printf("    4:     rmf                                                                      删除文件\n");printf("    5:     rmdir                                                                    删除目录\n");printf("    6:     dir                                                                      显示目录\n");printf("    7:     cd                                                                       进入指定目录\n");printf("    8:     cd..                                                                     返回上一级目录\n");printf("    9:     init                                                                     初始化系统\n");printf("    10:     help                                                                    显示帮助命令\n");printf("    11:     ls                                                                      查看空余盘块数目\n");printf("    12:     cls                                                                     清屏\n");printf("    13:     catDir                                                                  查看目录信息\n");cout << "==============================================================================\n"<< endl;cout << "\n请输入命令,回车确认" << endl;
}bool WritePara()
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "系统还未初始化" << endl;return false;}if (fseek(f, sizeof(short) * 51, 0))cout << "文件指针错误" << endl;fwrite(&freeBlockNum, sizeof(freeBlockNum), 1, f);fwrite(&freeTotalB, sizeof(freeTotalB), 1, f);fclose(f);return true;
}bool readSystem()
{FILE* f = fopen(FileName, "rb+");if (f == NULL){cout << "系统还未初始化\n"<< endl;return false;}if (fseek(f, 1024 * 1, 0))cout << "文件指针错误" << endl;//设置文件指针for (int i = 0; i < 10; i++) {fread(rootDir[i].childItem, sizeof(DirChild), 64, f);}if (fseek(f, sizeof(short) * 53, 0))cout << "文件指针错误" << endl;for (int i = 0; i < 10; i++) {fread(&(rootDir[i].DirCount), sizeof(short), 1, f);}if (fseek(f, 1024 * 11, 0))cout << "文件指针错误" << endl;fread(iNode, sizeof(INode), 640, f);BRead(SS, 0);if (fseek(f, sizeof(short) * 51, 0))cout << "文件指针错误" << endl;fread(&freeBlockNum, sizeof(freeBlockNum), 1, f);fread(&freeTotalB, sizeof(freeTotalB), 1, f);fclose(f);cout << "系统文件载入完成\n"<< endl;return true;
}void savaFile()
{WriteINode();WriteRootDir();WritePara();
}void initSystem()
{Format(); //初始化Linkdisk();Init();DirFloor = 0;currentDirIndex = 0;DirFloorArr[0] = 0;
}void disPlayNowDir()
{for (int i = 0; i <= currentDirIndex; i++){printf("%s", DirName[i]);printf("/");}printf(":");
}void enterDir(DirNode dir, char fileName[14])
{for (int i = 0; i < 64; i++){if (strcmp(fileName, dir.childItem[i].filename) == 0 && IsDir(dir.childItem[i].i_BNum)){currentDirIndex = iNode[dir.childItem[i].i_BNum].linkCount;DirFloor++;DirFloorArr[DirFloor] = currentDirIndex;strcpy(DirName[DirFloor], dir.childItem[i].filename);return;}}printf("此目录不存在\n");
}void exitDir()
{if (DirFloor == 0){return;}DirFloor--;currentDirIndex = DirFloorArr[DirFloor];}int main()
{bool run = true;int length = 1024;char fileName[14];char dirName[14];int command;//AuthorMessage();if (!readSystem()){initSystem();}strcpy(DirName[0], "root");help();while (run){disPlayNowDir();while (true){scanf("%d", &command);fflush(stdin);if (command > 0 && command <= 13)break;cout << "\n命令错误,请重新输入" << endl;getchar();command = -1;}switch (command){case 1:cout << "\n请输入文件名" << endl; //新建文件cin >> fileName;fflush(stdin);cout << "\n请输入文件长度,单位KB" << endl;cin >> length;fflush(stdin);if (length < 0 || length > freeTotalB){cout << "文件长度不合法\n"<< endl;break;}Mf(rootDir[currentDirIndex], fileName, length);savaFile();break;case 2:cout << "\n请输入目录名" << endl;cin >> dirName;Md(rootDir[currentDirIndex], dirName, 4);savaFile();break;case 3:cout << "\n请输入打开文件名" << endl; //打开文件cin >> fileName;OpenFile(rootDir[currentDirIndex], fileName);break;case 4:cout << "\n请输入删除文件名" << endl; //删除文件cin >> fileName;Del(rootDir[currentDirIndex], fileName);savaFile();break;case 5: //删除目录cout << "\n请输入目录名" << endl;cin >> dirName;Rd(rootDir[currentDirIndex], dirName);savaFile();break;case 6:Dir(); //显示当前目录下的信息break;case 7:printf("输入要进入的目录:");cin >> fileName;enterDir(rootDir[currentDirIndex], fileName);break;case 8:exitDir();break;case 9:initSystem();break;case 10:help();break;case 11:printf("还剩余%d个盘片\n", freeTotalB);break;case 12:system("cls"); //清屏break;case 13:cout << "\n请输入打开目录" << endl; //打开文件cin >> fileName;OpenDir(rootDir[currentDirIndex], fileName);break;default:break;}}return 0;
}

模拟UNIX/Linux 文件系统 c语言相关推荐

  1. Unix/Linux文件系统的目录结构

    完美解读Linux中文件系统的目录结构   发布时间:2007.03.16 03:28     来源:赛迪网技术社区    作者:skid 一.前 言 接触Linux也有一段时间了,不过这几天在编译开 ...

  2. unix/linux文件系统基础知识

    1.linux文件系统分配策略: 块分配( block allocation ) 和 扩展分配 ( extent allocation ) 块分配:磁盘上的文件块根据需要分配给文件,避免了存储空间的浪 ...

  3. Linux文件系统中文版,Linux 文件系统-Go语言中文社区

    文件系统: rootfs: 根文件系统 FHS: linux /boot : 系统启动相关的文件,如内核,initrd, 以及grub(bootloader) /dev : 设备文件 设备文件: 块设 ...

  4. 简单文件系统的实现_300来行代码带你实现一个能跑的最小Linux文件系统

    Linux作为一个类UNIX系统,其文件系统保留了原始UNIX文件系统的表象形式,它看起来是这个样子: t@name-VirtualBox:/# lsbin boot cdrom dev etc ho ...

  5. 300来行代码实现最小Linux文件系统

    Linux作为一个类UNIX系统,其文件系统保留了原始UNIX文件系统的表象形式,它看起来是这个样子: root@name-VirtualBox:/# ls bin  boot  cdrom  dev ...

  6. 300行代码带你实现一个Linux文件系统

    Linux作为一个类UNIX系统,其文件系统保留了原始UNIX文件系统的表象形式,它看起来是这个样子: root@name-VirtualBox:/# ls bin boot cdrom dev et ...

  7. linux下c语言调用mysql,Linux下C语言连接MySQL

    首先保证安装: 1:安装MySQL:sudo apt-get install mysql-server mysql-client 2:安装MySQL开发包:sudo apt-get install l ...

  8. Linux 文件系统之 inode 概述

    inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统操作水平,还有助于体会Unix设计哲学,即如何把底层的复杂性抽象成一个简单概念 ...

  9. 认识Linux文件系统inode和查看inode相关信息

    inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 1 inode是什么 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存 ...

最新文章

  1. 爱尔兰 APC 微生物组研究所—菌群研究的全球领航者之一
  2. 自学python推荐书籍2019-2019年Python入门书籍推荐
  3. 写给期待年薪百万的IT同学
  4. 计算机软件员证书用途,软考证书的五大好处(详解)
  5. win10电脑黑屏只有鼠标箭头_win7开机黑屏只有鼠标怎么办,我来教你解决
  6. 纯css3实现的鼠标悬停动画按钮
  7. 计算机视觉论文-2021-07-09
  8. 想从远程办公进入 toB 蓝海?它可以,你未必
  9. 这一次,彻底弄懂 Java 字节码文件!
  10. ubuntu或者fedora下编译淘宝tair key-value-db的开源内存数据库
  11. 复用类库内部已有功能
  12. linux7 yum安装Mysql5.7
  13. 2014 史丰收速算
  14. 网易邮箱与GMAIL
  15. 中基鸿业如何投资理财
  16. was服务器里面jar包_如何在was中解决jar包冲突
  17. shiro 安全(权限)框架
  18. 应用在复印机触摸屏中的触摸IC
  19. Vue 3.0 到底好在哪里?(尤雨溪点赞文)
  20. js获取当前日期未来七天的日期

热门文章

  1. 为什么现在计算机所有专业的研究生基本都搞机器学习和深度学习,国内真的需要这么多会人工智能的人才吗?...
  2. 读取qq聊天记录文件(诺基亚塞班S60v3平台)
  3. 不能无停顿一遍过此文,怎能说链表已不是问题?
  4. 常见的几种短信应用场景
  5. 语音短信的几种应用场景
  6. springboot基于java的校友同学录的交流网站设计ssm
  7. gjson - Golang 解析 JSON
  8. keil中不显示system_Viewer,无法查看寄存器的问题
  9. 江民杀毒 90天试用序列号申请
  10. 用c 语言中 矩阵乘法,C中实现矩阵乘法的一种高效的方法