用一个空白文件模拟磁盘外存,编程实现一个简单的文件系统,要求该文件系统支持一些基本的Linux指令:ls,创建、删除文件和文件夹,移动文件,关闭系统。
即实现以下的命令
ls /dir
move /src /dst
delete -d /dir
delete -f /file
create size /file
create -d /dir
shutdown
我们要处理的是维护超级块super_block和构建索引结点inode数组。
接下来分析文件系统的头文件fs_operation.h,
/*
* @Author: Deng Cai
* @Date: 2019-09-09 16:09:14
* @Last Modified by: ZeLin Jiang
* @Last Modified time: 2020-1-11 12:40:28
*/
// in this code : \
for the file system‘s space is so small, we don‘t need group descriptors acctually, so i just put some critical information in other structures and cut group descriptors. what‘s more, the inode map and block map are \
put into super block.
// in some degrees, this file system can be seemed as a system \
with only one block group, so we need just one super block and one group descriptor. then why don‘t we put them together \
and make them one single structure as "super_block"? that‘s \
how i handle with it.
// it had been modified from the original file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#define BLOCK_SIZE 1024
// 1KB.
typedef struct inode {
// 32 bytes;
// the number of blocks it have. 4
uint32_t size;
// 1->dir; 0->file; 2
uint16_t file_type;
// it doesn‘t matter if you don‘t know what this variable means.2
uint16_t mumu;
// the blocks belonging to this inode. 4*6 补全inode大小
//对于文件 block存的是数据
//对于文件夹 block存的是dir_item
uint32_t block_point[6];
} inode;
typedef struct super_block {
// 656 bytes;0块
// use system_mod to check if it \
is the first time to run the FS.0 first_time 1 not
int32_t system_mod;
// 2^12; 4096;
int32_t free_block_count;
// 1024;
int32_t free_inode_count;
int32_t dir_inode_count;
// 512 bytes;
uint32_t block_map[128];//4096个block
// 128 bytes;1-32块*32=1024
uint32_t inode_map[32];
} sp_block;
// 1 block;
typedef struct dir_item {
// the content of folders.
// 128 bytes;
uint32_t inode_id;
// 1 means the last one;
// it doesn‘t matter if you don‘t understand it.
uint16_t item_count;
// 1 represents dir;
uint8_t type;
char name[121];
} dir_item;
FILE *fp;
sp_block *spBlock;
inode inode_table[1024];//32blocks*32inodes*32bytes
dir_item block_buffer[8];//一个目项为 2 ^ 7 字节,一个块大小为 2 ^ 10 字节,因此一个块可以存放 2 ^ (10 - 7) = 8 个
//find a free inode
int find_free_inode();
//find a free block
int find_free_block();
// do some pre-work when you run the FS
void print_information();
//init
void fs_init();
//ls /path
void ls(char *path);
//create -f /name
void create_file(char *path, int size);
//create -d /name
void create_dir(char *path);
//delete -f /name
void delete_file(char *path);
//delete -d /name
void delete_dir(char *path);
//move /name.exe /dir
void move(char *from, char *to);
//save and shutdown
void shutdown();
首先需要留意的是block_size,因为我们每次操作磁盘时都是以block为单位进行读写的,所以每次使用fwrite/fread时这一点需要在实现函数时留意。在接下来的函数实现中可以看到的fwrite/fread(block_buffer, BLOCK_SIZE, 1, fp)中都是以block为单位的。
其次需要留意的是索引结点inode,它包含文件的大小,类型file_type,链接以及指向的数据块block_point。其中最重要的block_point保存的数据块编号了。
接下来是超级块,它是每次文件系统打开时第一个读入的块,其中包括初始化标记system_mod,空闲数据块计数free_block_count,空闲索引结点计数free_inode_count,文件夹索引结点计数dir_inode_count,块位示图block_map以及索引结点位示图inode_map。计数是用来打印进入系统时显示的空闲块/点数量的,而位示图是告诉你哪一块是空的。
最后是文件目录项,这是实现树状目录结构的重点。其中包括了这个目录项对应的索引结点号inode_id,目录项末尾标记item_count,文件类型type以及文件名name[]。
介绍完了我们需要维护的数据结构后,接下来的就是定义对于这些数据的操作了。
支持操作
构建超级块
构建超级块是你的文件系统第一次运行时应该对disk.os进行的操作。你需要将超级块中的各位进行正确的赋值,以保证接下来的操作能顺利进行。这里面包括system_mod(初始化标志),空闲块/结点计数、文件夹结点计数、位示图等等。你还需要建立一个根目录 “/”,并给他建立“.”和“..”
// Init load in spBlock void fs_init() { int i; char buf[100]; spBlock = (sp_block*)malloc(sizeof(sp_block)); if ((fp = fopen("disk.os", "rb+")) == NULL) { puts("Fail to open file!"); exit(0); } fseek(fp, 0, SEEK_SET);//跳转至该block fread(spBlock, sizeof(sp_block), 1, fp); if (spBlock->system_mod != 1) { //初始化 spBlock->system_mod = 1; spBlock->free_block_count = 4096-1-32; spBlock->free_inode_count = 1023;//0 spBlock->dir_inode_count = 1;//0 memset(spBlock->inode_map, 0, sizeof(spBlock->inode_map)); memset(spBlock->block_map, 0, sizeof(spBlock->block_map)); spBlock->inode_map[0] = spBlock->inode_map[0] | (1 << 31); inode_table[0].block_point[0] = find_free_block(); inode_table[0].file_type = 1; inode_table[0].size = 1; memset(block_buffer, 0, BLOCK_SIZE); //填充目录项 //在上层目录里面建立这个文件夹的dir_item //填充的是 .(自身)和 ..(上层) //写入. 自身 block_buffer[0].inode_id = 0; strcpy(block_buffer[0].name, "."); block_buffer[0].type = 1; block_buffer[0].item_count = 0; //写入.. 上层 block_buffer[1].inode_id = 0; strcpy(block_buffer[1].name, ".."); block_buffer[1].type = 1; block_buffer[1].item_count = 1; //写block fseek(fp, (1 + 32 + inode_table[0].block_point[0])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //写inode fseek(fp, BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(inode_table, sizeof(inode_table), 1, fp); //写入spblock fseek(fp, 0, SEEK_SET);//跳转至该block fwrite(spBlock, sizeof(sp_block), 1, fp); return; } fseek(fp, BLOCK_SIZE, SEEK_SET);//跳转至该block fread(inode_table, sizeof(inode_table), 1, fp); //fclose(fp); return; }
需要遍历巡视位示图的各位,找到一个为空的可使用的块/结点。
位示图是一段01构成的串,它的每一位都代表着一个块/结点的使用情况。由于我们使用C语言进行模拟,这里要注意的在超级块中留出的是uint32_t类型的block_map[128]数组(共4096位)和uint32_t类型的inode_map[32]数组(共1024位),在寻找空闲位时我的做法是从高到底进行搜索。当寻找到一个为0的位置时,将其置1作为使用标记,同时将该块/结点分配给申请的文件/文件夹,还要记得维护超级块中的count以防止对应错误。
int find_free_block() { int i, j; /*if ((fp = fopen("disk.os", "r+")) == NULL) { puts("Fail to open file!"); exit(0); }*/ int num = -1; uint16_t buf; for (i = 0; i < 128; i++)//block外层 128个blockmap { for (j = 0; j < 32; j++)//block内层 32位 { //0为最左 buf = (spBlock->block_map[i] >> (31-j))&(uint16_t)1; if (buf == 0) { num = i * 32 + j; spBlock->block_map[i] = spBlock->block_map[i] | (1 << (31 - j)); spBlock->free_block_count--; break; } } if (num != -1) { break; } } fseek(fp, 0, SEEK_SET);//跳转至该block fwrite(spBlock, sizeof(sp_block), 1, fp); return num; } //return the id of a free inode num = inodeid * 32 + j; int find_free_inode() { spBlock->free_inode_count--; /* if ((fp = fopen("disk.os", "r+")) == NULL) { puts("Fail to open file!"); exit(0); } */ int i, j; int num = -1; uint16_t buf; for (i = 0; i < 32; i++)//block外层 32个inode { for (j = 0; j < 32; j++)//block内层 32位 { //0为最左 buf = (spBlock->inode_map[i] >> (31 - j))&(uint16_t)1; if (buf == 0) { num = i * 32 + j; spBlock->inode_map[i] = spBlock->inode_map[i] | (1 << (31 - j)); break; } } if (num != -1) { break; } } fseek(fp, 0, SEEK_SET);//跳转至该block fwrite(spBlock, sizeof(sp_block), 1, fp); return num; }
寻找一个路径对应的inode_id
这一个功能是将我们输入的路径如“/Happy/Coding”进行解析分拆,进行目录的跳转。我的做法是从左往右搜索,以“/”为分割,每次分割出一个目录名时向里进一层目录。需要做的是对于找到的父节点,遍历父节点对应的inode,读出那个inode块后遍历其拥有的6个dir_item块中的8个dir_item以寻找名字匹配。
//查找一个路径对应的inode_id int find_name_inode(char *path) { int i,j,o; int a=0;//inode_id 0==null int flag = 0; int len = 0; int last_time=0; char name_buf[20]; len = strlen(path); //分割路径 for (o = 1; o <= len; o++) { if (path[o] == ‘/‘||o==len) { // /4/56/789 // 012345678 memset(name_buf,0,sizeof(name_buf)); strncpy(name_buf, path + last_time + 1, o - last_time-1); last_time = o; for (i = 0; i < 6; i++) { flag = 0; memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[a].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int for (j = 0; j < 8; j++) { if (strcmp(block_buffer[j].name,name_buf)==0)//匹配进一层 { a = block_buffer[j].inode_id; flag = 1; break; } if (block_buffer[j].item_count == 1) break; } if (flag == 1) break; } } } //fclose(fp); return
以上是我认为的文件系统的支持操作,接下来则是具体的创建create、展示ls、删除delete和移动move
创建
这里需要按照创建的类型不同来进行划分,输入的指令故传入的参数也不同,分为带size的文件和不带size的文件夹。
创建文件
指令为create size /file_dir/file_name
解析指令不再赘述,分析创建文件的过程。我们在匹配完路径后首先需要做的是分配一个空闲的inode,并标记其为文件项(file_type = 0)。
接下来就可以对新文件的父目录进行操作了,遍历父目录对应inode的block_point数组(8*6),寻找一个空着的位置(其上一个的item_count 位置为 1)
(PS:这个给的注释很假了!)
在寻找空闲位置的过程中又有需要注意的情况:如果标志位出现在一个块的最后一个位置,则需要修改的dir_item在下一个block_point内,且这个block_point需要重新分配出来。
最后,分配这个文件所需要的block的块数。
//创建一个文件 void create_file(char *path,int size) { int i_num, i,j,flag; int last_time = 0; char name_buf[20]; char path_buf[20]; memset(name_buf, 0, sizeof(name_buf)); memset(path_buf, 0, sizeof(path_buf)); int len = strlen(path); int father_dir; //path匹配过程 // /home/1 // 0123456 //i=5 len=7 for (i=len-1;i >= 0;i--) { if (i == 0 || path[i] == ‘/‘) { strncpy(name_buf, path + i+1,len-i-1); strncpy(path_buf, path ,i); break; } } if (strlen(path_buf) > 1) { father_dir = find_name_inode(path_buf);//父目录的inode } else { father_dir = 0; } //开始 //建立inode i_num = find_free_inode(); inode_table[i_num].file_type = 0; //修改父目录 for (i = 0; i < inode_table[father_dir].size; i++) { flag = 0; memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int for (j = 0; j < 8; j++) { if (block_buffer[j].item_count == 1)//是最后一个 { if (j < 7) { block_buffer[j].item_count = 0; block_buffer[j + 1].item_count = 1; block_buffer[j + 1].inode_id = i_num; block_buffer[j + 1].type = 0; strcpy(block_buffer[j + 1].name, name_buf); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //控制位 flag = 1; break; } else//新一块的第一个 { //修改原块final block_buffer[j].item_count = 0; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //写入下一块 memset(block_buffer, 0, sizeof(block_buffer)); block_buffer[0].item_count = 1; block_buffer[0].inode_id = i_num; block_buffer[0].type = 0; strcpy(block_buffer[0].name, name_buf); inode_table[father_dir].block_point[i + 1] = find_free_block(); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //控制位 flag = 1; break; } if(flag==1) break; } } if (flag == 1) break; } //没有空闲块 if (flag == 0) { if (inode_table[father_dir].size == 6)//最大值 { printf("Too many files in a dir!\n"); return; } else { inode_table[father_dir].block_point[inode_table[father_dir].size] = find_free_block; if (inode_table[father_dir].block_point[inode_table[father_dir].size] == -1)//无空闲块 { printf("Out of Blocks!\n"); return; } else { //修改上一块的结尾 block_buffer[7].item_count = 0; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[inode_table[father_dir].size])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //写入下一块 memset(block_buffer, 0, sizeof(block_buffer)); block_buffer[0].item_count = 1; block_buffer[0].inode_id = i_num; block_buffer[0].type = 1; strcpy(block_buffer[0].name, name_buf); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int inode_table[father_dir].size++; } } } //分配block int block_needed = 0; block_needed =((size-1) / BLOCK_SIZE) + 1; inode_table[i_num].size = block_needed; for (i = 0; i < block_needed; i++) { inode_table[i_num].block_point[i] = find_free_block();// } //fclose(fp); return; }
创建文件夹
与上面的创建文件类似,但区别在于:
1.创建的dir_item类型为1(这不是废话吗...)
2.分配大小时先分配一块,其中插入“.”和“..”的dir_item
//创建一个文件夹 void create_dir(char *path) { spBlock->dir_inode_count++; int i_num, i,j, flag; int last_time = 0; char name_buf[20]; char path_buf[20]; memset(name_buf, 0, sizeof(name_buf)); memset(path_buf, 0, sizeof(path_buf)); int father_dir; int len = strlen(path); //path匹配过程 // /home/1 // 0123456 //i=5 len=7 for (i = len - 1; i >= 0; i--) { if (i == 0 || path[i] == ‘/‘) { strncpy(name_buf, path + i + 1, len - i - 1); strncpy(path_buf, path, i ); break; } } if (strlen(path_buf) > 1) { father_dir = find_name_inode(path_buf);//父目录的inode } else { father_dir = 0; } //开始操作 // 寻找给它的空闲inode 建立inode i_num = find_free_inode(); //修改父目录 //上层不好填充 选择扔给上层增加 flag = 0; for (i = 0; i < inode_table[father_dir].size; i++) { memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int for (j = 0; j < 8; j++) { if (block_buffer[j].item_count == 1)//是最后一个 { if (j < 7) { block_buffer[j].item_count = 0; block_buffer[j + 1].item_count = 1; block_buffer[j + 1].inode_id = i_num; block_buffer[j + 1].type = 1; strcpy(block_buffer[j + 1].name, name_buf); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int flag = 1; break; } else//新一块的第一个 { //修改原块final block_buffer[j].item_count = 0; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //写入下一块 memset(block_buffer, 0, sizeof(block_buffer)); block_buffer[0].item_count = 1; block_buffer[0].inode_id = i_num; block_buffer[0].type = 1; strcpy(block_buffer[0].name, name_buf); inode_table[father_dir].block_point[i + 1] = find_free_block(); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int flag = 1; break; } if (flag == 1) break; } } if (flag == 1) break; } //没有空闲块 if (flag == 0) { if (inode_table[father_dir].size == 6)//最大值 { spBlock->dir_inode_count--; printf("Too many files in a dir!\n"); return; } else { inode_table[father_dir].block_point[inode_table[father_dir].size] = find_free_block; if (inode_table[father_dir].block_point[inode_table[father_dir].size] == -1)//无空闲块 { spBlock->dir_inode_count--; printf("Out of Blocks!\n"); return; } else { //修改上一块的结尾 block_buffer[7].item_count = 0; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[inode_table[father_dir].size])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //写入下一块 memset(block_buffer, 0, sizeof(block_buffer)); block_buffer[0].item_count = 1; block_buffer[0].inode_id = i_num; block_buffer[0].type = 1; strcpy(block_buffer[0].name, name_buf); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i + 1])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int inode_table[father_dir].size++; } } } //填充inode inode_table[i_num].file_type = 1; //分配block int block_needed = 1;//?.和 .. 后面得加 inode_table[i_num].size = block_needed;//2*dir_item? for (i = 0; i < block_needed; i++) { inode_table[i_num].block_point[i] = find_free_block();// } memset(block_buffer, 0, BLOCK_SIZE); //填充目录项 //在上层目录里面建立这个文件夹的dir_item //填充的是 .(自身)和 ..(上层) //写入. 自身 block_buffer[0].inode_id = i_num; strcpy(block_buffer[0].name, "."); block_buffer[0].type = 1; block_buffer[1].item_count = 0; //写入.. 上层 block_buffer[1].inode_id = father_dir; strcpy(block_buffer[1].name, ".."); block_buffer[1].type = 1; block_buffer[1].item_count = 1; //写回到disk //写block fseek(fp, (1 + 32 + inode_table[i_num].block_point[0])*BLOCK_SIZE , SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //fclose(fp); return; }
展示
这一段代码的功能是展示一个目录下所有的文件/文件夹。
即找到父目录->遍历父目录下的dir_item打印名字->访问到item_count == 1时结束。
//展示一个文件夹下的所有东西 void ls(char *path) { int i_num,j,i, flag; int last_time = 0; char name_buf[20]; char path_buf[20]; int len = strlen(path); int mumu; //path匹配过程 // /home/1 // 0123456 //i=5 len=7 if(len!=1) { mumu = find_name_inode(path);//父目录的inode } else { mumu = 0; } //读取 打印 for (i = 0; i < inode_table[mumu].size; i++) { flag = 0; memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[mumu].block_point[i])*BLOCK_SIZE , SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int for (j = 0; j < 8; j++) { if (block_buffer[j].type == 1)//是最后一个 printf("*"); printf("%s ", block_buffer[j].name); if (block_buffer[j].item_count == 1)//是最后一个 { printf("\n"); break; } } } //fclose(fp); return; }
删除
"一个人真正死去,是被所有人都遗忘的时候"
删除文件
一个文件/文件夹的删除,一方面是它所占有的块和结点被释放,另一方面则是它的父目录中不再有它的数据,这两者都做到才是删干净了。前者需要用到它的inode编号,进而访问block_point释放块,然后释放inode;后者则是要解析路径以找到父目录的inode再进行操作,在删除时要记得重新置last标志位,并在父目录的一个block_point为空时删除它。
//删除一个文件 void delete_file(char *path) { int i_num, i, j, k, flag; int last_time = 0; int block_out_num = 0, block_in_num = 0; int inode_out_num = 0, inode_in_num = 0; char name_buf[20]; char path_buf[20]; memset(name_buf, 0, sizeof(name_buf)); memset(path_buf, 0, sizeof(path_buf)); int len = strlen(path); int father_dir; int marker_i = -1, marker_j = -1; //path匹配过程 // /home/1 // 0123456 //i=5 len=7 dir_item buffer; for (i = len - 1; i >= 0; i--) { if (i == 0 || path[i] == ‘/‘) { strncpy(name_buf, path + i + 1, len - i - 1); strncpy(path_buf, path, i); break; } } if (strlen(path_buf) > 1) { father_dir = find_name_inode(path_buf);//父目录的inode } else { father_dir = 0; } //开始 //修改父目录 for (i = 0; i < inode_table[father_dir].size; i++) { flag = 0; memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int for (j = 0; j < 8; j++) { //找得到 if ((strcmp(name_buf, block_buffer[j].name) == 0)&&(block_buffer[j].type==0)) { //此时为block_buffer[j] //释放该文件占用的块 flag = 1; for (k = 0; k < inode_table[block_buffer[j].inode_id].size; k++) { block_out_num = (inode_table[block_buffer[j].inode_id].block_point[k]) / 32;//块号 block_in_num = (inode_table[block_buffer[j].inode_id].block_point[k]) % 32; spBlock->block_map[block_out_num] = spBlock->block_map[block_out_num] & (~(1 << (31 - block_in_num))); spBlock->free_block_count++; } //释放该文件占用的inode inode_out_num = (block_buffer[j].inode_id) / 32;//块号 inode_in_num = (block_buffer[j].inode_id) % 32; spBlock->inode_map[inode_out_num] = spBlock->inode_map[inode_out_num] & (~(1 << (31 - inode_in_num))); spBlock->free_inode_count++; marker_i = i; marker_j = j; } //释放该块占用的dir_item //这里注意要判定last==1? if (block_buffer[j].item_count == 1 && flag==1)//遍历到最后一个 { if (j > 0)//不是头 { // 去除标识位 block_buffer[j].item_count = 0; buffer = block_buffer[j]; //替换最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //替换待删除项 memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int block_buffer[marker_j] = buffer; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int flag = 2; //重新标识最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int block_buffer[j - 1].item_count = 1; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int break; } else//是头 { //去除标识位 block_buffer[j].item_count = 0; buffer = block_buffer[j]; //替换最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //替换待删除项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[marker_j] = buffer;//! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //重新标识最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[7].item_count = 1;//! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); flag = 2; break; } } if (flag == 2) { break; } } if (flag != 2) { printf("Wrong Path!\n"); return; } //fclose(fp); return; } }
删除文件夹
删除文件夹大体类似。在找到应删除文件夹在父目录下的dir_item后,操作应删除文件夹下的各个dir_item:
1. 对于其下的文件,调用delete_file进行删除
2. 对于文件夹,重复调用delete_dir进行删除
//删除一个文件夹以及其中所有的文件 void delete_dir(char *path) { int i_num, i, j, k, o, flag_lock=0, flag=0; int last_time = 0; int block_out_num = 0, block_in_num = 0; int inode_out_num = 0, inode_in_num = 0; char name_buf[20]; char path_buf[20]; char path_buf_2[20]; memset(name_buf, 0, sizeof(name_buf)); memset(path_buf, 0, sizeof(path_buf)); int len = strlen(path); int father_dir; int marker_i = -1, marker_j = -1; //path匹配过程 // /home/1 // 0123456 //i=5 len=7 dir_item buffer; for (i = len - 1; i >= 0; i--) { if (i == 0 || path[i] == ‘/‘) { strncpy(name_buf, path + i + 1, len - i - 1); strncpy(path_buf, path, i); break; } } if (strlen(path_buf) > 1) { father_dir = find_name_inode(path_buf);//父目录的inode } else { father_dir = 0; } //开始 //修改父目录 for (i = 0; i < inode_table[father_dir].size; i++) { //载入父目录一个新的block memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//fail? flag = 0; flag_lock = 0; for (j = 0; j < 8; j++)//i块j项 { //找得到 buffer = block_buffer[j]; if ((strcmp(name_buf, buffer.name) == 0) && (block_buffer[j].type == 1)) { //此时为block_buffer[j] //删除他下面的文件 //跳转到 该删除的目录下遍历他的儿子 //也即释放他的block for (o = 0; o < inode_table[buffer.inode_id].size; o++) { fseek(fp, (1 + 32 + inode_table[buffer.inode_id].block_point[o])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int //遍历其下的目录项 进行删除 for (k = 0; k < 6; k++) { if ((strcmp(block_buffer[k].name, ".") == 0 || strcmp(block_buffer[k].name, "..") == 0)&& block_buffer[k].item_count != 1) continue; if ((strcmp(block_buffer[k].name, ".") == 0 || strcmp(block_buffer[k].name, "..") == 0) && block_buffer[k].item_count == 1) { flag = 1; break; } if (block_buffer[k].type == 1)//dir { memset(path_buf_2, 0, sizeof(path_buf_2)); strcpy(path_buf_2, path); strcat(path_buf_2, "/"); strcat(path_buf_2, block_buffer[k].name); delete_dir(path_buf_2); fseek(fp, (1 + 32 + inode_table[buffer.inode_id].block_point[o])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int k--; } else if (block_buffer[k].type == 0)//file { memset(path_buf_2, 0, sizeof(path_buf_2)); strcpy(path_buf_2, path); strcat(path_buf_2, "/"); strcat(path_buf_2, block_buffer[k].name); delete_file(path_buf_2); fseek(fp, (1 + 32 + inode_table[buffer.inode_id].block_point[o])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int k--; } if (block_buffer[k].item_count == 1)//end { flag = 1; break; } } //释放这一个块 block_out_num = (inode_table[buffer.inode_id].block_point[o]) / 32;//块号 block_in_num = (inode_table[buffer.inode_id].block_point[o]) % 32; spBlock->block_map[block_out_num] = spBlock->block_map[block_out_num] & (~(1 << (31 - block_in_num))); spBlock->free_block_count++; if (flag == 1)//全部删除完毕 break; } //释放该文件占用的inode inode_out_num = (buffer.inode_id) / 32;//块号 inode_in_num = (buffer.inode_id) % 32; spBlock->inode_map[inode_out_num] = spBlock->inode_map[inode_out_num] & (~(1 << (31 - inode_in_num))); spBlock->free_inode_count++; spBlock->dir_inode_count--; marker_i = i; marker_j = j; //回到父目录下 //接下来释放该块占用的dir_item fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); } //找到最后一个 if (block_buffer[j].item_count == 1 && flag == 1) { if (j > 0)//不是头 { // 去除标识位 block_buffer[j].item_count = 0; buffer = block_buffer[j]; //替换最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int //替换待删除项 memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int block_buffer[marker_j] = buffer; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int flag = 2; //重新标识最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int block_buffer[j - 1].item_count = 1; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int break; } else//是头 { //去除标识位 block_buffer[j].item_count = 0; buffer = block_buffer[j]; //替换最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //替换待删除项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[marker_j] = buffer;//! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //重新标识最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[7].item_count = 1;//! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); flag = 2; break; } } if (flag == 2) { break; } } } if(flag != 2) { printf("Wrong Path!\n"); return; } //fclose(fp); return; }
移动
移动需要做的就是把它在原本的父目录下的dir_item移送到新的父目录下。还是需要注意增加/删除dir_item时的last标志位以及block的申请与释放。
/移动一个文件/文件夹 //move /file /dir void move(char *from, char *to) { int det_inode = find_name_inode(to); int i, j,k, father_dir, flag = 0; int marker_i, marker_j; char name_buf[30], path_buf[30]; memset(name_buf, 0, sizeof(name_buf)); memset(path_buf, 0, sizeof(path_buf)); int len = strlen(from); dir_item buffer; dir_item buffer2; for (i = len - 1; i >= 0; i--) { if (i == 0 || from[i] == ‘/‘) { strncpy(name_buf, from + i + 1, len - i - 1); strncpy(path_buf, from, i); break; } } if (strlen(path_buf) > 1) { father_dir = find_name_inode(path_buf);//父目录的inode } else { father_dir = 0; } //遍历父节点,寻找dir_item for (i = 0; i < inode_table[father_dir].size; i++) { memset(fp, 0, sizeof(fp)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//fail? for (j = 0; j < 8; j++) { //找到匹配项 if ((strcmp(name_buf, block_buffer[j].name) == 0)&&(block_buffer[j].type==0))//是否支持文件? { //记录 buffer2 = block_buffer[j]; marker_i = i; marker_j = j; flag = 1; } //清除 if (block_buffer[j].item_count == 1 && flag == 1)//找到最末尾 { if (j > 0)//不是头 { // 去除标识位后 // 用最后一项替换 block_buffer[j].item_count = 0; buffer = block_buffer[j]; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //替换待删除项 memset(block_buffer, 0, sizeof(block_buffer)); fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[marker_j] = buffer;//!! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); flag = 2; //重新标识最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//int block_buffer[j - 1].item_count = 1; fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int break; } else//是头 { //去除标识位 block_buffer[j].item_count = 0; buffer = block_buffer[j]; //替换最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //替换待删除项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[marker_j] = buffer;//! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[marker_i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //重新标识最后一项 fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp); block_buffer[7].item_count = 1;//! fseek(fp, (1 + 32 + inode_table[father_dir].block_point[i - 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); flag = 2; break; } } else if (block_buffer[j].item_count == 1) break; if (flag == 2) break; } } //寻找目的地,添加dir_item for (i = 0; i < inode_table[det_inode].size; i++) { fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fread(block_buffer, BLOCK_SIZE, 1, fp);//fail? for (j = 0; j < 8; j++) { if (block_buffer[j].item_count == 1 && flag == 2 && (block_buffer[j].type == 1))//遍历到最后一个 { if (j < 7) { block_buffer[j].item_count = 0; block_buffer[j + 1] = buffer2; block_buffer[j + 1].item_count = 1; fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int flag = 3; break; } else//新一块的第一个 { //修改原块final block_buffer[j].item_count = 0; fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp); //写入下一块 memset(block_buffer, 0, sizeof(block_buffer)); block_buffer[0] = buffer2; block_buffer[0].item_count = 1; fseek(fp, (1 + 32 + inode_table[det_inode].block_point[i + 1])*BLOCK_SIZE, SEEK_SET);//跳转至该block fwrite(block_buffer, BLOCK_SIZE, 1, fp);//int flag = 3; break; } } if (flag == 3) break; } } if (flag != 3) printf("Path error!\n"); return; }
以上就是一个简单的对于Linux的Ext2 File System中的操作的模拟。
欢迎大家交流~
原文:https://www.cnblogs.com/mumujzl/p/12179594.html