一、实验内容
[问题描述]
在任一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
#include
#include
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表示DIR
short 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,暂时20mb
fprintf(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--; //总剩余数-1
return 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; //49
BWrite(SS, 408 * 50 + 30);
cout << "磁盘disk.txt完成创建,大小20MB" << endl;
}
//================================================================
//函数描述:判断一个文件是一个普通文件
//入口参数:无
//返回值: -1,不存在,文件号
//===============================================================
bool IsFile(short diskNum)
{
if (iNode[diskNum].fileSpec == '0')
return true;
else
return false;
}
//================================================================
//函数描述:判断一个文件是一个普通文件
//入口参数:无
//返回值: -1,不存在,文件号
//===============================================================
bool IsDir(short diskNum)
{
if (iNode[diskNum].fileSpec == '1')
return true;
else
return 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]==50
BWrite(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;
}