深圳大学操作系统综合实验2简易文件系统设计

实验目的

综合利用文件管理的相关知识,结合对文件系统的认知,编写简易文件系统,加深操作系统中文件系统和资源共享的认识。

实验内容

可以使用Linux或其它Unix类操作系统;

全面实践文件和目录操作及其组织结构;

编写简易文件系统。

实验环境

硬件:桌面PC

软件:Linux 或其他操作系统

实验步骤及说明

一:理论部分:

学习书本文件管理和磁盘存储器管理的相关章节,理解文件和目录的树状组织结构。

二:编程部分:.

  1. 创建一个100M的文件或者创建一个100M的共享内存
  2. 尝试自行设计一个C语言小程序,使用步骤1分配的100M空间(共享内存或mmap),然后假设这100M空间为一个空白磁盘,设计一个简单的文件系统管理这个空白磁盘,给出文件和目录管理的基本数据结构,并画出文件系统基本结构图,以及基本操作接口。(30分)
  3. 在步骤1的基础上实现部分文件操作接口操作,创建目录mkdir,删除目录rmdir,修改名称,创建文件open,修改文件,删除文件rm,查看文件系统目录结构ls。(40分)注明:全部在内存中实现
  4. 参考进程同步的相关章节,通过信号量机制实现多个终端对上述文件系统的互斥访问,系统中的一个文件允许多个进程读,不允许写操作;或者只允许一个写操作,不允许读。(30分)

实验过程

说明:该实验只是基于本人浅薄的理解设计而成的,写的代码也没有很好的结构封装,所以一些地方有些啰嗦。

一:理论部分:

学习书本文件管理和磁盘存储器管理的相关章节,理解文件和目录的树状组织结构。

文件和目录的树状组织结构

  1. 根目录:在文件系统中,所有的文件和目录都是从根目录开始的。在Unix和Linux系统中,根目录用"/"表示。
  2. 目录:目录可以包含文件和其他目录,形成了一个树状结构。每个目录项都有一个指向其子目录的链接。
  3. 文件:文件是数据的集合,它们可以是文本、图片、程序等。在文件系统中,文件通常以文件名和扩展名来标识。
  4. 路径:文件或目录的路径是描述其在文件系统中位置的字符串,可以是绝对路径或相对路径。
  5. 链接:链接可以是硬链接或软链接(符号链接)。硬链接是指向相同文件数据的另一个文件名,而软链接则是指向另一个文件或目录的路径。

二:编程部分:.

1.创建一个100M的文件或者创建一个100M的共享内存

        在create_mem.c(图1)程序中获取了100MB的共享内存,并且在程序结束前利用io阻塞程序,以在其他终端利用ipcs -m查看系统共享内存情况。

/*   create_mem.c   */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#define MB 1048576; //1024*1024
//static int MB = 1048576; //1024*1024

int main() {
    key_t key = 123123;
    //共享内存
    void* shared_memory = (void*)0;

    int shmid; //共享内存的ID

    /*获取共享内存区,并挂入内存*/
    int shm_size = 100*MB;
    printf("shared_memory's size: %dbytes\n", shm_size);
    //创建共享内存
    shmid = shmget(key, shm_size, IPC_CREAT | 0666);//key = 123123
    if (shmid < 0) {
        perror("shmget fail");
        exit(1);
    }
    shared_memory = shmat(shmid, 0, 0);

    char input[256];
    printf("You can input any to del the shared_memory:");
    scanf("%s", input);

    /*释放共享内存*/
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl failed");
        exit(EXIT_FAILURE);
    }
    return 0;
}

编译运行create_mem程序,如图2所示。

图 2 create_mem运行时显示屏

通过ipcs -m查看系统共享内存情况(如图3所示):确实存在100MB的共享内存,并且有一个进程正在连接。

图 3 查看create_mem创建的共享内存

结束create_mem程序(如图4所示)

图 4 create_mem结束

再次查看系统共享内存(如图5所示):共享内存已被释放

图 5 create_mem结束后系统共享内存情况

2.尝试自行设计一个C语言小程序,使用步骤1分配的100M空间(共享内存或mmap),然后假设这100M空间为一个空白磁盘,设计一个简单的文件系统管理这个空白磁盘,给出文件和目录管理的基本数据结构,并画出文件系统基本结构图,以及基本操作接口。(30分)

文件系统数据结构:

图 6 文件系统数据结构

编写testSize.c程序(如图9所示):调整设置data_block和inode数量,以达到系统内存达到100MB左右。

/*     testSize.c    */
#include<stdio.h>

#define KB 1024
// 100M === 25600 * 4Kb
// 1 file --- 1024KB --- 256 Data_block
#define Max_ListNum 20           // 最大子目录数量
#define INODE_MAXNum 200         // I_node最大数量
#define DataBlock_MAXNum 25344   // I_block最大数量 / 256*99
#define Max_FloorNum 8           // 最大层级

//数据块
typedef struct {
    unsigned char data[4 * KB];
}Data_block;

typedef struct {
    int inode_tag;          // 0 --- 未使用  1 --- 已使用
    int type;               // 0 --- 未定义类型  1 --- 文件夹  2 --- 文件
    int myIndex;            // 自身索引
    char path[256];         // 绝对路径
    char name[256];         // 文件/文件夹 名字

    /*          -------文件属性-------          */
    int size;
    int start_data_index;
    int end_data_index;
    /*         -------文件夹属性-------          */
    char son_namelist[Max_ListNum][256];
    int son_index_list[Max_ListNum];
    int list_lastpoint;
} Inode;

typedef struct {
    //索引区
    Inode i_bmap[INODE_MAXNum];
    int d_bmap[DataBlock_MAXNum];
    //数据区
    Data_block data_region[DataBlock_MAXNum];
}fSystem;

int main() {
	printf("Inode的大小为%ldB\n", sizeof(Inode));
    printf("Data_block的大小为%ldB\n", sizeof(Data_block));
    printf("Data_block的大小为%lfM\n", (double)sizeof(fSystem)/1024/1024);
}

图 9 testSize.c代码

由以下输出可以看到:经过调整,文件系统的内存达到99.9MB,近似100MB(如图10所示)。

图 10 testSize程序运行结果

3.在步骤1的基础上实现部分文件操作接口操作,创建目录mkdir,删除目录rmdir,修改名称,创建文件open,修改文件,删除文件rm,查看文件系统目录结构ls。(40分)注明:全部在内存中实现

该系统实现了以下接口:

图 11 文件系统功能接口

以下是各接口的具体实现过程:

makedir

流程图:

图 12 makedir函数流程图

代码:

int makedir(fSystem* sys, char* path) { //"/a/b/c" ---> [[a],[b],[c]]
    int i;
    //char dir_floor[2][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);

    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> dir_floor=[[a],[b]] --- floorNum=1

    // 检测路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("catalogue's path doesn't exit, path:%s\n", path);
        return -1;
    }

    //寻找父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);
    if (father_inode == NULL)
        printf("father_inode is NULL\n");
    //检测是否存在目录
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i != father_inode->list_lastpoint) {
        printf("catalogue's path has exited\n");
        return -1;
    }
    //此时father_inode指向的是创建最终目录的上一级目录,以下统称最后一级目录为子目录,其上一级目录称为父目录

    /*为子目录分配i_block以及inode*/
    //分配并初始化inode
    Inode* newInode = NULL;
    int newInode_index = init_inode(sys, &newInode);
    newInode->type = 1;
    strcopy(newInode->path, path);
    strcopy(newInode->name, dir_floor[floorNum]);
    printf("newInode:\nindex:%d,\nname:%s\ndirfloor[floorNnm]:%s\n", newInode->myIndex, newInode->name, dir_floor[floorNum]);

    //将子目录的inode_index写入父目录,name写入父目录的i_block
    addInode(sys, father_inode, newInode);

    printf("make catalogue success, path:%s\n", path);
    //释放指针
    father_inode = NULL;
    free(father_inode);
    newInode = NULL;
    free(newInode);

    return 0;
}

makefile:

流程图:

图 14 makefile函数流程图

代码:

int makefile(fSystem* sys, char* path, int size) {
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测父目录路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("file's path doesn't exit,path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    //检测文件是否已存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1) {
            printf("file has exited, path:%s\n", path);
            return -1;
        }
    }

    //创建文件
    int dataBlockNum = size / 4;
    if (dataBlockNum % 4 != 0) {
        dataBlockNum++;
    }
    //初始化dataBlockNum个data_block(连续的)
    //int init_datablockZone(int dataBlockNum) 返回起始下标
    int start_data_index = init_datablockZone(sys, dataBlockNum);
    int end_data_index = start_data_index + dataBlockNum - 1;

    //分配inode
    Inode* newInode = NULL;
    int inode_index = init_inode(sys, &newInode);
    newInode->type = 2;
    strcopy(newInode->path, path);
    strcopy(newInode->name, dir_floor[floorNum]);
    newInode->size = size;
    newInode->start_data_index = start_data_index;
    newInode->end_data_index = end_data_index;

    addInode(sys, father_inode, newInode);

    printf("make file success, path:%s,file's size: %dKB\n", newInode->path, newInode->size);

    father_inode = NULL;
    free(father_inode);
    newInode = NULL;
    free(newInode);

    return 0;
}

图 15 makefile代码

removedir:

流程图:

图 16 removedir函数流程图

代码:

int removedir(fSystem* sys, char* path) {
    //解析路径
    int i;
    //char dir_floor[2][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> dir_floor=[[a],[b]] --- floorNum=2 

    // 检测父目录路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("catalogue's path doesn't exit, path:%s\n", path);
        return -1;
    }

    //寻找父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    //检测是否存在目录
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i == 0 && isSame(father_inode->son_namelist[0], dir_floor[floorNum]) == 0) {
        printf("catalogue's path doesn't exit\n");
        return -1;
    }

    //释放该目录的子目录
    int son_inode_index = father_inode->son_index_list[i];
    Inode* son_inode = &(sys->i_bmap[son_inode_index]);
    char* base_path = son_inode->path;
    for (i = 0; i < son_inode->list_lastpoint; i++) {
        char newpath[256];
        newpath[0] = '\0';
        //printf("strlen:%d", strlen(newpath));
        spliceStr(newpath, base_path);
        newpath[strlen(newpath) + 1] = '\0';
        newpath[strlen(newpath)] = '/';
        spliceStr(newpath, son_inode->son_namelist[i]);
        //printf("newpath:%s\n",newpath);
        Inode new_inode = sys->i_bmap[son_inode->son_index_list[i]];
        if (new_inode.type == 1) {     //文件夹
            removedir(sys, newpath);
        }
        if (new_inode.type == 2) {      //文件
            removefile(sys, newpath);
        }
    }

    //在父目录删除该文件
    int del_inode_index = delInode(sys, father_inode, dir_floor[floorNum]);
    printf("remove catalogue success, path:%s\n", path);

    //释放指针
    father_inode = NULL;
    free(father_inode);
    son_inode = NULL;
    free(son_inode);
    return 0;
}

图 17 removedir代码

removefile:

流程图

图 18 removefile函数流程图

代码:

int removefile(fSystem* sys, char* path) {
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测父目录路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("file's path doesn't exit,path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    //检测文件是否存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1) {
            break;
        }
    }
    if (i == father_inode->list_lastpoint) {
        printf("file doesn't exit\n");
        return -1;
    }

    //在父目录删除该文件
    int del_inode_index = delInode(sys, father_inode, dir_floor[floorNum]);

    /*  释放该文件的inode、datablock  */
    Inode* del_inode = &(sys->i_bmap[del_inode_index]);

    //释放datablock
    int start_datablock = del_inode->start_data_index;
    int end_datablock = del_inode->end_data_index;
    for (i = start_datablock; i <= end_datablock; i++)
        sys->d_bmap[i] = 0;

    //释放inode
    del_inode->inode_tag = 0;
    del_inode->path[0] = '\0';
    del_inode->name[0] = '\0';
    del_inode->size = 0;
    del_inode->start_data_index = 0;
    del_inode->end_data_index = 0;

    printf("remove file success,path:%s,file's size:%dKB\n", path, (end_datablock - start_datablock + 1) * 4);
    father_inode = NULL;
    free(father_inode);
    del_inode = NULL;
    free(del_inode);
    return 0;
}

图 19 removefile代码

enlargefile:

流程图

图 20 enlargefile函数流程图

代码:

int enlargefile(fSystem* sys, char* path, int large_size_kb) {
    int large_size = large_size_kb / 4;
    if (large_size_kb % 4 != 0) {
        large_size++;
    }
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("File does not exist, path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    // 检测文件是否存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i == 0 && isSame(father_inode->son_namelist[0], dir_floor[floorNum]) == 0) {
        printf("File does not exist, path:%s", path);
        return -1;
    }

    //此时i为目标文件在父目录中的索引
    int inode_index = father_inode->son_index_list[i];
    Inode* file_inode = &(sys->i_bmap[inode_index]);

    //判断文件存储区后是否有足够的连续区域
    int ishave = 1;     // 0---没有足够区域   1---有足够区域
    int size = file_inode->size;
    int data_start = file_inode->start_data_index;
    int data_end = file_inode->end_data_index;
    for (i = data_end + 1; i <= data_end + large_size; i++) {
        if (sys->d_bmap[i] == 1) {
            ishave = 0;
            break;
        }
    }
    if (ishave == 1) {
        //直接在原有内存后分配
        file_inode->size += large_size * 4;
        file_inode->end_data_index += large_size;
    }
    else {
        // 重新分配所有内存
        // 释放原有的data
        for (i = data_start; i <= data_end; i++)
            sys->d_bmap[i] = 0;

        int new_data_start = init_datablockZone(sys, size + large_size);
        if (new_data_start == -1) {
            for (i = data_start; i <= data_end; i++)
                sys->d_bmap[i] = 1;
            printf("system's memory not enough, enlargefile fail\n");
            return -1;
        }
        for (i = new_data_start; i < new_data_start + size + large_size; i++)
            sys->d_bmap[i] = 1;
        file_inode->size += large_size * 4;
        file_inode->start_data_index = new_data_start;
        file_inode->end_data_index = new_data_start + size + large_size - 1;
    }
    printf("modify file success! filename:%s,enlarge %dKB. after enlarging,size: %dKB\n", file_inode->name, large_size, file_inode->size);

    //释放指针
    father_inode = NULL;
    free(father_inode);
    file_inode = NULL;
    free(file_inode);
    return 0;
}

图 21 enlargefile代码

reducefile:

流程图

图 22 reducefile函数流程图

代码:

int reducefile(fSystem* sys, char* path, int reduce_size_kb) {
    int reduce_size = reduce_size_kb / 4;
    if (reduce_size_kb % 4 != 0) {
        reduce_size++;
    }
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("File does not exist, path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    // 检测文件是否存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i == 0 && isSame(father_inode->son_namelist[0], dir_floor[floorNum]) == 0) {
        printf("File does not exist, path:%s", path);
        return -1;
    }

    //此时i为目标文件在父目录中的索引
    int inode_index = father_inode->son_index_list[i];
    Inode* file_inode = &(sys->i_bmap[inode_index]);
    if (reduce_size_kb >= file_inode->size) {
        if (reduce_size_kb == file_inode->size)
            printf("input equal to file's size, modify file fail\n");
        else
            printf("input larger than file's size, modify file fail\n");
        return -1;
    }
    file_inode->size -= reduce_size * 4;
    file_inode->end_data_index -= reduce_size / 4;
    printf("modify file success! filename:%s,reduce %dKB. after reducing,size: %dKB\n", file_inode->name, reduce_size, file_inode->size);

    //释放指针
    father_inode = NULL;
    free(father_inode);
    file_inode = NULL;
    free(file_inode);
    return 0;
}

图 23 reducefile代码

实现了以上接口,现在需要编写系统端和用户端代码,如下图24、25所示。

file_system:

/*    createSystem.c    */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>

#include "file_sys.h"

int* readCnt;
sem_t* read_mutex, * write_mutex;   //初始值 1
void read_lock() {
    sem_wait(read_mutex);
    *readCnt++;
    if (*readCnt == 1)
        sem_wait(write_mutex);
    sem_post(read_mutex);
}
void read_unlock() {
    sem_wait(read_mutex);
    *readCnt--;
    if (*readCnt == 0)
        sem_post(write_mutex);
    sem_post(read_mutex);
}
void write_lock() {
    sem_wait(write_mutex);
}
void write_unlock() {
    sem_post(write_mutex);
}

int main() {
    //共享内存
    void* shared_memory = (void*)0;
    fSystem* sys;

    int shmid; //共享内存的ID

    /*获取共享内存区,并挂入内存*/
    int shm_size = sizeof(fSystem);
    printf("shared_memory's size: %dbytes\n", shm_size);
    //创建共享内存
    shmid = shmget(key, shm_size, IPC_CREAT | 0666);//key = 123123
    if (shmid < 0) {
        perror("shmget fail");
        exit(1);
    }
    // 将共享内存挂载到sys上
    shared_memory = shmat(shmid, 0, 0);
    sys = (fSystem*)shared_memory;

    /*读写互斥量初始化*/
    sem_unlink(read_mutex_sign);
    sem_unlink(write_mutex_sign);
    read_mutex = sem_open(read_mutex_sign, O_CREAT | O_EXCL, 0644, 1);
    write_mutex = sem_open(write_mutex_sign, O_CREAT | O_EXCL, 0644, 1);

    //readCnt初始化
    int shmid_cnt = shmget(key_cnt, sizeof(int), 0666 | IPC_CREAT);
    if (shmid_cnt < 0) {
        perror("shmget fail");
        exit(1);
    }
    readCnt = (int*)shmat(shmid_cnt, 0, 0);

    //启动系统
    initSystem(sys);

    char input[256];
    printf("System is serving ....\n");
    printf("You can input any to pause the System:");
    scanf("%s", input);

    /*释放信号量*/
    sem_close(read_mutex);
    sem_close(write_mutex);
    unlink(read_mutex_sign);
    unlink(write_mutex_sign);

    /*释放共享内存*/
    //分离内存
    if (shmdt(shared_memory) == -1) {
        perror("shmdt fail");
        exit(EXIT_FAILURE);
    }
    //释放
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl failed");
        exit(EXIT_FAILURE);
    }
    /*释放readCnt*/
    shmdt(readCnt);
    shmctl(shmid_cnt, IPC_RMID, NULL);

    exit(EXIT_SUCCESS);
    return 0;
}

图 24 createSystem.c代码

User:

/*      user.c       */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>

#include "file_sys.h"

int* readCnt;
sem_t* read_mutex, * write_mutex;   //初始值 1
void read_lock() {
    sem_wait(read_mutex);
    *readCnt++;
    if (*readCnt == 1)
        sem_wait(write_mutex);
    sem_post(read_mutex);
}
void read_unlock() {
    sem_wait(read_mutex);
    *readCnt--;
    if (*readCnt == 0)
        sem_post(write_mutex);
    sem_post(read_mutex);
}
void write_lock() {
    sem_wait(write_mutex);
}
void write_unlock() {
    sem_post(write_mutex);
}

int main() {
    //共享内存
    void* shared_memory = (void*)0;
    fSystem* sys;

    int shmid; //共享内存的ID

    /*获取共享内存区,并挂入内存*/
    int shm_size = sizeof(fSystem);
    printf("shared_memory's size: %dbytes\n", shm_size);
    //创建共享内存
    shmid = shmget(key, shm_size, 0666);//key = 123123
    if (shmid < 0) {
        perror("shmget fail");
        exit(1);
    }
    // 将共享内存挂载到sys上
    shared_memory = shmat(shmid, 0, 0);
    sys = (fSystem*)shared_memory;

    /*获取读写互斥量*/
    read_mutex = sem_open(read_mutex_sign, 0);
    write_mutex = sem_open(write_mutex_sign, 0);
    if (read_mutex == SEM_FAILED) {
        perror("sem_open");
    }
    if (write_mutex == SEM_FAILED) {
        perror("sem_open");
    }

    //readCnt初始化
    int shmid_cnt = shmget(key_cnt, sizeof(int), 0666);
    if (shmid_cnt < 0) {
        perror("shmget fail");
        exit(1);
    }
    readCnt = (int*)shmat(shmid_cnt, 0, 0);

    while (1) {
        int opt = -1;
        printf("******---Simple File System---******\n");
        printf("*-----Create Directory  Enter:1----*\n");
        printf("*-----Delete Directory  Enter:2----*\n");
        printf("*-----Create File       Enter:3----*\n");
        printf("*-----Delete File       Enter:4----*\n");
        printf("*-----Modify File       Enter:5----*\n");
        printf("*-----Print  System     Enter:6----*\n");
        printf("*-----Exit System       Enter:0----*\n");
        printf("************************************\n");
        printf("please input a number:");
        scanf("%d", &opt);
        char path[256];
        int res, size, modi;
        switch (opt) {
        case 1:
            write_lock();
            printf("Please enter the directory path: ");
            scanf("%s", path);
            res = makedir(sys, path);
            if (res == -1)
                printf("Failed to create directory\n");
            write_unlock();
            break;
        case 2:
            write_lock();
            printf("Please enter the path of the directory to delete: ");
            scanf("%s", path);
            res = removedir(sys, path);
            if (res == -1)
                printf("Failed to delete directory\n");
            write_unlock();
            break;
        case 3:
            write_lock();
            printf("Please enter the file path: ");
            scanf("%s", path);
            printf("Please enter the file size (KB): ");
            scanf("%d", &size);
            res = makefile(sys, path, size);
            if (res == -1)
                printf("Failed to create file\n");
            write_unlock();
            break;
        case 4:
            write_lock();
            printf("Please enter the path of the file to delete: ");
            scanf("%s", path);
            res = removefile(sys, path);
            if (res == -1)
                printf("Failed to delete file\n");
            write_unlock();
            break;
        case 5:
            write_lock();
            printf("Please enter the path of the file to modify: ");
            scanf("%s", path);
            printf("Increase file size or decrease file size (1: Increase, 2: Decrease): ");
            scanf("%d", &modi);
            if (modi == 1) {
                printf("Please enter the amount to increase (KB): ");
                scanf("%d", &size);
                res = enlargefile(sys, path, size);
                if (res == -1)
                    printf("Failed to modify file\n");
            }
            else if (modi == 2) {
                printf("Please enter the amount to decrease (KB): ");
                scanf("%d", &size);
                res = reducefile(sys, path, size);
                if (res == -1)
                    printf("Failed to modify file\n");
            }
            else {
                printf("Invalid input, please try again\n");
            }
            write_unlock();
            break;
        case 6:
            read_lock();
            printSys(sys, 0);
            read_unlock();
            break;
        case 0:
            printf("Exiting system, goodbye!\n");
            break;
        default:
            printf("Please check the entered number option\n");
        }
        if (opt == 0)
            break;
    }
    /*释放信号量*/
    sem_close(read_mutex);
    sem_close(write_mutex);
    return 0;
}

图 25 user.c代码

测试文件系统:

编译运行文件系统系统(如图26所示)

图 26 运行file_system

运行用户端,打印系统情况(如图27所示)。

图 27 系统演示_运行用户端

创建目录

首先在根目录下创建a、b目录(如图28所示)

图 28 系统演示_创建目录_1

然后在根目录下创建c目录,在a目录下创建d目录(如图29所示)

图 29 系统演示_创建目录_2

打印系统情况检验,结果与上述操作预期一致(如图30所示)。

图 30 系统演示_创建目录_结果

若是重复创建,系统会提示创建失败(如图31所示)。

图 31 系统演示_创建目录_3

删除目录

随后我们删除/b、/a目录(此时/a目录下还有d目录):从结果可以看到/a、/b目录都被删除,并且/a目录下的子目录d也被删除了,做到了级联删除的效果(如图32所示)。

图 32 系统演示_删除目录_1

重复删除目录。若是重复删除目录,系统会给出提示,删除失败。(如图33所示)

图 33 系统演示_删除目录_2

打印系统情况检验,结果与上述操作预期一致。(如图34所示)

图 34 系统演示_删除目录_结果

创建文件

在根目录和c目录下分别创建a.txt文件,前者大小为48KB,后者大小为16KB(如图35所示)。

图 35 系统演示_创建文件_1

重复创建文件,系统提示文件已存在,创建失败(如图36所示)。

图 36 系统演示_创建文件_2

打印系统情况检验,结果与上述操作预期一致(如图37所示)。

图 37 系统演示_创建文件_结果

删除文件

删除c目录下的a.txt文件,并且测试重复删除(如图38所示)。

图 38 系统演示_删除文件_1

打印系统情况检验,结果与上述操作预期一致(如图39所示)。

图 39 系统演示_删除文件_结果

修改文件

增大文件

对根目录下的a.txt修改内存,让其大小增加16KB。经过增加后,/a.txt文件大小变为64KB(如图40所示)。

图 40 系统演示_修改文件_增大文件

减小文件

对/a.txt文件(size=64KB)减小128KB,系统给出错误提示(如图41所示)。

图 41 系统演示_修改文件_减小文件_1

对/a.txt文件(size=64KB)减小32KB,减小成功(如图42所示)。

图 42 系统演示_修改文件_减小文件_2

用户端退出系统(如图43所示)

图 43 系统演示_退出系统

结束文件系统(如图44所示)

图 44 系统演示_结束文件系统

4.参考进程同步的相关章节,通过信号量机制实现多个终端对上述文件系统的互斥访问,系统中的一个文件允许多个进程读,不允许写操作;或者只允许一个写操作,不允许读。(30分)

读写锁顺序:

Writer:

        wait(write_mutex);

        //write

        post(wmutex);

Reader:

        wait(read_mutex);

        *readerCnt++;

        If(*readerCnt == 1)

                wait(write_mutex);

        post(read_mutex);

        //read

        wait(read_mutex);

        *readerCnt--;

        if(*readerCnt == 0)

                post(write_mutex);

        post(read_mutex);

代码实现:

图 45 读写锁定义及函数

我利用函数封装读写操作锁,并且利用共享内存readCnt来实现对多进程读操作计数。这样的设计使得文件系统同一时刻能够有多进程读取数据,但只能有一个进程修改数据。并且当一个进程请求修改文件权限时,需要等待所有正在读的进程退出后才能进行写操作。

实验过程:

启动文件系统,并且打开两个用户进程(如图46、47所示)。

图 46 运行file_system程序

图 47 同时运行两个user程序

其中一个进程输入1进入创建目录,但此时先不输入目录路径,随后在另一进程也输入1进入创建目录,此时可以看到第二个进程并没有弹出输入路径的提示,说明此时该进程处于阻塞状态,因为它在等待第一个进程释放write_mutex(如图48所示)。

图 48 写操作阻塞

该系统操作只有printSys是读操作,由于这是简易文件系统,主要是实现内存分配管理,在实验时并没有真正的文件数据输入,所以分配的data_block都是空的,但是其中确实可以放数据。若是有文件数据,添加一个返回指定文件数据的接口即可。

完整代码

file_sys.h

#ifndef FILE_SYS_H
#define FILE_SYS_H

#include<fcntl.h>
#include<sys/stat.h>
#include<semaphore.h>	//***#include<semaphore.h>
#include<stdio.h>
#include <stdlib.h>
#include<string.h>

//用于创建信号量时的识别ID
static char* read_mutex_sign = "read_mutex";
static char* write_mutex_sign = "write_mutex";

static key_t key = 123123;
static key_t key_cnt = 000333;

#define KB 1024
// 100M === 25600 * 4Kb
#define Max_ListNum 20        // 最大子目录数量
#define INODE_MAXNum 200      // I_node最大数量
#define DataBlock_MAXNum 25344  // I_block 256KB*99
#define Max_FloorNum 8       // 最大层级

//数据块
typedef struct {
    unsigned char data[4 * KB];
}Data_block;

typedef struct {
    int inode_tag;          // 0 --- 未使用  1 --- 已使用
    int type;               // 0 --- 未定义类型  1 --- 文件夹  2 --- 文件
    int myIndex;            // 自身索引
    char path[256];         // 绝对路径
    char name[256];         // 文件/文件夹 名字

    /*          -------文件属性-------          */
    int size;
    int start_data_index;
    int end_data_index;
    /*         -------文件夹属性-------          */
    char son_namelist[Max_ListNum][256];
    int son_index_list[Max_ListNum];
    int list_lastpoint;
} Inode;

typedef struct {
    //索引区
    Inode i_bmap[INODE_MAXNum];
    int d_bmap[DataBlock_MAXNum];
    //数据区
    Data_block data_region[DataBlock_MAXNum];
}fSystem;

//工具函数
int spliceStr(char* front, char* back);
int strcopy(char* dest, char* source);
int isSame(char* dest, char* source);
int prasePath(char* path, char** dir_floor);
int find_father_inode(fSystem* sys, char** dir_floor, int floorNum, Inode** father_inode);
int isPathRight(fSystem* sys, char** dir_floor, int floorNum);
int addInode(fSystem* sys, Inode* father_inode, Inode* son_inode);
int delInode(fSystem* sys, Inode* father_inode, char* son_name);

//初始化函数
void initSystem(fSystem* sys);
int init_inode(fSystem* sys, Inode** newInode); // 返回inode_index
int init_datablockZone(fSystem* sys, int dataBlockNum);           //返回起始下标

//功能函数
int makedir(fSystem* sys, char* path);              // 创建目录
int removedir(fSystem* sys, char* path);            // 删除目录
int makefile(fSystem* sys, char* path, int size);   // 创建文件
int removefile(fSystem* sys, char* path);           // 删除文件
int enlargefile(fSystem* sys, char* path, int large_size);  // 修改文件-增大文件
int reducefile(fSystem* sys, char* path, int reduce_size);  // 修改文件-减小文件
void printSys(fSystem* sys, int index);             // 输出系统情况

#endif // FILE_SYS_H

file_sys.c

#include "file_sys.h"

void initSystem(fSystem* sys) {
    int i;
    for (i = 0; i < INODE_MAXNum; i++)
        sys->i_bmap[i].inode_tag = 0;
    for (i = 0; i < DataBlock_MAXNum; i++)
        sys->d_bmap[i] = 0;

    Inode* n = NULL;
    int index = init_inode(sys, &n);
    n->path[0] = '/';
    n->path[1] = '\0';
    strcopy(n->name, n->path);
    n->type = 1;

}
int init_inode(fSystem* sys, Inode** newInode) {
    int i;
    int newInode_index = -1;
    for (i = 0; i < INODE_MAXNum; i++) {
        if (sys->i_bmap[i].inode_tag == 0) {
            //printf("inode有位置\n");
            newInode_index = i;
            break;
        }
    }
    *newInode = &(sys->i_bmap[newInode_index]);
    (*newInode)->inode_tag = 1;
    (*newInode)->type = 0;
    (*newInode)->myIndex = newInode_index;
    (*newInode)->name[0] = '\0';
    (*newInode)->path[0] = '\0';

    (*newInode)->size = 0;
    (*newInode)->start_data_index = -1;
    (*newInode)->end_data_index = -1;

    (*newInode)->list_lastpoint = 0;

    return newInode_index;
}
int init_datablockZone(fSystem* sys, int dataBlockNum) {
    int i, j;
    int find_tag = 0;
    for (i = 0; i < DataBlock_MAXNum; i++) {
        if (sys->d_bmap[i] == 0) {
            int ishave = 1;
            for (j = i; j < i + dataBlockNum; j++) {
                if (sys->d_bmap[j] == 1)
                    ishave = 0;
            }
            if (ishave == 1) {
                find_tag = 1;
                break;
            }
        }
    }
    if (find_tag == 1) {
        for (j = i; j < i + dataBlockNum; j++)
            sys->d_bmap[j] = 1;
    }
    return find_tag == 1 ? i : -1;
}

int prasePath(char* path, char** dir_floor) {
    int i, index = 0;
    int floorNum = -1;
    for (i = 0; i < strlen(path); i++) {
        if (path[i] == '/') {
            if (floorNum != -1) {
                dir_floor[floorNum][index] = '\0';
            }
            floorNum++;
            index = 0;
            continue;
        }
        dir_floor[floorNum][index++] = path[i];
    }
    dir_floor[floorNum][index] = '\0';
    return floorNum;
}
int find_father_inode(fSystem* sys, char** dir_floor, int floorNum, Inode** father_inode) {   //传入指针的地址才能改变指针
    int i, j;
    *father_inode = &(sys->i_bmap[0]);
    int father_inode_index = 0;
    for (i = 0; i < floorNum; i++) {

        if ((*father_inode)->type == 1) {                //当前inode为文件夹
            int ishave = 0;
            for (j = 0; j < (*father_inode)->list_lastpoint; j++)
            {
                if (isSame(dir_floor[i], (*father_inode)->son_namelist[j]) == 1) {
                    break;
                }
            }
            father_inode_index = (*father_inode)->son_index_list[j];
            *father_inode = &(sys->i_bmap[father_inode_index]);
        }
        else {
            printf("find_father_inode参数路径错误\n");
            return -1;
            //break;
        }
    }
    return 0;
}
int isPathRight(fSystem* sys, char** dir_floor, int floorNum) {
    int i, j;
    Inode* father_inode = &(sys->i_bmap[0]);
    int father_inode_index = 0;
    for (i = 0; i < floorNum; i++) {
        printf("inode'name: %s\n", father_inode->name);
        if (father_inode->type == 1) {                //当前inode为文件夹
            int ishave = 0;
            for (j = 0; j < father_inode->list_lastpoint; j++)
            {
                if (isSame(dir_floor[i], father_inode->son_namelist[j]) == 1) {
                    ishave = 1;
                    break;
                }
            }
            if (ishave == 0) {  //当前父目录不存在目标子目录
                return -1;
            }
            else {                                  //当前父目录存在目标子目录
                //printf("检测到目标目录");
                father_inode_index = father_inode->son_index_list[j];
                father_inode = &(sys->i_bmap[father_inode_index]);
            }
        }
        else {
            printf("参数路径错误\n");
            return -1;
        }
    }
    return 0;
}
void printSys(fSystem* sys, int index) {

    Inode* father_inode = &(sys->i_bmap[index]);

    if (father_inode->type == 2) {
        //printf("file:%s\n",  father_inode.name);
    }
    else {

        int i;
        printf("folder:%s ---> ", father_inode->name);
        for (i = 0; i < father_inode->list_lastpoint; i++) {
            printf("%s-", father_inode->son_namelist[i]);
        }
        printf("NULL\n");
        for (i = 0; i < father_inode->list_lastpoint; i++) {
            printSys(sys, father_inode->son_index_list[i]);
        }
    }
}
int spliceStr(char* front, char* back) {
    int f_len = strlen(front);
    int b_len = strlen(back);
    int i, j = 0;
    for (i = f_len; i < f_len + b_len; i++)
        front[i] = back[j++];
    front[f_len + b_len] = '\0';
    return f_len + b_len;
}
int strcopy(char* dest, char* source) {

    int dest_len = strlen(dest);
    int sour_len = strlen(source);

    printf("dest:%s size:%d\nsource:%s size:%d\n", dest, dest_len, source, sour_len);
    int i;
    for (i = 0; i < sour_len; i++) {
        dest[i] = source[i];
    }
    dest[i] = '\0';
    /*printf("dest_len:%d,sour_len:%d\n", dest_len, sour_len);
    printf("source:%s\n", source);
    printf("dest:%s\n\n", dest);*/
    return i;
}
int isSame(char* dest, char* source) {
    int dest_len = strlen(dest);
    int sour_len = strlen(source);
    if (sour_len != dest_len)
        return 0;
    int i;
    for (i = 0; i < sour_len; i++) {
        if (dest[i] != source[i])
            break;
    }
    return i == dest_len ? 1 : 0;
}

int addInode(fSystem* sys, Inode* father_inode, Inode* son_inode) {
    //将子目录的inode_index写入父目录,name写入父目录的i_block
    int last_p = father_inode->list_lastpoint;

    father_inode->son_index_list[last_p] = son_inode->myIndex;
    //printf("newInode_index:%d\n", newInode_index);
    strcopy(father_inode->son_namelist[last_p], son_inode->name);
    father_inode->list_lastpoint++;

    return 0;
}
int delInode(fSystem* sys, Inode* father_inode, char* son_name) {
    printf("todel_name:%s\n", son_name);
    //将子目录的inode_index写入父目录,name写入父目录的i_block
    int last_p = father_inode->list_lastpoint;
    int del_inode_index = -1;
    int i, j;

    for (i = 0; i < last_p; i++) {
        if (isSame(son_name, father_inode->son_namelist[i]) == 1)
            break;
    }
    if (i == last_p) {
        printf("delInode fail:the file doesn't exit\n");
        return -1;
    }
    del_inode_index = father_inode->son_index_list[i];
    for (j = i; j < last_p - 1; j++) {
        //printf("father_block->name_sonlist[j + 1]:%s\n", father_block->name_sonlist[j + 1]);
        strcopy(father_inode->son_namelist[j], father_inode->son_namelist[j + 1]);
        father_inode->son_index_list[j] = father_inode->son_index_list[j + 1];
    }
    father_inode->list_lastpoint--;
    return del_inode_index;
}


int makedir(fSystem* sys, char* path) { //"/a/b/c" ---> [[a],[b],[c]]
    int i;
    //char dir_floor[2][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);

    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> dir_floor=[[a],[b]] --- floorNum=1

    // 检测路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("catalogue's path doesn't exit, path:%s\n", path);
        return -1;
    }

    //寻找父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);
    if (father_inode == NULL)
        printf("father_inode is NULL\n");
    //检测是否存在目录
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i != father_inode->list_lastpoint) {
        printf("catalogue's path has exited\n");
        return -1;
    }
    //此时father_inode指向的是创建最终目录的上一级目录,以下统称最后一级目录为子目录,其上一级目录称为父目录

    /*为子目录分配i_block以及inode*/
    //分配并初始化inode
    Inode* newInode = NULL;
    int newInode_index = init_inode(sys, &newInode);
    newInode->type = 1;
    strcopy(newInode->path, path);
    strcopy(newInode->name, dir_floor[floorNum]);
    printf("newInode:\nindex:%d,\nname:%s\ndirfloor[floorNnm]:%s\n", newInode->myIndex, newInode->name, dir_floor[floorNum]);

    //将子目录的inode_index写入父目录,name写入父目录的i_block
    addInode(sys, father_inode, newInode);

    printf("make catalogue success, path:%s\n", path);
    //释放指针
    father_inode = NULL;
    free(father_inode);
    newInode = NULL;
    free(newInode);

    return 0;
}
int makefile(fSystem* sys, char* path, int size) {
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测父目录路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("file's path doesn't exit,path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    //检测文件是否已存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1) {
            printf("file has exited, path:%s\n", path);
            return -1;
        }
    }

    //创建文件
    int dataBlockNum = size / 4;
    if (dataBlockNum % 4 != 0) {
        dataBlockNum++;
    }
    //初始化dataBlockNum个data_block(连续的)
    //int init_datablockZone(int dataBlockNum) 返回起始下标
    int start_data_index = init_datablockZone(sys, dataBlockNum);
    int end_data_index = start_data_index + dataBlockNum - 1;

    //分配inode
    Inode* newInode = NULL;
    int inode_index = init_inode(sys, &newInode);
    newInode->type = 2;
    strcopy(newInode->path, path);
    strcopy(newInode->name, dir_floor[floorNum]);
    newInode->size = size;
    newInode->start_data_index = start_data_index;
    newInode->end_data_index = end_data_index;

    addInode(sys, father_inode, newInode);

    printf("make file success, path:%s,file's size: %dKB\n", newInode->path, newInode->size);

    father_inode = NULL;
    free(father_inode);
    newInode = NULL;
    free(newInode);

    return 0;
}
int removefile(fSystem* sys, char* path) {
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测父目录路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("file's path doesn't exit,path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    //检测文件是否存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1) {
            break;
        }
    }
    if (i == father_inode->list_lastpoint) {
        printf("file doesn't exit\n");
        return -1;
    }

    //在父目录删除该文件
    int del_inode_index = delInode(sys, father_inode, dir_floor[floorNum]);

    /*  释放该文件的inode、datablock  */
    Inode* del_inode = &(sys->i_bmap[del_inode_index]);

    //释放datablock
    int start_datablock = del_inode->start_data_index;
    int end_datablock = del_inode->end_data_index;
    for (i = start_datablock; i <= end_datablock; i++)
        sys->d_bmap[i] = 0;

    //释放inode
    del_inode->inode_tag = 0;
    del_inode->path[0] = '\0';
    del_inode->name[0] = '\0';
    del_inode->size = 0;
    del_inode->start_data_index = 0;
    del_inode->end_data_index = 0;

    printf("remove file success,path:%s,file's size:%dKB\n", path, (end_datablock - start_datablock + 1) * 4);
    father_inode = NULL;
    free(father_inode);
    del_inode = NULL;
    free(del_inode);
    return 0;
}
int removedir(fSystem* sys, char* path) {
    //解析路径
    int i;
    //char dir_floor[2][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> dir_floor=[[a],[b]] --- floorNum=2 

    // 检测父目录路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("catalogue's path doesn't exit, path:%s\n", path);
        return -1;
    }

    //寻找父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    //检测是否存在目录
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i == 0 && isSame(father_inode->son_namelist[0], dir_floor[floorNum]) == 0) {
        printf("catalogue's path doesn't exit\n");
        return -1;
    }

    //释放该目录的子目录
    int son_inode_index = father_inode->son_index_list[i];
    Inode* son_inode = &(sys->i_bmap[son_inode_index]);
    char* base_path = son_inode->path;
    for (i = 0; i < son_inode->list_lastpoint; i++) {
        char newpath[256];
        newpath[0] = '\0';
        //printf("strlen:%d", strlen(newpath));
        spliceStr(newpath, base_path);
        newpath[strlen(newpath) + 1] = '\0';
        newpath[strlen(newpath)] = '/';
        spliceStr(newpath, son_inode->son_namelist[i]);
        //printf("newpath:%s\n",newpath);
        Inode new_inode = sys->i_bmap[son_inode->son_index_list[i]];
        if (new_inode.type == 1) {     //文件夹
            removedir(sys, newpath);
        }
        if (new_inode.type == 2) {      //文件
            removefile(sys, newpath);
        }
    }

    //在父目录删除该文件
    int del_inode_index = delInode(sys, father_inode, dir_floor[floorNum]);
    printf("remove catalogue success, path:%s\n", path);

    //释放指针
    father_inode = NULL;
    free(father_inode);
    son_inode = NULL;
    free(son_inode);
    return 0;
}
int enlargefile(fSystem* sys, char* path, int large_size_kb) {
    int large_size = large_size_kb / 4;
    if (large_size_kb % 4 != 0) {
        large_size++;
    }
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("File does not exist, path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    // 检测文件是否存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i == 0 && isSame(father_inode->son_namelist[0], dir_floor[floorNum]) == 0) {
        printf("File does not exist, path:%s", path);
        return -1;
    }

    //此时i为目标文件在父目录中的索引
    int inode_index = father_inode->son_index_list[i];
    Inode* file_inode = &(sys->i_bmap[inode_index]);

    //判断文件存储区后是否有足够的连续区域
    int ishave = 1;     // 0---没有足够区域   1---有足够区域
    int size = file_inode->size;
    int data_start = file_inode->start_data_index;
    int data_end = file_inode->end_data_index;
    for (i = data_end + 1; i <= data_end + large_size; i++) {
        if (sys->d_bmap[i] == 1) {
            ishave = 0;
            break;
        }
    }
    if (ishave == 1) {
        //直接在原有内存后分配
        file_inode->size += large_size * 4;
        file_inode->end_data_index += large_size;
    }
    else {
        // 重新分配所有内存
        // 释放原有的data
        for (i = data_start; i <= data_end; i++)
            sys->d_bmap[i] = 0;

        int new_data_start = init_datablockZone(sys, size + large_size);
        if (new_data_start == -1) {
            for (i = data_start; i <= data_end; i++)
                sys->d_bmap[i] = 1;
            printf("system's memory not enough, enlargefile fail\n");
            return -1;
        }
        for (i = new_data_start; i < new_data_start + size + large_size; i++)
            sys->d_bmap[i] = 1;
        file_inode->size += large_size * 4;
        file_inode->start_data_index = new_data_start;
        file_inode->end_data_index = new_data_start + size + large_size - 1;
    }
    printf("modify file success! filename:%s,enlarge %dKB. after enlarging,size: %dKB\n", file_inode->name, large_size, file_inode->size);

    //释放指针
    father_inode = NULL;
    free(father_inode);
    file_inode = NULL;
    free(file_inode);
    return 0;
}
int reducefile(fSystem* sys, char* path, int reduce_size_kb) {
    int reduce_size = reduce_size_kb / 4;
    if (reduce_size_kb % 4 != 0) {
        reduce_size++;
    }
    //解析路径
    int i;
    //char dir_floor[Max_FloorNum][256];
    char** dir_floor = (char**)malloc(sizeof(char*) * Max_FloorNum);
    for (i = 0; i < Max_FloorNum; i++)
        dir_floor[i] = (char*)malloc(sizeof(char) * 256);
    int floorNum = prasePath(path, dir_floor);  // "/a/b" ---> [[a],[b]] --- floorNum=2 

    // 检测路径合法性
    int path_ok = isPathRight(sys, dir_floor, floorNum);
    if (path_ok == -1) {
        printf("File does not exist, path:%s\n", path);
        return -1;
    }

    //找到父目录
    Inode* father_inode = NULL;
    find_father_inode(sys, dir_floor, floorNum, &father_inode);

    // 检测文件是否存在
    for (i = 0; i < father_inode->list_lastpoint; i++) {
        if (isSame(father_inode->son_namelist[i], dir_floor[floorNum]) == 1)
            break;
    }
    if (i == 0 && isSame(father_inode->son_namelist[0], dir_floor[floorNum]) == 0) {
        printf("File does not exist, path:%s", path);
        return -1;
    }

    //此时i为目标文件在父目录中的索引
    int inode_index = father_inode->son_index_list[i];
    Inode* file_inode = &(sys->i_bmap[inode_index]);
    if (reduce_size_kb >= file_inode->size) {
        if (reduce_size_kb == file_inode->size)
            printf("input equal to file's size, modify file fail\n");
        else
            printf("input larger than file's size, modify file fail\n");
        return -1;
    }
    file_inode->size -= reduce_size * 4;
    file_inode->end_data_index -= reduce_size / 4;
    printf("modify file success! filename:%s,reduce %dKB. after reducing,size: %dKB\n", file_inode->name, reduce_size, file_inode->size);

    //释放指针
    father_inode = NULL;
    free(father_inode);
    file_inode = NULL;
    free(file_inode);
    return 0;
}

  • 26
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值