首页 > 其他 > 详细

myfs 操作系统课内实验 文件管理系统 Ext2

时间:2020-04-07 17:47:23      阅读:82      评论:0      收藏:0      [点我收藏+]

任务描述:

  用一个空白文件模拟磁盘外存,编程实现一个简单的文件系统,要求该文件系统支持一些基本的Linux指令:ls,创建、删除文件和文件夹,移动文件,关闭系统。


  即实现以下的命令

ls /dir
move /src /dst
delete -d /dir
delete -f /file
create size /file
create -d /dir
shutdown

 

文件系统结构解析:

  技术分享图片

 

 

 我们要处理的是维护超级块super_block和构建索引结点inode数组。

接下来分析文件系统的头文件fs_operation.h,

/*
 * @Author: Deng Cai
 * @Date: 2019-09-09 16:09:14
 * @Last Modified by: ZeLin Jiang
 * @Last Modified time: 2020-1-11 12:40:28
 */

//  in this code : \
    for the file systems space is so small, we dont need     group descriptors acctually, so i just put     some critical information in other structures and cut group     descriptors. whats more, the inode map and block map are \
    put into super block.
//  in some degrees, this file system can be seemed as a system \
    with only one block group, so we need just one super block     and one group descriptor. then why dont we put them together \
    and make them one single structure as "super_block"? thats \
    how i handle with it.
// it had been modified from the original file

#include
<stdio.h> #include <stdlib.h> #include <string.h> #include <stdlib.h> #define BLOCK_SIZE 1024 // 1KB. typedef struct inode { // 32 bytes; // the number of blocks it have. 4 uint32_t size; // 1->dir; 0->file; 2 uint16_t file_type; // it doesn‘t matter if you don‘t know what this variable means.2 uint16_t mumu; // the blocks belonging to this inode. 4*6 补全inode大小 //对于文件 block存的是数据 //对于文件夹 block存的是dir_item uint32_t block_point[6]; } inode; typedef struct super_block { // 656 bytes;0块 // use system_mod to check if it \ is the first time to run the FS.0 first_time 1 not int32_t system_mod; // 2^12; 4096; int32_t free_block_count; // 1024; int32_t free_inode_count; int32_t dir_inode_count; // 512 bytes; uint32_t block_map[128];//4096个block // 128 bytes;1-32块*32=1024 uint32_t inode_map[32]; } sp_block; // 1 block; typedef struct dir_item { // the content of folders. // 128 bytes; uint32_t inode_id; // 1 means the last one; // it doesn‘t matter if you don‘t understand it. uint16_t item_count; // 1 represents dir; uint8_t type; char name[121]; } dir_item; FILE *fp; sp_block *spBlock; inode inode_table[1024];//32blocks*32inodes*32bytes dir_item block_buffer[8];//一个目项为 2 ^ 7 字节,一个块大小为 2 ^ 10 字节,因此一个块可以存放 2 ^ (10 - 7) = 8 个 //find a free inode int find_free_inode(); //find a free block int find_free_block(); // do some pre-work when you run the FS void print_information(); //init void fs_init(); //ls /path void ls(char *path); //create -f /name void create_file(char *path, int size); //create -d /name void create_dir(char *path); //delete -f /name void delete_file(char *path); //delete -d /name void delete_dir(char *path); //move /name.exe /dir void move(char *from, char *to); //save and shutdown void shutdown();

首先需要留意的是block_size,因为我们每次操作磁盘时都是以block为单位进行读写的,所以每次使用fwrite/fread时这一点需要在实现函数时留意。在接下来的函数实现中可以看到的fwrite/fread(block_buffer, BLOCK_SIZE, 1, fp)中都是以block为单位的。

其次需要留意的是索引结点inode,它包含文件的大小,类型file_type,链接以及指向的数据块block_point。其中最重要的block_point保存的数据块编号了。

接下来是超级块,它是每次文件系统打开时第一个读入的块,其中包括初始化标记system_mod,空闲数据块计数free_block_count,空闲索引结点计数free_inode_count,文件夹索引结点计数dir_inode_count,块位示图block_map以及索引结点位示图inode_map。计数是用来打印进入系统时显示的空闲块/点数量的,而位示图是告诉你哪一块是空的。

 最后是文件目录项,这是实现树状目录结构的重点。其中包括了这个目录项对应的索引结点号inode_id,目录项末尾标记item_count,文件类型type以及文件名name[]。

介绍完了我们需要维护的数据结构后,接下来的就是定义对于这些数据的操作了。

文件系统操作解析:

  支持操作

  构建超级块

    构建超级块是你的文件系统第一次运行时应该对disk.os进行的操作。你需要将超级块中的各位进行正确的赋值,以保证接下来的操作能顺利进行。这里面包括system_mod(初始化标志),空闲块/结点计数、文件夹结点计数、位示图等等。你还需要建立一个根目录 “/”,并给他建立“.”和“..”

 

// Init   load in spBlock
void fs_init()
{
    int i;
    char buf[100];
    spBlock = (sp_block*)malloc(sizeof(sp_block));
    if ((fp = fopen("disk.os", "rb+")) == NULL) {
        puts("Fail to open file!");
        exit(0);
    }
    fseek(fp, 0, SEEK_SET);//跳转至该block
    fread(spBlock, sizeof(sp_block), 1, fp);
    if (spBlock->system_mod != 1)
    {
        //初始化
        spBlock->system_mod = 1;
        spBlock->free_block_count = 4096-1-32;
        spBlock->free_inode_count = 1023;//0
        spBlock->dir_inode_count = 1;//0

        memset(spBlock->inode_map, 0, sizeof(spBlock->inode_map));
        memset(spBlock->block_map, 0, sizeof(spBlock->block_map));

        spBlock->inode_map[0] = spBlock->inode_map[0] | (1 << 31);
        inode_table[0].block_point[0] = find_free_block();
        inode_table[0].file_type = 1;
        inode_table[0].size = 1;

        memset(block_buffer, 0, BLOCK_SIZE);
        //填充目录项
        //在上层目录里面建立这个文件夹的dir_item
        //填充的是 .(自身)和 ..(上层)
        //写入. 自身
        block_buffer[0].inode_id = 0;
        strcpy(block_buffer[0].name, ".");
        block_buffer[0].type = 1;
        block_buffer[0].item_count = 0;
        //写入.. 上层
        block_buffer[1].inode_id = 0;
        strcpy(block_buffer[1].name, "..");
        block_buffer[1].type = 1;
        block_buffer[1].item_count = 1;
        //写block
        fseek(fp, (1 + 32 + inode_table[0].block_point[0])*BLOCK_SIZE, SEEK_SET);//跳转至该block
        fwrite(block_buffer, BLOCK_SIZE, 1, fp);
        //写inode
        fseek(fp, BLOCK_SIZE , SEEK_SET);//跳转至该block
        fwrite(inode_table, sizeof(inode_table), 1, fp);
        //写入spblock
        fseek(fp, 0, SEEK_SET);//跳转至该block
        fwrite(spBlock, sizeof(sp_block), 1, fp);
        return;
    }
    fseek(fp, BLOCK_SIZE, SEEK_SET);//跳转至该block
    fread(inode_table, sizeof(inode_table), 1, fp);
    //fclose(fp);
    return;
}

 

 

 

  寻找空闲块/空闲索引结点

    需要遍历巡视位示图的各位,找到一个为空的可使用的块/结点。

    位示图是一段01构成的串,它的每一位都代表着一个块/结点的使用情况。由于我们使用C语言进行模拟,这里要注意的在超级块中留出的是uint32_t类型的block_map[128]数组(共4096位)和uint32_t类型的inode_map[32]数组(共1024位),在寻找空闲位时我的做法是从高到底进行搜索。当寻找到一个为0的位置时,将其置1作为使用标记,同时将该块/结点分配给申请的文件/文件夹,还要记得维护超级块中的count以防止对应错误。

 

int find_free_block()
{
    int i, j;
    /*if ((fp = fopen("disk.os", "r+")) == NULL) {
        puts("Fail to open file!");
        exit(0);
    }*/
    int num = -1;
    uint16_t buf;
    for (i = 0; i < 128; i++)//block外层 128个blockmap
    {
        for (j = 0; j < 32; j++)//block内层 32位
        {
            //0为最左
            buf = (spBlock->block_map[i] >> (31-j))&(uint16_t)1;
            if (buf == 0)
            {
                num = i * 32 + j;
                spBlock->block_map[i] = spBlock->block_map[i] | (1 << (31 - j));
                spBlock->free_block_count--;
                break;
            }
        }
        if (num != -1)
        {
            break;
        }
    }
    fseek(fp, 0, SEEK_SET);//跳转至该block
    fwrite(spBlock, sizeof(sp_block), 1, fp);
    return num;
}

//return the id of a free inode   num = inodeid * 32 + j;
int find_free_inode()
{

    spBlock->free_inode_count--;
    /*
    if ((fp = fopen("disk.os", "r+")) == NULL) {
        puts("Fail to open file!");
        exit(0);
    }
    */
    int i, j;
    int num = -1;
    uint16_t buf;
    for (i = 0; i < 32; i++)//block外层 32个inode
    {
        for (j = 0; j < 32; j++)//block内层 32位
        {
            //0为最左
            buf = (spBlock->inode_map[i] >> (31 - j))&(uint16_t)1;
            if (buf == 0)
            {
                num = i * 32 + j;
                spBlock->inode_map[i] = spBlock->inode_map[i] | (1 << (31 - j));
                break;
            }
        }
        if (num != -1)
        {
            break;
        }
    }

    fseek(fp, 0, SEEK_SET);//跳转至该block
    fwrite(spBlock, sizeof(sp_block), 1, fp);
    return num;
}

   

  寻找一个路径对应的inode_id

    这一个功能是将我们输入的路径如“/Happy/Coding”进行解析分拆,进行目录的跳转。我的做法是从左往右搜索,以“/”为分割,每次分割出一个目录名时向里进一层目录。需要做的是对于找到的父节点,遍历父节点对应的inode,读出那个inode块后遍历其拥有的6个dir_item块中的8个dir_item以寻找名字匹配。

     

//查找一个路径对应的inode_id
int find_name_inode(char *path)
{
    int i,j,o;
    int a=0;//inode_id 0==null
    int flag = 0;
    int len = 0;
    int last_time=0;
    char name_buf[20];
    len = strlen(path);
    //分割路径
    for (o = 1; o <= len; o++)
    {
        if (path[o] == /||o==len)
        {
            // /4/56/789
            // 012345678
            memset(name_buf,0,sizeof(name_buf));
            strncpy(name_buf, path + last_time + 1, o - last_time-1);
            last_time = o;
            for (i = 0; i < 6; i++)
            {
                flag = 0;
                memset(block_buffer, 0, sizeof(block_buffer));
                fseek(fp, (1 + 32 + inode_table[a].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                for (j = 0; j < 8; j++)
                {
                    
                    if (strcmp(block_buffer[j].name,name_buf)==0)//匹配进一层
                    {
                        a = block_buffer[j].inode_id;
                        flag = 1;
                        break;
                    }
                    if (block_buffer[j].item_count == 1)
                        break;
                }
                if (flag == 1)
                    break;
            }
        }
    }

    //fclose(fp);
    return

 

 

  以上是我认为的文件系统的支持操作,接下来则是具体的创建create、展示ls、删除delete和移动move

 

  创建

    这里需要按照创建的类型不同来进行划分,输入的指令故传入的参数也不同,分为带size的文件和不带size的文件夹。

 

     创建文件

    指令为create size /file_dir/file_name

    解析指令不再赘述,分析创建文件的过程。我们在匹配完路径后首先需要做的是分配一个空闲的inode,并标记其为文件项(file_type = 0)。

    接下来就可以对新文件的父目录进行操作了,遍历父目录对应inode的block_point数组(8*6),寻找一个空着的位置(其上一个的item_count 位置为 1)

    (PS:技术分享图片这个给的注释很假了!)

    在寻找空闲位置的过程中又有需要注意的情况:如果标志位出现在一个块的最后一个位置,则需要修改的dir_item在下一个block_point内,且这个block_point需要重新分配出来。

    最后,分配这个文件所需要的block的块数。

//创建一个文件
void create_file(char *path,int size)
{
    int i_num, i,j,flag;
    int last_time = 0;
    char name_buf[20];
    char path_buf[20];
    memset(name_buf, 0, sizeof(name_buf));
    memset(path_buf, 0, sizeof(path_buf));
    int len = strlen(path);
    int father_dir;
    //path匹配过程
    // /home/1
    // 0123456
    //i=5 len=7
    for (i=len-1;i >= 0;i--)
    {
        if (i == 0 || path[i] == /)
        {
            strncpy(name_buf, path + i+1,len-i-1);
            strncpy(path_buf, path ,i);
            break;
        }
    }
    if (strlen(path_buf) > 1)
    {
        father_dir = find_name_inode(path_buf);//父目录的inode
    }
    else
    {
        father_dir = 0;
    }
    //开始
    //建立inode
    i_num = find_free_inode();
    inode_table[i_num].file_type = 0;
    //修改父目录
    for (i = 0; i < inode_table[father_dir].size; i++)
    {
        flag = 0;
        memset(block_buffer, 0, sizeof(block_buffer));
        fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//int
        for (j = 0; j < 8; j++)
        {
            if (block_buffer[j].item_count == 1)//是最后一个
            {
                if (j < 7)
                {
                    block_buffer[j].item_count = 0;
                    block_buffer[j + 1].item_count = 1;
                    block_buffer[j + 1].inode_id = i_num;
                    block_buffer[j + 1].type = 0;
                    strcpy(block_buffer[j + 1].name, name_buf);
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    //控制位
                    flag = 1;
                    break;
                }
                else//新一块的第一个
                {
                    //修改原块final
                    block_buffer[j].item_count = 0;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    //写入下一块
                    memset(block_buffer, 0, sizeof(block_buffer));
                    block_buffer[0].item_count = 1;
                    block_buffer[0].inode_id = i_num;
                    block_buffer[0].type = 0;
                    strcpy(block_buffer[0].name, name_buf);
                    inode_table[father_dir].block_point[i + 1] = find_free_block();
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    //控制位
                    flag = 1;
                    break;
                }
                if(flag==1)
                    break;
            }
        }
        if (flag == 1)
            break;
    }
    //没有空闲块
    if (flag == 0)
    {
        if (inode_table[father_dir].size == 6)//最大值
        {
            printf("Too many files in a dir!\n");
            return;
        }
        else
        {
            inode_table[father_dir].block_point[inode_table[father_dir].size] = find_free_block;
            if (inode_table[father_dir].block_point[inode_table[father_dir].size] == -1)//无空闲块
            {
                printf("Out of Blocks!\n");
                return;
            }
            else
            {
                //修改上一块的结尾
                block_buffer[7].item_count = 0;
                fseek(fp, (1 + 32 + inode_table[father_dir].block_point[inode_table[father_dir].size])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                //写入下一块
                memset(block_buffer, 0, sizeof(block_buffer));
                block_buffer[0].item_count = 1;
                block_buffer[0].inode_id = i_num;
                block_buffer[0].type = 1;
                strcpy(block_buffer[0].name, name_buf);
                fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                inode_table[father_dir].size++;
            }
        }
    }
    //分配block
    int block_needed = 0;
    block_needed =((size-1) / BLOCK_SIZE) + 1;
    inode_table[i_num].size = block_needed;
    for (i = 0; i < block_needed; i++)
    {
        inode_table[i_num].block_point[i] = find_free_block();//
    }
    //fclose(fp);
    return;
}

  创建文件夹

   与上面的创建文件类似,但区别在于:

    1.创建的dir_item类型为1(这不是废话吗...)

    2.分配大小时先分配一块,其中插入“.”和“..”的dir_item

//创建一个文件夹
void create_dir(char *path)
{
    spBlock->dir_inode_count++;
    int i_num, i,j, flag;
    int last_time = 0;
    char name_buf[20];
    char path_buf[20];
    memset(name_buf, 0, sizeof(name_buf));
    memset(path_buf, 0, sizeof(path_buf));
    int father_dir;
    int len = strlen(path);
    //path匹配过程
    // /home/1
    // 0123456
    //i=5 len=7
    for (i = len - 1; i >= 0; i--)
    {
        if (i == 0 || path[i] == /)
        {
            strncpy(name_buf, path + i + 1, len - i - 1);
            strncpy(path_buf, path, i );
            break;
        }
    }
    if (strlen(path_buf) > 1) {
        father_dir = find_name_inode(path_buf);//父目录的inode
    }
    else
    {
        father_dir = 0;
    }
    //开始操作


    // 寻找给它的空闲inode 建立inode
    i_num = find_free_inode();
    //修改父目录
    //上层不好填充 选择扔给上层增加
    flag = 0;
    for (i = 0; i < inode_table[father_dir].size; i++)
    {
        memset(block_buffer, 0, sizeof(block_buffer));
        fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//int
        for (j = 0; j < 8; j++)
        {
            if (block_buffer[j].item_count == 1)//是最后一个
            {
                if (j < 7)
                {
                    block_buffer[j].item_count = 0;
                    block_buffer[j + 1].item_count = 1;
                    block_buffer[j + 1].inode_id = i_num;
                    block_buffer[j + 1].type = 1;
                    strcpy(block_buffer[j + 1].name, name_buf);
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    flag = 1;
                    break;
                }
                else//新一块的第一个
                {
                    //修改原块final
                    block_buffer[j].item_count = 0;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    //写入下一块
                    memset(block_buffer, 0, sizeof(block_buffer));
                    block_buffer[0].item_count = 1;
                    block_buffer[0].inode_id = i_num;
                    block_buffer[0].type = 1;
                    strcpy(block_buffer[0].name, name_buf);
                    inode_table[father_dir].block_point[i + 1] = find_free_block();
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    flag = 1;
                    break;
                }
                if (flag == 1)
                    break;
            }
        }
        if (flag == 1)
            break;
    }
    //没有空闲块
    if (flag == 0)
    {
        if (inode_table[father_dir].size == 6)//最大值
        {
            spBlock->dir_inode_count--;
            printf("Too many files in a dir!\n");
            return;
        }
        else
        {
            inode_table[father_dir].block_point[inode_table[father_dir].size] = find_free_block;
            if (inode_table[father_dir].block_point[inode_table[father_dir].size] == -1)//无空闲块
            {
                spBlock->dir_inode_count--;
                printf("Out of Blocks!\n");
                return;
            }
            else
            {
                //修改上一块的结尾
                block_buffer[7].item_count = 0;
                fseek(fp, (1 + 32 + inode_table[father_dir].block_point[inode_table[father_dir].size])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                //写入下一块
                memset(block_buffer, 0, sizeof(block_buffer));
                block_buffer[0].item_count = 1;
                block_buffer[0].inode_id = i_num;
                block_buffer[0].type = 1;
                strcpy(block_buffer[0].name, name_buf);
                fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block
                fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                inode_table[father_dir].size++;
            }
        }
    }

    //填充inode
    inode_table[i_num].file_type = 1;
    //分配block
    int block_needed = 1;//?.和 .. 后面得加
    inode_table[i_num].size = block_needed;//2*dir_item?
    for (i = 0; i < block_needed; i++)
    {
        inode_table[i_num].block_point[i] = find_free_block();//
    }
    memset(block_buffer, 0, BLOCK_SIZE);
    //填充目录项
    //在上层目录里面建立这个文件夹的dir_item
    //填充的是 .(自身)和 ..(上层)
    //写入. 自身
    block_buffer[0].inode_id = i_num;
    strcpy(block_buffer[0].name, ".");
    block_buffer[0].type = 1;
    block_buffer[1].item_count = 0;
    //写入.. 上层
    block_buffer[1].inode_id = father_dir;
    strcpy(block_buffer[1].name, "..");
    block_buffer[1].type = 1;
    block_buffer[1].item_count = 1;
    //写回到disk
    //写block
    fseek(fp, (1 + 32 + inode_table[i_num].block_point[0])*BLOCK_SIZE , SEEK_SET);//跳转至该block
    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
    //fclose(fp);
    return;

}

 展示

  这一段代码的功能是展示一个目录下所有的文件/文件夹。

  即找到父目录->遍历父目录下的dir_item打印名字->访问到item_count == 1时结束。

//展示一个文件夹下的所有东西
void ls(char *path)
{
    int i_num,j,i, flag;
    int last_time = 0;
    char name_buf[20];
    char path_buf[20];
    int len = strlen(path);
    int mumu;
    //path匹配过程
    // /home/1
    // 0123456
    //i=5 len=7

    if(len!=1)
    {
        mumu = find_name_inode(path);//父目录的inode
    }
    else
    {
        mumu = 0;
    }
    //读取 打印
    for (i = 0; i < inode_table[mumu].size; i++)
    {
        flag = 0;
        memset(block_buffer, 0, sizeof(block_buffer));
        fseek(fp, (1 + 32 + inode_table[mumu].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//int
        for (j = 0; j < 8; j++)
        {
            if (block_buffer[j].type == 1)//是最后一个
                printf("*");
            printf("%s  ", block_buffer[j].name);
            if (block_buffer[j].item_count == 1)//是最后一个
            {
                printf("\n");
                break;
            }
        }
    }
    //fclose(fp);

    return;
}

  删除

  "一个人真正死去,是被所有人都遗忘的时候"

    

  删除文件

  一个文件/文件夹的删除,一方面是它所占有的块和结点被释放,另一方面则是它的父目录中不再有它的数据,这两者都做到才是删干净了。前者需要用到它的inode编号,进而访问block_point释放块,然后释放inode;后者则是要解析路径以找到父目录的inode再进行操作,在删除时要记得重新置last标志位,并在父目录的一个block_point为空时删除它。

 

//删除一个文件
void delete_file(char *path)
{
    int i_num, i, j, k, flag;
    int last_time = 0;
    int block_out_num = 0, block_in_num = 0;
    int inode_out_num = 0, inode_in_num = 0;
    char name_buf[20];
    char path_buf[20];
    memset(name_buf, 0, sizeof(name_buf));
    memset(path_buf, 0, sizeof(path_buf));
    int len = strlen(path);
    int father_dir;
    int marker_i = -1, marker_j = -1;
    //path匹配过程
    // /home/1
    // 0123456
    //i=5 len=7
    dir_item buffer;
    for (i = len - 1; i >= 0; i--)
    {
        if (i == 0 || path[i] == /)
        {
            strncpy(name_buf, path + i + 1, len - i - 1);
            strncpy(path_buf, path, i);
            break;
        }
    }
    if (strlen(path_buf) > 1) {
        father_dir = find_name_inode(path_buf);//父目录的inode
    }
    else
    {
        father_dir = 0;
    }
    //开始

    //修改父目录
    for (i = 0; i < inode_table[father_dir].size; i++)
    {
        flag = 0;
        memset(block_buffer, 0, sizeof(block_buffer));
        fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//int
        for (j = 0; j < 8; j++)
        {
            //找得到
            if ((strcmp(name_buf, block_buffer[j].name) == 0)&&(block_buffer[j].type==0))
            {
                //此时为block_buffer[j]
                //释放该文件占用的块

                flag = 1;
                for (k = 0; k < inode_table[block_buffer[j].inode_id].size; k++)
                {
                    block_out_num = (inode_table[block_buffer[j].inode_id].block_point[k]) / 32;//块号
                    block_in_num = (inode_table[block_buffer[j].inode_id].block_point[k]) % 32;
                    spBlock->block_map[block_out_num] = spBlock->block_map[block_out_num] & (~(1 << (31 - block_in_num)));
                    spBlock->free_block_count++;
                }
                //释放该文件占用的inode
                inode_out_num = (block_buffer[j].inode_id) / 32;//块号
                inode_in_num = (block_buffer[j].inode_id) % 32;
                spBlock->inode_map[inode_out_num] = spBlock->inode_map[inode_out_num] & (~(1 << (31 - inode_in_num)));
                spBlock->free_inode_count++;
                marker_i = i;
                marker_j = j;
            }
            //释放该块占用的dir_item
            //这里注意要判定last==1?
            if (block_buffer[j].item_count == 1 && flag==1)//遍历到最后一个 
            {
                if (j > 0)//不是头
                {
                    // 去除标识位
                    block_buffer[j].item_count = 0;
                    buffer = block_buffer[j];
                    //替换最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    //替换待删除项
                    memset(block_buffer, 0, sizeof(block_buffer));
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                    block_buffer[marker_j] = buffer;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    flag = 2;

                    //重新标识最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                    block_buffer[j - 1].item_count = 1;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    break;
                }
                else//是头
                {
                    //去除标识位
                    block_buffer[j].item_count = 0;
                    buffer = block_buffer[j];
                    //替换最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    //替换待删除项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[marker_j] = buffer;//!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    //重新标识最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[7].item_count = 1;//!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    flag = 2;
                    break;
                }
            }
            if (flag == 2) 
            {
                break;
            }

        }
        if (flag != 2)
        {
            printf("Wrong Path!\n");
            return;
        }
        //fclose(fp);
        return;
    }
}

 

  删除文件夹

    删除文件夹大体类似。在找到应删除文件夹在父目录下的dir_item后,操作应删除文件夹下的各个dir_item:

    1. 对于其下的文件,调用delete_file进行删除

    2. 对于文件夹,重复调用delete_dir进行删除

//删除一个文件夹以及其中所有的文件
void delete_dir(char *path)
{
    int i_num, i, j, k, o, flag_lock=0, flag=0;
    int last_time = 0;
    int block_out_num = 0, block_in_num = 0;
    int inode_out_num = 0, inode_in_num = 0;
    char name_buf[20];
    char path_buf[20];
    char path_buf_2[20];
    memset(name_buf, 0, sizeof(name_buf));
    memset(path_buf, 0, sizeof(path_buf));
    int len = strlen(path);
    int father_dir;
    int marker_i = -1, marker_j = -1;
    //path匹配过程
    // /home/1
    // 0123456
    //i=5 len=7
    dir_item buffer;
    for (i = len - 1; i >= 0; i--)
    {
        if (i == 0 || path[i] == /)
        {
            strncpy(name_buf, path + i + 1, len - i - 1);
            strncpy(path_buf, path, i);
            break;
        }
    }
    if (strlen(path_buf) > 1) {
        father_dir = find_name_inode(path_buf);//父目录的inode
    }
    else
    {
        father_dir = 0;
    }
    //开始

    //修改父目录
    for (i = 0; i < inode_table[father_dir].size; i++)
    {
        //载入父目录一个新的block
        memset(block_buffer, 0, sizeof(block_buffer));
        fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//fail?
        flag = 0;
        flag_lock = 0;
        for (j = 0; j < 8; j++)//i块j项
        {
            //找得到
            buffer = block_buffer[j];
            if ((strcmp(name_buf, buffer.name) == 0) && (block_buffer[j].type == 1))
            {
                //此时为block_buffer[j]
                //删除他下面的文件
                //跳转到 该删除的目录下遍历他的儿子
                //也即释放他的block
                for (o = 0; o < inode_table[buffer.inode_id].size; o++)
                {
                    fseek(fp, (1 + 32 + inode_table[buffer.inode_id].block_point[o])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                    //遍历其下的目录项 进行删除
                    for (k = 0; k < 6; k++)
                    {
                        if ((strcmp(block_buffer[k].name, ".") == 0 || strcmp(block_buffer[k].name, "..") == 0)&& block_buffer[k].item_count != 1)
                            continue;
                        if ((strcmp(block_buffer[k].name, ".") == 0 || strcmp(block_buffer[k].name, "..") == 0) && block_buffer[k].item_count == 1)
                        {
                            flag = 1;
                            break;
                        }
                        if (block_buffer[k].type == 1)//dir
                        {
                            memset(path_buf_2, 0, sizeof(path_buf_2));
                            strcpy(path_buf_2, path);
                            strcat(path_buf_2, "/");
                            strcat(path_buf_2, block_buffer[k].name);
                            delete_dir(path_buf_2);
                            fseek(fp, (1 + 32 + inode_table[buffer.inode_id].block_point[o])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                            fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                            k--;
                        }
                        else if (block_buffer[k].type == 0)//file
                        {
                            memset(path_buf_2, 0, sizeof(path_buf_2));
                            strcpy(path_buf_2, path);
                            strcat(path_buf_2, "/");
                            strcat(path_buf_2, block_buffer[k].name);
                            delete_file(path_buf_2);
                            fseek(fp, (1 + 32 + inode_table[buffer.inode_id].block_point[o])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                            fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                            k--;
                        }
                        if (block_buffer[k].item_count == 1)//end
                        {
                            flag = 1;
                            break;
                        }
                    }
                    //释放这一个块
                    
                    block_out_num = (inode_table[buffer.inode_id].block_point[o]) / 32;//块号
                    block_in_num = (inode_table[buffer.inode_id].block_point[o]) % 32;
                    spBlock->block_map[block_out_num] = spBlock->block_map[block_out_num] & (~(1 << (31 - block_in_num)));
                    spBlock->free_block_count++;
                    if (flag == 1)//全部删除完毕
                        break;
                }
                //释放该文件占用的inode
                inode_out_num = (buffer.inode_id) / 32;//块号
                inode_in_num = (buffer.inode_id) % 32;
                spBlock->inode_map[inode_out_num] = spBlock->inode_map[inode_out_num] & (~(1 << (31 - inode_in_num)));
                spBlock->free_inode_count++;
                spBlock->dir_inode_count--;
                marker_i = i;
                marker_j = j;
                //回到父目录下
                //接下来释放该块占用的dir_item
                fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                fread(block_buffer, BLOCK_SIZE, 1, fp);
            }
            //找到最后一个
            if (block_buffer[j].item_count == 1 && flag == 1)
            {
                if (j > 0)//不是头
                {
                    // 去除标识位
                    block_buffer[j].item_count = 0;
                    buffer = block_buffer[j];
                    //替换最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    //替换待删除项
                    memset(block_buffer, 0, sizeof(block_buffer));
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                    block_buffer[marker_j] = buffer;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    flag = 2;

                    //重新标识最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                    block_buffer[j - 1].item_count = 1;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    break;
                }
                else//是头
                {
                    //去除标识位
                    block_buffer[j].item_count = 0;
                    buffer = block_buffer[j];
                    //替换最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    //替换待删除项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[marker_j] = buffer;//!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    //重新标识最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[7].item_count = 1;//!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    flag = 2;
                    break;
                }
            }
            if (flag == 2) {
                break;
            }
        }
    }
    if(flag != 2)
    {
        printf("Wrong Path!\n");
        return;
    }
    //fclose(fp);
    return;
}

 

  移动

  移动需要做的就是把它在原本的父目录下的dir_item移送到新的父目录下。还是需要注意增加/删除dir_item时的last标志位以及block的申请与释放。

/移动一个文件/文件夹
//move /file /dir
void move(char *from, char *to)
{
    int det_inode = find_name_inode(to);
    int i, j,k, father_dir, flag = 0;
    int marker_i, marker_j;
    char name_buf[30], path_buf[30];
    memset(name_buf, 0, sizeof(name_buf));
    memset(path_buf, 0, sizeof(path_buf));
    int len = strlen(from);
    dir_item buffer;
    dir_item buffer2;
    for (i = len - 1; i >= 0; i--)
    {
        if (i == 0 || from[i] == /)
        {
            strncpy(name_buf, from + i + 1, len - i - 1);
            strncpy(path_buf, from, i);
            break;
        }
    }
    if (strlen(path_buf) > 1) {
        father_dir = find_name_inode(path_buf);//父目录的inode
    }
    else
    {
        father_dir = 0;
    }
    //遍历父节点,寻找dir_item
    for (i = 0; i < inode_table[father_dir].size; i++)
    {
        memset(fp, 0, sizeof(fp));
        fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//fail?
        for (j = 0; j < 8; j++)
        {
            //找到匹配项
            if ((strcmp(name_buf, block_buffer[j].name) == 0)&&(block_buffer[j].type==0))//是否支持文件?
            {
                //记录
                buffer2 = block_buffer[j];
                marker_i = i;
                marker_j = j;
                flag = 1;
            }
            //清除
            if (block_buffer[j].item_count == 1 && flag == 1)//找到最末尾
            {
                if (j > 0)//不是头
                {
                    // 去除标识位后
                    // 用最后一项替换
                    block_buffer[j].item_count = 0;
                    buffer = block_buffer[j];
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);

                    //替换待删除项
                    memset(block_buffer, 0, sizeof(block_buffer));
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[marker_j] = buffer;//!!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    flag = 2;

                    //重新标识最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);//int
                    block_buffer[j - 1].item_count = 1;
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    break;
                }
                else//是头
                {
                    //去除标识位
                    block_buffer[j].item_count = 0;
                    buffer = block_buffer[j];

                    //替换最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);

                    //替换待删除项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[marker_j] = buffer;//!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);

                    //重新标识最后一项
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fread(block_buffer, BLOCK_SIZE, 1, fp);
                    block_buffer[7].item_count = 1;//!
                    fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    flag = 2;
                    break;
                }
            }
            else if (block_buffer[j].item_count == 1)
                break;
            if (flag == 2)
                break;
        }
    }
    //寻找目的地,添加dir_item
    for (i = 0; i < inode_table[det_inode].size; i++)
    {
        fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
        fread(block_buffer, BLOCK_SIZE, 1, fp);//fail?
        for (j = 0; j < 8; j++)
        {
            if (block_buffer[j].item_count == 1 && flag == 2 && (block_buffer[j].type == 1))//遍历到最后一个 
            {
                if (j < 7)
                {
                    block_buffer[j].item_count = 0;
                    block_buffer[j + 1] = buffer2;
                    block_buffer[j + 1].item_count = 1;
                    fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    flag = 3;
                    break;
                }
                else//新一块的第一个
                {
                    //修改原块final
                    block_buffer[j].item_count = 0;
                    fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);
                    //写入下一块
                    memset(block_buffer, 0, sizeof(block_buffer));
                    block_buffer[0] = buffer2;
                    block_buffer[0].item_count = 1;
                    fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i + 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block
                    fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int
                    flag = 3;
                    break;
                }
            }
            if (flag == 3)
                break;
        }
    }
    if (flag != 3)
        printf("Path error!\n");
    return;
}

    以上就是一个简单的对于Linux的Ext2 File System中的操作的模拟。

  欢迎大家交流~

 

 

 

 

  

 

  

myfs 操作系统课内实验 文件管理系统 Ext2

原文:https://www.cnblogs.com/mumujzl/p/12179594.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!