【OS】操作系统-实验五:文件系统的编写

操作环境:

  • 主机:MacOS 10.13.3

实验要求:

  1. 在内存中开辟一个虚拟磁盘空间作为文件存储分区,在其上实现一个简单的基于多级目录的单用户单任务系统中的文件系统。在退出该文件系统的使用时,应将虚拟磁盘上的内容以一个文件的方式保存到磁盘上,以便下次可以再将它恢复到内存的虚拟磁盘中。
  2. 文件物理结构可采用显式链接或其他结构。
  3. 空闲磁盘空间的管理可选择 FAT 表、位示图或其他办法。
  4. 文件目录结构采用多级目录结构。为简单起见,可以不使用索引结点,每个目录项应包含文件名、物理地址、长度等信息,还可以通过目录项实现对文件的读和写的保护。
  5. 要求提供以下操作命令:
    • my_format:对文件存储器进行格式化,即按照文件系统的结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。
    • my_mkdir:用于创建子目录。
    • my_rmdir:用于删除子目录。
    • my_ls:用于显示目录中的内容。
    • my_cd:用于更改当前目录。
    • my_create:用于创建文件。
    • my_open:用于打开文件。
    • my_close:用于关闭文件。
    • my_write:用于写文件。
    • my_read:用于读文件。
    • my_rm:用于删除文件。
    • my_exitsys:用于退出文件系统。

设计思路:

  1. 磁盘信息:
    • 磁盘大小: 10MB
    • 块大小:1KB
    • 最大打开文件数:10个
  2. 采用了基于i节点的文件系统结构,i节点的定义如下:
    typedef struct D_INODE { // 共占用空间 64B
    	unsigned long size; // 8B
    	unsigned long borntime; //8B
    	unsigned long lmodtime; //8B
    	unsigned int i_addr[8]; // 4B*8
    	unsigned char attribute; // 1B 4:4 type:auth
    	unsigned char linknum; //1B
    } d_inode;
    
  3. 磁盘空间管理采用成组链接法,每组包含200块:
    typedef struct GROUP {
    	unsigned int blocks[200];
    	unsigned int count;
    	int max;
    } group;
    
  4. 记录文件打开的结构体:
    • 只有在文件改动后才会在关闭文件时修改文件的修改时间
    typedef struct USEROPEN {
    	char filename[28];
    	d_inode * inode;
    	char op;
    	int fp;
    	int ischanged;
    } useropen;
    
  5. 分配了 512B 的空间给 BOOT 分区,在i节点的文件系统中, BOOT 分区没有实际的用处,所以就用来保存一些没什么用的信息。
  6. 超级块的定义如下:
    • 保存了一些文件系统信息
    • 成组链接块中的第一部分
    • i节点的空闲管理表,最多288块
    typedef struct SUPER {
    	unsigned short s_block_size; /* 文件系统的数据块大小*/ // 2
    	unsigned short s_inode_blocks; /* 磁盘索引节点区所占用的数据块数*/ // 2
    	unsigned int s_block_amt; /* 整个文件系统的数据块数*/ // 4
    
    	unsigned int s_free_block_amt; /* 在空闲块登录表中当前登记的空闲块数目*/ // 4
    	unsigned int s_frees[20]; /* 空闲块登记表*/
    	unsigned int cu_group;
    
    	unsigned int s_free_inode_amt; /* 空闲索引节点数*/ // 4
    	unsigned int s_inode[288]; /* 空闲节点登记表*/
    
    	char ronly; /* 文件系统只读标志*/ // 1
    	unsigned int root_ino;
    
    	unsigned long born_time; /* 超级块上次修改的时间*/ // 4
    	unsigned long s_time; /* 超级块上次修改的时间*/ // 4
    } superBolck;
    
  7. 程序的结构:
    1. Terminal.c - 主程序
    2. AEFS.h - 文件系统结构的定义
    3. operations.h - operations.c 的头文件
    4. operations.c - 文件系统各操作的实现(写的超累)
  8. 实现了以下操作:
    1. 文件与文件夹的创建与删除
    2. cd 命令,支持绝对路径和 .. 返回上级目录
    3. 文件的打开与关闭:
      1. r 只读
      2. w 只写
      3. a 读写
    4. 文件的读取与写入:
      1. w 从头开始覆盖写,根据最终大小申请/释放磁盘快
      2. a 可以从指定位置(默认最后)开始写,根据最终大小申请/释放磁盘快
      3. r 从开头读取指定字节的数据
    5. 文件与文件夹的硬链接

效果展示:

1.png

操作说明:

程序开始运行时会尝试读取同一目录下的SAVED.aefs文件,若不存在,则会创建新的文件系统

  • 命令解析:
    1. "ls":显示当前文件夹下的所有文件的信息
    2. "cd":跳转到某一目录下
      • cd 回车 路径 回车
    3. "mkdir":创建文件夹
      • mkdir 回车 文件夹名称 回车
    4. "touch":创建文件
      • touch 回车 文件名称 回车
    5. "rm":删除文件
      • rm 回车 文件名 回车
    6. "open":打开文件,会返回 fd
      • open 回车 文件名 空格 打开方式 回车
    7. "close":关闭文件
      • close 回车 fd 回车
    8. "write":写文件
      • write 回车 fd 回车
    9. "read":读文件
      • read 回车 fd 回车
    10. "info":磁盘信息
    11. "ln":硬链接
      • ln from 回车 to 回车
    12. "rm -r":删除文件夹
      • rm 回车 文件夹名 回车
    13. "pwd":显示当前目录

附录:

  1. AEFS.h
#ifndef __AEFS_H__
#define __AEFS_H__

#define BLOCKSIZE 1024 // 1K
#define DISKSIZE 10485760 //10M
#define END 65535
#define FREE 0
#define ROOTBLOCKNUM 2
#define MAXOPENFILE 10



typedef struct D_INODE { // 64B
    unsigned long size; // 8
    unsigned long borntime; //8
    unsigned long lmodtime; //8
    unsigned int i_addr[8]; // 4*10
    unsigned char attribute; // 1 4:4 type:auth
    unsigned char linknum; //1
} d_inode;

typedef struct INDEX { // 32B
    char filename[28];
    unsigned int inode; // 4
} fileIndex;

typedef struct GROUP {
    unsigned int blocks[200];
    unsigned int count;
    int max;
} group;

//((DISKSIZE/BLOCKSIZE)/200)+1
typedef struct SUPER {
    unsigned short s_block_size; /* 文件系统的数据块大小*/ // 2
    unsigned short s_inode_blocks; /* 磁盘索引节点区所占用的数据块数*/ // 2
    unsigned int s_block_amt; /* 整个文件系统的数据块数*/ // 4

    unsigned int s_free_block_amt; /* 在空闲块登录表中当前登记的空闲块数目*/ // 4
    unsigned int s_frees[20]; /* 空闲块登记表*/
    unsigned int cu_group;

    unsigned int s_free_inode_amt; /* 空闲索引节点数*/ // 4
    unsigned int s_inode[288]; /* 空闲节点登记表*/

    char ronly; /* 文件系统只读标志*/ // 1
    unsigned int root_ino;

    unsigned long born_time; /* 超级块上次修改的时间*/ // 4
    unsigned long s_time; /* 超级块上次修改的时间*/ // 4
} superBolck;

typedef struct BOOT { // 512B
    unsigned short root;
    unsigned char * startblock;
    char sysname[32];
    char info[464];
} boot;


typedef struct USEROPEN {
    char filename[28];
    d_inode * inode;
    char op;
    int fp;
    int ischanged;
} useropen;


typedef struct OPENREG {
    useropen list[MAXOPENFILE];
    int isfree[MAXOPENFILE];
    int freen;

} openreg_t;

static unsigned char * vdisk;

static boot * p_boot;

static superBolck * p_super;

static group * p_group;

static d_inode * p_inode;

static unsigned int cudir;

static char cupath[80];
static int cupathlen;

static openreg_t openreg;


#endif 
  1. operations.c
#include "operations.h"
#include "AEFS.h"
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>


char **split(char * input, const char div, int * amount) {
	int count = 0;
	char c_last = div;
	int len = 0;

	for(int i  = 0; *(input+i) != '\0'; i++) {
		if(*(input+i) == div && c_last != div){ count++;}
		c_last = *(input+i);
		len ++;
	}
	*(amount) = count+1; // para amount
	char ** array = (char **)malloc((count+2)*sizeof(char*));

	int cu_para = 0;

	c_last = div;
	for(int i  = 0; i < len; i++) {
		if(*(input+i) != div && c_last == div){ //para[0]
			array[cu_para] = input+i;
		} else if(*(input+i) == div && c_last != div){ 
			*(input+i) = '\0';
			cu_para ++;
			c_last = div;
			continue;
		}
		c_last = *(input+i);
	}
	return array;
}

void * getBlock(unsigned int num) {
    return vdisk + BLOCKSIZE*num -1;
}

unsigned int block_alloc() {
    unsigned int r;
    
    if(p_group) {
        // printf("fine now\n");
        if(p_group->count > 1) {
            r = p_group->blocks[200-p_group->count];
            p_group->count--;
        }else {
            
            if(p_group->blocks[199]) {
                // p_group->count = 0;
                p_super->cu_group = p_group->blocks[199];
                p_group = getBlock(p_group->blocks[199]);
                r = p_group->blocks[200-p_group->count];
                p_group->count--;
            }else {
                printf("No Space Left!\n");
                printf("%d\n",p_group->count);
                return 0;
            }
        }
    }else {
        if(p_super->s_free_block_amt > 1) {
            r = p_super->s_frees[20-p_super->s_free_block_amt];
            p_super->s_free_block_amt--;
        }else {
            p_super->cu_group = p_super->s_frees[20-p_super->s_free_block_amt];
            p_group = getBlock(p_super->cu_group);
            p_super->s_free_block_amt = 0;
            r = p_group->blocks[200-p_group->count];
            p_group->count--;
        }
    }
    return r;
}

void * block_alloc_p() {
    return getBlock(block_alloc());
}

void block_free(unsigned int num) {
    if(p_group) {
        if(p_group->count < p_group->max-1) {
            printf("%d\n",p_group->count);
            p_group->count++;
            p_group->blocks[200-p_group->count] = num;
        }else {
            p_group->count++;
            p_group->blocks[200-p_group->count] = num;
            p_super->cu_group -= 200;
            p_group = getBlock(p_super->cu_group);
        }
    }else {
        p_super->s_free_block_amt++;
        p_super->s_frees[20-p_super->s_free_block_amt] = num;
       
    }
}

unsigned int ino_alloc() {
    unsigned int r;
    if(p_super->s_free_inode_amt) {
        r = p_super->s_inode[288-p_super->s_free_inode_amt];
        p_super->s_free_inode_amt--;
    }else {
        printf("No Inode LEFT!\n");
        return 0;
    }
    return r;
}

void ino_free(unsigned int num) {
    p_super->s_free_inode_amt++;
    p_super->s_inode[288-p_super->s_free_inode_amt] = num;
}

int checkname(char * dirname) {
    d_inode * cud = &p_inode[cudir];
    int subfiles = cud->size/sizeof(fileIndex);
    if(cud->size) {
        int usedBlocks = cud->size/BLOCKSIZE + 1;
        for(int i = 0; i < usedBlocks; i++) {
            fileIndex * fi = getBlock(cud->i_addr[i]);
            if(i == usedBlocks-1) {
                for(int j = 0; j < subfiles%(BLOCKSIZE/sizeof(fileIndex)); j++) {
                    if(!strcmp(dirname,fi[j].filename)) {
                        return fi[j].inode;
                    }
                }
            }else {
                for(int j = 0; j < BLOCKSIZE/sizeof(fileIndex); j++) {
                    if(!strcmp(dirname,fi[j].filename)) {
                        return fi[j].inode;
                    }
                }
            }
        }
    }
    return 0;
}



void startsys() {
    vdisk = (unsigned char *)malloc(DISKSIZE);
    memset(vdisk, 0, DISKSIZE);

    printf("\033[33mLoading FileSystem...\033[0m\n");
    FILE*fp;
    fp = fopen("SAVED.aefs","rb");// localfile文件名  

    p_boot = (boot *)vdisk;
    p_super = (superBolck *)(vdisk+sizeof(boot));
    p_inode = getBlock(3);

    strcpy(cupath, "/");
    openreg.freen = MAXOPENFILE;
    memset(&openreg.isfree,1,MAXOPENFILE);

    if(fp) {
        fseek(fp,0L,SEEK_SET); /* 定位到文件开头 */
        fread(vdisk, DISKSIZE, 1, fp); /* 一次性读取全部文件内容 */
        if(p_group) {
            p_group = getBlock(p_super->cu_group);
        }else {
            p_group = NULL;
        }
        
        printf("\033[32mFileSystem Loaded!\033[0m\n");
        
    }else {
        printf("\033[31mNo IMG file found!\033[0m\n");
        aefs_format();
    }
    cudir = p_super->root_ino;
    fclose(fp);
}


void aefs_format() {
    printf("\033[33mCreating FileSystem...\033[0m\n");

    strcpy(p_boot->sysname, "Aeonni FileSystem");
    strcpy(p_boot->info, "Exercise for OS class, based on inode");

    p_super->s_block_size = BLOCKSIZE;
    p_super->s_inode_blocks = 18; /* 磁盘索引节点区所占用的数据块数*/ // 2
    p_super->s_block_amt = DISKSIZE/BLOCKSIZE;
    p_super->born_time = time(NULL);

    // Group Init
    int i = 40;
    for(i = 40; i < p_super->s_block_amt; i+=200) {
        p_group = (group *)getBlock(i);
        for(int j = 1; j < 200; j++) {
            p_group->blocks[j-1] = i+j;
        }
        p_group->blocks[199] = i+200;
        p_group->count = 200;
        p_group->max = 200;
        // printf("i: %d\n",i);
    }
    p_group->blocks[199] = 0;
    p_group->count = 199;
    p_group->max = 199;
    for(i = 21; i <= 40; i++) {
        p_super->s_frees[i-21] = i;
    }
    p_super->s_free_block_amt = 20;
    p_group = NULL;
    p_super->cu_group = 0;

    // inode Init
    for(i = 0; i < 288; i++) {
        p_super->s_inode[i] = i;
    }
    p_super->s_free_inode_amt = 288;
    p_inode = getBlock(3);
    p_inode[2].borntime = time(NULL);


    // Setup root
    p_super->root_ino = ino_alloc();
    d_inode * inop = &p_inode[p_super->root_ino];
    inop->size = 0;
    inop->borntime = time(NULL);
    inop->lmodtime = time(NULL);
    inop->linknum = 0;
    inop->attribute = (unsigned char)0x01ff;



    p_super->s_time = time(NULL);
    printf("\033[32mFileSystem Created!\033[0m\n");
}



void aefs_cd(char * dirname0) {
    char dirname[80];
    if(!strcmp(dirname0, ".")) {
        return;
    }
    strcpy(dirname, dirname0);
    if(!strcmp(dirname0, "..")) {
        if(!strcmp(cupath, "/")) {
            return;
        }
        cupath[strlen(cupath) - cupathlen] = '\0';
        strcpy(dirname, cupath);
        // printf("%s\n",dirname);
    }

    int len = 0;
    char **array;
    if(dirname[0] == '/') {
        cudir = p_super->root_ino;
        strcpy(cupath, "/");
        array = split(&dirname[1], '/', &len);
    }else {
        array = split(dirname, '/', &len);
    }
    // printf("len: %d",len);
    for(int n = 0; n < len; n++) {
        if(array[n]) {
            unsigned int ino = checkname(array[n]);
            if(ino) {
                d_inode * fino = &p_inode[ino];
                if((fino->attribute & 0xf0)) {
                    cudir = ino;
                    strcpy(&cupath[strlen(cupath)], array[n]);
                    strcpy(&cupath[strlen(cupath)], "/");
                    cupathlen = strlen(array[n])+1;
                }else {
                    printf("%s is not a dir!\n", array[n]);
                }
            }else {
                printf("No dir called %s!\n", array[n]);
            }
        }
    }
    
}

void aefs_mkdir(char * dirname) {
    // 是否重名
    if(checkname(dirname)) {
        printf("Name %s is USED!\n", dirname);
        return;
    }

    d_inode * cud = &p_inode[cudir];
    int subfiles = cud->size/sizeof(fileIndex);
    int usedBlocks = cud->size/BLOCKSIZE;

    // 创建新的目录文件
    if(subfiles%(BLOCKSIZE/sizeof(fileIndex)) == 0) {
        cud->i_addr[usedBlocks] = block_alloc();
    }
    int i = subfiles%(BLOCKSIZE/sizeof(fileIndex));
    fileIndex * fi = getBlock(cud->i_addr[usedBlocks]);
    strcpy(fi[i].filename, dirname);
    fi[i].inode = ino_alloc();
    d_inode * inop = &p_inode[fi[i].inode];
    inop->size = 0;
    inop->borntime = time(NULL);
    inop->lmodtime = time(NULL);
    inop->linknum = 1;
    inop->attribute = 0xff;
    for(int x = 0; x < 8; x++) {
        inop->i_addr[x] = -1;
    }

    // 父目录大小加大
    cud->size += sizeof(fileIndex);
    cud->lmodtime = time(NULL);
}

void aefs_rmdir(char * dirname) {
    // unsigned int ino = checkname(dirname);
    unsigned int ino ;
    fileIndex * f;
    d_inode * cud = &p_inode[cudir];
    int subfiles = cud->size/sizeof(fileIndex);
    if(cud->size) {
        int usedBlocks = cud->size/BLOCKSIZE + 1;
        for(int i = 0; i < usedBlocks; i++) {
            fileIndex * fi = getBlock(cud->i_addr[i]);
            if(i == usedBlocks-1) {
                for(int j = 0; j < subfiles%(BLOCKSIZE/sizeof(fileIndex)); j++) {
                    if(!strcmp(dirname,fi[j].filename)) {
                        f = &fi[j];
                        ino = fi[j].inode;
                    }
                }
            }else {
                for(int j = 0; j < BLOCKSIZE/sizeof(fileIndex); j++) {
                    if(!strcmp(dirname,fi[j].filename)) {
                        f = &fi[j];
                        ino = fi[j].inode;
                    }
                }
            }
        }
    }
    if(ino) {
        d_inode * fino = &p_inode[ino];
        if((fino->attribute & 0xf0)) {
            if(fino->linknum > 1) {
                fino->linknum--;
                memset(f->filename,NULL,28);
                return;
            }
            int x = 0;
            while(fino->i_addr[x] != -1 && x<8) {
                printf("block %d free\n", fino->i_addr[x]);
                block_free(fino->i_addr[x]);
                x++;
            }
            ino_free(ino);
            // d_inode * cud = &p_inode[cudir];
            // cud->size -= sizeof(fileIndex);
            cud->lmodtime = time(NULL);
            memset(f->filename,NULL,28);
        }else {
            printf("%s is not a dir!\n", dirname);
        }
    }else {
        printf("No dir called %s!\n", dirname);
    }
    
}

void aefs_ls() {
    d_inode * cud = &p_inode[cudir];
    int subfiles = cud->size/sizeof(fileIndex);
    int files = 0;
    printf("\033[32mtype  %16s  links      size     inode     borntime\033[0m\n", "name");
    if(cud->size) {
        int usedBlocks = cud->size/BLOCKSIZE + 1;
        for(int i = 0; i < usedBlocks; i++) {
            
            fileIndex * fi = getBlock(cud->i_addr[i]);
            if(i == usedBlocks-1) {
                for(int j = 0; j < subfiles%(BLOCKSIZE/sizeof(fileIndex)); j++) {
                    if(fi[j].filename[0]) {
                        d_inode * fino = &p_inode[fi[j].inode];
                        if((fino->attribute & 0xf0)) {
                            printf(" dir  ");
                            printf("\033[33m%16s  \033[0m", fi[j].filename);
                        }else {
                            printf("file  ");
                            printf("%16s  ", fi[j].filename);
                        }
                        
                        printf("%5hhu  ", fino->linknum);
                        printf("%8lu  ", fino->size);
                        printf("%8u  ", fi[j].inode);
                        printf("-- %s", ctime(((time_t *)&fino->borntime)));
                        // printf("%s\n", ctime(&fino->lmodtime));
                        files++;
                    }  
                }
            }else {
                for(int j = 0; j < BLOCKSIZE/sizeof(fileIndex); j++) {
                    if(fi[j].filename[0]) {
                        d_inode * fino = &p_inode[fi[j].inode];
                        if((fino->attribute & 0xf0)) {
                            printf(" dir  ");
                            printf("\033[33m%16s  \033[0m", fi[j].filename);
                        }else {
                            printf("file  ");
                            printf("%16s  ", fi[j].filename);
                        }
                        
                        printf("%5hhu  ", fino->linknum);
                        printf("%8lu  ", fino->size);
                        printf("%8u  ", fi[j].inode);
                        printf("-- %s", ctime(((time_t *)&fino->borntime)));
                        // printf("%s\n", ctime(&fino->lmodtime));
                        files++;
                    }   
                }
            }
        }
    }
    printf("Total: \033[32m%d\033[0m files\n", files);
    // printf("\n");
}

void pwd() {
    printf("%s\n", cupath);
}

void aefs_create(char * filename) {
    // 是否重名
    if(checkname(filename)) {
        printf("Name %s is USED!\n", filename);
        return;
    }
    d_inode * cud = &p_inode[cudir];
    int subfiles = cud->size/sizeof(fileIndex);
    int usedBlocks = cud->size/BLOCKSIZE;

    // 创建新的目录文件
    if(subfiles%(BLOCKSIZE/sizeof(fileIndex)) == 0) {
        cud->i_addr[usedBlocks] = block_alloc();
    }
    int i = subfiles%(BLOCKSIZE/sizeof(fileIndex));
    fileIndex * fi = getBlock(cud->i_addr[usedBlocks]);
    strcpy(fi[i].filename, filename);
    fi[i].inode = ino_alloc();
    d_inode * inop = &p_inode[fi[i].inode];
    inop->size = 0;
    inop->borntime = time(NULL);
    inop->lmodtime = time(NULL);
    inop->linknum = 1;
    inop->attribute = 0x0f;
    for(int x = 0; x < 8; x++) {
        inop->i_addr[x] = -1;
    }

    // 父目录大小加大
    cud->size += sizeof(fileIndex);
    cud->lmodtime = time(NULL);
}

void aefs_rm(char * filename) {
    unsigned int ino ;
    fileIndex * f;
    d_inode * cud = &p_inode[cudir];
    int subfiles = cud->size/sizeof(fileIndex);
    if(cud->size) {
        int usedBlocks = cud->size/BLOCKSIZE + 1;
        for(int i = 0; i < usedBlocks; i++) {
            fileIndex * fi = getBlock(cud->i_addr[i]);
            if(i == usedBlocks-1) {
                for(int j = 0; j < subfiles%(BLOCKSIZE/sizeof(fileIndex)); j++) {
                    if(!strcmp(filename,fi[j].filename)) {
                        f = &fi[j];
                        ino = fi[j].inode;
                    }
                }
            }else {
                for(int j = 0; j < BLOCKSIZE/sizeof(fileIndex); j++) {
                    if(!strcmp(filename,fi[j].filename)) {
                        f = &fi[j];
                        ino = fi[j].inode;
                    }
                }
            }
        }
    }
    if(ino) {
        d_inode * fino = &p_inode[ino];
        if(!(fino->attribute & 0xf0)) {
            if(fino->linknum > 1) {
                fino->linknum--;
                memset(f->filename,NULL,28);
                return;
            }
            int x = 0;
            while(fino->i_addr[x] != -1 && x<8) {
                printf("block %d free\n", fino->i_addr[x]);
                block_free(fino->i_addr[x]);
                x++;
            }
            ino_free(ino);
            // d_inode * cud = &p_inode[cudir];
            // cud->size -= sizeof(fileIndex);
            cud->lmodtime = time(NULL);
            memset(f->filename,NULL,28);
        }else {
            printf("%s is a dir!\n", filename);
        }
    }else {
        printf("No file called %s!\n", filename);
    }
}

int aefs_open(char * filename, char op) {
    // if opened
    for(int i = 0; i < MAXOPENFILE; i++) {
        if(!(openreg.isfree[i]) && !(strcmp(filename, openreg.list[i].filename))) {
            printf("%s is already opened! fp = %d\n", filename, i);
            return -1;
        }
    }
    switch(op) {
        case 'w': break;
        case 'r': break;
        case 'a': break;
        case 'x': break;
        default: printf("ileagel op!\n"); return -1;
    }
    // if exist
    unsigned int ino = checkname(filename);
    if(ino) {
        d_inode * fino = &p_inode[ino];
        if(!(fino->attribute & 0xf0)) {
            // 分配fd
            if(!openreg.freen) {
                printf("Max OPENFILE!\n");
                return -1;
            }
            int fd;
            for(int i = 0; i < MAXOPENFILE; i++) {
                if(openreg.isfree[i]) {
                    fd = i;
                    break;
                }
            }
            // reg info
            strcpy(openreg.list[fd].filename, filename);
            openreg.list[fd].inode = fino;
            openreg.list[fd].fp = 0;
            openreg.list[fd].op = op;
            openreg.list[fd].ischanged = 0;

            openreg.isfree[fd] = 0;
            openreg.freen--;
            printf("fd = %d\n", fd);
            return fd;
        }else {
            printf("%s is a dir!\n", filename);
            return -1;
        }
    }else {
        printf("No file called %s!\n", filename);
        return -1;
    }
}
void aefs_close(int fd) {
    if(openreg.list[fd].ischanged) {
        openreg.list[fd].inode->lmodtime = time(NULL);
    }
    openreg.freen++;
    openreg.isfree[fd] = 1;
}

int aefs_write(int fd) {
    if(0 > fd | fd > MAXOPENFILE | openreg.isfree[fd]) {
        printf("fd not exist!\n");
        return -1;
    }
    if(openreg.list[fd].op == 'r') {
        printf("Readonly file!\n");
        return -1;
    }
    char text[10240];
    printf("Enter text: \n");
    gets(text);
    int len = strlen(text);
    if(openreg.list[fd].op == 'a') {
        int fp = -1;
        // do {
        printf("Enter proper fp: ");
        scanf("%d",&fp); getchar();
        // }while(fp > openreg.list[fd].inode->size);
        if(fp > openreg.list[fd].inode->size) {fp = -1;}
        
        if(fp >= 0) { // fp
            openreg.list[fd].fp = fp;
            return do_write(fd, text, len, 1);
        }else { // 末位
            return do_write(fd, text, len, 2);
        }
    }else {
        openreg.list[fd].fp = 0;
        return do_write(fd, text, len, 0);
    }
}
int do_write(int fd, char * text, int len, int wstyle) {
    d_inode * ino = openreg.list[fd].inode;
    int size = ino->size;
    // int ori_size = ino->size;
    switch(wstyle) {
        case 0: size = len; break;
        case 2: openreg.list[fd].fp = size; size += len; break;
        case 1: size = size + len - openreg.list[fd].fp; break;
    }
    int needBlocks = size/BLOCKSIZE + 1;
    // int ori_blocks = ori_size/BLOCKSIZE + 1;
    // alloc block
    int i;
    for(i = 0; i < needBlocks; i++) {
        if(ino->i_addr[i] == -1) {
            // printf("miao %d\n",ino->i_addr[i]);
            ino->i_addr[i] = block_alloc();
            // block_alloc();

            printf("get block %d\n", ino->i_addr[i]);
        }
    }
    for(; i < 8; i++) {
        // printf("%d\n", ino->i_addr[i]);
        if(ino->i_addr[i] != -1) {
            // printf("free block %d\n", ino->i_addr[i]);
            block_free(ino->i_addr[i]);
        }
    }
    // write
    
    int buff = len;
    char * textp = text;
    
    while(buff > 0) {
        int cublock = openreg.list[fd].fp/BLOCKSIZE;
        int cuword = openreg.list[fd].fp%BLOCKSIZE;
        char * p = (char *)getBlock(ino->i_addr[cublock]);
        p += cuword;
        int wsize = BLOCKSIZE - cuword;
        if(buff < wsize) {
            wsize = buff;
        }
        // printf("miao %p\n",textp+(len-buff));
        // printf("miao %d\n",wsize);
        
        memcpy(p, textp+(len-buff), wsize);
        // printf("miao %d\n",wsize);
        buff -= wsize;
        openreg.list[fd].fp += wsize;

    }

    openreg.list[fd].ischanged = 1;
    openreg.list[fd].inode->size = size;
    return len;
}
int aefs_read(int fd) {
    if(0 > fd | fd > MAXOPENFILE | openreg.isfree[fd]) {
        printf("fd not exist!\n");
        return -1;
    }
    if(openreg.list[fd].op == 'w') {
        printf("Writeonly file!\n");
        return -1;
    }
    int len = 0;
    printf("Enter length: ");
    scanf("%d",&len); getchar();
    if(len > openreg.list[fd].inode->size) {len = 0;}

    return do_read(fd, len, NULL);
}
int do_read(int fd, int len, char * text) {
    d_inode * ino = openreg.list[fd].inode;
    int buff;
    if(len) {
        buff = len;
    }else {
        buff = ino->size;
    }

    int needBlocks = buff/BLOCKSIZE + 1;
    for(int i = 0; i < needBlocks; i++) {
        int out = BLOCKSIZE;
        if(buff < out) {
            out = buff;
        }
        char * p = (char *)getBlock(ino->i_addr[i]);
        for(int j = 0; j < out; j++) {
            putchar(*(p+j));
        }
    }
    putchar('\n');

}

void aefs_ln(char * from, char * to) {
    unsigned int from_ino;
    from_ino = checkname(from);
    if(from_ino) {
        if(checkname(to)) {
            printf("Name %s is USED!\n", to);
            return;
        }else {
            d_inode * cud = &p_inode[cudir];
            int subfiles = cud->size/sizeof(fileIndex);
            int usedBlocks = cud->size/BLOCKSIZE;

            // 创建新的目录文件
            if(subfiles%(BLOCKSIZE/sizeof(fileIndex)) == 0) {
                cud->i_addr[usedBlocks] = block_alloc();
            }
            int i = subfiles%(BLOCKSIZE/sizeof(fileIndex));
            fileIndex * fi = getBlock(cud->i_addr[usedBlocks]);
            strcpy(fi[i].filename, to);
            fi[i].inode = from_ino;
            d_inode * fino = &p_inode[from_ino];
            fino->linknum++;
            // 父目录大小加大
            cud->size += sizeof(fileIndex);
            cud->lmodtime = time(NULL);
        }
    }else {
        printf("File %s not exist!\n", from);
        return;
    }
}

void exitsys() {
    printf("\033[33mSaving Disk Image...\033[0m\n");

    FILE*fp;
    fp = fopen("SAVED.aefs", "wb");// localfile文件名  
    fseek(fp,0L,SEEK_SET);
    fwrite(vdisk, DISKSIZE, 1, fp);

    printf("\033[32mFileSystem Saved!\033[0m\n");
}


void diskinfo() {
    printf("FileSystem: %s \n", p_boot->sysname);
    printf("Block Size: %d \n", p_super->s_block_size);
    printf("Born Time:  %s", ctime((time_t *)&p_super->born_time));
    printf("Info:       %s \n", p_boot->info);
}
  1. Terminal.c
#include <stdio.h>
#include <string.h>
#include "operations.h"
#include "AEFS.h"

int main() {
 
    char commands[15][8] = {"ls", "cd", "mkdir", "touch", "rm", 
                            "open", "close", "write", "read", "info", 
                            "ln", "rm -r", "pwd"};
    char cmd[100];
    
    printf("\033[32mStarting...\033[0m\n");
    startsys();
    
    while(1) {
        printf(">>> ");
        gets(cmd);
        if(!strcmp(cmd, "")) {
            ;
        }else if(!strcmp(cmd, "exit")) {
            printf("\033[31mExiting...\033[0m\n");
            break;
            ;
        }else {
            int cid = -1;
            for(int i = 0; i < 13; i++) {
                if(!strcmp(cmd, commands[i])) {
                    cid = i;
                    break;
                }
            }
            int d;
            char s[80]; 
            char s2[80]; 
            char op;
            switch(cid) {
                case 0: aefs_ls(); break;
                case 1: gets(s); aefs_cd(s); break;
                case 2: gets(s); aefs_mkdir(s); break;
                case 3: gets(s); aefs_create(s); break;
                case 4: gets(s); aefs_rm(s); break;
                case 5: scanf("%s %c", s, &op); getchar(); aefs_open(s, op); break;
                case 6: scanf("%d",&d); getchar(); aefs_close(d); break;
                case 7: scanf("%d",&d); getchar(); aefs_write(d);  break;
                case 8: scanf("%d",&d); getchar(); aefs_read(d); break;
                case 9: diskinfo(); break;
                case 10: gets(s); gets(s2); aefs_ln(s, s2); break;
                case 11: gets(s); aefs_rmdir(s); break;
                case 12: pwd(); break;

                default: printf("\033[31mNo such command!\033[0m\n"); break;
            }
        }
    }

    
    exitsys();
    printf("\033[32mFinished!\033[0m\n");
    return 0;
}