myfs 操作系统课内实验 文件管理系统 Ext2
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中的操作的模拟。
欢迎大家交流~
myfs 操作系统课内实验 文件管理系统 Ext2的更多相关文章
- 清华大学ucore操作系统课笔记
操作系统 清华大学ucore操作系统课笔记 全文思维导图 1. 操作系统概述 1.1 什么是操作系统? 操作系统的定义 没有公认的精确定义 一个控制程序 一个系统软件 控制程序执行过程,防止错误和计算 ...
- JDFS:一款分布式文件管理系统,第三篇(流式云存储)
一 前言 看了一下,距离上一篇博客的发表已经过去了4个月,时间过得好快啊.本篇博客是JDFS系列的第三篇博客,JDFS的目的是为了实现一个分布式的文件管理系统,前两篇实现了基本的上传.下载功能,但是那 ...
- NeHe OpenGL教程 第三十八课:资源文件
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- Hadoop HDFS概念学习系列之分布式文件管理系统(二十五)
数据量越来越多,在一个操作系统管辖的范围存在不了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来 管理多台机器上的文件,这就是分布式文件管理系统. 是一种允许文件 ...
- JDFS:一款分布式文件管理系统,第四篇(流式云存储续篇)
一 前言 本篇博客是JDFS系列博客的第四篇,从最初简单的上传.下载,到后来加入分布式功能,背后经历了大量的调试,尤其当实验的虚拟计算结点数目增加后,一些潜在的隐藏很深的bug就陆续爆发.在此之前笔者 ...
- 分布式文件管理系统HDFS
Hadoop 分布式文件管理系统HDFS可以部署在廉价硬件之上,能够高容错. 可靠地存储海量数据(可以达到TB甚至PB级),它还可以和Yam中的MapReduce 编程模型很好地结合,为应用程序提供高 ...
- [转帖]使用fastdfs搭建文件管理系统
使用fastdfs搭建文件管理系统 https://www.jianshu.com/p/4e80069c84d3 今天同事说他们的系统用到了这个分布式文件管理系统. 一.FastDFS介绍 FastD ...
- 手把手教你用 FastDFS 构建分布式文件管理系统
说起分布式文件管理系统,大家可能很容易想到 HDFS.GFS 等系统,前者是 Hadoop 的一部分,后者则是 Google 提供的分布式文件管理系统.除了这些之外,国内淘宝和腾讯也有自己的分布式文件 ...
- 【windows 操作系统】文件保护:文件访问类型和访问控制
文件保护:文件访问类型和访问控制 为了防止文件共享可能会导致文件被破坏或未经核准的用户修改文件,文件系统必须控制用户对文件的存取,即解决对文件的读.写.执行的许可问题. 为此,必须在文件系统中建立相应 ...
随机推荐
- AsExpandable EF多条件查询
我个人学习新技术有一个方法,如果遇到问题会根据以前的经验来寻找一些类似的解决方法.有人会说,如果这个问题在你的学习或者工作生涯中都没有遇到过呢?很简单,通过搜索资料或查阅相关书籍学习别人的经验. 在如 ...
- Python知识整理(一)
一.Python交互模式(终端上进行) python # 进入到Python交互模式,提示符是 >>> exit() # 退出Python交互模式 python xxx.py # 执 ...
- 看动画学算法之:hashtable
目录 简介 散列表的关键概念 数组和散列表 数组的问题 hash的问题 线性探测 二次探测 双倍散列 分离链接 rehash 简介 java中和hash相关并且常用的有两个类hashTable和has ...
- SpringCloud升级之路2020.0.x版-40. spock 单元测试封装的 WebClient(上)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们来测试下前面封装好的 WebClient,这里开始,我们使用 spock 编写 gro ...
- [luogu5294]序列
也是一道保序回归的题,但思路不同于论文中模板题 考虑两个开口向上的二次函数$f(x)$和$g(x)$,求任意实数$x,y$满足$x\le y$且最小化$f(x)+g(y)$,这个最小值可以分类讨论求出 ...
- [nowcoder5669A]Ancient Distance
对于一个$k$,可以二分枚举答案并判断,判断过程可以贪心找最深的点(线段树区间max)+倍增+线段树区间覆盖(清0)来实现,时间复杂度$o(klog_{2}n)$ 考虑反过来,暴力枚举答案$x$并求出 ...
- 4、使用SetOperations(无序)操作redis(Set集合)
文章来源:https://www.cnblogs.com/shiguotao-com/p/10560599.html 方法 c参数 s说明 Long add(K key, V... values); ...
- 【NOI导刊200908模拟试题02 题4】【二分+Dijkstra】 收费站
Description 在某个遥远的国家里,有n个城市.编号外1,2,3,-,n. 这个国家的政府修建了m条双向的通路.每条公路连接着两个城市.沿着某条公路,开车从一个城市到另一个城市,需要花费一定的 ...
- Codeforces 1276D - Tree Elimination(树形 dp)
Codeforces 题面传送门 & 洛谷题面传送门 繁琐的简单树形 dp(大雾),要是现场肯定弃了去做 F 题 做了我一中午,写篇题解纪念下. 提供一种不太一样的思路. 首先碰到这样的题肯定 ...
- 【机器学*与R语言】2-懒惰学*K*邻(kNN)
目录 1.理解使用KNN进行分类 KNN特点 KNN步骤 1)计算距离 2)选择合适的K 3)数据准备 2.用KNN诊断乳腺癌 1)收集数据 2)探索和准备数据 3)训练模型 4)评估模型的性能 5) ...