操作系统实验十二:文件系统模拟

该程序在内存中模拟了一个简单的文件系统,支持touch、rm、ls、mkdir、rmdir和cd命令。用户通过命令行与系统交互,不涉及硬盘读写,无并发处理。文件系统基于ext2模型,包含超级块、组描述、块位图、inode位图等数据结构。程序提供文件和目录的创建、删除、查看及切换目录功能,并能保存和加载状态。
摘要由CSDN通过智能技术生成

实验内容

一、程序主要功能

1、在内存中开辟一块空间来模拟文件系统的运行,不读写硬盘。

2、面向单用户、单任务,不考虑并发,不考虑文件属主、组等概念。

3、程序开始后,初始化并接收用户输入。若输入”enter”,则重新建立文件系统, 读取上次的退出状态,以上次目录为当前目录; 若输入”q”则退出程序。

系统采用命令行方式与用户交互:touch, rm, ls, mkdir, rmdir, cd ;显示每条命令的执行结果;然后准备接收下一条命令。

用户输入”exit”后,保存当前状态,退出系统 ,等待用户输入。

二、程序主要数据结构

1、文件的属性:

  • 文件名(最大长度?) ;
  • 文件类型:目录、数据;不考虑链接。
  • 文件权限:w/r/x ;
  • 文件大小:字节为单位。
  • 文件最后修改时间:取程序运行来的时钟滴答数(转换为float)。

2、文件系统的组织:模仿ext2文件系统。

  • 超级块:结构体;
  • 组描述:结构体;
  • 块位图:一维数组;
  • inode位图:一维数组;
  • inode table::二维数组,每行a~m位表示**,n~x位表示**… ;
  • 数据块:每个数据块的头2个字节作指针,指向同一文件的下一数据块。

3、文件的结构:

  • 数据文件:第一个数据块的地址在inode table 表项中,后续数据块通过指针连接起来;
  • 目录文件:同上。每2个字节用来记录一个子inode。
  • 存储空间组织:内存空间分成若干小块。

4、关于touch:

  • touch filename:若filename不存在,则创建新数据文件,分配inode,不分配数据块;若filename存在,则修改文件时间。
  • touch size filename: 若filename不存在,则创建新数据文件,分配inode,根据size分配数据块; 若filename存在,则修改文件大小和时间。

5、其他命令均简单实现:rm删除一个文件,cd 改变工作目录,mkdir创建一个目录文件,rmdir删除一个空目录。所有命令都要有输出(结果或信息)。

三、程序主要算法

1、存储空间分配算法。

2、回收。

3、命令的实现。

四、程序实现

该程序实现了一个简化的文件系统模拟,包括文件和目录的创建、删除、查看和切换。程序使用了一个名为FileSystem的结构体来表示文件系统,其中包含了块位图、inode位图、inode表和当前目录的inode索引。

代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAX_NAME_LENGTH 255
#define MAX_BLOCKS 1024
#define MAX_INODES 1024
#define MAX_DATA_BLOCKS 1024
#define SAVE_FILE "filesystem_state.bin"

typedef struct {
    char name[MAX_NAME_LENGTH];
    enum {DIRECTORY, DATA} type;
    int permissions; // 使用位操作表示权限,例如:0110 (rw-)
    int size;
    float last_modified_time;
} FileAttributes;

typedef struct {
    FileAttributes attributes;
    int inode_index;
    int data_block_indices[MAX_DATA_BLOCKS];
} File;

typedef struct {
    FileAttributes attributes;
    int data_block_indices[MAX_DATA_BLOCKS];
} InodeTableEntry;

typedef struct {
    int block_bitmap[MAX_BLOCKS];
    int inode_bitmap[MAX_INODES];
    InodeTableEntry inode_table[MAX_INODES];
    int current_directory_inode;
} FileSystem;

float get_current_time() {
    return (float)time(NULL);
}

int find_inode(FileSystem *fs, const char *filename) {
    for (int i = 0; i < MAX_INODES; i++) {
        if (fs->inode_bitmap[i] && strcmp(fs->inode_table[i].attributes.name, filename) == 0) {
            return i;
        }
    }
    return -1;
}

int allocate_inode(FileSystem *fs) {
    for (int i = 0; i < MAX_INODES; i++) {
        if (!fs->inode_bitmap[i]) {
            fs->inode_bitmap[i] = 1;
            return i;
        }
    }
    return -1;
}

void touch(FileSystem *fs, const char *filename, int size) {
    int inode_index = find_inode(fs, filename);
    if (inode_index == -1) {
        // 文件不存在,创建新文件
        inode_index = allocate_inode(fs);
        if (inode_index == -1) {
            printf("无法分配inode\n");
            return;
        }
        fs->inode_table[inode_index].attributes.type = DATA;
        strncpy(fs->inode_table[inode_index].attributes.name, filename, MAX_NAME_LENGTH);
    }
    // 更新文件属性
    fs->inode_table[inode_index].attributes.size = size;
    fs->inode_table[inode_index].attributes.last_modified_time = get_current_time();
    printf("文件已更新\n");
}

void rm(FileSystem *fs, const char *filename) {
    int inode_index = find_inode(fs, filename);
    if (inode_index == -1) {
        printf("文件不存在\n");
        return;
    }
    if (fs->inode_table[inode_index].attributes.type == DIRECTORY) {
        printf("不能删除目录,请使用rmdir命令\n");
        return;
    }
    fs->inode_bitmap[inode_index] = 0;
    printf("文件已删除\n");
}

void ls(FileSystem *fs) {
    printf("文件名\t类型\t大小\t修改时间\n");
    for (int i = 0; i < MAX_INODES; i++) {
        if (fs->inode_bitmap[i]) {
            FileAttributes attr = fs->inode_table[i].attributes;
            printf("%s\t%s\t%d\t%.0f\n", attr.name, attr.type == DIRECTORY ? "目录" : "文件", attr.size, attr.last_modified_time);
        }
    }
}

void mkdir(FileSystem *fs, const char *dirname) {
    int inode_index = find_inode(fs, dirname);
    if (inode_index != -1) {
        printf("目录已存在\n");
        return;
    }
    inode_index = allocate_inode(fs);
    if (inode_index == -1) {
        printf("无法分配inode\n");
        return;
    }
    fs->inode_table[inode_index].attributes.type = DIRECTORY;
    strncpy(fs->inode_table[inode_index].attributes.name, dirname, MAX_NAME_LENGTH);
    printf("目录已创建\n");
}

void rmdir(FileSystem *fs, const char *dirname) {
    int inode_index = find_inode(fs, dirname);
    if (inode_index == -1) {
        printf("目录不存在\n");
        return;
    }
    if (fs->inode_table[inode_index].attributes.type != DIRECTORY) {
        printf("不能删除文件,请使用rm命令\n");
        return;
    }
    fs->inode_bitmap[inode_index] = 0;
    printf("目录已删除\n");
}

void cd(FileSystem *fs, const char *dirname) {
    int inode_index = find_inode(fs, dirname);
    if (inode_index == -1) {
        printf("目录不存在\n");
        return;
    }
    if (fs->inode_table[inode_index].attributes.type != DIRECTORY) {
        printf("不能切换到文件,请输入目录名\n");
        return;
    }
    fs->current_directory_inode = inode_index;
    printf("已切换到目录:%s\n", dirname);
}

void save_filesystem_state(FileSystem *fs) {
    FILE *file = fopen(SAVE_FILE, "wb");
    if (file == NULL) {
        printf("无法保存文件系统状态\n");
        return;
    }
    fwrite(fs, sizeof(FileSystem), 1, file);
    fclose(file);
    printf("文件系统状态已保存\n");
}

void load_filesystem_state(FileSystem *fs) {
    FILE *file = fopen(SAVE_FILE, "rb");
    if (file == NULL) {
        printf("无法加载文件系统状态\n");
        return;
    }
    fread(fs, sizeof(FileSystem), 1, file);
    fclose(file);
    printf("文件系统状态已加载\n");
}

int main() {
    FileSystem fs;
    memset(&fs, 0, sizeof(fs));
    fs.current_directory_inode = 0; // 初始化当前目录为根目录

    printf("输入 \"enter\" 以重新建立文件系统并读取上次的退出状态,输入 \"q\" 退出程序。\n");
    char initial_command[10];
    fgets(initial_command, sizeof(initial_command), stdin);
    initial_command[strcspn(initial_command, "\n")] = 0;

    if (strcmp(initial_command, "enter") == 0) {
        load_filesystem_state(&fs);
    } else if (strcmp(initial_command, "q") == 0) {
        return 0;
    } else {
        printf("未知命令,将使用默认文件系统状态\n");
    }

    char command[256];
    while (1) {
        printf("> ");
        fgets(command, sizeof(command), stdin);
        command[strcspn(command, "\n")] = 0; // 去除换行符

        if (strcmp(command, "q") == 0) {
            save_filesystem_state(&fs);
            break;
        } else if (strncmp(command, "touch ", 6) == 0) {
            char filename[MAX_NAME_LENGTH];
            int size;
            sscanf(command + 6, "%s %d", filename, &size);
            touch(&fs, filename, size);
        } else if (strncmp(command, "rm ", 3) == 0) {
            char filename[MAX_NAME_LENGTH];
            sscanf(command + 3, "%s", filename);
            rm(&fs, filename);
        } else if (strcmp(command, "ls") == 0) {
            ls(&fs);
        } else if (strncmp(command, "mkdir ", 6) == 0) {
            char dirname[MAX_NAME_LENGTH];
            sscanf(command + 6, "%s", dirname);
            mkdir(&fs, dirname);
        } else if (strncmp(command, "rmdir ", 6) == 0) {
            char dirname[MAX_NAME_LENGTH];
            sscanf(command + 6, "%s", dirname);
            rmdir(&fs, dirname);
        } else if (strncmp(command, "cd ", 3) == 0) {
            char dirname[MAX_NAME_LENGTH];
            sscanf(command + 3, "%s", dirname);
            cd(&fs, dirname);
        } else {
            printf("未知命令\n");
        }
    }

    return 0;
}
结果:

  

说明:

1、结构体和类型定义

- FileAttributes:表示文件或目录的属性,包括名称、类型(文件或目录)、权限、大小和最后修改时间。 - File:表示一个文件,包括文件属性、inode索引和数据块索引。 - InodeTableEntry:表示inode表中的一个条目,包括文件属性和数据块索引。 - FileSystem:表示整个文件系统,包括块位图、inode位图、inode表和当前目录的inode索引。

2、辅助函数

- get_current_time():获取当前时间,用于设置文件的最后修改时间。 - find_inode():在文件系统中查找具有给定文件名的inode索引。 - allocate_inode():在文件系统中分配一个新的inode,并返回其索引。

3、文件和目录操作函数

- touch():创建或更新一个文件。如果文件不存在,将创建一个新文件;如果文件已存在,将更新其大小和最后修改时间。 - rm():删除一个文件。如果给定的名称是目录,将提示用户使用rmdir命令。 - ls():列出文件系统中的所有文件和目录。 - mkdir():创建一个新目录。 - rmdir():删除一个目录。如果给定的名称是文件,将提示用户使用rm命令。 - cd():切换到指定的目录。

4、文件系统状态保存和加载函数

- save_filesystem_state():将当前文件系统状态保存到一个二进制文件中。 - load_filesystem_state():从二进制文件中加载文件系统状态。

5、主函数

主函数首先初始化一个FileSystem结构体,并提示用户输入"enter"以重新建立文件系统并读取上次的退出状态,或输入"q"退出程序。然后,程序进入一个循环,等待用户输入命令。用户可以输入touch、rm、ls、mkdir、rmdir和cd命令来操作文件系统。当用户输入"q"时,程序将保存当前文件系统状态并退出。

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【实验目的】 1. 了解文件系统的原理; 2. 用高级语言编写和调试一个简单文件系统模拟文件管理的工作过程。从而对各种文件操作命令的实质内容和执行过程有比较深入的了解。 【实验准备】 1.文件的逻辑结构  顺序文件  索引文件  索引顺序文件  直接文件和哈希文件 2.外存分配方式  连续分配  链接分配  索引分配 【实验内容】 1. 实验要求 要求设计一个 n个用户的文件系统,每次用户可保存m个文件,用户在一次运行中只能打开一个文件,对文件必须设置保护措施,且至少有Create、delete、open、close、read、write等命令。 2. 实验题目  设计一个10个用户的文件系统,每次用户可保存10个文件,一次运行用户可以打开5个文件。  程序采用二级文件目录(即设置主目录[MFD])和用户文件目录(UED)。另外,为打开文件设置了运行文件目录(AFD)。  为了便于实现,对文件的读写作了简化,在执行读写命令时,只需改读写指针,并不进行实际的读写操作。 因系统小,文件目录的检索使用了简单的线性搜索。文件保护简单使用了三位保护码:允许读写执行、对应位为 1,对应位为0,则表示不允许读写、执行。程序中使用的主要设计结构如下:主文件目录和用户文件目录( MFD、UFD)打开文件目录( AFD)(即运行文件目录)。 M D F 用户名 文件目录指针 用户名 文件目录指针 U F D 文件名 保护码 文件长度 文件名 A F D 打开文件名 打开保护码 读写指针
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值