美文网首页
李巨虎《操作系统》课设----“文件系统”基于C的实现(Day1

李巨虎《操作系统》课设----“文件系统”基于C的实现(Day1

作者: 原石_9815 | 来源:发表于2019-06-01 10:37 被阅读0次
# 今天是六一儿童节
# 下周一就要开始课设了
# 争取在第一天给老师检查吧
# 之后一个礼拜就可以好好复习算法设计的期末考试了
# 病了两天真是难受
# 两天没有好好学习 QWQ

Part 0 前言

整个程序是在Mac os的环境下开发的,因为有一些底层系统调,Windows可能无法正常运行,不过Linux应该问题不大。

首先我是很想拿这个课设的满分的,仔细看了课设的要求,如果要拿到满分的话,需要有完整的文件系统,还要做到“命令端”和“文件系统端”的独立运行、相互通信。这个真的是比算法设计的课设工作量大多了(算法课设我就写了百来行的代码,这个估摸着得上千了)。

讲实话多进程的东西写的并不多,有写,但是也没有太多的研究这个,所以这次课设对我来说难点就在于进程间的通信了。也百度了一下Unix/Linux下的进程通信的东西,要实现的话基本就是用FIFO、消息队列来实现。

Part 1 架构

架构

架构就如上图吧,FileSystem以读写的方式连接disk.dat(模拟的物理磁盘),再以IPC的方式连接各个Shell(命令端),当然这里还有很多细节就先不讨论了。

Part 2 文件系统的核心代码

这里先上一个FileSystem的实现代码(还没Debug),共413行。

FileSys.h
(6.2号更新,补了一些注释,修复了一些“肉眼可见”的Bug,因为整个文件系统还未真正运行过。)

#ifndef FileSys_h
#define FileSys_h

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define DISK_MEMO 10 * 1024 * 1024    // 磁盘总空间
#define DISK_SIZE 1024                 // 每个磁盘块的大小
#define DISK_NUM DISK_MEMO / DISK_SIZE // 磁盘块的数目

#define FAT_SIZE DISK_NUM * sizeof(fatitem)   // FAT表的大小
#define ROOT_DISK_NO FAT_SIZE / DISK_SIZE + 1 // 根目录起始盘块号
#define ROOT_DISK_SIZE sizeof(direct)         // 目录大小

#define DIR_MAXSIZE 1024     // 路径最大长度
#define MSD 5                // 目录最大子文件数量
#define MOFN 20              // 最大打开文件
#define MAX_WRITE 1024 * 128 // 最大写入文字长度
#define FILENAME_MAXLEN 64   // 最长文件名称长度

typedef struct
{
    int item;     // 下一个磁盘的指针
    char em_disk; // 是否空闲(‘0’为空闲,‘1’为非空闲)
} fatitem;

// FCB结构体
typedef struct
{
    char name[FILENAME_MAXLEN]; // 名字
    char property;              // 属性(‘1’是目录,‘0’是文件)
    int size;                   // 文件/目录 字节数
    int firstdisk;              // 文件/目录 起始盘块号
    int next;                   // 子目录起始盘块号
    int sign;                   // 根目录识别符(1为根目录标识,0为非根目录标识)
} FCB;

typedef struct
{
    FCB directitem[MSD + 2];
} direct;

// 打开文件表 实例结构体
struct opentableitem
{
    char name[9];  // 文件名称
    int firstdisk; // 文件起始盘块号
    int size;      // 文件大小
};

// 打开文件 结构体
typedef struct
{
    struct opentableitem openitem[MOFN];
    int cur_size; // 当前打开文件的数目
} opentable;

fatitem *fat;          // FAT表
direct *root;          // 根目录地址
direct *cur_dir;       // 当前目录
opentable u_opentable; // 文件打开表
int fd = -1;           // 文件打开表的序号
char *bufferdir;       // 记录当前路径的名称
char *fdisk;           // 虚拟磁盘起始地址(内存中)

// FAT表数据设定函数
void fatitemset(fatitem *, int, char);

// FCB数据设定函数
void FCBset(FCB *, int, int, char *, int, char, int);

// 文件初始化,生成空的模拟磁盘物理文件(当没有disk.dat文件时执行)
void initfile();

// 模拟磁盘数据初始化
void format();

// 进入物理磁盘文件
void enter();

// 退出程序,保存物理文件
void halt();

// 新建文件
int create(char *);

// 打开文件
int open(char *);

// 关闭文件
int close(char *);

// 文件写入
int write(int, char *, int);

// 文件读取
int read(int, char *);

// 文件删除
int del(char *);

// 新建文件夹
int mkdir(char *);

// 删除文件夹
int rmdir(char *);

void initfile()
{
    fdisk = (char *)malloc(DISK_MEMO * sizeof(char));
    format();
}

void fatitemset(fatitem *f, int i, char e)
{
    f->item = I;
    f->em_disk = e;
}

void FCBset(FCB *fcb, int sign, int firstdisk, char *name, int next, char property, int size)
{
    fcb->sign = sign;
    fcb->firstdisk = firstdisk;
    strcpy(fcb->name, name);
    fcb->next = next;
    fcb->property = property;
    fcb->size = size;
}

void format()
{
    int I;
    FILE *fp;
    // FAT初始化
    // FAT的初始地址是disk的地址往后移 1K
    fat = (fatitem *)(fdisk + DISK_SIZE);
    fatitemset(&fat[0], -1, '1'); // 引导块初始化
    // 1-ROOT全部置为1
    for (i = 1; i < ROOT_DISK_NO - 1; I++)
        fatitemset(&fat[i], i + 1, '1');
    fatitemset(&fat[ROOT_DISK_NO], -1, '0');
    for (i = ROOT_DISK_NO + 1; i < DISK_NUM - 1; I++)
        fatitemset(&fat[i], -1, '0');

    root = (direct *)(fdisk + DISK_SIZE + FAT_SIZE);
    FCBset(&root->directitem[0], 1, ROOT_DISK_NO, ".", ROOT_DISK_NO, '1', ROOT_DISK_SIZE);
    FCBset(&root->directitem[1], 1, ROOT_DISK_NO, "..", ROOT_DISK_NO, '1', ROOT_DISK_SIZE);
    for (i = 2; i < MSD + 2; I++)
        FCBset(&root->directitem[i], 0, -1, "", -1, '0', 0);

    if ((fp = fopen("./disk.dat", "wb")) == NULL)
    {
        printf("Error: Can't open disk.");
        return;
    }
    if ((fwrite(fdisk, DISK_MEMO, 1, fp)) != 1)
        printf("Error: Disk write error!");
    fclose(fp);
};

void enter()
{
    FILE *fp;
    int I;
    fdisk = (char *)malloc(DISK_MEMO * sizeof(char));
    if ((fp = fopen("./disk.dat", "rb")) == NULL)
    {
        printf("Error: Can't open disk.");
        return;
    }
    if (!fread(fdisk, DISK_MEMO, 1, fp))
    {
        printf("Error: Can't open disk.");
        exit(0);
    }
    fat = (fatitem *)(fdisk + DISK_SIZE);
    root = (direct *)(fdisk + DISK_SIZE + FAT_SIZE);
    fclose(fp);
    for (i = 0; i < MOFN; I++)
    {
        strcpy(u_opentable.openitem[i].name, "");
        u_opentable.openitem[i].firstdisk = -1;
        u_opentable.openitem[i].size = 0;
    }
    u_opentable.cur_size = 0;
    cur_dir = root;
    // bufferdir = (char *)malloc(DIR_MAXSIZE * sizeof(char));
    // strcpy(bufferdir, "Root:");
}

void halt()
{
    FILE *fp;
    int I;
    if ((fp = fopen("./disk.dat", "wb")) == NULL)
    {
        printf("Error: Can't open disk.");
        return;
    }
    if ((fwrite(fdisk, DISK_MEMO, 1, fp)) != 1)
        printf("Error: Disk write error!");
    fclose(fp);
    free(fdisk);
    free(bufferdir);
    return;
}

int create(char *name)
{
    int i, j;
    if (strlen(name) > FILENAME_MAXLEN)
        return -1;
    for (j = 2; j < MSD + 2; j++)
        if (!strcmp(cur_dir->directitem[j].name, name))
            return -4;
    for (i = 2; i < MSD + 2; I++)
        if (cur_dir->directitem[i].firstdisk == -1)
            break;
    if (i > MSD + 2)
        return -2;
    if (u_opentable.cur_size >= MOFN)
        return -3;
    for (j = ROOT_DISK_NO + 1; j < DISK_NUM; j++)
        if (fat[j].em_disk == '0')
            break;
    if (j >= DISK_NUM)
        return -5;
    fat[j].em_disk = '1';
    FCBset(&cur_dir->directitem[i], 0, j, name, j, '0', 0);
    fd = open(name);
    return 0;
}

int open(char *name)
{
    int i, j;
    for (i = 2; i < MSD + 2; I++)
        if (strcmp(cur_dir->directitem[i].name, name))
            break;
    if (i >= MSD + 2)
        return -1;
    if (cur_dir->directitem[i].property == '1')
        return -4;
    for (j = 0; j < MOFN; j++)
        if (!strcmp(u_opentable.openitem[j].name, name))
            break;
    if (j < MOFN)
        return -2;
    if (u_opentable.cur_size >= MOFN)
        return -3;
    for (j = 0; j < MOFN; j++)
        if (u_opentable.openitem[j].firstdisk == -1)
            break;
    u_opentable.openitem[j].firstdisk = cur_dir->directitem[i].firstdisk;
    strcpy(u_opentable.openitem[j].name, name);
    u_opentable.openitem[j].size = cur_dir->directitem[i].size;
    u_opentable.cur_size++;
    return j;
}

int close(char *name)
{
    int I;
    for (i = 0; i < MOFN; I++)
        if (!strcmp(u_opentable.openitem[i].name, name))
            break;
    if (i >= MOFN)
        return -1;
    u_opentable.openitem[i].firstdisk = -1;
    u_opentable.openitem[i].size = 0;
    strcpy(u_opentable.openitem[i].name, "");
    u_opentable.cur_size--;
    return 0;
}

int write(int fd, char *buf, int len)
{
    char *first;
    int item, i, j, k;
    int ilen1, ilen2, modlen, temp;

    item = u_opentable.openitem[fd].firstdisk;
    for (i = 2; i < MSD + 2; I++)
        if (cur_dir->directitem[i].firstdisk == item)
            break;
    temp = I;
    while (fat[item].item != -1)
        item = fat[item].item;
    // 找到文件的末地址
    first = fdisk + item * DISK_SIZE + u_opentable.openitem[fd].size % DISK_SIZE;
    if (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE > len)
    {
        // 最后一块磁盘剩余的大小大于要写入的大小
        strcpy(first, buf);
        u_opentable.openitem[fd].size += len;
        cur_dir->directitem[temp].size += len;
    }
    else
    {
        for (i = 0; i < (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE); I++)
            first[i] = buf[I];

        // 剩余长度
        ilen1 = len - (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE);
        // 需要新磁盘块
        ilen2 = (ilen1 - 1) / DISK_SIZE + 1;
        // 最后一块磁盘的长度
        modlen = ilen1 % DISK_SIZE;

        for (j = 0; j < ilen2; j++)
        {
            for (i = ROOT_DISK_NO + 1; i < DISK_NUM; I++)
                if (fat[i].em_disk == '0')
                    break;
            if (i >= DISK_NUM)
                return -1;
            first = fdisk + i * DISK_SIZE;
            if (j == ilen2 - 1)
                for (k = 0; k < len - (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE - j * DISK_SIZE); k++)
                    first[k] = buf[k];
            else
                for (k = 0; k < DISK_SIZE; k++)
                    //这里的k是不是有问题??
                    first[k] = buf[k];
            //这里的item是不是也有问题??
            fat[item].item = I;
            fat[i].em_disk = '1';
            fat[i].item = -1;
        }
        u_opentable.openitem[fd].size += len;
        cur_dir->directitem[temp].size += len;
    }
    return 0;
}

int read(int fd, char *buf)
{
    int len = u_opentable.openitem[fd].size;
    char *first;
    int i, j, item;
    int ilen1, modlen;
    item = u_opentable.openitem[fd].firstdisk;
    ilen1 = (len - 1) / DISK_SIZE + 1;
    modlen = len % DISK_SIZE;
    first = fdisk + item * DISK_SIZE;
    for (i = 0; i < ilen1; i++)
    {
        if (i == ilen1 - 1)
            for (j = 0; j < len - i * DISK_SIZE; j++)
                buf[i * DISK_SIZE + j] = first[j];
        else
        {
            for (j = 0; j < len - i * DISK_SIZE; j++)
                buf[i * DISK_SIZE + j] = first[j];
            item = fat[item].item;
            first = fdisk + item * DISK_SIZE;
        }
    }
    return 0;
}

int del(char *name)
{
    int i, cur_item, item, temp;
    for (i = 2; i < MSD + 2; I++)
        if (!strcmp(cur_dir->directitem[i].name, name))
            break;
    if (i >= MSD + 2)
        return -1;
    cur_item = I;
    if (cur_dir->directitem[cur_item].property != '0')
        return -3;
    for (i = 0; i < MOFN; I++)
        if (!strcmp(u_opentable.openitem[i].name, name))
            return -2;
    item = cur_dir->directitem[cur_item].firstdisk;
    while (item != -1)
    {
        temp = fat[item].item;
        fat[item].item = -1;
        fat[item].em_disk = '0';
        item = temp;
    }
    FCBset(&cur_dir->directitem[cur_item], 0, -1, "", -1, '0', 0);
    return 0;
}

int mkdir(char *name)
{
    int i, j;
    direct *cur_mkdir;
    if (!strcmp(name, ".") || !strcmp(name, ".."))
        return -4;
    if (strlen(name) > FILENAME_MAX)
        return -1;
    for (j = 2; j < MSD + 2; j++)
        if (!strcmp(cur_dir->directitem[j].name, name))
            break;
    if (j < MSD + 2)
        return -3;
    for (j = ROOT_DISK_NO + 1; j < DISK_NUM; j++)
        if (fat[j].em_disk == '0')
            break;
    if (j > DISK_NUM)
        return -5;
    fat[j].em_disk = '1';
    FCBset(&cur_dir->directitem[i], 0, j, name, j, '1', ROOT_DISK_SIZE);
    cur_mkdir = (direct *)(fdisk + cur_dir->directitem[i].firstdisk * DISK_SIZE);
    FCBset(&cur_mkdir->directitem[0], 0, cur_dir->directitem[i].firstdisk, ".", cur_mkdir->directitem[0].firstdisk, '1', ROOT_DISK_SIZE);
    FCBset(&cur_mkdir->directitem[0], cur_dir->directitem[0].sign, cur_dir->directitem[0].firstdisk, "..", cur_mkdir->directitem[1].firstdisk, '1', ROOT_DISK_SIZE);
    for (i = 2; i < MSD + 2; I++)
        FCBset(&cur_mkdir->directitem[i], 0, -1, "", -1, '0', 0);
    return 0;
}

int rmdir(char *name)
{
    int i, j, item;
    direct *temp_dir;
    for (i = 2; i < MSD + 2; I++)
        if (!strcmp(cur_dir->directitem[i].name, name))
            break;
    if (i >= MSD + 2)
        return -1;
    if (cur_dir->directitem[i].property != '1')
        return -3;
    temp_dir = (direct *)(fdisk + cur_dir->directitem[i].next * DISK_SIZE);
    for (j = 2; j < MSD + 2; j++)
        // 文件夹不为空
        if (temp_dir->directitem[j].next != -1)
            break;
    if (j < MSD + 2)
        return -2;
    item = cur_dir->directitem[i].firstdisk;
    fat[item].em_disk = '0';
    FCBset(&cur_dir->directitem[i], 0, -1, "", -1, '0', 0);
    return 0;
}

#endif

一更(6/2上午10:08)更新一下6.1号所有的工作量

先这么写着,等课设做完再把整篇文章的格式规范一下。


代码统计量截图

Part 3 “前后端”通信

截至目前已经写了1,446行代码了,但是感觉还只是完成了一个空架(真是好大的工作量啊😭)。重要的是,着1,446行代码中已经实现了用IPC协议(消息列队)实现进程通信。为什么不用命名管道(FIFO)呢,主要是FIFO在处理一对多要这种情况时,要使用这种结构:

FIFO实现机制
这样子的话,假设有N个命令端的话,我们则需要建立 2+N 条FIFO,虽然说课设并不需要考虑这种极端情况,但是强迫症的我(🤦‍♂️)还是觉得这种做法不是很好,因为FIFO多次创建、释放容易出问题。

于是,我打算用F2S(file_system to shell)、S2F(shell to file system)来实现命令端和文件管理端的通信(理论上其实一个消息队列也可以实现)。

自定义的Message结构体

struct s2fmsg 
{
    long int mtype;
    int serverid;
    int oper;
    char data[128];
};

struct f2smsg
{
    long int mtype;
    int oper;
    int status;
    char data[128];
};

命令端用S2F队列向文件系统端发送请求,文件系统用F2S向命令端发送请求结果(像极了request,原谅我的浅薄理解)。乍一看,和FIFO很像,那它是怎么实现只用两条队列呢?这里是因为消息队列比FIFO多了一个关键性的功能,就是消息队列传输的消息有一个 long int mtype的属性,而命令端在接收文件系统端的回传信息的时候,可以根据这个long int mtype来选择接收mtype等于特定值的消息。基于这个,我们就可以给 f2smsgmtype附加命令端的id。

(要继续写课设了,争取明天前做好)
持续更新中……
最后一次更新于6/1上午10:36

相关文章

网友评论

      本文标题:李巨虎《操作系统》课设----“文件系统”基于C的实现(Day1

      本文链接:https://www.haomeiwen.com/subject/pzrotctx.html