实现一个简单文件系统

前言

这是操作系统实践课程的一个实验作业,让我们在虚拟磁盘上实现一个简单的文件系统,我认为有一定的难度,虽然是小组完成(幸好组里有大佬)。

现在已经是假期了,重新把这个简单文件系统的实现梳理一遍。(平时没时间)(~~ 要被划掉的内容 ~~)


首先来说,把一些重要的数据结构体看一下。

主要结构体

目录(Direction)和目录项(Direction Entry)分别是什么?

目录简单来说就是文件夹,目录中有若干目录项,目录项可以是文件或者子目录,目录将文件组织成树形结构,目录项中包含一些文件的元信息(文件索引号、文件名、父目录等),通过文件索引号可以找到索引节点inode,而索引节点中保存了文件存储的磁盘块号,于是就能读取到文件数据。

下面的两张图有助于理解我们这个简单文件系统实现,但是要注意,这两张图是inode的实现,而我们这个采用的是FAT,还是有区别的。

img

v2-1b0afa95e56ddf0cdd95ee2ad1d75d09_1440w

UserOpen

图2中每个进程都有自己的files_struct文件打开表,用于管理进程打卡的文件,文件打开表的索引称为文件描述符fd。这里以链表的形式实现文件打开表。

typedef struct UserOpen
{
char dir[2048]; //完整路径,包括文件名
FCB *fcb; //FCB
short openCount; //被打开计数,为0时移除
int ptr; //读写指针
int fd; //文件描述符
int permission; //权限,第一位表示可读,第二位表示可写
struct UserOpen *next; //下一个表项位置
} UserOpen; //链表

FCB

图2的file结构体是文件的抽象表示,通过file我们可以从磁盘中找到文件数据,这里file对应的是FCB(文件控制块),也就是说,目录项保存文件名到file的映射。子目录的目录项的文件数据是目录项表。

typedef struct FCB {
char filename[256]; //完整文件名
char exname[8]; //扩展名
unsigned char attribute; //0为普通文件|1为目录文件
short block_num; //分配磁盘块数量
int len; //文件长度(尾指针位置)
short first; //第一个磁盘块编号
char free; //是否为空
int permission; //权限,第一位表示可读,第二位表示可写
int item_num; //目录文件内容数量
int save_place; //存储的起始位置
} FCB;
//目录文件的内容是FCB顺序表

FAT

不过这里的简单文件系统并没有采取inode来作为文件存储的方式,而是采用FAT(文件分配表)。顺便一提,FAT是通过管理一张表来记录文件的磁盘块,而且必须将整张表加载到内存中。

typedef struct FAT {
short next[DISK_SIZE / BLOCK_SIZE];
} FAT;

img

img

Bitmap

typedef struct Bitmap {
int map[DISK_SIZE / BLOCK_SIZE / 32 + 1]; //示位图
int free_num; //空闲磁盘块数量
} Bitmap;

位示图,用来表示所有磁盘块的状态,0为占用,1为空闲,和FAT对应,一个表示磁盘块状态,一个表示文件所存储的逻辑连续的磁盘块位置。

打开文件&读写文件

打开文件

之前说到使用目录项实现文件的组织结构,那么文件加载到内存之后又是怎么组织管理的?

打开文件只需要文件路径,解析文件路径,找到文件的FCB,在UserOpen中新增打开的文件。

//用户接口 打开文件 返回fd
int my_open(char *dir) {
int permission;
printf("请输入开启方式(十进制数字,其二进制位第一位表示可读,第二位表示可写):");
scanf("%d", &permission);
int fd;
if(file_open(dir, &fd, permission)) {
printf("file : %s failed to open\n", dir);
return -1;
}
printf("file : %s open sucessed. fd is %d\n", dir, fd);
return fd;
}

//打开文件
int file_open(char *dir, int *fd, int permission) {
FCB *fcb;
if(file_find(dir, &fcb, NULL))
return 1;
if(fcb->attribute)
permission = 0;
if(((fcb->permission) | permission) > fcb->permission)
return 1;
char full_dir[2048];
if(dir[0] == '.') {
if(strcmp(current_dir, "/")) {
strcpy(full_dir, current_dir);
strcat(full_dir, dir + 1);
} else {
strcpy(full_dir, dir + 1);
}
} else {
strcpy(full_dir, dir);
}
for(UserOpen *i = user_open; i; i = i->next) {
if(!strcmp(full_dir, i->dir)) {
i->openCount++;
i->permission |= permission;
*fd = i->fd;
return 0;
}
}
if(opening_num == MAX_OPEN_FILE)
return 1;
opening_num++;
UserOpen *new_user_open = (UserOpen*) malloc(sizeof(UserOpen));
strcpy(new_user_open->dir, full_dir);
for(int i = 0; i < MAX_OPEN_FILE; i++) {
if(!free_fd[i]) {
free_fd[i] = 1;
new_user_open->fd = i;
*fd = i;
break;
}
}
new_user_open->permission = permission;
new_user_open->openCount = 1;
new_user_open->ptr = 0;
new_user_open->fcb = fcb;
new_user_open->next = user_open;
user_open = new_user_open;
return 0;
}

读文件

我们以读文件切入,可以把上述结构体串联起来。当一个进程要读取文件的时候,一开始用户提供的信息只有文件描述符fd,拿着文件描述符在进程的UserOpen文件打开表中我们可以找到对应的FCB文件控制块,通过FATBitmap找到文件在磁盘中的位置,进而读取文件数据。

//用户接口 向打开的文件写入数据
void my_read(int fd) {
int len;
printf("请输入读取长度:");
scanf("%d", &len);
char *text = (char*) malloc(sizeof(char) * len);
if(do_read(fd, text, len))
return;
printf("读取内容:\n");
for(int i = 0; i < len; i++) putchar(text[i]);
printf("\n");
}

//实际读函数 向打开的文件写入数据
int do_read(int fd, char *text, int len) {
FCB *fcb;
UserOpen *uo;
if(fd < 0 || fd >= MAX_OPEN_FILE || !free_fd[fd]) {
printf("invalid fd\n");
return 1;
}
for(UserOpen *i = user_open; i; i = i->next) {
if(i->fd == fd) {
fcb = i->fcb;
uo = i;
if(!(uo->permission & 1)) {
printf("this file is not readable\n");
return 1;
}
if(uo->ptr + len >= fcb->len) {
printf("read area(%d, %d) out of file space\n", uo->ptr, uo->ptr + len);
return 1;
}
break;
}
}
if(file_read(*fcb, text, uo->ptr, len)) {
printf("read failed\n");
}
return 0;
}

//读取文件中内容
int file_read(FCB fcb, char *text, int start, int len) {
if(start + len > fcb.len)
return 1;
for(short i = fcb.first, t = 0; i != -1; i = fat.next[i], t++) {
if(t == start / BLOCK_SIZE) {
if(block_read(i, text, start % BLOCK_SIZE, min(len, BLOCK_SIZE - start % BLOCK_SIZE)))
return 1;
if(start / BLOCK_SIZE == (start + len) / BLOCK_SIZE)
break;
}
if(t > start / BLOCK_SIZE && t < (start + len) / BLOCK_SIZE) {
if(block_read(i, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), 0, BLOCK_SIZE))
return 1;
}
if(t == (start + len) / BLOCK_SIZE) {
if(block_read(i, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), 0, (start + len - 1) % BLOCK_SIZE + 1))
return 1;
break;
}
}
return 0;
}

写文件

//用户接口 向打开的文件写入数据
void my_write(int fd) {
int size = BLOCK_SIZE;
int len = 0;
char c;
char *text = (char*) malloc(sizeof(char) * BLOCK_SIZE);
printf("请输入数据(输入ctrl+d或ctrl+z以结束输入):\n");
while(~(c = getchar())) {
if(len == size) {
size += BLOCK_SIZE;
text = (char*) realloc(text, sizeof(char) * size);
}
text[len++] = c;
}
clearerr(stdin);
printf("请输入写入方式(a 追加 | c 覆盖 | w 截断):");
c = getchar();
do_write(fd, text, len, c);
free(text);
}

//实际写函数 向打开的文件写入数据
int do_write(int fd, char *text, int len, char wstyle) {
FCB *fcb;
UserOpen *uo;
if(fd < 0 || fd >= MAX_OPEN_FILE || !free_fd[fd]) {
printf("invalid fd\n");
return 1;
}
for(UserOpen *i = user_open; i; i = i->next) {
if(i->fd == fd) {
fcb = i->fcb;
uo = i;
if(!(uo->permission & 2)) {
printf("this file is not writeable\n");
return 1;
}
break;
}
}
int start = 0;
if(wstyle == 'a') {
start = fcb->len;
} else if(wstyle == 'w') {
file_clear(fcb);
start = 0;
} else if(wstyle == 'c') {
start = uo->ptr;
} else {
printf("invalid wstyle\n");
return 1;
}
if(file_write(fcb, text, start, len) || update_fcb(fcb)) {
printf("write failed\n");
return 1;
}
return 0;
}

//将数据写入文件
int file_write(FCB *fcb, char *text, int start, int len) {
if(start + len > fcb->len) {
fcb->len = start + len;
}
if((start + len) / BLOCK_SIZE + 1 > fcb->block_num) {
if(file_get_block(fcb, (start + len) / BLOCK_SIZE + 1 - fcb->block_num))
return 1;
}
char buffer[BLOCK_SIZE];
for(short i = fcb->first, t = 0; i != -1; i = fat.next[i], t++) {
if(t == start / BLOCK_SIZE) {
memcpy(buffer, text, min(len, BLOCK_SIZE - start % BLOCK_SIZE));
if(block_write(i, buffer, start % BLOCK_SIZE, min(len, BLOCK_SIZE - start % BLOCK_SIZE)))
return 1;
if(start / BLOCK_SIZE == (start + len) / BLOCK_SIZE)
break;
}
if(t > start / BLOCK_SIZE && t < (start + len) / BLOCK_SIZE) {
memcpy(buffer, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), BLOCK_SIZE);
if(block_write(i, buffer, 0, BLOCK_SIZE))
return 1;
}
if(t == (start + len) / BLOCK_SIZE) {
memcpy(buffer, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), (start + len - 1) % BLOCK_SIZE + 1);
if(block_write(i, buffer, 0, (start + len - 1) % BLOCK_SIZE + 1))
return 1;
break;
}
}
return 0;
}

和读文件大差不差,写文件就是把用户的输入以给定的写入方式将数据写入到磁盘块中

文件系统初始化

启动文件系统,如果文件系统有保存文件,那么就读取文件中的数据,如果没有保存文件,那么初始化文件系统。

因为是虚拟文件系统,在内存中申请空间作为虚拟磁盘空间,做一些初始化的空间划分,初始化一些全局变量(当前FCB,当前目录等)

//初始化
int init(char *disk_dir, int new) {
disk = (char*) malloc(DISK_SIZE * sizeof(char));
if(new) {
bitmap_init();
fat_init();
root_init();
//划分初始空间
get_block(ROOT_BLOCK_NUM + FAT_BLOCK_NUM + BITMAP_BLOCK_NUM);
save_root();
} else {
if(load_disk(disk_dir))
return 1;
}
current_fcb = &root_fcb;
current_menu = root_menu;
current_fd = -1;
strcpy(current_dir, "/");
opening_num = 0;
user_open = NULL;
memset(free_fd, 0, sizeof(free_fd));

return 0;
}

tips: 像是这种markdown样式可以通过前加>实现

源码

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

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

#define MAX_LENGTH 2048
#define BLOCK_SIZE 1024
#define DISK_SIZE 1024000
#define END -1
#define ROOT_BLOCK_NUM (sizeof(FCB)-1)/BLOCK_SIZE+1
#define FAT_BLOCK_NUM (sizeof(FAT)-1)/BLOCK_SIZE+1
#define BITMAP_BLOCK_NUM (sizeof(Bitmap)-1)/BLOCK_SIZE+1
#define MAX_OPEN_FILE 10
#define SAVE_DISK_DIR "./disk.sv"

#define INSTRUCTION_OPEN "open"
#define INSTRUCTION_CLOSE "close"
#define INSTRUCTION_LS "ls"
#define INSTRUCTION_LSOF "lsof"
#define INSTRUCTION_CD "cd"
#define INSTRUCTION_MKDIR "mkdir"
#define INSTRUCTION_RMDIR "rmdir"
#define INSTRUCTION_FORMAT "format"
#define INSTRUCTION_EXITSYS "exit"
#define INSTRUCTION_SEEK "seek"
#define INSTRUCTION_WRITE "write"
#define INSTRUCTION_READ "read"
#define INSTRUCTION_CREATE "create"
#define INSTRUCTION_RM "rm"

typedef struct FCB {
char filename[256]; //完整文件名
char exname[8]; //扩展名
unsigned char attribute; //0为普通文件|1为目录文件
short block_num; //分配磁盘块数量
int len; //文件长度(尾指针位置)
short first; //第一个磁盘块编号
char free; //是否为空
int permission; //权限,第一位表示可读,第二位表示可写
int item_num; //目录文件内容数量
int save_place; //存储的起始位置
} FCB;
//目录文件的内容是FCB顺序表

typedef struct UserOpen
{
char dir[2048]; //完整路径,包括文件名
FCB *fcb; //FCB
short openCount; //被打开计数,为0时移除
int ptr; //读写指针
int fd; //文件描述符
int permission; //权限,第一位表示可读,第二位表示可写
struct UserOpen *next; //下一个表项位置
} UserOpen; //链表

typedef struct Bitmap {
int map[DISK_SIZE / BLOCK_SIZE / 32 + 1]; //示位图
int free_num; //空闲磁盘块数量
} Bitmap;

typedef struct FAT {
short next[DISK_SIZE / BLOCK_SIZE]; //下一个磁盘块位置
} FAT;

FAT fat;
Bitmap bitmap;
UserOpen *user_open = NULL; //打开文件表
int opening_num; //打开文件数 | 剩余可分配fd数
short free_fd[MAX_OPEN_FILE] = {0}; //用于分配fd
char current_dir[2048]; //当前目录路径
FCB *current_fcb; //当前目录的FCB
FCB *current_menu; //当前目录下的所有FCB
int current_fd; //当前目录的fd
FCB root_fcb; //root本身的FCB
FCB *root_menu; //root目录下的所有FCB
char *disk; //模拟磁盘

//初始化 new为1新建,为0读取
int init(char *disk_dir, int new);
//释放目标磁盘块
int free_block(short block);
//获取num个磁盘块
short *get_block(int num);
//向目标磁盘块写入数据
int block_write(short block, char *text, int start, int len);
//在目标磁盘块读出数据
int block_read(short block, char *text, int start, int len);
//读取文件中内容
int file_read(FCB fcb, char *text, int start, int len);
//将数据写入文件
int file_write(FCB *fcb, char *text, int start, int len);
//为文件划分盘块
int file_get_block(FCB *fcb, int num);
//清空文件,回收磁盘空间,但保留FCB
int file_clear(FCB *fcb);
//将目标目录读入内存
int read_menu(FCB menu_fcb, FCB **menu_item);
//打开文件
int file_open(char *dir, int *fd, int permission);
//关闭文件
int file_close(int fd);
//根据路径找到文件的FCB
int file_find(char *dir, FCB **fcb, FCB *menu_fcb);
//创建文件 attribute对应FCB的同名项
int file_create(char *filename, FCB *menu_fcb, int attribute, int permission);
//删除文件
int file_delete(int target, FCB *menu_fcb, char *full_dir);
//给出文件名,在目标目录中寻找其序号where,不存在时where为-1
int file_find_menu(char *filename, FCB *menu_fcb, int *where);
//展示当前目录
void do_ls();
//展示当前打开文件
void do_lsof();
//跳转到对应目录
int do_cd(char *dir);
//保存根目录FCB
int save_root();
//更新磁盘中的fcb
int update_fcb(FCB *fcb);
//保存示位图
int save_bitmap();
//保存FAT表
int save_fat();
//保存到磁盘 全部保存仅需调用此函数
int save_disk(char *dir);
//从磁盘加载虚拟磁盘 初始加载仅需调用此函数
int load_disk(char *dir);
//加载FAT表
int load_fat();
//加载示位图
int load_bitmap();
//加载根目录FCB
int load_root();
//初始化根目录
void root_init();
//初始化示位图
void bitmap_init();
//初始化FAT表
void fat_init();
//用户接口 打开文件 返回fd
int my_open(char *dir);
//用户接口 关闭文件 根据fd关闭
void my_close(int fd);
//用户接口 创建文件
void my_create(char *dir);
//用户接口 删除文件
void my_rm(char *dir);
//用户接口 展示当前目录
void my_ls();
//用户接口 展示当前打开文件表
void my_lsof();
//用户接口 跳转到对应目录
void my_cd(char *dir);
//用户接口 创建目录
void my_mkdir(char *dir);
//用户接口 删除目录
void my_rmdir(char *dir);
//用户接口 格式化磁盘
void my_format();
//启动文件系统函数
void startsys();
//用户接口 退出文件系统
void my_exitsys();
//执行函数 设置读写指针位置
int do_seek(int fd, int where);
//用户接口 设置读写指针位置
void my_seek(int fd);
//实际写函数 向打开的文件写入数据
int do_write(int fd, char *text, int len, char wstyle);
//实际读函数 向打开的文件写入数据
int do_read(int fd, char *text, int len);
//用户接口 向打开的文件写入数据
void my_write(int fd);
//用户接口 向打开的文件写入数据
void my_read(int fd);
//命令行接口
void shell();

//命令行接口
void shell() {
char line[MAX_LENGTH];
while(1) {
printf("%s >", current_dir);
char section[MAX_LENGTH];
char *param1;
int section_ptr = 0, part = 0;
int instruction = -1;
int flag = 0;
fgets(line, MAX_LENGTH, stdin);
while(strlen(line) < 2) fgets(line, MAX_LENGTH, stdin);
for(int i = 0; i < strlen(line); i++) {
if(flag) break;
if(line[i] == ' ' || i == strlen(line) - 1) {
char *buffer = (char*) malloc(sizeof(char) * (section_ptr + 1));
memcpy(buffer, section, section_ptr);
buffer[section_ptr] = '\0';
section_ptr = 0;
if(part == 0) {
if(!strcmp(buffer, INSTRUCTION_CD)) instruction = 0;
if(!strcmp(buffer, INSTRUCTION_CLOSE)) instruction = 1;
if(!strcmp(buffer, INSTRUCTION_EXITSYS)) {
instruction = 2;
my_exitsys();
flag = 1;
}
if(!strcmp(buffer, INSTRUCTION_FORMAT)) {
instruction = 3;
my_format();
flag = 1;
}
if(!strcmp(buffer, INSTRUCTION_LS)) {
instruction = 4;
my_ls();
flag = 1;
}
if(!strcmp(buffer, INSTRUCTION_LSOF)) {
instruction = 5;
my_lsof();
flag = 1;
}
if(!strcmp(buffer, INSTRUCTION_MKDIR)) instruction = 6;
if(!strcmp(buffer, INSTRUCTION_OPEN)) instruction = 7;
if(!strcmp(buffer, INSTRUCTION_READ)) instruction = 8;
if(!strcmp(buffer, INSTRUCTION_RMDIR)) instruction = 9;
if(!strcmp(buffer, INSTRUCTION_SEEK)) instruction = 10;
if(!strcmp(buffer, INSTRUCTION_WRITE)) instruction = 11;
if(!strcmp(buffer, INSTRUCTION_CREATE)) instruction = 12;
if(!strcmp(buffer, INSTRUCTION_RM)) instruction = 13;
if(!(~instruction)) {
printf("instruction %s not find\n", buffer);
flag = 1;
}
part = 1;
free(buffer);
continue;
}
if(part == 1) {
if(instruction == 0) {
my_cd(buffer);
flag = 1;
}
if(instruction == 1) {
int fd = 0, doing = 1;
for(int j = 0; j < strlen(buffer); j++) {
if(buffer[j] < '0' || buffer[j] > '9') {
printf("invalid param: %s\n", buffer);
doing = 0;
break;
}
fd = fd * 10 + buffer[j] - '0';
}
if(doing)
my_close(fd);
flag = 1;
}
if(instruction == 6) {
my_mkdir(buffer);
flag = 1;
}
if(instruction == 7) {
my_open(buffer);
flag = 1;
}
if(instruction == 8) {
int fd = 0, doing = 1;
for(int j = 0; j < strlen(buffer); j++) {
if(buffer[j] < '0' || buffer[j] > '9') {
printf("invalid param: %s\n", buffer);
doing = 0;
break;
}
fd = fd * 10 + buffer[j] - '0';
}
if(doing)
my_read(fd);
flag = 1;
}
if(instruction == 9) {
my_rmdir(buffer);
flag = 1;
}
if(instruction == 10) {
int fd = 0, doing = 1;
for(int j = 0; j < strlen(buffer); j++) {
if(buffer[j] < '0' || buffer[j] > '9') {
printf("invalid param: %s\n", buffer);
doing = 0;
break;
}
fd = fd * 10 + buffer[j] - '0';
}
if(doing)
my_seek(fd);
flag = 1;
}
if(instruction == 11) {
int fd = 0, doing = 1;
for(int j = 0; j < strlen(buffer); j++) {
if(buffer[j] < '0' || buffer[j] > '9') {
printf("invalid param: %s\n", buffer);
doing = 0;
break;
}
fd = fd * 10 + buffer[j] - '0';
}
if(doing)
my_write(fd);
flag = 1;
}
if(instruction == 12) {
my_create(buffer);
flag = 1;
}
if(instruction == 13) {
my_rm(buffer);
flag = 1;
}
part = 2;
free(buffer);
continue;
}
}
section[section_ptr++] = line[i];
}
}
}

//用户接口 向打开的文件写入数据
void my_read(int fd) {
int len;
printf("请输入读取长度:");
scanf("%d", &len);
char *text = (char*) malloc(sizeof(char) * len);
if(do_read(fd, text, len))
return;
printf("读取内容:\n");
for(int i = 0; i < len; i++) putchar(text[i]);
printf("\n");
}

//实际读函数 向打开的文件写入数据
int do_read(int fd, char *text, int len) {
FCB *fcb;
UserOpen *uo;
if(fd < 0 || fd >= MAX_OPEN_FILE || !free_fd[fd]) {
printf("invalid fd\n");
return 1;
}
for(UserOpen *i = user_open; i; i = i->next) {
if(i->fd == fd) {
fcb = i->fcb;
uo = i;
if(!(uo->permission & 1)) {
printf("this file is not readable\n");
return 1;
}
if(uo->ptr + len >= fcb->len) {
printf("read area(%d, %d) out of file space\n", uo->ptr, uo->ptr + len);
return 1;
}
break;
}
}
if(file_read(*fcb, text, uo->ptr, len)) {
printf("read failed\n");
}
return 0;
}

//用户接口 向打开的文件写入数据
void my_write(int fd) {
int size = BLOCK_SIZE;
int len = 0;
char c;
char *text = (char*) malloc(sizeof(char) * BLOCK_SIZE);
printf("请输入数据(输入ctrl+d或ctrl+z以结束输入):\n");
while(~(c = getchar())) {
if(len == size) {
size += BLOCK_SIZE;
text = (char*) realloc(text, sizeof(char) * size);
}
text[len++] = c;
}
clearerr(stdin);
printf("请输入写入方式(a 追加 | c 覆盖 | w 截断):");
c = getchar();
do_write(fd, text, len, c);
free(text);
}

//实际写函数 向打开的文件写入数据
int do_write(int fd, char *text, int len, char wstyle) {
FCB *fcb;
UserOpen *uo;
if(fd < 0 || fd >= MAX_OPEN_FILE || !free_fd[fd]) {
printf("invalid fd\n");
return 1;
}
for(UserOpen *i = user_open; i; i = i->next) {
if(i->fd == fd) {
fcb = i->fcb;
uo = i;
if(!(uo->permission & 2)) {
printf("this file is not writeable\n");
return 1;
}
break;
}
}
int start = 0;
if(wstyle == 'a') {
start = fcb->len;
} else if(wstyle == 'w') {
file_clear(fcb);
start = 0;
} else if(wstyle == 'c') {
start = uo->ptr;
} else {
printf("invalid wstyle\n");
return 1;
}
if(file_write(fcb, text, start, len) || update_fcb(fcb)) {
printf("write failed\n");
return 1;
}
return 0;
}

//用户接口 设置读写指针位置
void my_seek(int fd) {
int where;
printf("请输入指针位置:");
scanf("%d", &where);
if(do_seek(fd, where))
return;
}

//用户接口 设置读写指针位置
int do_seek(int fd, int where) {
if(fd < 0 || fd >= MAX_OPEN_FILE || !free_fd[fd]) {
printf("invali fd\n");
return 1;
}
for(UserOpen *i = user_open; i; i = i->next) {
if(i->fd == fd) {
if(where < 0) {
printf("invali pointer\n");
return 1;
}
i->ptr = where;
return 0;
}
}
return 1;
}

//用户接口 退出文件系统
void my_exitsys() {
if(save_disk(SAVE_DISK_DIR))
printf("disk saving failed");
free(disk);
exit(0);
}

//启动文件系统函数
void startsys() {
if(init(SAVE_DISK_DIR, 0))
if(init(NULL, 1))
printf("can't start file system\n");
printf("file system start\n");
}

//用户接口 格式化磁盘
void my_format() {
free(disk);
if(init(NULL, 1))
printf("format failed\n");
printf("format sucessed\n");
}

//用户接口 删除目录
void my_rmdir(char *dir) {
FCB *menu_fcb;
int target, ptr = strlen(dir) - 1;
while(ptr >= 0 && dir[ptr] != '/') ptr--;
if(ptr < 0 || ptr == strlen(dir) - 1) {
printf("failed due to a wrong dir\n");
return;
}
char full_dir[2048];
if(dir[0] == '.') {
if(strcmp(current_dir, "/")) {
strcpy(full_dir, current_dir);
strcat(full_dir, dir + 1);
} else {
strcpy(full_dir, dir + 1);
}
} else {
strcpy(full_dir, dir);
}
char *menu_dir = (char*) malloc(sizeof(char) * ptr + 1);
memcpy(menu_dir, dir, ptr);
menu_dir[ptr] = '\0';
char *filename = (char*) malloc(sizeof(char) * (strlen(dir) - ptr));
memcpy(filename, dir + ptr + 1, strlen(dir) - ptr - 1);
filename[strlen(dir) - ptr - 1] = '\0';
if(ptr == 0) {
menu_fcb = &root_fcb;
} else if(ptr == 1 && menu_dir[0] == '.') {
menu_fcb = current_fcb;
} else {
if(file_find(menu_dir, &menu_fcb, NULL)) {
printf("failed due to a wrong dir\n");
free(menu_dir); free(filename);
return;
}
}
free(menu_dir);
if(file_find_menu(filename, menu_fcb, &target) || !~target) {
printf("failed due to a wrong dir\n");
free(filename);
return;
}

FCB *menu;
if(read_menu(*menu_fcb, &menu)) {
printf("failed due to a wrong dir\n");
free(filename);
return;
}

if(!(menu + target)->attribute) {
printf("please use rmdir to remove a file\n");
free(filename);
return;
}

if(file_delete(target, menu_fcb, full_dir)) {
printf("failed to rm the file %s\n", dir);
free(filename);
return;
}
free(filename);
}

//用户接口 创建目录
void my_mkdir(char *dir) {
if(dir[strlen(dir) - 1] == '/') {
printf("failed due to a wrong dir\n");
return;
}
int ptr = 0, fnptr = 0;
FCB *fcb, *menu;
if(dir[ptr] == '.' && dir[ptr + 1] == '/') {
fcb = current_fcb;
menu = current_menu;
ptr += 2;
} else if(dir[ptr] == '/') {
fcb = &root_fcb;
menu = root_menu;
ptr++;
} else {
printf("failed due to a wrong dir\n");
return;
}
char filename[256];
int permission = 3;
int attribute = 1;
while(ptr <= strlen(dir)) {
if(dir[ptr] == '/' || ptr == strlen(dir)) {
if(!fnptr) {
printf("failed due to a wrong dir\n");
return;
}
int where;
char *buffer = (char*) malloc(sizeof(char) * fnptr + sizeof(char));
memcpy(buffer, filename, fnptr);
buffer[fnptr] = '\0';
if(file_find_menu(buffer, fcb, &where)) {
printf("file : %s failed to create\n", dir);
free(buffer);
return;
}
if(~where && ptr == strlen(dir)) {
{
printf("file : %s has existed\n", dir);
free(buffer);
return;
}
}
if(!~where) {
if(file_create(buffer, fcb, ptr == strlen(dir) ? attribute : 1, 3)) {
printf("file : %s failed to create\n", dir);
free(buffer);
return;
}
if(read_menu(*fcb, &menu)) {
printf("file : %s failed to create\n", dir);
free(buffer);
return;
}
where = fcb->item_num - 1;
}
free(buffer);
if(ptr == strlen(dir))
return;
fcb = menu + where;
if(read_menu(*fcb, &menu)) {
printf("file : %s failed to create\n", dir);
return;
}
ptr++;
fnptr = 0;
continue;
}
filename[fnptr++] = dir[ptr++];
}
}

//用户接口 跳转到对应目录
void my_cd(char *dir) {
if(do_cd(dir))
printf("failed to move to %s\n", dir);
}

//用户接口 展示当前目录
void my_ls() {
do_ls();
}

//用户接口 展示当前打开文件表
void my_lsof() {
do_lsof();
}

//用户接口 删除文件
void my_rm(char *dir) {
FCB *menu_fcb;
int target, ptr = strlen(dir) - 1;
while(ptr >= 0 && dir[ptr] != '/') ptr--;
if(ptr < 0 || ptr == strlen(dir) - 1) {
printf("failed due to a wrong dir\n");
return;
}
char full_dir[2048];
if(dir[0] == '.') {
if(strcmp(current_dir, "/")) {
strcpy(full_dir, current_dir);
strcat(full_dir, dir + 1);
} else {
strcpy(full_dir, dir + 1);
}
} else {
strcpy(full_dir, dir);
}
char *menu_dir = (char*) malloc(sizeof(char) * ptr + 1);
memcpy(menu_dir, dir, ptr);
menu_dir[ptr] = '\0';
char *filename = (char*) malloc(sizeof(char) * (strlen(dir) - ptr));
memcpy(filename, dir + ptr + 1, strlen(dir) - ptr - 1);
filename[strlen(dir) - ptr - 1] = '\0';
if(ptr == 0) {
menu_fcb = &root_fcb;
} else if(ptr == 1 && menu_dir[0] == '.') {
menu_fcb = current_fcb;
} else {
if(file_find(menu_dir, &menu_fcb, NULL)) {
printf("failed due to a wrong dir\n");
free(menu_dir); free(filename);
return;
}
}
free(menu_dir);
if(file_find_menu(filename, menu_fcb, &target) || !~target) {
printf("failed due to a wrong dir\n");
free(filename);
return;
}

FCB *menu;
if(read_menu(*menu_fcb, &menu)) {
printf("failed due to a wrong dir\n");
free(filename);
return;
}

if((menu + target)->attribute) {
printf("please use rmdir to remove a menu\n");
free(filename);
return;
}

if(file_delete(target, menu_fcb, full_dir)) {
printf("failed to rm the file %s\n", dir);
free(filename);
return;
}
free(filename);
}

//用户接口 创建文件
void my_create(char *dir) {
if(dir[strlen(dir) - 1] == '/') {
printf("failed due to a wrong dir\n");
return;
}
int ptr = 0, fnptr = 0;
FCB *fcb, *menu;
if(dir[ptr] == '.' && dir[ptr + 1] == '/') {
fcb = current_fcb;
menu = current_menu;
ptr += 2;
} else if(dir[ptr] == '/') {
fcb = &root_fcb;
menu = root_menu;
ptr++;
} else {
printf("failed due to a wrong dir\n");
return;
}
char filename[256];
int permission = 3;
int attribute = 0;
while(ptr <= strlen(dir)) {
if(dir[ptr] == '/' || ptr == strlen(dir)) {
if(!fnptr) {
printf("failed due to a wrong dir\n");
return;
}
int where;
char *buffer = (char*) malloc(sizeof(char) * fnptr + sizeof(char));
memcpy(buffer, filename, fnptr);
buffer[fnptr] = '\0';
if(file_find_menu(buffer, fcb, &where)) {
printf("file : %s failed to create\n", dir);
free(buffer);
return;
}
if(~where && ptr == strlen(dir)) {
{
printf("file : %s has existed\n", dir);
free(buffer);
return;
}
}
if(!~where) {
if(file_create(buffer, fcb, ptr == strlen(dir) ? attribute : 1, 3)) {
printf("file : %s failed to create\n", dir);
free(buffer);
return;
}
if(read_menu(*fcb, &menu)) {
printf("file : %s failed to create\n", dir);
free(buffer);
return;
}
where = fcb->item_num - 1;
}
free(buffer);
if(ptr == strlen(dir))
return;
fcb = menu + where;
if(read_menu(*fcb, &menu)) {
printf("file : %s failed to create\n", dir);
return;
}
ptr++;
fnptr = 0;
continue;
}
filename[fnptr++] = dir[ptr++];
}
}

//用户接口 关闭文件 根据fd关闭
void my_close(int fd) {
for(UserOpen *i = user_open; i; i = i->next) {
if(i->fd == fd) {
if(!strcmp(i->dir, current_dir)) {
printf("can't close current menu\n");
return;
}
}
}
if(file_close(fd)) {
printf("failed to close\n");
}
}

//用户接口 打开文件 返回fd
int my_open(char *dir) {
int permission;
printf("请输入开启方式(十进制数字,其二进制位第一位表示可读,第二位表示可写):");
scanf("%d", &permission);
int fd;
if(file_open(dir, &fd, permission)) {
printf("file : %s failed to open\n", dir);
return -1;
}
printf("file : %s open sucessed. fd is %d\n", dir, fd);
return fd;
}

//加载示位图
int load_bitmap() {
Bitmap *buffer = (Bitmap*) malloc(sizeof(Bitmap));
memcpy(buffer, disk + (ROOT_BLOCK_NUM + FAT_BLOCK_NUM) * BLOCK_SIZE, sizeof(Bitmap));
bitmap = *buffer;
return 0;
}

//加载FAT表
int load_fat() {
FAT *buffer = (FAT*) malloc(sizeof(FAT));
memcpy(buffer, disk + ROOT_BLOCK_NUM * BLOCK_SIZE, sizeof(FAT));
fat = *buffer;
return 0;
}

//加载根目录FCB
int load_root() {
FCB *fcb = (FCB*) malloc(sizeof(FCB));
memcpy(fcb, disk, sizeof(FCB));
root_fcb = *fcb;
return 0;
}

//从磁盘加载虚拟磁盘
int load_disk(char *dir) {
FILE *file = fopen(dir, "rb");
if(file == NULL)
return 1;
fread(disk, sizeof(char), sizeof(char) * DISK_SIZE, file);

fclose(file);
printf("load from %s\n", dir);
if(load_fat()) return 1;
if(load_root()) return 1;
if(load_bitmap()) return 1;
if(read_menu(root_fcb, &root_menu)) return 1;
return 0;
}

//保存到磁盘
int save_disk(char *dir) {
if(save_fat()) return 1;
if(save_root()) return 1;
if(save_bitmap()) return 1;
FILE *file = fopen(dir, "wb");
if (file == NULL) {
return 1;
}
fwrite(disk, sizeof(char),sizeof(char) * DISK_SIZE, file);

fclose(file);
printf("saved to %s\n", dir);
return 0;
}

//保存FAT表
int save_fat() {
char *buffer = (char*) &fat;
memcpy(disk + ROOT_BLOCK_NUM * BLOCK_SIZE, buffer, sizeof(FAT));
return 0;
}

//保存示位图
int save_bitmap() {
char *buffer = (char*) &bitmap;
memcpy(disk + (ROOT_BLOCK_NUM + FAT_BLOCK_NUM) * BLOCK_SIZE, buffer, sizeof(Bitmap));
return 0;
}

//保存根目录FCB
int save_root() {
char *buffer = (char*) &root_fcb;
memcpy(disk, buffer, sizeof(FCB));
return 0;
}

//更新磁盘中的fcb
int update_fcb(FCB *fcb) {
int fcb_size = sizeof(FCB);
short block = fcb->save_place / BLOCK_SIZE;
int start = fcb->save_place % BLOCK_SIZE;
int rest_byte = fcb_size;
while(rest_byte) {
if(rest_byte + start <= BLOCK_SIZE) {
if(block_write(block, ((char*) fcb) + fcb_size - rest_byte, start, rest_byte))
return 1;
rest_byte = 0;
} else {
if(block_write(block, ((char*) fcb) + fcb_size - rest_byte, start, BLOCK_SIZE - start))
return 1;
rest_byte -= BLOCK_SIZE - start;
start = 0;
block = fat.next[block];
}
}
return 0;
}

//跳转到对应目录
int do_cd(char *dir) {
FCB *fcb;
if((file_find(dir, &fcb, NULL) || !fcb->attribute) && strcmp(dir, "/"))
return 1;

if(current_fd != -1) {
if(file_close(current_fd))
return 1;
}

if(!strcmp(dir, "/")) {
current_fcb = &root_fcb;
current_menu = root_menu;
strcpy(current_dir, "/");
current_fd = -1;
return 0;
}

char full_dir[2048];
if(dir[0] == '.') {
if(strcmp(current_dir, "/")) {
strcpy(full_dir, current_dir);
strcat(full_dir, dir + 1);
} else {
strcpy(full_dir, dir + 1);
}
} else {
strcpy(full_dir, dir);
}

if(file_open(dir, &current_fd, 0))
return 1;

FCB *menu;
if(read_menu(*fcb, &menu))
return 1;
strcpy(current_dir, full_dir);
current_fcb = fcb;
current_menu = menu;
return 0;
}

//展示当前打开文件
void do_lsof() {
for(UserOpen *i = user_open; i; i = i->next) {
printf("文件描述符:%d\t路径:%s\t读写指针:%d\n", i->fd, i->dir, i->ptr);
}
}

//展示当前目录
void do_ls() {
for(int i = 0; i < current_fcb->item_num; i++) {
printf("文件名: %s\t文件类型: %s\t 文件长度(B):%d\n", (current_menu + i)->filename, (current_menu + i)->attribute ? "目录": "文件", (current_menu + i)->len);
}
}

//给出文件名,在目标目录中寻找其序号where,不存在时where为-1
int file_find_menu(char *filename, FCB *menu_fcb, int *where) {
FCB *menu;
if(read_menu(*menu_fcb, &menu))
return 1;
for(int i = 0; i < menu_fcb->item_num; i++) {
if(!strcmp((menu + i)->filename, filename)) {
*where = i;
return 0;
}
}
*where = -1;
return 0;
}

//删除文件
int file_delete(int target, FCB *menu_fcb, char *full_dir) {
if(!(menu_fcb->permission & 2)) {
printf("can't remove the menu %s\n", menu_fcb->filename);
return 0;
}
FCB *menu;
if(read_menu(*menu_fcb, &menu))
return 1;
if(!((menu + target) -> permission & 2)) {
printf("can't remove the file %s\n", (menu + target)->filename);
return 1;
}
for(UserOpen *i = user_open; i; i = i->next) {
if(!strcmp(full_dir, i->dir)) {
printf("the file %s is opening\n", (menu + target)->filename);
return 1;
}
}

FCB target_fcb = menu[target];
if(target_fcb.attribute == 1) {
FCB *target_menu;
if(read_menu(target_fcb, &target_menu))
return 1;
for(int i = target_fcb.item_num - 1; i >=0; i--) {
char buffer[2048];
strcpy(buffer, full_dir);
strcat(buffer, "/");
strcat(buffer, (target_menu + i)->filename);
if(file_delete(i, &target_fcb, buffer))
return 1;
}
}
for(int i = menu_fcb->item_num - 1; i > target; i--)
menu[i].save_place = menu[i - 1].save_place;
for(int i = target; i < menu_fcb->item_num - 1; i++) {
menu[i] = menu[i + 1];
}
char *buffer = (char*) menu;
if(file_clear(menu_fcb))
return 1;
if(file_write(menu_fcb, buffer, 0, (menu_fcb->item_num - 1) * sizeof(FCB))) {
menu_fcb->item_num = 0;
return 1;
}
menu_fcb->item_num--;
if(update_fcb(menu_fcb))
return 1;
if(read_menu(root_fcb, &root_menu))
return 1;
if(read_menu(*current_fcb, &current_menu))
return 1;
return 0;
}

//创建文件 attribute对应FCB的同名项
int file_create(char *filename, FCB *menu_fcb, int attribute, int permission) {
if(!menu_fcb->attribute)
return 1;
FCB *menu;
if(read_menu(*menu_fcb, &menu))
return 1;
for(int i = 0; i < menu_fcb->item_num; i++)
if(!strcmp(filename, (menu + i)->filename))
return 1;
FCB new_fcb;
new_fcb.attribute = attribute;
strcpy(new_fcb.filename, filename);
int dotptr = 0;
while(filename[dotptr] != '.' && dotptr < strlen(filename))
dotptr++;
if(filename[dotptr] == strlen(filename)) {
strcpy(new_fcb.exname, filename + dotptr + 1);
}
new_fcb.first = -1;
new_fcb.free = 1;
new_fcb.len = 0;
new_fcb.item_num = 0;
new_fcb.block_num = 0;
new_fcb.permission = permission;
new_fcb.save_place = 0;
char *buffer = (char*) &new_fcb;
if(file_write(menu_fcb, buffer, menu_fcb->len, sizeof(FCB)))
return 1;
menu_fcb->item_num += 1;
short block = menu_fcb->first, t=0;
while(t < (menu_fcb->len - sizeof(FCB)) / BLOCK_SIZE) {
t++;
block = fat.next[block];
}
new_fcb.save_place = block * BLOCK_SIZE + (menu_fcb->len - sizeof(FCB)) % BLOCK_SIZE;
if(file_write(menu_fcb, buffer, menu_fcb->len - sizeof(FCB), sizeof(FCB)))
return 1;
if(update_fcb(menu_fcb))
return 1;
if(read_menu(root_fcb, &root_menu))
return 1;
if(read_menu(*current_fcb, &current_menu))
return 1;
return 0;
}

//根据路径找到文件的FCB
int file_find(char *dir, FCB **fcb, FCB *menu_fcb) {
char filename[256];
int filename_ptr = 0;
FCB *menu = root_menu;
int menu_num = root_fcb.item_num;
int i = 0;
if(dir[i] == '.') {
if(menu_fcb == NULL) {
menu = current_menu;
menu_num = current_fcb->item_num;
} else {
if(read_menu(*menu_fcb, &menu))
return 1;
menu_num = menu_fcb->item_num;
}
i++;
}
if(dir[i] != '/') {
return 1;
}
while(i < strlen(dir)) {
if(dir[i + 1] == '/') {
i++;
int find = 0;
for(int j = 0; j < menu_num; j++) {
if(!strcmp(filename, (menu + j)->filename)) {
if(!(menu + j)->attribute)
return 1;
menu_num = (menu + j)->item_num;
if(read_menu(*(menu + j), &menu)) {
if(menu != root_menu && menu != current_menu)
free(menu);
return 1;
}
find = 1;
}
}
if(!find)
return 1;
filename_ptr = 0;
}
filename[filename_ptr++] = dir[++i];
}
if(!filename_ptr)
return 1;
for(int i = 0; i < menu_num; i++) {
if(!strcmp(filename, (menu + i)->filename)) {
*fcb = (menu + i);
return 0;
}
}
return 1;
}

//关闭文件
int file_close(int fd) {
if(!(free_fd[fd]))
return 1;
UserOpen *prev;
for(UserOpen *i = user_open; i; prev = i, i = i->next) {
if(i->fd == fd) {
if(!--(i->openCount)) {
free_fd[fd] = 0;
opening_num--;
if(i == user_open)
user_open = i->next;
else
prev->next = i->next;
free(i);
}
return 0;
}
}
return 1;
}

//打开文件
int file_open(char *dir, int *fd, int permission) {
FCB *fcb;
if(file_find(dir, &fcb, NULL))
return 1;
if(fcb->attribute)
permission = 0;
if(((fcb->permission) | permission) > fcb->permission)
return 1;
char full_dir[2048];
if(dir[0] == '.') {
if(strcmp(current_dir, "/")) {
strcpy(full_dir, current_dir);
strcat(full_dir, dir + 1);
} else {
strcpy(full_dir, dir + 1);
}
} else {
strcpy(full_dir, dir);
}
for(UserOpen *i = user_open; i; i = i->next) {
if(!strcmp(full_dir, i->dir)) {
i->openCount++;
i->permission |= permission;
*fd = i->fd;
return 0;
}
}
if(opening_num == MAX_OPEN_FILE)
return 1;
opening_num++;
UserOpen *new_user_open = (UserOpen*) malloc(sizeof(UserOpen));
strcpy(new_user_open->dir, full_dir);
for(int i = 0; i < MAX_OPEN_FILE; i++) {
if(!free_fd[i]) {
free_fd[i] = 1;
new_user_open->fd = i;
*fd = i;
break;
}
}
new_user_open->permission = permission;
new_user_open->openCount = 1;
new_user_open->ptr = 0;
new_user_open->fcb = fcb;
new_user_open->next = user_open;
user_open = new_user_open;
return 0;
}

//将目标目录读入内存
int read_menu(FCB menu_fcb, FCB **menu_item) {
if(!menu_fcb.attribute)
return 1;
char *buffer = (char*) malloc(sizeof(char) * menu_fcb.len);
if(file_read(menu_fcb, buffer, 0, menu_fcb.len)) {
free(buffer);
return 1;
}
*menu_item = (FCB*) buffer;
return 0;
}

//初始化FAT表
void fat_init() {
memset(fat.next, -1, sizeof(fat.next));
}

//初始化示位图
void bitmap_init() {
memset(bitmap.map, 0, sizeof(bitmap.map));
bitmap.free_num = DISK_SIZE / BLOCK_SIZE;
}

//初始化根目录
void root_init() {
strcpy(root_fcb.filename, "root");
root_fcb.attribute = 1;
root_fcb.block_num = 0;
root_fcb.first = -1;
root_fcb.free = 1;
root_fcb.item_num = 0;
root_fcb.len = 0;
root_fcb.permission = 3;
root_fcb.save_place = 0;
}

//清空文件,回收磁盘空间,但保留FCB
int file_clear(FCB *fcb) {
short next;
for(short i = fcb->first; i != -1; i = next) {
next = fat.next[i];
if(free_block(i))
return 1;
fat.next[i] = -1;
}
fcb->free = 1;
fcb->len = 0;
fcb->first = -1;
fcb->block_num = 0;
return 0;
}

//为文件划分空间
int file_get_block(FCB *fcb, int num) {
short *blocks = get_block(num);
if(!blocks) return 1;
int t = 0;
if(!~(fcb->first)) {
fcb->first = blocks[t];
}
while(t < num - 1) {
fat.next[blocks[t]] = blocks[t + 1];
t++;
}
fcb->free = 0;
fcb->block_num += num;
free(blocks);
return 0;
}

//将数据写入文件
int file_write(FCB *fcb, char *text, int start, int len) {
if(start + len > fcb->len) {
fcb->len = start + len;
}
if((start + len) / BLOCK_SIZE + 1 > fcb->block_num) {
if(file_get_block(fcb, (start + len) / BLOCK_SIZE + 1 - fcb->block_num))
return 1;
}
char buffer[BLOCK_SIZE];
for(short i = fcb->first, t = 0; i != -1; i = fat.next[i], t++) {
if(t == start / BLOCK_SIZE) {
memcpy(buffer, text, min(len, BLOCK_SIZE - start % BLOCK_SIZE));
if(block_write(i, buffer, start % BLOCK_SIZE, min(len, BLOCK_SIZE - start % BLOCK_SIZE)))
return 1;
if(start / BLOCK_SIZE == (start + len) / BLOCK_SIZE)
break;
}
if(t > start / BLOCK_SIZE && t < (start + len) / BLOCK_SIZE) {
memcpy(buffer, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), BLOCK_SIZE);
if(block_write(i, buffer, 0, BLOCK_SIZE))
return 1;
}
if(t == (start + len) / BLOCK_SIZE) {
memcpy(buffer, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), (start + len - 1) % BLOCK_SIZE + 1);
if(block_write(i, buffer, 0, (start + len - 1) % BLOCK_SIZE + 1))
return 1;
break;
}
}
return 0;
}

//读取文件中内容
int file_read(FCB fcb, char *text, int start, int len) {
if(start + len > fcb.len)
return 1;
for(short i = fcb.first, t = 0; i != -1; i = fat.next[i], t++) {
if(t == start / BLOCK_SIZE) {
if(block_read(i, text, start % BLOCK_SIZE, min(len, BLOCK_SIZE - start % BLOCK_SIZE)))
return 1;
if(start / BLOCK_SIZE == (start + len) / BLOCK_SIZE)
break;
}
if(t > start / BLOCK_SIZE && t < (start + len) / BLOCK_SIZE) {
if(block_read(i, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), 0, BLOCK_SIZE))
return 1;
}
if(t == (start + len) / BLOCK_SIZE) {
if(block_read(i, text - start % BLOCK_SIZE + BLOCK_SIZE * (t - start / BLOCK_SIZE), 0, (start + len - 1) % BLOCK_SIZE + 1))
return 1;
break;
}
}
return 0;
}

//在目标磁盘块读出数据
int block_read(short block, char *text, int start, int len) {
if(block < 0 || block >= DISK_SIZE / BLOCK_SIZE || start <0 || len < 0 || start + len > BLOCK_SIZE)
return 1;
memcpy(text, disk + block * BLOCK_SIZE + start, len);
return 0;
}

//向目标磁盘块写入数据
int block_write(short block, char *text, int start, int len) {
if(block < 0 || block >= DISK_SIZE / BLOCK_SIZE || start <0 || len < 0 || start + len > BLOCK_SIZE)
return 1;
memcpy(disk + block * BLOCK_SIZE + start, text, len);
return 0;
}

//获取num个磁盘块
short *get_block(int num) {
short *free_block = (short*) malloc(num * sizeof(short));
int n = num;
if(num > bitmap.free_num || num <= 0) {
free(free_block);
return free_block;
}
bitmap.free_num -= n;
for(short i = 0; i < DISK_SIZE / BLOCK_SIZE / 32 + 1; i++) {
for(short j = 0; j < 32; j++) {
if(i * 32 + j + 1 > DISK_SIZE / BLOCK_SIZE || !n) {
break;
}
if(!((bitmap.map[i] >> j) & 1)) {
bitmap.map[i] |= (1 << j);
free_block[num - n--] = i * 32 + j;
}
}
if(!n) {
break;
}
}
return free_block;
}

//释放目标磁盘块
int free_block(short block) {
if(block < 0 || block >= DISK_SIZE / BLOCK_SIZE)
return 1;
bitmap.free_num += (bitmap.map[(block >> 5)] >> (block & 31)) & 1;
bitmap.map[(block >> 5)] &= ~(1 << (block & 31));
return 0;
}

//初始化
int init(char *disk_dir, int new) {
disk = (char*) malloc(DISK_SIZE * sizeof(char));
if(new) {
bitmap_init();
fat_init();
root_init();
//划分初始空间
get_block(ROOT_BLOCK_NUM + FAT_BLOCK_NUM + BITMAP_BLOCK_NUM);
save_root();
} else {
if(load_disk(disk_dir))
return 1;
}
current_fcb = &root_fcb;
current_menu = root_menu;
current_fd = -1;
strcpy(current_dir, "/");
opening_num = 0;
user_open = NULL;
memset(free_fd, 0, sizeof(free_fd));

return 0;
}

int main() {
startsys();
shell();
return 0;
}

参考链接

【掘金·文件系统】https://juejin.cn/post/6844904102258819080?searchId=20250711010901E6177F82775F5FA7DFB4

鸣谢我的组长