实验目的
综合利用文件管理的相关知识,结合对文件系统的认知,编写简易文件系统,加深操作系统中文件系统和资源共享的认识。
实验内容
可以使用Linux或其它Unix类操作系统;
全面实践文件和目录操作及其组织结构;
编写简易文件系统。
实验环境
硬件:桌面PC
软件:Linux 或其他操作系统
实验步骤及说明
一:理论部分:
学习书本文件管理和磁盘存储器管理的相关章节,理解文件和目录的树状组织结构。
二:编程部分:.
- 创建一个100M的文件或者创建一个100M的共享内存
- 尝试自行设计一个C语言小程序,使用步骤1分配的100M空间(共享内存或mmap),然后假设这100M空间为一个空白磁盘,设计一个简单的文件系统管理这个空白磁盘,给出文件和目录管理的基本数据结构,并画出文件系统基本结构图,以及基本操作接口。(30分)
- 在步骤1的基础上实现部分文件操作接口操作,创建目录mkdir,删除目录rmdir,修改名称,创建文件open,修改文件,删除文件rm,查看文件系统目录结构ls。(40分)注明:全部在内存中实现
- 参考进程同步的相关章节,通过信号量机制实现多个终端对上述文件系统的互斥访问,系统中的一个文件允许多个进程读,不允许写操作;或者只允许一个写操作,不允许读。(30分)
实验过程
说明:该实验只是基于本人浅薄的理解设计而成的,写的代码也没有很好的结构封装,所以一些地方有些啰嗦。
一:理论部分:
学习书本文件管理和磁盘存储器管理的相关章节,理解文件和目录的树状组织结构。
文件和目录的树状组织结构
- 根目录:在文件系统中,所有的文件和目录都是从根目录开始的。在Unix和Linux系统中,根目录用"/"表示。
- 目录:目录可以包含文件和其他目录,形成了一个树状结构。每个目录项都有一个指向其子目录的链接。
- 文件:文件是数据的集合,它们可以是文本、图片、程序等。在文件系统中,文件通常以文件名和扩展名来标识。
- 路径:文件或目录的路径是描述其在文件系统中位置的字符串,可以是绝对路径或相对路径。
- 链接:链接可以是硬链接或软链接(符号链接)。硬链接是指向相同文件数据的另一个文件名,而软链接则是指向另一个文件或目录的路径。
二:编程部分:.
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;
}