To 学弟学妹们:

  写这个随笔原意是记录一下这个很有趣的实验 ,记录一下写的时候的细节和思路。

  要是光是抄这个代码,反而使得这个实验失去了意义。

  加油,这个实验收获真的很大。

 

任务描述:

  用一个空白文件模拟磁盘外存,编程实现一个简单的文件系统,要求该文件系统支持一些基本的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中的操作的模拟。

  欢迎大家交流~

  

  

最新文章

  1. 一个简单的socket程序运行与抓包查看
  2. Loadrunner在场景中添加多个负载机报错:Action.c(38): Error -26488: Could not obtain information about submitted解决方法
  3. styleCop
  4. EF实体框架之CodeFirst六
  5. 三种配置linux环境变量的方法(以java为例)
  6. spring HibernateValidator 验证 子类不起作用
  7. Silverlight中本地化的实现(语言切换)
  8. Js原型模式
  9. 汉得第二次考核答案整理(通信,IO,文件等)
  10. Objective-c 截取子字符串
  11. 杂谈3之English
  12. mongodb 3.6 集群搭建:分片+副本集
  13. 长期招收linux驱动工程师
  14. linus 下redis守护进程启动
  15. IOS11 底部输入框被手机输入法遮住
  16. jexus托管.net core
  17. 包含了重复的“Content”项。.NET SDK 默认包含你项目目录中的“Content”项。可从项目文件中删除这些项;如果希望将其显式包含在项目文件中,可将“EnableDefaultContentItems”属性设置为“false”
  18. [Nginx]用Nginx实现与应用结合的訪问控制 - 防盗链
  19. 【spfa训练】HDU4725 (层级建图)
  20. 【转】Eclipse,MyEclipse快捷键及字体设置

热门文章

  1. 《Python语言程序设计》【第1周】Python基本语法元素
  2. python中jsonpath模块,解析多层嵌套的json数据
  3. jenkins-发送allure邮件测试报告
  4. [atARC114F]Permutation Division
  5. 千呼万唤,web人脸识别登录完整版来了,这样式我爱了
  6. Java异常与错误
  7. Treevalue(0x03)——函数树化详细解析(下篇)
  8. No &#39;Access-Control-Allow-Origin&#39; header: 跨域问题踩坑记录
  9. 学军中学csp-noip2020模拟5
  10. 【百奥云GS专栏】全基因组选择之工具篇