模拟UNIX/Linux 文件系统 c语言

一、实验内容

     [问题描述]

在任一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表示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;
}

  • 11
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
模拟Linux文件系统。在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的 模拟Linux文件系统 在现有机器硬盘上开辟20M的硬盘空间,作为设定的硬盘空间。 2. 编写一管理程序对此空间进行管理,以模拟Linux文件系统,具体要求如下: (1) 要求盘块大小1k 正规文件 (2) i 结点文件类型 目录文件 (共1byte) 块设备 管道文件 物理地址(索引表) 共有13个表项,每表项2byte 文件长度 4byte 。联结计数 1byte (3)0号块 超级块 栈长度50 空闲盘块的管理:成组链接 ( UNIX) 位示图法 (Linux) (4)每建一个目录,分配4个物理块 文件名 14byte (5)目录项信息 i 结点号 2byte (6)结构: 0#: 超级块 1#-20#号为 i 结点区 20#-30#号为根目录区 3. 该管理程序的功能要求如下: (1) 能够显示整个系统信息,源文件可以进行读写保护。目录名和文件名支持全路径名和相对路径名,路径名各分量间用“/”隔开。 (2) 改变目录:改变当前工作目录,目录不存在时给出出错信息。 (3) 显示目录:显示指定目录下或当前目录下的信息,包括文件名、物理地址、保护码、文件长度、子目录等(带/s参数的dir命令,显示所有子目录)。 (4) 创建目录:在指定路径或当前路径下创建指定目录。重名时给出错信息。 (5) 删除目录:删除指定目录下所有文件和子目录。要删目录不空时,要给出提示是否要删除。 (6) 建立文件(需给出文件名,文件长度)。 (7) 打开文件(显示文件所占的盘块)。 (8) 删除文件:删除指定文件,不存在时给出出错信息。 4. 程序的总体流程为: (1) 初始化文件目录; (2) 输出提示符,等待接受命令,分析键入的命令; (3) 对合法的命令,执行相应的处理程序,否则输出错误信息,继续等待新命令,直到键入EXIT退出为止。
实验二 UNIX磁盘空间管理算法 (一) 实验目的 掌握UNIX外存空间管理中的分组链接算法。 (二) 实验内容 编写C语言程序,模拟UNIX磁盘空间管理中使用的分组链接法。 1.定义一个记录磁盘块号的堆栈S—free[10],以及记录栈中现有磁盘块数的变量S—nfree。 2.定义一个由40个元素构成的结构数组block[40]用作磁盘块存放。 struct size { int blocl[10]; } struct blocd { struct size a[10]; //用于在空闲磁盘块号链中存放磁盘块号 }block[40]; 3. 假设系统文件的最大容量为100个磁盘块,且最多只有5个文件,定义一个由5个元素构成的结构数组file[5]用于记录各个文件占用的磁盘块,。 struct File { int fileblocd[100]; //用于记录分别分配给文件的磁盘块号 }file[5]; 4. 编写函数init( )完成空闲磁盘块号堆栈、空闲磁盘块号队列及记录文件占用磁盘块状态的file结构数组。 5. 编写函数alloc(fileno,blockd),完成磁盘块的分配操作。其中的参数fileno为文件序号,用于指定需要分配的文件。 6. 编写函数free(fileno),完成文件占用磁盘块的释放操作。其中的参数fileno为文件序号,用于指定需要释放磁盘块的文件。 7. 编写main( )函数完成下列操作: 调用init( )函数完成初始设置。 从终端输入命令,控制磁盘块的分配与回收操作。 (三) 实验要求 1. 在程序运行的结果中应包含磁盘块的分配与回收操作。 2. 可根据输入的文件名、文件大小进行模拟磁盘分配,并在每次分配与回收后显示分配与回收是否成功,以及分配、回收的磁盘块号。 3. 在程序执行过程中,至少应包含分配不成功一次的信息。 4. 可以查看当前磁盘块的使用情况:哪些块空闲,哪些块被哪些文件占用。
共两个不同设计例子,都含详细的文档资料。 任务2.设计一个简单的二级文件系统 设计要求: 在任一OS下,建立一个大文件,把它假象成硬盘,在其中实现一个简单的模拟文件系统。 编写一管理程序对此空间进行管理,要求: 1. 实现盘块管理 2. 实现文件的读写操作 3. 每组最多2人,小组内要有明确分工,课程设计报告中设计部分可以相同,个人实现部分不同 参考建议: 将模拟硬盘的文件空间划分为目录区,文件区;采用位示图进行空间管理,盘块的分配使用显示链接(FAT表)的方式。 设计技术参数(数据结构)参考: #define MaxSize 100 #define Disk 512 //每个盘块大小为512bit #define NumDisk 2048 //有2048个盘块,既可分配空间为 1M /*************目录和文件的结构定义***********************/ struct DirectoryNode { char name[9]; /*目录或文件的名字*/ int type; /*0代表目录,1代表普通文件*/ struct DirectoryNode *next; /*指向下一个兄弟结点的指针*/ struct DirectoryNode *preDirFile; /*指向父结点的指针*/ struct DirectoryNode *subFile; /*指向第一个子结点的指针*/ int size; /*如果是文件则表示文件的大小*/ int first; /*起始盘块号*/ int last; /*末尾盘块号*/ int order; /*备用*/ }; //连续分配 struct FileSys { int VacTable[NumDisk]; //空闲表,0为空闲,1为被用 struct DirectoryNode root; //根目录 struct DirectoryNode Directory[NumDisk]; } *filesys; typedef struct { struct DirectoryNode *DirFile; char name[9]; }DataType; //包含一个指向目录的指针和名字 typedef struct { //队列结构的实现 DataType data[MaxSize]; int front,rear; //分别表示队列的头结点和尾结点 }Tp; void InitQueue(Tp *sq) //队列初始化 int EnAddQueue(Tp *sq,DataType data) //在队列中增加元素 DataType EnDelQueue(Tp *sq) //从队列中删除一个元素 int Empty(Tp *sq) //判断队列是否为空,返回0表示队列为空 ①.Dir:显示目录内容命令,显示当前目录下的文件和子目录。 ②.Md:创建目录操作。 ③.Create:创建文件,在当前目录下创建一个文件。 ④. all:显示从根目录开始的所有目录和文件及其层次结点。 ⑤.Cd:改变目录。 ⑥.Del:删除文件操作。 ⑦. Rd:删除目录操作,删除当前目录下的子目录。 ⑧. Ren:重命名函数 ⑨. Exit:退出命令
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值