CSAPP Lab —— FSLAB
写在前面:
本实验的代码中清除了大部分调试痕迹,但是保留了一部分,以展示作者写实验时崩溃的精神状态
实验概览
完成一个运行在用户态的文件系统,对模拟的块设备进行读写,从而实现一些基本的文件读
写以及管理功能。
准备
各部分文件大小:
// 至少支持文件或目录数量
#define FILE_NUM 32768 //来自实验文档要求
// inode节点大小
#define INODE_SIZE 128
// super block大小
#define SUPERBLOCK_SIZE 4096// 4KB
// Imap大小
#define IMAP_SIZE 4096 // 4KB
// Dmap大小
#define DMAP_SIZE 8192 // 2*4KB = 8KB
// Inodes table大小
#define INODE_TABLE_SIZE (FILE_NUM * INODE_SIZE)
// 块大小
#define BLOCK_SIZE 4096 // 4KB
// 文件最大大小
#define MAX_SIZE 8<<20 // 8MB
// 总块数
#define BLOCK_NUM 65536 // 0-65535 block_id
Supernode数据结构:
typedef struct super_node
{
int inode_num; // inode_num = FILE_NUM
int block_num; // block_num = BLOCK_NUM
int* imap_block; // Imap位置
int* dmap_block; // Dmap位置
int dir_count; // 目录数量
int file_count; // 文件数量
int* inode_table_block; // Inodes table位置
}super_node, *SuperNode;
Inode数据结构:
typedef struct inode // 128B
{
mode_t i_mode; // 文件mode/目录mode
nlink_t i_links_count; // 链接数
off_t i_size; // 文件大小
time_t i_atime; // 文件被访问的时间
time_t i_mtime; // 文件被修改的时间
time_t i_ctime; // 文件状态改变时间
int i_blocks_count; // 文件占据block数量
int i_block_pointer[18]; // 18个一级指针 // 4B * 18 = 72B
int i_double_block_pointer; // 1个二级指针 // 4B * 1 = 4B
}inode, *Inode;
Inode数据结构包含了fuse ppt中应该包含的全部内容。指针的数量分配要满足两个条件:
- Inode大小为128B(为了让一个块中有完整的32个Inode块)
- Inode的指针指向的文件区域大于等于8MB
遗憾的是,直到完成实验,本人才发现,自己在最一开始算错了。这里的Inode只能满足18 * 4KB + 1024 * 4KB = 4168KB
的文件大小。幸运的是,刚好能够满足本实验的测试需要。由于整个实验已经完成,本人没有修改该数据结构。但真正正确的指针分配应该是:
int i_block_pointer[14]; // 14个一级指针 // 4B * 14 = 56B
int i_double_block_pointer[2]; // 1个二级指针 // 4B * 2 = 8B
// 支持14 * 4KB + 2 * 1024 * 4KB = 8248KB 的文件大小
catalog数据结构:
typedef struct catalog //32B
{
char name[24]; //名字 //24B
// nlink_t i_links_count; //链接数 //2B
mode_t i_mode; //模式(目录/文件) //2B
int i_ino; //i-number //4B
}catalog, *Catalog;
catalog是存放在目录块中的数据结构,一个目录块中有128个catalog,可以存放128个子目录或子文件。在这里我最一开始犯了一个严重的错误:我并不清楚nlink_t的大小,却贸然在这里使用了,结果nlink_t并非我最一开始以为的2B而是8B,因此导致了目录块的错乱。
Imap、Dmap数据结构:
// int共32位,每一位代表一个inode/datablock
int Imap[1024]; //32786 //1024 * 4 = 4KB
int Dmap[2048]; //65536 //2048 * 4 = 8KB
mkfs
思路:
- 创建super_block
- 创建Imap
- 创建Dmap
- 创建Inode_table
- 初始化super_block
- 创建根目录root的inode
- 创建root的datablock
- super_block更新(由于创建了根目录,dir_count ++)
- Imap更新(只有root占用1个inode)
- Dmap更新
- 将super_block, Imp, Dmap, Root 写入磁盘
- 释放内存空间
其中,superblock初始化如下:
/ 初始化super_block
super_block->inode_num = FILE_NUM;
super_block->block_num = BLOCK_NUM;
super_block->imap_block = Imap;
super_block->dmap_block = Dmap;
super_block->dir_count = 0;
super_block->file_count = 0;
super_block->inode_table_block = Dmap + DMAP_SIZE;
根目录初始化如下:
Inode_table[0].i_mode = DIRMODE;
Inode_table[0].i_links_count = 0;
Inode_table[0].i_size = sizeof(catalog);
Inode_table[0].i_atime = time(NULL);
Inode_table[0].i_mtime = time(NULL);
Inode_table[0].i_ctime = time(NULL);
Inode_table[0].i_blocks_count = 1;
for(int i = 0; i < 18; i++)
Inode_table[0].i_block_pointer[i] = -1;
Inode_table[0].i_double_block_pointer = -1;
各部分占据磁盘情况如下:
super_block -> block[0], Imap -> block[1], Dmap -> block[2] + block[3], Inode_table -> block[4] ~ block[1027], datablock从block[1028]开始
// 将super_block, Imp, Dmap, Root 写入磁盘
disk_write(0, super_block);
disk_write(1, Imap);
disk_write(2, Dmap);
disk_write(3, Dmap + (DMAP_SIZE) / 2);
for(i = 0; i < 1024; i++)
disk_write(i + 4, (Inode_table + i * BLOCK_SIZE));
disk_write(1028, cata_buffer);
在mkfs中,已经出现了非常困难的两个敌人:malloc -> free,以及disk_read -> disk_write 这两个部分将给我的fslab写作带来极坏的体验
fs_getattr
思路:
- 解析目录
- 访问根目录inode
- 访问根目录datablock
- 根据名称找到一级目录的inumber
- 若一级目录不是目标目录,找到一级目录inode和datablock
- 重复4、5步,直至找到目标目录
- 找到目标inode
- 写入stat attr
细节:
解析目录:将目录以char ** 数组的形式存储,按照’/'拆分,每一个char 是一级目录。在malloc char** 的时候,要多分配一个char* 空间,以确保最后一级目录的下一个path一定是NULL或strlen为0.
寻找目标目录:对于每一个inode,遍历它的所有目录块。对于这个块下面的所有目录,如果找到对应目录/文件,如果是文件 或 最后一个目录,完成搜索;如果是目录(且非最后一个),找到该目录的inode,读取下一个目录。如果已经完成搜索 或 需要更换Inode,跳出指针遍历循环。如果遍历了所有指针块仍然没有找到目标,返回未找到。
问题:
getattr作为最频繁被调用的函数,问题实在是太太太多了……首先是解析目录,一开始没有为目录多分配一个char*空间(我的分发是:只要遇到’/',num++,真实的目录数量是num+1,要多分配就要变成num+2),导致path[k+1]常常是乱码,无法终止循环
然后是attr结构体,不能malloc,不能free,不然会有奇怪的内存错误
最后是不要随意修改返回值,会造成bad error value的错误
还有很多错误,都忘记怎么解决的了。但是看到我在这个函数里写的调试信息,应该能感受到我写时的精神状态
fs_readdir
思路:
- 利用getattr 查询该目录信息
- 获取目录inumber/block等磁盘位置信息
- 读取目录对应inode内容
- 遍历db每一个dir_node, 将有效文件/目录写入buffer
- 释放内存
细节:
在遍历db每一个dir_node的时候,注意判断该文件或目录是否已经被删除
if(strlen(db_buffer[i].name) == 0)
{
if(db_buffer[i].i_ino == -5)
continue;
else
break;
}
问题同细节
fs_read
思路:
- 利用getattr查询该文件信息
- 读取Inode
- 更新atime,写回磁盘
- 把该文件的所有内容都读取到file中
- 利用memcpy,从offset处读取file,共读取readline个字节
- 释放内存空间
细节:
读取Inode:
int blk = ((ino * INODE_SIZE) / BLOCK_SIZE) + 4; //Inode在第blk个块中
int sec = ((ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE; //Inode在该块中的第sec个位置
disk_read(blk, inode_buffer);
遍历所有的datablock(利用一级指针和二级指针),读取内容至file中
for(int i = 0; i < current.i_blocks_count; i++) //遍历所有datablock
{
if(i < 18) //对于一级指针块
{
cur_blk = current.i_block_pointer[i];
disk_read(cur_blk, file);
file += BLOCK_SIZE; //更新起始位置
}
else //对于二级指针块
{
dir_blk = current.i_double_block_pointer; //目录快
disk_read(dir_blk,dir_buffer);
cur_blk = dir_buffer[i - 18]; //文件块
disk_read(cur_blk, file);
file += BLOCK_SIZE; //更新起始位置
}
}
printf("read data is done\n");
利用memcpy读取:
char* start = origin + offset; //读取的起始位置
int readlen;
if(current.i_size - offset >= size) //如果剩余字节足够
readlen = size;
else
readlen = current.i_size - offset; //如果剩余字节不足
memcpy(buffer,start,readlen);
问题:
最一开始,没有设置origin指针记录file的起始位置,结果由于file指针变更,读取失败
fs_mknod
思路:
- 遍历查找Imap中第一个空位并写
- 创建并初始化该文件inode
- 将该文件Inode写回磁盘中
- super_block更新
- 将该目录挂载在父目录下
6. 分离父目录与子目录名, 并调用getattr()获取新创建目录的上一级目录信息
7. 查询父目录信息
8. 读取父目录的inode
9. 挂载父目录
10. 修改父目录inode
11. 将父目录inode写回磁盘中 - 释放内存空间
细节:
挂载父目录: - 找到父目录最后一个目录块
int block_num = node_buffer[iloc].i_size / BLOCK_SIZE;
- 若block_num < 18, 只使用一级指针
if(node_buffer[iloc].i_block_pointer[block_num] < 0) //该指针尚未分配块
{
new_cata_once(&node_buffer[iloc],block_num);
}
cata_db = node_buffer[iloc].i_block_pointer[block_num]; //最后一个目录块
printf("use once pointer, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
for(int j = 0; j < 128; j++) //寻找父目录的第一个空闲cata
{
if(strlen(cata_buffer[j].name) == 0) //找到空闲块,挂载
{
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[j].name,myself,strlen(myself));
cata_buffer[j].i_mode = REGMODE;
cata_buffer[j].i_ino = start_i;
disk_write(cata_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
break;
}
}
若该块空间不够,为父目录分配新块
如果cata_db != 17,一级指针尚有空间。分配一级指针快并且写入第一个catalog
否则,分配二级指针块
3. 如果block_num > 18,说明已经分配了二级指针
重复一级指针块的操作直至二级指针的目录块也被分配满
4. 如果所有的块都挂满,返回-ENOSPC
分配二级指针块:
void new_cata_twice(Inode parent_node)
{
int dir_db = find_dmap(); //为二级指针块分配空间
parent_node->i_double_block_pointer = dir_db;
// 清空二级指针块
int * int_buffer = (int *)malloc(BLOCK_SIZE);
disk_read(dir_db, int_buffer);
for(int i = 0; i < 1024; i++) //清空指针
int_buffer[i] = -1;
// 为二级指针db中第一个int指针分配db
int first_double_db = find_dmap();
int_buffer[0] = first_double_db;
disk_write(dir_db, int_buffer);
parent_node->i_blocks_count += 1;
free(int_buffer);
}
分配一级指针块的过程过于简单,在此不赘述
问题:
问题实在是太多了,这个函数应该是我debug倒数第二久的一个函数(最久的是getattr),直到ddl当天的上午还在de。大部分错误都忘了是怎么回事了,仅举几例还记得的:
- 未检测指针块是否已分配,直接挂载,导致指针乱指,disk_write失败(随机写入块)
- disk_read后未及时write,磁盘里写入的数据和预想的不一样
- 将 遍历查找Imap中第一个空位并写 封装成一个函数,但是没有在函数内部malloc和free Inode,而是作为参数传递,导致segmentation fault. 此事给我的教训特别深刻,以后在写的时候都尽量将malloc和free在同一个函数中成对进行
- 当文件名长度为24时,strcpy和memcpy都无法为cata.name设置’/0’,导致字符串结尾乱码。这个我看了一圈,没有什么太好的解决办法。为了维持catalog的大小不超过32B,char[]只能分配24B。最后没有办法,使用strncmp和strncpy,忽略结尾的乱码,只比较和读取前24个字节
fs_mkdir
和fs_mknod几乎完全相同,把REGMODE改成DIRMODE就行了
说到这里,再说一下一个奇怪问题。使用fuse中定义的REGMODE和DIRMODE,不知为何无法正确判断==和!=,我猜测是由于fuse定义的REGMODE和DIRMODE不是一般意义上的整数,将其直接定义为对应的整数就解决了
fs_rmdir
思路:
- 找到父目录
- 更新父目录的ctime与mtime
- 将该目录从父目录的db中删除
- 父目录的link数减一
- 将父目录的Inode和db写回磁盘
- 清除本目录的Inode信息
- 释放本目录占据的db(置为0)(此时清除对应的Dmap)
- 清除Imap
细节:
与mkdir相匹配,将目录从父目录中删除时,需要遍历一级指针和二级指针以找到该目录
在删除时,将cata.name置为0,并将cata.ino设置为-5,以标志这是一个被删除的目录
在清除datablock时,也要清除全部的一级指针和二级指针以及二级目录块
问题:
最一开始写的时候,只是单纯把cata.name置为0(其实那个时候catalog里还包含i_blocks_link,我用那个判断,后来将其删除后才使用cata.name判断),没有设置cata.ino标志,在ls中就会出现找到了对应文件(空文件名也是文件名)但是找不到对应块的情况。必须在readdir中检查标志位。
fs_unlink
与fs_rmdir基本相同
fs_rename
思路:
- 解析新旧目录,获取新旧父目录的ino和文件名
- 若父路径不变,只修改名字
- 否则删除就路径,更改为新路径
4. 遍历旧路径db寻找待改路径文件/目录
5. 更新旧路径inode
6. 将target node加入新路径
7. 遍历新路径db寻找是否有空位写入dir_node
8. 若无,则分配新db
细节:更新路径时注意遍历二级指针块
问题:意外的没有什么问题
fs_write
思路:
- 判断权限
- 解析目录
- 获得要写的文件的inumber
- 若该文件还未被创建
5. 创建新文件
6. 将文件写入db - 若已被创建
8. 覆盖写,修改文件大小,清空该文件的db,将文件写入db
9. 追加写,修改文件大小,若需要写入的字节数不整齐,则写入剩余的字节,再写入整齐的字节 - 修改inode,写入磁盘
细节:
写入整块:循环写入新块,寻找Dmap的空位并写Dmap,将buffer写入disk,更新下次写的起始位置。注意分配二级指针。
问题:创建文件不能直接调用mknod,因为不能随意修改返回值,否则出现错误
fs_truncate
思路:
- 根据inumber找到inode
- 读取inode
- 修改size、ctime
- 在修改size的时候判断剩余空间
- 写回inode
细节:
注意修改的文件size不能大于8MB
fs_utime
思路:
- 读取inode
- 修改time
- 写回磁盘
fs_statfs
思路:
- 遍历Imap,Dmap,找出空闲块数量
- 写入statvfs *stat
细节:
注意位运算正确性。为了确定自己的位运算正确,我在调试时将每一条Imap[i]和Dmap[i]以二进制格式打印出来
fs_open
思路:
- 利用getattr查询文件信息
- 检查权限
细节:
linux fuse判断文件权限有自己的一套规则,我csdn了一下,然后找着实际fuse的规则写的
结果
前14个trace在mount模式下通过,最后一个trace在debug模式下通过(是的我手动敲了128个mkdir和cd dir),但不知为何无法在mount模式下通过
完整代码
/*
Filesystem Lab disigned and implemented by Liang Junkai,RUC
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <fuse.h>
#include <errno.h>
#include <stdlib.h>
#include "disk.h"
// 目录mode与普通文件mode
#define DIRMODE 16877
#define REGMODE 33188
// 至少支持文件或目录数量
#define FILE_NUM 32768
// inode节点大小
#define INODE_SIZE 128
// super block大小
#define SUPERBLOCK_SIZE 4096
// Imap大小
#define IMAP_SIZE 4096
// Dmap大小
#define DMAP_SIZE 8192
// Inodes table大小
#define INODE_TABLE_SIZE (FILE_NUM * INODE_SIZE)
// 块大小
#define BLOCK_SIZE 4096 // 4KB
// 文件最大大小
#define MAX_SIZE 8<<20 // 8MB
// 总块数
#define BLOCK_NUM 65536 // 0-65535 block_id
// 全1掩码
#define MASK_ALL ~1 + 1
// 最高位为1的掩码
#define MASK_ONE 1<<31
typedef struct super_node
{
int inode_num; // inode_num = FILE_NUM
int block_num; // block_num = BLOCK_NUM
int* imap_block; // Imap位置
int* dmap_block; // Dmap位置
int dir_count; // 目录数量
int file_count; // 文件数量
int* inode_table_block; // Inodes table位置
}super_node, *SuperNode;
typedef struct inode // 128B
{
mode_t i_mode; // 文件mode/目录mode
nlink_t i_links_count; // 链接数
off_t i_size; // 文件大小
time_t i_atime; // 文件被访问的时间
time_t i_mtime; // 文件被修改的时间
time_t i_ctime; // 文件状态改变时间
int i_blocks_count; // 文件占据block数量
int i_block_pointer[18]; // 18个一级指针 // 4B * 18 = 72B
int i_double_block_pointer; // 1个二级指针 // 4B * 1 = 4B
}inode, *Inode;
// 创建目录结构体,存放在目录的db中
typedef struct catalog //32B
{
char name[24]; //名字 //24B
//nlink_t i_links_count; //链接数 //2B
mode_t i_mode; //模式(目录/文件) //2B
int i_ino; //i-number //4B
}catalog, *Catalog;
SuperNode super_block;
int find_imap();
int find_dmap();
char** getpath(const char* path, char** temp);
int find_target(char** temp);
void cleardb(Inode current); //给定inode,清除它的所有db
void clearimap(int file_ino); //给定Inode的ino,清除它的imap标志
int find_parent(char* path,char* myself);
// /* disk.h宏定义 */
// #define BLOCK_SIZE 4096 // 4KB
// #define BLOCK_NUM 65536 // 0-65535 block_id
// #define DISK_SIZE (BLOCK_SIZE * BLOCK_NUM) // 256MB
// /*
// block_id : 0-65535
// buffer : 指向一块4KB的连续内存
// 当执行写操作后,buffer指向的内存中的数据会被写入指定块中
// */
// int disk_read(int block_id, void *buffer);
// int disk_write(int block_id, void *buffer);
//Format the virtual block device in the following function
int mkfs()
{
int* Imap;
int* Dmap;
Inode Inode_table;
// 创建super_block
super_block = (SuperNode)malloc(SUPERBLOCK_SIZE); // 4KB
// 创建Imap
Imap = (int*)malloc(IMAP_SIZE); // 4KB
memset(Imap, 0, IMAP_SIZE);
// 创建Dmap
Dmap = (int*)malloc(DMAP_SIZE); // 8KB
memset(Dmap, 0, DMAP_SIZE);
// 创建Inode_table
Inode_table = (Inode)malloc(INODE_TABLE_SIZE); // 4MB
memset(Inode_table, 0, INODE_TABLE_SIZE);
// 初始化super_block
super_block->inode_num = FILE_NUM;
super_block->block_num = BLOCK_NUM;
super_block->imap_block = Imap;
super_block->dmap_block = Dmap;
super_block->dir_count = 0;
super_block->file_count = 0;
super_block->inode_table_block = Dmap + DMAP_SIZE;
// 创建根目录root的inode
Inode_table[0].i_mode = DIRMODE;
Inode_table[0].i_links_count = 0;
Inode_table[0].i_size = sizeof(catalog);
Inode_table[0].i_atime = time(NULL);
Inode_table[0].i_mtime = time(NULL);
Inode_table[0].i_ctime = time(NULL);
Inode_table[0].i_blocks_count = 1;
for(int i = 0; i < 18; i++)
Inode_table[0].i_block_pointer[i] = -1;
Inode_table[0].i_double_block_pointer = -1;
// 创建root的datablock
Inode_table[0].i_block_pointer[0] = 1028;
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE);
cata_buffer[0].i_ino = 0;
cata_buffer[0].i_mode = DIRMODE;
strcpy(cata_buffer[0].name, "/");
// super_block更新
super_block->dir_count += 1;
// Imap更新
Imap[0] |= 1 << 31; // 只有root占用1个inode
// Dmap更新
/*
super block, imap, dmap, inodes table
共占据db 1+1+2+1024+1=1028个db
需要将1028个bit置1
*/
int i = 0;
for(i = 0; i < 1029 / 32; i++) Dmap[i] = -1; // 前1024个bit置1
Dmap[i] = 1 << 31 >> (1029 % 32 - 1); // 剩余5个bit置1
// 将super_block, Imp, Dmap, Root 写入磁盘
disk_write(0, super_block);
disk_write(1, Imap);
disk_write(2, Dmap);
disk_write(3, Dmap + (DMAP_SIZE) / 2);
for(i = 0; i < 1024; i++)
disk_write(i + 4, (Inode_table + i * BLOCK_SIZE));
disk_write(1028, cata_buffer);
// 释放内存空间
free(Imap);
free(Dmap);
free(Inode_table);
free(cata_buffer);
return 0;
}
//将路径拆分为目录名和文件名
char** getpath(const char* path, char** temp)
{
char array[2560];
char *buf = array;
if(path[0] == '/' && strlen(path) > 1){
path++;
}
strcpy(buf, path);
int num = 0;
for(int i = 0; i < strlen(buf); i++)
if(buf[i] == '/') num++;
num += 2;
temp = (char **)malloc(sizeof(char *) * num);
memset(temp, 0, (sizeof(char *) * num));
printf("make temp\n");
for(int k = 0; k < num; k++){
temp[k] = (char*)malloc(24 * sizeof(char));
memset(temp[k], 0, 24);
// printf("make temp[%d]\n",k);
}
printf("finish make temp\n");
int argc = 0;
int i = 0;
strcpy(buf, path);
printf("finish copy buf,buf is:%s\n",buf);
printf("strlen buf:%d\n",strlen(buf));
int count = strlen(buf);
char* origin = buf;
while(buf < (origin+count)){
if((*buf) == '/'){
temp[argc][i] = '\0';
i = 0;
printf("argc:%d\n",argc);
argc++;
buf++;
}
temp[argc][i++] = *buf;
buf++;
}
printf("finish make buf\n");
temp[argc][i] = '\0';
return temp;
}
int find_target(char** temp)
{
printf("start find target\n");
// 特殊处理root根目录"/"
if(strlen(temp[0]) == 0)
temp[0] = "/";
Inode node_buffer = (Inode)malloc(BLOCK_SIZE); //4KB空间用于存放得到的inode
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE); //4KB空间用于存放得到的catalog
disk_read(4,node_buffer); //访问根目录inode
printf("finish read root inode\n");
char* dir = temp[0];
inode current; //当前搜索的Inode
int cata_db; //目录文件的db
int k = 0;
int blk; //inode所在磁盘块的编号
int iloc; //inode在所在磁盘块中的位置
int count = 0;
int block_num;
int flag = 0;
int find_flag = 0;
int file_ino = -1; // 最终找到的inumber
int end_search_flag = 0;
// 从根目录db开始检索子目录/子文件
current = node_buffer[0];
block_num = node_buffer[0].i_blocks_count;
printf(" length : %d\n", block_num);
while(!end_search_flag) //对于每一个inode
{
find_flag = 0; //新的Inode
count = 0; //每一个inode共遍历了几个目录块
block_num = current.i_blocks_count;
for(int p = 0; p < block_num; p++) //遍历它的所有目录块
{
count++;
if(find_flag) //已经完成搜索 或 需要更换Inode
break;
if(p < 18)
{
cata_db = current.i_block_pointer[p];
disk_read(cata_db, cata_buffer);
for(int i = 0; i < 128; i++) //对于这个块下面的所有目录
{
// if(strlen(cata_buffer[i].name) == 0){
// if(cata_buffer[i].i_ino != -5){
// flag = 0;
// break;
// }
// }
if(!strncasecmp(dir,cata_buffer[i].name,strlen(dir))) //如果找到对应目录/文件
{
printf("find target\n");
// printf("next strlen:%d\n",strlen(temp[k+1]));
if(cata_buffer[i].i_mode == REGMODE || temp[k+1] == NULL || strlen(temp[k+1]) == 0)
{ //如果是文件 或 最后一个目录
file_ino = cata_buffer[i].i_ino;
end_search_flag = 1;
find_flag = 1;
// printf("in cata_buffer[%d], find target %s\n",i,cata_buffer[i].name);
break;
}
else //如果是目录(且非最后一个)
{
// 找到该目录的inode
blk = (cata_buffer[i].i_ino * INODE_SIZE) / BLOCK_SIZE + 4;
iloc = ((cata_buffer[i].i_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
// 访问该目录的inode
disk_read(blk, node_buffer);
// 找到该目录的inode
current = node_buffer[iloc];
find_flag = 1;
k++; //读取下一个目录
dir = temp[k];
if(dir == NULL)
{
printf("can't find target with k: %d\n",k);
return -ENOSPC;
}
// printf("next target is: %s\n",dir);
break;
}
}
}
}
else
{
int* dir_buffer = (int*)malloc(BLOCK_SIZE);
int dir_db = current.i_double_block_pointer;
disk_read(dir_db,dir_buffer);
cata_db = dir_buffer[p - 18 - 1];
disk_read(cata_db, cata_buffer);
for(int i = 0; i < 128; i++) //对于这个块下面的所有目录
{
if(!strncasecmp(dir,cata_buffer[i].name,strlen(dir))) //如果找到对应目录/文件
{
printf("find target\n");
printf("next strlen:%d\n",strlen(temp[k+1]));
if(cata_buffer[i].i_mode == REGMODE || temp[k+1] == NULL || strlen(temp[k+1]) == 0)
{ //如果是文件 或 最后一个目录
file_ino = cata_buffer[i].i_ino;
end_search_flag = 1;
find_flag = 1;
// printf("in cata_buffer[%d], find target %s\n",i,cata_buffer[i].name);
break;
}
else //如果是目录(且非最后一个)
{
// 找到该目录的inode
blk = (cata_buffer[i].i_ino * INODE_SIZE) / BLOCK_SIZE + 4;
iloc = ((cata_buffer[i].i_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
// 访问该目录的inode
disk_read(blk, node_buffer);
// 找到该目录的inode
current = node_buffer[iloc];
find_flag = 1;
k++; //读取下一个目录
dir = temp[k];
if(dir == NULL)
{
printf("can't find target with k: %d\n",k);
return -ENOSPC;
}
// printf("next target is: %s\n",dir);
break;
}
}
}
free(dir_buffer);
}
}
if(count == block_num && end_search_flag == 0 && find_flag == 0) //如果遍历了这个inode的所有目录块仍未找到
{
file_ino = -1;
end_search_flag = 1;
}
}
free(node_buffer);
free(cata_buffer);
return file_ino;
}
int find_parent(char* path,char* myself)
{
printf("start find parent with path: %s\n",path);
char temp[2560]; //父目录名
strcpy(temp, path);
printf("str: %d\n",strlen(temp));
printf("old temp:%s\n",temp);
// 提取新目录名, 分离父目录
for(int i = strlen(temp) - 2; i >= 0; i--){
if(temp[i] == '/'){
temp[i] = '\0';
strcpy(myself, temp + i + 1);
break;
}
}
// 若path只有新目录名无父目录, 则父目录为根目录root
if(strlen(temp) == 0){
temp[0] = '/';
temp[1] = '\0';
}
printf("myself:%s\n",myself);
printf("new temp:%s\n",temp);
int parent_ino = cur_find(temp);
return parent_ino;
}
int cur_find(const char* path)
{
char** temp;
temp = getpath(path,temp); //解析目录
int file_ino; //文件 或 最后一级目录的inumber
//mode_t c_mode; //文件模式
int cata_db; //目录文件的db
int blk; //inode所在磁盘块的编号
int iloc; //inode在所在磁盘块中的位置
file_ino = find_target(temp);
if(file_ino < 0)
{
printf("(Getattr) Cannot find path: %s\n", path);
return -ENOENT;
}
printf("finish find target inode\n");
return file_ino;
}
//Filesystem operations that you need to implement
int fs_getattr (const char *path, struct stat *attr)
{
//查询一个目录文件或常规文件的信息
//解析目录-访问根目录inode-访问根目录db-根据名称找到一级目录的inumber
//-找到一级目录inode-找到一级目录db-根据名称找到二级目录/文件的inumber
//-找到文件inode-获得文件stat
printf("Getattr is called:%s\n",path);
char** temp;
temp = getpath(path,temp); //解析目录
int file_ino = find_target(temp);
if(file_ino < 0)
{
printf("(Getattr) Cannot find path: %s\n", path);
return -ENOENT;
}
printf("finish find target inode\n");
printf("file ino:%d\n",file_ino);
// 读取目标文件/目录的inode
Inode node_buffer = (Inode)malloc(BLOCK_SIZE);
int blk = (file_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((file_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("blk:%d iloc:%d\n",blk,iloc);
if(disk_read(blk, node_buffer))
printf("fail to read target inode\n");
attr->st_ino = file_ino;
attr->st_mode = node_buffer[iloc].i_mode;
attr->st_nlink = 1;
attr->st_uid = getuid();
attr->st_gid = getgid();
attr->st_size = node_buffer[iloc].i_size;
attr->st_atime = node_buffer[iloc].i_atime;
attr->st_mtime = node_buffer[iloc].i_mtime;
attr->st_ctime = node_buffer[iloc].i_ctime;
printf("%d %d %d %d\n", attr->st_mode, attr->st_ino, attr->st_size, attr->st_atime);
free(node_buffer);
// free(temp);
printf("Getattr is finished: %s\n", path);
return 0;
}
//查询一个目录下的所有文件
int fs_readdir(const char *path, void *buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
printf("Readdir is called:%s\n", path);
// 查询该目录信息
char name[28];
struct stat attr;
fs_getattr(path, &attr);
int ino = attr.st_ino;
if(attr.st_mode == DIRMODE)
ino = attr.st_ino;
else
return -ENOENT;
printf("attr.st_ino:%d\n",attr.st_ino);
// 获取目录inumber/block等磁盘位置信息
int blk = ((ino * INODE_SIZE) / BLOCK_SIZE) + 4;
int sec = ((ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
Inode inode_buffer = (Inode)malloc(BLOCK_SIZE);
Catalog db_buffer = (Catalog)malloc(BLOCK_SIZE);
// 读取目录对应inode内容
disk_read(blk, inode_buffer);
// 遍历db每一个dir_node, 将有效文件/目录写入buffer
int block_num = inode_buffer[sec].i_blocks_count;
for(int p = 0; p < block_num; p++)
{
if(p < 18)
{
disk_read(inode_buffer[sec].i_block_pointer[p], db_buffer);
printf("pointer:%d pointer db:%d\n",p,inode_buffer[sec].i_block_pointer[p]);
int i = 0;
if(inode_buffer[sec].i_block_pointer[p] == 1028) i = 1;
for(i; i < 128; i++)
{
if(strlen(db_buffer[i].name) == 0)
{
if(db_buffer[i].i_ino == -5)
continue;
else
break;
}
struct stat *temp = (struct stat *)malloc(sizeof(struct stat));
Inode tempBlock = (Inode)malloc(sizeof(inode) * 32);
int kid_ino = db_buffer[i].i_ino;
int kid_blk = ((kid_ino * INODE_SIZE) / BLOCK_SIZE) + 4;
int kid_sec = ((kid_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(kid_blk, tempBlock);
temp->st_mode = tempBlock[kid_sec].i_mode;
temp->st_nlink = 1;
temp->st_uid = getuid();
temp->st_gid = getgid();
temp->st_size = tempBlock[kid_sec].i_size;
temp->st_atime = time(NULL);
temp->st_mtime = tempBlock[kid_sec].i_mtime;
temp->st_ctime = tempBlock[kid_sec].i_ctime;
int num = 24;
strncpy(name,db_buffer[i].name,24);
name[24] = '\0';
printf("name:%s\n",name);
// 写入缓冲区
filler(buffer, name, temp, offset);
free(temp);
free(tempBlock);
}
}
else
{
int indir = inode_buffer[sec].i_double_block_pointer;
int * int_buffer = (int *)malloc(sizeof(int) * 1024);
disk_read(indir, int_buffer);
disk_read(int_buffer[p - 18 - 1], db_buffer);
free(int_buffer);
int i = 0;
if(inode_buffer[sec].i_block_pointer[p] == 1028) i = 1;
for(i; i < 128; i++)
{
if(strlen(db_buffer[i].name) == 0)
{
if(db_buffer[i].i_ino == -5)
continue;
else
break;
}
struct stat *temp = (struct stat *)malloc(sizeof(struct stat));
Inode tempBlock = (Inode)malloc(sizeof(inode) * 32);
int kid_ino = db_buffer[i].i_ino;
int kid_blk = ((kid_ino * INODE_SIZE) / BLOCK_SIZE) + 4;
int kid_sec = ((kid_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(kid_blk, tempBlock);
temp->st_mode = tempBlock[kid_sec].i_mode;
temp->st_nlink = 1;
temp->st_uid = getuid();
temp->st_gid = getgid();
temp->st_size = tempBlock[kid_sec].i_size;
temp->st_atime = time(NULL);
temp->st_mtime = tempBlock[kid_sec].i_mtime;
temp->st_ctime = tempBlock[kid_sec].i_ctime;
// 写入缓冲区
filler(buffer, db_buffer[i].name, temp, offset);
free(temp);
free(tempBlock);
}
}
}
// 释放内存
free(inode_buffer);
free(db_buffer);
printf("Readdir is finished : %s\n", path);
return 0;
}
int fs_read(const char *path, char *buffer, size_t size, off_t offset, struct fuse_file_info *fi)
{
//查询该文件信息
printf("Read is called : %s\n", path);
struct stat attr;
fs_getattr(path, &attr);
if(attr.st_mode == DIRMODE)
{
printf("this is not a file!\n");
return -EISDIR;
}
if(offset > attr.st_size)
{
printf("too much offset\n");
return -ERANGE;
}
// 获取文件inumber/block等磁盘位置信息
int ino = attr.st_ino;
int blk = ((ino * INODE_SIZE) / BLOCK_SIZE) + 4;
int sec = ((ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("(Read:)blk:%d sec:%d\n",blk,sec);
Inode inode_buffer = (Inode)malloc(BLOCK_SIZE);
disk_read(blk, inode_buffer);
// 更新atime
inode_buffer[sec].i_atime = time(NULL);
inode current = inode_buffer[sec];
disk_write(blk, inode_buffer);
free(inode_buffer);
char* origin = (char*)malloc(MAX_SIZE);
memset(origin, 0, MAX_SIZE);
char* file = origin;
int* dir_buffer = (int*)malloc(BLOCK_SIZE);
int cur_blk,dir_blk;
// 把该文件的所有内容都读取到file中
for(int i = 0; i < current.i_blocks_count; i++)
{
if(i < 18)
{
cur_blk = current.i_block_pointer[i];
disk_read(cur_blk, file);
file += BLOCK_SIZE;
}
else
{
dir_blk = current.i_double_block_pointer;
disk_read(dir_blk,dir_buffer);
cur_blk = dir_buffer[i - 18];
disk_read(cur_blk, file);
file += BLOCK_SIZE;
}
}
printf("read data is done\n");
char* start = origin + offset;
int readlen;
if(current.i_size - offset >= size)
readlen = size;
else
readlen = current.i_size - offset;
printf("readlen:%d\n",offset + readlen);
memcpy(buffer,start,readlen);
free(dir_buffer);
free(origin);
printf("Read is finished : %s\n", path);
return readlen;
}
// 为父目录分配一个新的一级块
void new_cata_once(Inode parent_node,int block_num)
{
int start_d = find_dmap();
printf("new cata start_d: %d\n",start_d);
if(block_num >= 18)
{
printf("block_num > 18\n");
return -EPERM;
}
parent_node->i_block_pointer[block_num] = start_d;
parent_node->i_blocks_count += 1;
}
// 为父目录分配一个新的二级块并设置第一个二级指针
void new_cata_twice(Inode parent_node)
{
int dir_db = find_dmap(); //为二级指针块分配空间
printf("new dir start_d:%d\n",dir_db);
parent_node->i_double_block_pointer = dir_db;
// 清空二级指针块
int * int_buffer = (int *)malloc(BLOCK_SIZE);
disk_read(dir_db, int_buffer);
for(int i = 0; i < 1024; i++) //清空指针
int_buffer[i] = -1;
// 为二级指针db中第一个int指针分配db
int first_double_db = find_dmap();
printf("first double db:%d\n",first_double_db);
int_buffer[0] = first_double_db;
disk_write(dir_db, int_buffer);
parent_node->i_blocks_count += 1;
free(int_buffer);
}
// 创建一个常规文件
int fs_mknod (const char *path, mode_t mode, dev_t dev)
{
printf("Mknod is called:%s\n",path);
// 遍历查找Imap中第一个空位并写
int start_i = find_imap();
printf("find imap is finished,start_i is %d\n",start_i);
if(start_i < 0)
exit(0);
//创建inode
Inode Inode_buffer = (Inode)malloc(BLOCK_SIZE);
int i_blk = ((start_i * INODE_SIZE) / BLOCK_SIZE) + 4;
int i_sec = ((start_i * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("i_blk: %d i_sec: %d\n",i_blk,i_sec);
disk_read(i_blk,Inode_buffer);
Inode_buffer[i_sec].i_mode = REGMODE;
Inode_buffer[i_sec].i_links_count = 0;
Inode_buffer[i_sec].i_size = 0;
Inode_buffer[i_sec].i_atime = time(NULL);
Inode_buffer[i_sec].i_mtime = time(NULL);
Inode_buffer[i_sec].i_ctime = time(NULL);
Inode_buffer[i_sec].i_blocks_count = 0;
for(int i = 0; i < 18; i++)
Inode_buffer[i_sec].i_block_pointer[i] = -1;
Inode_buffer[i_sec].i_double_block_pointer = -1;
//将Inode写回磁盘中
disk_write(i_blk,Inode_buffer);
printf("write inode is finished\n");
//super_block更新
super_block->file_count += 1;
printf("create inode is finished\n");
//将该目录挂载在父目录下
char myself[24]; //自己的文件名
Inode node_buffer = (Inode)malloc(BLOCK_SIZE); //4KB空间用于存放得到的inode
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE); //4KB空间用于存放得到的catalog
// 分离父目录与子目录名, 并调用getattr()获取新创建目录的上一级目录信息
char temp[2560];
strcpy(temp, path);
// 提取新目录名, 分离父目录
for(int i = strlen(temp) - 2; i >= 0; i--){
if(temp[i] == '/'){
temp[i] = '\0';
strcpy(myself, temp + i + 1);
break;
}
}
// 若path只有新目录名无父目录, 则父目录为根目录root
if(strlen(temp) == 0){
temp[0] = '/';
temp[1] = '\0';
}
printf("parent path:%s\n",temp);
// 查询父目录信息
int parent_ino = cur_find(temp);
if(parent_ino < 0)
{
printf("(Mknod): Cannot find path: %s\n", path);
return -ECHILD;
}
printf("find parent is finished\n");
// 读取父目录的inode
int blk = (parent_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((parent_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("parent blk:%d parent iloc:%d\n",blk,iloc);
disk_read(blk, node_buffer);
// 挂载在父目录上
int cata_db; //目录块序号
int find_flag = 0;
int enough_flag = 0;
// 找到父目录最后一个目录块
int block_num = node_buffer[iloc].i_size / BLOCK_SIZE;
if(block_num < 18) //只使用一级指针
{ if(node_buffer[iloc].i_block_pointer[block_num] < 0) //该指针尚未分配块
{
new_cata_once(&node_buffer[iloc],block_num);
}
cata_db = node_buffer[iloc].i_block_pointer[block_num]; //最后一个目录块
printf("use once pointer, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
for(int j = 0; j < 128; j++) //寻找父目录的第一个空闲cata
{
if(strlen(cata_buffer[j].name) == 0) //找到空闲块,挂载
{
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[j].name,myself,strlen(myself));
// strcpy(cata_buffer[j].name,myself);
printf("block is:%d, cata block is: %d, my name is: %s\n",cata_db,j,cata_buffer[j].name);
//cata_buffer[j].i_links_count += 1;
cata_buffer[j].i_mode = REGMODE;
cata_buffer[j].i_ino = start_i;
disk_write(cata_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
break;
}
}
if(!enough_flag) //如果该块剩余空间不足
{
if(cata_db != 17) //一级指针尚有空间
{
//为父目录分配一个新的cata块
new_cata_once(&node_buffer[iloc],block_num + 1);
// int num = node_buffer[iloc].i_blocks_count;
cata_db = node_buffer[iloc].i_block_pointer[block_num + 1];
printf("new once cata, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
// 新块,直接写在第0个就可以了
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[0].name,myself,strlen(myself));
// strcpy(cata_buffer[0].name,myself);
printf("block is:%d, cata block is: %d, my name is: %s\n",cata_db,0,cata_buffer[0].name);
//cata_buffer[0].i_links_count += 1;
cata_buffer[0].i_mode = REGMODE;
cata_buffer[0].i_ino = start_i;
disk_write(cata_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
}
else //分配二级指针块
{
new_cata_twice(&node_buffer[iloc]);
int dir_db = node_buffer[iloc].i_double_block_pointer;
int* int_buffer = (int*)malloc(BLOCK_SIZE);
cata_db = int_buffer[0];
printf("new twice cata, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
// 新块,直接写在第0个就可以了
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[0].name,myself,strlen(myself));
// strcpy(cata_buffer[0].name,myself);
printf("block is:%d, cata block is: %d, my name is: %s\n",cata_db,0,cata_buffer[0].name);
//cata_buffer[0].i_links_count += 1;
cata_buffer[0].i_mode = REGMODE;
cata_buffer[0].i_ino = start_i;
disk_write(cata_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
free(int_buffer);
}
}
}
else //已经分配了二级指针
{
int * int_buffer = (int *)malloc(BLOCK_SIZE);
disk_read(node_buffer[iloc].i_double_block_pointer, int_buffer);
printf("have had twice pointer\n");
for(int i = 0; i < 1024; i++) //遍历指针块
{
if(find_flag)
break;
if(int_buffer[i] != -1) //该目录块已被分配
{
disk_read(int_buffer[i], cata_buffer);
printf("use twice pointer, cata_db is:%d\n",int_buffer[i]);
for(int j = 0; j < 128; j++)
{
if(strlen(cata_buffer[j].name) == 0) //找到空闲块,挂载
{
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[j].name,myself,strlen(myself));
// strcpy(cata_buffer[j].name,myself);
printf("block is:%d, cata block is: %d, my name is: %s\n",int_buffer[i],j,cata_buffer[j].name);
//cata_buffer[j].i_links_count += 1;
cata_buffer[j].i_mode = REGMODE;
cata_buffer[j].i_ino = start_i;
disk_write(int_buffer[i],cata_buffer);
enough_flag = 1;
find_flag = 1;
break;
}
}
}
else if(!find_flag && int_buffer[i] == -1) //需要分配新的目录块
{
int dir_db = find_dmap();
int_buffer[i] = dir_db;
disk_read(dir_db, cata_buffer);
printf("new twice cata, cata_db is:%d\n",dir_db);
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[0].name,myself,strlen(myself));
// strcpy(cata_buffer[0].name,myself);
printf("block is:%d, cata block is: %d, my name is: %s\n",dir_db,0,cata_buffer[0].name);
//cata_buffer[0].i_links_count += 1;
cata_buffer[0].i_mode = REGMODE;
cata_buffer[0].i_ino = start_i;
disk_write(dir_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
// 更新父目录的inode
node_buffer[iloc].i_blocks_count += 1;
break;
}
}
free(int_buffer);
}
if(!enough_flag) //如果没有足够空间
{
return -ENOSPC;
}
node_buffer[iloc].i_size += sizeof(catalog);
printf("mount dir is finished\n");
// 修改父目录inode
printf("%d %d %d\n", node_buffer[iloc].i_mode, node_buffer[iloc].i_size, node_buffer[iloc].i_atime);
node_buffer[iloc].i_links_count += 1;
node_buffer[iloc].i_atime = time(NULL);
node_buffer[iloc].i_mtime = time(NULL);
//将父目录inode写回磁盘中
if(disk_write(blk, node_buffer))
printf("fail to write parent inode\n");
// //将父目录db写回磁盘中
// if(disk_write(cata_db,cata_buffer))
// printf("fail to write parent datablock\n");
// printf("write parent is finished\n");
printDirInode(parent_ino); //检验是否挂载成功
free(Inode_buffer);
free(node_buffer);
free(cata_buffer);
printf("Mknod is finished:%s\n",path);
return 0;
}
int find_imap() // 遍历查找Imap中第一个空位并写
{
int* Imap;
Imap = (int*)malloc(IMAP_SIZE); // 4KB
disk_read(1,Imap);
int free_flag = 0;
int start_i = -100; //Imap中第一个空位
for(int i = 0; i < 1024; i++)
{
for(int j = 0; j < 32; j++)
{
int mask = 1 << (31 - j);
if(!((Imap[i] & mask) >> (31 - j)))
{
free_flag = 1;
start_i = i * 32 + j;
// 更新imap
int mask_i = start_i / 32;
int mask_j = start_i % 32;
int mask = 1 << (31 - mask_j);
Imap[mask_i] = Imap[mask_i] | mask;
break;
}
}
if(free_flag) break;
}
disk_write(1,Imap);
free(Imap);
return start_i;
}
int find_dmap() //遍历查找dmap中第一个空位并写
{
int start_d = -100;
int free_block_flag = 0;
int* Dmap;
Dmap = (int*)malloc(DMAP_SIZE); // 8KB
disk_read(2,Dmap);
disk_read(3,Dmap + (DMAP_SIZE) / 2);
for(int i = 0; i < 2048; i++)
{
for(int j = 0; j < 32; j++)
{
int mask = 1 << (31 - j);
if(!((Dmap[i] & mask) >> (31 - j)))
{
free_block_flag = 1;
start_d = i * 32 + j;
// 更新Dmap
Dmap[i] = Dmap[i] | mask;
break;
}
}
if(free_block_flag) break;
}
disk_write(2,Dmap);
disk_write(3,Dmap + (DMAP_SIZE) / 2);
free(Dmap);
return start_d;
}
void printDirInode(int parent_ino)
{
//读取父目录的db
//遍历db,打印db中的目录
//如果有当前目录,则挂载成功
Inode node_buffer = (Inode)malloc(BLOCK_SIZE);
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE);
int blk = (parent_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((parent_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
if(disk_read(blk, node_buffer))
printf("fail to read target inode\n");
// 找到父目录的db
int cata_db = node_buffer[iloc].i_block_pointer[0];
printf("(Print node):cata_db is: %d\n",cata_db);
// 访问父目录db
disk_read(cata_db,cata_buffer);
for(int i = 0; i < 5; i++)
{
if(cata_buffer[i].name != NULL)
{
printf("child dir is: %s\n",cata_buffer[i].name);
}
else
break;
}
free(node_buffer);
free(cata_buffer);
}
int fs_mkdir (const char *path, mode_t mode)
{
// 创建目录的inode
// 创建目录的db
printf("Mkdir is called:%s\n",path);
// 读取Imap
// int* Imap;
// Imap = (int*)malloc(IMAP_SIZE); // 4KB
// int* Dmap;
// Dmap = (int*)malloc(DMAP_SIZE); // 8KB
// 遍历查找Imap中第一个空位并写
int start_i = find_imap();
printf("find imap is finished,start_i is %d\n",start_i);
if(start_i < 0)
exit(0);
//遍历查找dmap中第一个空位并写
int start_d = find_dmap();
printf("find dmap is finished,start_d is %d\n",start_d);
if(start_d < 0)
exit(0);
//创建inode
Inode Inode_buffer = (Inode)malloc(BLOCK_SIZE);
int i_blk = ((start_i * INODE_SIZE) / BLOCK_SIZE) + 4;
int i_sec = ((start_i * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("i_blk: %d i_sec: %d\n",i_blk,i_sec);
disk_read(i_blk,Inode_buffer);
Inode_buffer[i_sec].i_mode = DIRMODE;
Inode_buffer[i_sec].i_links_count = 1;
Inode_buffer[i_sec].i_size = sizeof(catalog);
Inode_buffer[i_sec].i_size = sizeof(catalog);
Inode_buffer[i_sec].i_atime = time(NULL);
Inode_buffer[i_sec].i_mtime = time(NULL);
Inode_buffer[i_sec].i_ctime = time(NULL);
Inode_buffer[i_sec].i_blocks_count = 1;
for(int i = 0; i < 18; i++)
Inode_buffer[i_sec].i_block_pointer[i] = -1;
Inode_buffer[i_sec].i_double_block_pointer = -1;
Inode_buffer[i_sec].i_block_pointer[0] = start_d;
//将Inode写回磁盘中
disk_write(i_blk,Inode_buffer);
printf("write inode is finished\n");
//super_block更新
super_block->dir_count += 1;
printf("create inode is finished\n");
//将该目录挂载在父目录下
char myself[24]; //自己的文件名
Inode node_buffer = (Inode)malloc(BLOCK_SIZE); //4KB空间用于存放得到的inode
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE); //4KB空间用于存放得到的catalog
// 分离父目录与子目录名, 并调用getattr()获取新创建目录的上一级目录信息
char temp[2560];
strcpy(temp, path);
// 提取新目录名, 分离父目录
for(int i = strlen(temp) - 2; i >= 0; i--){
if(temp[i] == '/'){
temp[i] = '\0';
strcpy(myself, temp + i + 1);
break;
}
}
// 若path只有新目录名无父目录, 则父目录为根目录root
if(strlen(temp) == 0){
temp[0] = '/';
temp[1] = '\0';
}
printf("parent path:%s\n",temp);
// 查询父目录信息
int parent_ino = cur_find(temp);
if(parent_ino < 0)
{
printf("(Mkdir) Cannot find path: %s\n", path);
return -ECHILD;
}
printf("find parent is finished\n");
// 读取父目录的inode
int blk = (parent_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((parent_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("parent blk:%d parent iloc:%d\n",blk,iloc);
if(disk_read(blk, node_buffer))
printf("fail to read target inode\n");
// 挂载在父目录上
int cata_db; //目录块序号
int find_flag = 0;
int enough_flag = 0;
// 找到父目录最后一个目录块
int block_num = node_buffer[iloc].i_size / BLOCK_SIZE;
if(block_num < 18) //只使用一级指针
{ if(node_buffer[iloc].i_block_pointer[block_num] < 0) //该指针尚未分配块
{
new_cata_once(&node_buffer[iloc],block_num);
}
cata_db = node_buffer[iloc].i_block_pointer[block_num]; //最后一个目录块
printf("use once pointer, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
for(int j = 0; j < 128; j++) //寻找父目录的第一个空闲cata
{
if(strlen(cata_buffer[j].name) == 0) //找到空闲块,挂载
{
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[j].name,myself,strlen(myself));
// strcpy(cata_buffer[j].name,myself);
printf("cata block is: %d, my name is: %s\n",j,cata_buffer[j].name);
//cata_buffer[j].i_links_count += 1;
cata_buffer[j].i_mode = DIRMODE;
cata_buffer[j].i_ino = start_i;
enough_flag = 1;
find_flag = 1;
break;
}
}
disk_write(cata_db,cata_buffer);
if(!enough_flag) //如果该块剩余空间不足
{
if(cata_db != 17) //一级指针尚有空间
{
//为父目录分配一个新的cata块
new_cata_once(&node_buffer[iloc],block_num + 1);
// int num = node_buffer[iloc].i_blocks_count;
cata_db = node_buffer[iloc].i_block_pointer[block_num + 1];
printf("new once cata, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
// 新块,直接写在第0个就可以了
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[0].name,myself,strlen(myself));
// strcpy(cata_buffer[0].name,myself);
printf("cata block is: %d, my name is: %s\n",0,cata_buffer[0].name);
//cata_buffer[0].i_links_count += 1;
cata_buffer[0].i_mode = DIRMODE;
cata_buffer[0].i_ino = start_i;
disk_write(cata_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
}
else //分配二级指针块
{
new_cata_twice(&node_buffer[iloc]);
int dir_db = node_buffer[iloc].i_double_block_pointer;
int* int_buffer = (int*)malloc(BLOCK_SIZE);
cata_db = int_buffer[0];
printf("new twice cata, cata_db is:%d\n",cata_db);
disk_read(cata_db,cata_buffer);
// 新块,直接写在第0个就可以了
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[0].name,myself,strlen(myself));
// strcpy(cata_buffer[0].name,myself);
printf("cata block is: %d, my name is: %s\n",0,cata_buffer[0].name);
//cata_buffer[0].i_links_count += 1;
cata_buffer[0].i_mode = DIRMODE;
cata_buffer[0].i_ino = start_i;
disk_write(cata_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
free(int_buffer);
}
}
}
else //已经分配了二级指针
{
int * int_buffer = (int *)malloc(BLOCK_SIZE);
disk_read(node_buffer[iloc].i_double_block_pointer, int_buffer);
printf("have had twice pointer\n");
for(int i = 0; i < 1024; i++) //遍历指针块
{
if(find_flag)
break;
if(int_buffer[i] != -1) //该目录块已被分配
{
disk_read(int_buffer[i], cata_buffer);
printf("use twice pointer, cata_db is:%d\n",int_buffer[i]);
for(int j = 0; j < 128; j++)
{
if(strlen(cata_buffer[j].name) == 0) //找到空闲块,挂载
{
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[j].name,myself,strlen(myself));
// strcpy(cata_buffer[j].name,myself);
printf("cata block is: %d, my name is: %s\n",j,cata_buffer[j].name);
//cata_buffer[j].i_links_count += 1;
cata_buffer[j].i_mode = DIRMODE;
cata_buffer[j].i_ino = start_i;
enough_flag = 1;
find_flag = 1;
break;
}
}
disk_write(int_buffer[i],cata_buffer);
}
else if(!find_flag && int_buffer[i] == -1) //需要分配新的目录块
{
int dir_db = find_dmap();
int_buffer[i] = dir_db;
disk_read(dir_db, cata_buffer);
printf("new twice cata, cata_db is:%d\n",dir_db);
printf("strlen:%d\n",strlen(myself));
memcpy(cata_buffer[0].name,myself,strlen(myself));
// strcpy(cata_buffer[0].name,myself);
printf("cata block is: %d, my name is: %s\n",0,cata_buffer[0].name);
//cata_buffer[0].i_links_count += 1;
cata_buffer[0].i_mode = DIRMODE;
cata_buffer[0].i_ino = start_i;
disk_write(dir_db,cata_buffer);
enough_flag = 1;
find_flag = 1;
// 更新父目录的inode
node_buffer[iloc].i_blocks_count += 1;
break;
}
}
free(int_buffer);
}
if(!enough_flag) //如果没有足够空间
{
return -ENOSPC;
}
node_buffer[iloc].i_size += sizeof(catalog);
printf("mount dir is finished\n");
// 修改父目录inode
printf("%d %d %d\n", node_buffer[iloc].i_mode, node_buffer[iloc].i_size, node_buffer[iloc].i_atime);
node_buffer[iloc].i_links_count += 1;
node_buffer[iloc].i_atime = time(NULL);
node_buffer[iloc].i_mtime = time(NULL);
//将父目录inode写回磁盘中
if(disk_write(blk, node_buffer))
printf("fail to write parent inode\n");
//将父目录db写回磁盘中
// if(disk_write(cata_db,cata_buffer))
// printf("fail to write parent datablock\n");
// printf("write parent is finished\n");
// printDirInode(parent_ino); //检验是否挂载成功
// free(Imap);
// free(Dmap);
free(Inode_buffer);
free(node_buffer);
free(cata_buffer);
printf("Mkdir is finished:%s\n",path);
return 0;
}
// 删除一个目录文件
int fs_rmdir (const char *path)
{
printf("Rmdir is called:%s\n",path);
//找到父目录,更新父目录的ctime与mtime,将该文件从父目录的db中删除,父目录的link数减一
char myself[24]; //自己的文件名
Inode node_buffer = (Inode)malloc(BLOCK_SIZE); //4KB空间用于存放得到的inode
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE); //4KB空间用于存放得到的catalog
int parent_ino = find_parent(path,myself); //找到父目录inumber
if(parent_ino < 0)
{
printf("(Rmdir) Cannot find parent path: %s\n", path);
return -ECHILD;
}
char** temp;
temp = getpath(path,temp); //解析目录
int file_ino = find_target(temp); //找到自己的ino
if(file_ino < 0)
{
printf("(Rmdir) Cannot find path: %s\n", path);
return -ENOENT;
}
printf("(Rmdir) need to remove found (%s) inodeId %d\n", myself, file_ino);
printf("(Rmdir) parent found inodeId %d\n", parent_ino);
// 读取父目录的inode
int blk = (parent_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((parent_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(blk, node_buffer);
// 找到父目录的db
int cata_db = node_buffer[iloc].i_block_pointer[0];
printf("(Rmdir):cata_db is: %d\n",cata_db);
// 访问父目录db
disk_read(cata_db,cata_buffer);
// 修改父目录ctime和mtime
node_buffer[iloc].i_ctime = time(NULL);
node_buffer[iloc].i_mtime = time(NULL);
// 父目录link - 1
node_buffer[iloc].i_size -= sizeof(catalog);
node_buffer[iloc].i_links_count -= 1;
// 目录从父目录的db中删除
int j = 0;
for(int i = 0; i < 128; i++) //父目录中的该目录
{
if(!strcmp(cata_buffer[i].name,myself)) //找到该目录
{
printf("block is: %d, my name is: %s\n",i,cata_buffer[i].name);
file_ino = cata_buffer[i].i_ino;
strcpy(cata_buffer[i].name,"");
//cata_buffer[i].i_links_count = 0;
cata_buffer[i].i_ino = -5;
break;
}
}
// 将父目录的Inode和db写回磁盘
disk_write(blk, node_buffer);
disk_write(cata_db, cata_buffer);
// 访问本文件的Inode
blk = (file_ino * INODE_SIZE) / BLOCK_SIZE + 4;
iloc = ((file_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(blk, node_buffer);
// 清除本文件的Inode信息
node_buffer[iloc].i_size = 0;
node_buffer[iloc].i_links_count = 0;
node_buffer[iloc].i_blocks_count = 0;
// 释放本文件占据的db(置为0)(此时清除对应的Dmap),之后清除Imap
// 释放本文件的全部db(其实就是分配的目录db)
cleardb(&node_buffer[iloc]);
printf("finish clear db\n");
disk_write(blk, node_buffer);
// 修改Imap
clearimap(file_ino);
printf("finish clear imap\n");
free(node_buffer);
free(cata_buffer);
return 0;
}
void FuncOutputBin(unsigned int value) //打印二进制
{
int binaryNum[32] = {0};
int i = 0;
while(value > 0)
{
binaryNum[i] = value % 2;
value = value / 2;
i++;
}
for(int j = 31; j >= 0; j--)
printf("%d",binaryNum[j]);
printf("\n");
}
void cleardb(Inode current) //给定inode,清除它的所有db,并且清除对应的inode指针
{
printf("start cleardb\n");
int file_db;
int dir_db;
int dmap_i, dmap_j;
unsigned int mask_one = 1<<31; //最高位为1的掩码,进行无符号位移
FuncOutputBin(mask_one);
int* Dmap = (int*)malloc(DMAP_SIZE);
disk_read(2,Dmap);
disk_read(3,Dmap + (DMAP_SIZE) / 2);
char* buffer = (char*)malloc(BLOCK_SIZE);
memset(buffer, 0, BLOCK_SIZE);
int* dir_buffer = (int*)malloc(BLOCK_SIZE);
for(int i = 0; i < current->i_blocks_count; i++)
{
if(i < 18) //一级指针链接
{
file_db = current->i_block_pointer[i];
disk_write(file_db,buffer); //清空该块中的数据
dmap_i = file_db/32;
dmap_j = file_db%32;
printf("file ino:%d dmap_i: %d dmap_j: %d\n",file_db,dmap_i,dmap_j);
FuncOutputBin(Dmap[dmap_i]);
mask_one = mask_one >> dmap_j; //00001000
FuncOutputBin(mask_one);
mask_one = ~mask_one; //11110111
FuncOutputBin(mask_one);
Dmap[dmap_i] = Dmap[dmap_i] & mask_one; //将第i个数字的第j位置0
FuncOutputBin(Dmap[dmap_i]);
current->i_block_pointer[i] = -1;
}
else //二级指针链接
{
dir_db = current->i_double_block_pointer; //指针块,块中存放着指向数据块的指针
// 读取指针块
disk_read(dir_db,dir_buffer);
// 释放db块
file_db = dir_buffer[i-18];
disk_write(file_db,buffer);
dmap_i = file_db/32;
dmap_j = file_db%32;
mask_one = mask_one >> dmap_j; //00001000
mask_one = ~mask_one; //11110111
Dmap[dmap_i] = Dmap[dmap_i] & mask_one; //将第i个数字的第j位置0
}
}
if(current->i_blocks_count > 18) //释放二级指针块
{
file_db = current->i_double_block_pointer;
disk_write(file_db,buffer);
dmap_i = file_db/32;
dmap_j = file_db%32;
mask_one = mask_one >> dmap_j; //00001000
mask_one = ~mask_one; //11110111
Dmap[dmap_i] = Dmap[dmap_i] & mask_one; //将第i个数字的第j位置0
current->i_double_block_pointer = -1;
}
current->i_blocks_count = 0; //清空指针数量
//将dmap写回磁盘中
disk_write(2,Dmap);
disk_write(3,Dmap + (DMAP_SIZE) / 2);
free(Dmap);
free(buffer);
free(dir_buffer);
}
void clearimap(int file_ino) //给定Inode的ino,清除它的imap标志
{
printf("start clear imap\n");
int imap_i,imap_j;
unsigned int mask_one = 1<<31;
FuncOutputBin(mask_one);
int* Imap = (int*)malloc(IMAP_SIZE);
disk_read(1,Imap);
imap_i = file_ino/32;
imap_j = file_ino%32;
printf("imap_i:%d imp_j:%d\n",imap_i,imap_j);
FuncOutputBin(Imap[imap_i]);
mask_one = mask_one >> imap_j; //00001000
FuncOutputBin(mask_one);
mask_one = ~mask_one; //11110111
FuncOutputBin(mask_one);
Imap[imap_i] = Imap[imap_i] & mask_one; //将第i个数字的第j位置0
FuncOutputBin(Imap[imap_i]);
disk_write(1,Imap);
free(Imap);
}
// 删除一个常规文件
int fs_unlink (const char *path)
{
printf("Unlink is callded:%s\n",path);
char* myself = (char*)malloc(32*sizeof(char)); //自己的文件名
Inode node_buffer = (Inode)malloc(BLOCK_SIZE); //4KB空间用于存放得到的inode
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE); //4KB空间用于存放得到的catalog
int parent_ino = find_parent(path,myself); //找到父目录inumber
if(parent_ino < 0)
{
printf("(Unlink) Cannot find parent path: %s\n", path);
return -ECHILD;
}
char** temp;
temp = getpath(path,temp); //解析目录
int file_ino = find_target(temp); //找到自己的ino
if(file_ino < 0)
{
printf("(Unlink) Cannot find path: %s\n", path);
return -ENOENT;
}
printf("(Unlink) need to remove found (%s) inodeId %d\n", myself, file_ino);
printf("(Unlink) parent found inodeId %d\n", parent_ino);
// 读取父目录的inode
int blk = (parent_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((parent_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
if(disk_read(blk, node_buffer))
printf("fail to read target inode\n");
// 找到父目录的db
int cata_db = node_buffer[iloc].i_block_pointer[0];
printf("(Unlink):cata_db is: %d\n",cata_db);
// 访问父目录db
disk_read(cata_db,cata_buffer);
// 修改父目录ctime和mtime
node_buffer[iloc].i_ctime = time(NULL);
node_buffer[iloc].i_mtime = time(NULL);
// 父目录link - 1
node_buffer[iloc].i_links_count -= 1;
// 文件从父目录的db中删除
for(int i = 0; i < 128; i++) //父目录中的该文件
{
if(!strcmp(cata_buffer[i].name,myself)) //找到该文件
{
printf("block is: %d, my name is: %s\n",i,cata_buffer[i].name);
file_ino = cata_buffer[i].i_ino;
strcpy(cata_buffer[i].name,"");
//cata_buffer[i].i_links_count = 0;
cata_buffer[i].i_ino = -5;
break;
}
}
// 将父目录的Inode和db写回磁盘
disk_write(blk, node_buffer);
disk_write(cata_db, cata_buffer);
// 访问本文件的Inode
blk = (file_ino * INODE_SIZE) / BLOCK_SIZE + 4;
iloc = ((file_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(blk, node_buffer);
// 释放本文件占据的db(置为0)(此时清除对应的Dmap),之后清除Imap
// 释放本文件的全部db
cleardb(&node_buffer[iloc]);
// 清除本文件的Inode信息
node_buffer[iloc].i_size = 0;
node_buffer[iloc].i_links_count = 0;
node_buffer[iloc].i_blocks_count = 0;
disk_write(blk,node_buffer);
// 修改Imap
clearimap(file_ino);
return 0;
}
// 更改一个目录文件或常规文件的名称(及/或路径)
int fs_rename (const char *oldpath, const char *newpath)
{
printf("Rename is called:%s\n",newpath);
int oldparent, newparent;
char* oldname = (char*)malloc(32 * sizeof(char));
char* newname = (char*)malloc(32 * sizeof(char));
oldparent = find_parent(oldpath,oldname);
if(oldparent < 0)
{
printf("(Rename:)Cannot find old parent\n");
return -ECHILD;
}
newparent = find_parent(newpath,newname);
if(newparent < 0)
{
printf("(Rename:)Cannot find new parent\n");
return -ECHILD;
}
printf("oldparent ino:%d newparent ino:%d\n",oldparent,newparent);
printf("oldname: %s newname:%s\n",oldname,newname);
int o_blk = ((oldparent * INODE_SIZE) / BLOCK_SIZE) + 4;
int o_sec = ((oldparent * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
int n_blk = ((newparent * INODE_SIZE) / BLOCK_SIZE) + 4;
int n_sec = ((newparent * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
int cata_db;
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE);
Inode old_buffer = (Inode)malloc(BLOCK_SIZE);
Inode new_buffer = (Inode)malloc(BLOCK_SIZE);
disk_read(o_blk,old_buffer);
disk_read(n_blk,new_buffer);
int flag = 0;
if(oldparent == newparent) //父路径不变,只修改名字
{
printf("just change name\n");
for(int i = 0; i < old_buffer[o_sec].i_blocks_count; i++)
{
if(i < 18)
{
cata_db = old_buffer[o_sec].i_block_pointer[i];
disk_read(cata_db,cata_buffer);
for(int j = 0; j < 128; j++)
{
if(!strcmp(oldname,cata_buffer[j].name)) //find old name
{
strcpy(cata_buffer[j].name,newname);
flag = 1;
break;
}
}
disk_write(cata_db,cata_buffer);
}
else
{
cata_db = old_buffer[o_sec].i_double_block_pointer;
int * dir_buffer = (int *)malloc(BLOCK_SIZE);
disk_read(cata_db, dir_buffer);
disk_read(dir_buffer[i - 18 - 1], cata_buffer);
for(int j = 0; j < 128; j++)
{
if(strcmp(cata_buffer[j].name, oldname) == 0)
{
strcpy(cata_buffer[j].name, newname);
flag = 1;
break;
}
}
disk_write(dir_buffer[i - 18 - 1], cata_buffer);
free(dir_buffer);
}
if(flag)
break;
}
old_buffer[o_sec].i_ctime = time(NULL);
old_buffer[o_sec].i_mtime = time(NULL);
disk_write(o_blk,old_buffer);
}
else //删除就路径,更改为新路径
{
printf("change path start\n");
catalog target_node;
// 遍历旧路径db寻找待改路径文件/目录
for(int i = 0; i < old_buffer[o_sec].i_blocks_count; i++)
{
if(i < 18)
{
disk_read(old_buffer[o_sec].i_block_pointer[i], cata_buffer);
for(int j = 0; j < 128; j++)
{
if(strcmp(cata_buffer[j].name, oldname) == 0){
// 复制旧文件/目录的dir_node
target_node.i_ino = cata_buffer[j].i_ino;
target_node.i_mode = cata_buffer[j].i_mode;
strcpy(target_node.name, newname);
// 将旧文件/目录的dir_node从旧的路径中删除
cata_buffer[j].i_ino = -5;
cata_buffer[j].i_mode = 0;
// 更新父目录db
disk_write(old_buffer[o_sec].i_block_pointer[i], cata_buffer);
flag = 1;
break;
}
}
}
else
{
cata_db = old_buffer[o_sec].i_double_block_pointer;
int * dir_buffer = (int *)malloc(BLOCK_SIZE);
disk_read(cata_db, dir_buffer);
disk_read(dir_buffer[i - 18 - 1], cata_buffer);
for(int j = 0; j < 128; j++)
{
if(strcmp(cata_buffer[j].name, oldname) == 0)
{
// 复制旧文件/目录的dir_node
target_node.i_ino = cata_buffer[j].i_ino;
target_node.i_mode = cata_buffer[j].i_mode;
strcpy(target_node.name, newname);
// 将旧文件/目录的dir_node从旧的路径中删除
cata_buffer[j].i_ino = -5;
cata_buffer[j].i_mode = 0;
// 更新父目录db
disk_write(dir_buffer[i - 18 - 1], cata_buffer);
flag = 1;
break;
}
}
}
if(flag) break;
}
// 更新旧路径inode
old_buffer[o_sec].i_links_count -= 1;
old_buffer[o_sec].i_mtime = time(NULL);
old_buffer[o_sec].i_ctime = time(NULL);
disk_write(o_blk, old_buffer);
// 将target node加入新路径
// 遍历新路径db寻找是否有空位写入dir_node
int flag = 0;
for(int i = 0; i < new_buffer[n_sec].i_blocks_count; i++)
{
if(i < 18)
{
disk_read(new_buffer[n_sec].i_block_pointer[i], cata_buffer);
for(int j = 0; j < 128; j++)
{
if(strlen(cata_buffer[j].name) == 0)
{
// 写入旧文件/目录的dir_node
cata_buffer[j].i_ino = target_node.i_ino;
cata_buffer[j].i_mode = target_node.i_mode;
strcpy(cata_buffer[j].name, target_node.name);
flag = 1;
break;
}
}
disk_write(new_buffer[n_sec].i_block_pointer[i], cata_buffer);
if(flag) break;
}
else{
cata_db = new_buffer[n_sec].i_double_block_pointer;
int * int_buffer = (int *)malloc(sizeof(int) * 1024);
disk_read(cata_db, int_buffer);
disk_read(int_buffer[i - 18 - 1], cata_buffer);
for(int j = 0; j < 128; j++)
{
if(strlen(cata_buffer[j].name) == 0)
{
// 写入旧文件/目录的dir_node
cata_buffer[j].i_ino = target_node.i_ino;
cata_buffer[j].i_mode = target_node.i_mode;
strcpy(cata_buffer[j].name, target_node.name);
flag = 1;
break;
}
}
// 更新新路径db
disk_write(int_buffer[i - 18 - 1], cata_buffer);
}
if(flag) break;
}
if(!flag)
{ // 需要开辟新的db
if(new_buffer[n_sec].i_links_count < 18)
{
int new_db = find_dmap();
printf("new db:%d\n",new_db);
if(new_db > 0){
new_buffer[n_sec].i_block_pointer[new_buffer[n_sec].i_links_count] = new_db;
new_buffer[n_sec].i_blocks_count += 1;
disk_read(new_db, cata_buffer);
cata_buffer[0].i_ino = target_node.i_ino;
cata_buffer[0].i_mode = target_node.i_mode;
strcpy(cata_buffer[0].name, target_node.name);
disk_write(new_db, cata_buffer);
}
else return -ENOSPC;
}
else if(new_buffer[n_sec].i_links_count == 18){
int new_db = find_dmap();
printf("new db:%d\n",new_db);
if(new_db < 0) return -ENOSPC;
new_buffer[n_sec].i_double_block_pointer = new_db;
int * int_buffer = (int *)malloc(sizeof(int) * 1024);
disk_read(new_db, int_buffer);
new_db = find_dmap();
if(new_db < 0) return -ENOSPC;
int_buffer[0] = new_db;
disk_read(int_buffer[0], cata_buffer);
cata_buffer[0].i_ino = target_node.i_ino;
cata_buffer[0].i_mode = target_node.i_mode;
strcpy(cata_buffer[0].name, target_node.name);
disk_write(int_buffer[0], cata_buffer);
disk_write(new_buffer[n_sec].i_double_block_pointer, int_buffer);
new_buffer[n_sec].i_blocks_count += 2;
free(int_buffer);
}
else{
int flag1 = 0;
int * int_buffer = (int *)malloc(sizeof(int) * 1024);
disk_read(new_buffer[n_sec].i_double_block_pointer, int_buffer);
for(int k = 0; k < 1024; k++){
if(k > 0 && int_buffer[k] <= 0 && int_buffer[k - 1] > 0){
// 需要开辟新的db
int new_db = find_dmap();
printf("new db:%d\n",new_db);
if(new_db < 0) return -ENOSPC;
int_buffer[k] = new_db;
new_buffer[n_sec].i_blocks_count += 1;
disk_write(new_buffer[n_sec].i_double_block_pointer, int_buffer);
disk_read(new_db, cata_buffer);
cata_buffer[0].i_ino = target_node.i_ino;
cata_buffer[0].i_mode = target_node.i_mode;
strcpy(cata_buffer[0].name, target_node.name);
disk_write(new_db, cata_buffer);
break;
}
}
}
}
// 更新新路径inode
new_buffer[n_sec].i_links_count += 1;
disk_write(n_blk, new_buffer);
free(old_buffer);
free(new_buffer);
free(cata_buffer);
}
return 0;
}
// 分配Dmap,写入数据并写入磁盘
int writenewdb(char* buf)
{
int start_d = find_dmap(); //寻找Dmap的空位并写Dmap
int blk = start_d; //db所在的block
printf("write db blk:%d\n",blk);
if(start_d < 0)
exit(0);
disk_write(blk,buf); //将buffer写入disk
printf("finish write new db\n");
return blk; //返回新分配的block id
}
void write_datablock(Inode inode, char* buf, int size)
{
printf("start write_datablock\n");
char* current = buf;
int cur_blk;
int* dir_db = (int*)malloc(BLOCK_SIZE);
memset(dir_db, 0, BLOCK_SIZE);
while(current - buf < size) //循环写入新块
{
cur_blk = writenewdb(current); //分配并写入新块
current += BLOCK_SIZE; //更新下次写的起始位置
if(inode->i_blocks_count < 18)
{
inode->i_block_pointer[inode->i_blocks_count] = cur_blk;
inode->i_blocks_count += 1;
}
else if(inode->i_blocks_count == 18)
{
// 分配一个二级指针块
dir_db[inode->i_blocks_count - 18] = cur_blk; //设置二级指针
int dir_blk = writenewdb((char*)dir_db); //写入二级指针
inode->i_double_block_pointer = dir_blk; //指向二级指针
inode->i_blocks_count += 1;
}
else
{
int dir_blk = inode->i_double_block_pointer; //找到二级指针
disk_read(dir_blk, dir_db); //读取二级指针
dir_db[inode->i_blocks_count - 18] = cur_blk; //设置二级指针
disk_write(dir_blk, dir_db); //写入二级指针
inode->i_blocks_count += 1;
}
}
free(dir_db);
}
int create_file(const char* path)
{
printf("start create_file:%s\n",path);
// 遍历查找Imap中第一个空位并写
int start_i = find_imap();
printf("find imap is finished,start_i is %d\n",start_i);
if(start_i < 0)
exit(0);
//创建inode
Inode Inode_buffer = (Inode)malloc(BLOCK_SIZE);
int i_blk = ((start_i * INODE_SIZE) / BLOCK_SIZE) + 4;
int i_sec = ((start_i * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("i_blk: %d i_sec: %d\n",i_blk,i_sec);
disk_read(i_blk,Inode_buffer);
Inode_buffer[i_sec].i_mode = REGMODE;
Inode_buffer[i_sec].i_links_count = 0;
Inode_buffer[i_sec].i_size = 0;
Inode_buffer[i_sec].i_atime = time(NULL);
Inode_buffer[i_sec].i_mtime = time(NULL);
Inode_buffer[i_sec].i_ctime = time(NULL);
Inode_buffer[i_sec].i_blocks_count = 0;
for(int i = 0; i < 18; i++)
Inode_buffer[i_sec].i_block_pointer[i] = -1;
Inode_buffer[i_sec].i_double_block_pointer = -1;
// Inode_buffer[i_sec].i_block_pointer[0] = start_d;
//将Inode写回磁盘中
disk_write(i_blk,Inode_buffer);
printf("write inode is finished\n");
//super_block更新
super_block->file_count += 1;
printf("create inode is finished\n");
//将该目录挂载在父目录下
char* myself = (char*)malloc(32*sizeof(char)); //自己的文件名
Inode node_buffer = (Inode)malloc(BLOCK_SIZE); //4KB空间用于存放得到的inode
Catalog cata_buffer = (Catalog)malloc(BLOCK_SIZE); //4KB空间用于存放得到的catalog
// 分离父目录与子目录名, 并调用getattr()获取新创建目录的上一级目录信息
char temp[2560];
strcpy(temp, path);
// 提取新目录名, 分离父目录
for(int i = strlen(temp) - 2; i >= 0; i--){
if(temp[i] == '/'){
temp[i] = '\0';
strcpy(myself, temp + i + 1);
break;
}
}
// 若path只有新目录名无父目录, 则父目录为根目录root
if(strlen(temp) == 0){
temp[0] = '/';
temp[1] = '\0';
}
printf("parent path:%s\n",temp);
// 查询父目录信息
int parent_ino = cur_find(temp);
if(parent_ino < 0)
{
printf("(Create file): Cannot find path: %s\n", path);
return -ECHILD;
}
printf("find parent is finished\n");
// 读取父目录的inode
int blk = (parent_ino * INODE_SIZE) / BLOCK_SIZE + 4;
int iloc = ((parent_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
printf("parent blk:%d parent iloc:%d\n",blk,iloc);
disk_read(blk, node_buffer);
// 找到父目录的db
int cata_db = node_buffer[iloc].i_block_pointer[0];
printf("(Create file):cata_db is: %d\n",cata_db);
// 访问父目录db
disk_read(cata_db,cata_buffer);
// 挂载文件
int enough_flag = 0;
for(int i = 0; i < 128; i++) //寻找父目录的第一个空闲cata
{
if(strlen(cata_buffer[i].name) == 0)
{
strcpy(cata_buffer[i].name,myself);
printf("block is: %d, my name is: %s\n",i,cata_buffer[i].name);
//cata_buffer[i].i_links_count += 1;
cata_buffer[i].i_mode = REGMODE;
cata_buffer[i].i_ino = start_i;
enough_flag = 1;
break;
}
}
if(!enough_flag) //如果没有足够空间
{
return -ENOSPC;
}
printf("mount dir is finished\n");
// 修改父目录inode
printf("%d %d %d\n", node_buffer[iloc].i_mode, node_buffer[iloc].i_size, node_buffer[iloc].i_atime);
node_buffer[iloc].i_links_count += 1;
node_buffer[iloc].i_atime = time(NULL);
node_buffer[iloc].i_mtime = time(NULL);
//将父目录inode写回磁盘中
if(disk_write(blk, node_buffer))
printf("fail to write parent inode\n");
//将父目录db写回磁盘中
if(disk_write(cata_db,cata_buffer))
printf("fail to write parent datablock\n");
printf("write parent is finished\n");
printDirInode(parent_ino); //检验是否挂载成功
free(Inode_buffer);
free(node_buffer);
free(cata_buffer);
printf("Create file is finished:%s\n",path);
return start_i;
}
int fs_write (const char *path, const char *buffer, size_t size, off_t offset, struct fuse_file_info *fi)
{
printf("Write is called:%s\n",path);
int wmode = fi->flags;
// 若是只读模式则退出
if(wmode & O_RDONLY)
return -EACCES;
// 若要写的字节数超过文件最大容量则退出
if(size > MAX_SIZE)
return -EACCES;
// char* file = (char*)malloc(MAX_SIZE); //用来存放buf的空间
Inode node_buffer = (Inode)malloc(BLOCK_SIZE);
int i_blk,sec,file_size;
char** temp;
temp = getpath(path,temp); //解析目录
int file_ino = find_target(temp); //获得要写的文件的inumber
if(file_ino < 0) //该文件还未被创建
{
printf("file hasn't been created\n");
file_ino = create_file(path); //创建新文件
i_blk = ((file_ino * INODE_SIZE) / BLOCK_SIZE) + 4;
sec = ((file_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(i_blk,node_buffer);
file_size = size;
write_datablock(&node_buffer[sec],buffer,size); // 将文件写入db
}
else
{
printf("file is exist\n");
if(wmode & O_EXCL)
{
if(wmode & O_CREAT)
return -EEXIST;
}
i_blk = ((file_ino * INODE_SIZE) / BLOCK_SIZE) + 4;
sec = ((file_ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
disk_read(i_blk,node_buffer);
file_size = node_buffer[sec].i_size;
if(wmode & O_APPEND) //若追加写
{
if(wmode & O_TRUNC) //覆盖写
{
file_size = size; //修改文件大小
cleardb(&node_buffer[sec]); //清空该文件的db
write_datablock(&node_buffer[sec],buffer,size); // 将文件写入db
}
else
{
char* tempBlock = (char*)malloc(BLOCK_SIZE);
int aline = file_size % BLOCK_SIZE;
file_size += size; //修改文件大小
int remain_size = size; //剩余要写入的文件大小
if(aline != 0)
{
if(node_buffer[sec].i_blocks_count <= 18)
{
int blk = node_buffer[sec].i_block_pointer[node_buffer[sec].i_blocks_count - 1];
disk_read(blk, tempBlock);
memcpy(tempBlock + aline, buffer, BLOCK_SIZE - aline);
disk_write(blk, tempBlock);
buffer += BLOCK_SIZE - aline;
remain_size -= BLOCK_SIZE - aline;
}
else
{
int dir_blk = node_buffer[sec].i_double_block_pointer;
disk_read(dir_blk, tempBlock);
int dir_num = ((int *)tempBlock)[node_buffer[sec].i_blocks_count - 14 - 1];
disk_read(dir_num, tempBlock);
memcpy(tempBlock + aline, buffer, BLOCK_SIZE - aline);
disk_write(dir_num, tempBlock);
buffer += BLOCK_SIZE - aline;
remain_size -= BLOCK_SIZE - aline;
}
}
if(remain_size > 0) //写入剩余的整齐数据
{
write_datablock(&node_buffer[sec],buffer,remain_size); // 将文件写入db
}
free(tempBlock);
}
}
else
{
file_size = offset + size;
if(size > 0)
write_datablock(&node_buffer[sec],buffer,size);
}
}
node_buffer[sec].i_size = file_size;
node_buffer[sec].i_ctime = time(NULL);
node_buffer[sec].i_mtime = time(NULL);
disk_write(i_blk,node_buffer);
// free(file);
free(node_buffer);
return size;
}
int fs_truncate (const char *path, off_t size)
{
// 根据path找到attr
// 根据inumber找到inode
// 读取inode
// 修改size、ctime
// 在修改size的时候判断剩余空间
// 写回inode
printf("Truncate is called:%s\n",path);
struct stat attr;
fs_getattr(path, &attr);
if(attr.st_mode == DIRMODE){
printf("this is not a file!\n");
return -EISDIR;
}
int ino = attr.st_ino;
int blk = ((ino * INODE_SIZE) / BLOCK_SIZE) + 4;
int sec = ((ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
Inode inode_buffer = (Inode)malloc(BLOCK_SIZE);
disk_read(blk, inode_buffer);
inode_buffer[sec].i_ctime = time(NULL);
if(size > MAX_SIZE)
return -ENOSPC;
inode_buffer[sec].i_size = size;
if(size == 0)
cleardb(&inode_buffer[sec]);
disk_write(blk, inode_buffer);
free(inode_buffer);
return 0;
}
int fs_utime (const char *path, struct utimbuf *buffer)
{
printf("Utime is called:%s\n",path);
struct stat attr;
fs_getattr(path, &attr);
if(attr.st_mode == DIRMODE){
printf("this is not a file!\n");
return -EISDIR;
}
int ino = attr.st_ino;
int blk = ((ino * INODE_SIZE) / BLOCK_SIZE) + 4;
int sec = ((ino * INODE_SIZE) % BLOCK_SIZE) / INODE_SIZE;
Inode inode_buffer = (Inode)malloc(sizeof(inode) * 32);
disk_read(blk, inode_buffer);
inode_buffer[sec].i_ctime = time(NULL);
inode_buffer[sec].i_atime = buffer->actime;
inode_buffer[sec].i_mtime = buffer->modtime;
disk_write(blk, inode_buffer);
free(inode_buffer);
// free(attr);
return 0;
}
int fs_statfs (const char *path, struct statvfs *stat)
{
printf("Statfs is called:%s\n",path);
/*
unsigned long f_bsize; //块大小
fsblkcnt_t f_blocks; //块数量
fsblkcnt_t f_bfree; //空闲块数量
fsblkcnt_t f_bavail; //可用块数量
fsfilcnt_t f_files; //文件节点数
fsfilcnt_t f_ffree; //空闲节点数
fsfilcnt_t f_favail; //可用节点数
unsigned long f_namemax; //文件名长度上限
*/
stat->f_bsize = BLOCK_SIZE;
stat->f_blocks = BLOCK_NUM;
stat->f_namemax = 24;
int freeblock;
//读取imap与dmap
int* Imap = (int*)malloc(IMAP_SIZE);
int* Dmap = (int*)malloc(DMAP_SIZE); // 8KB
if(disk_read(1,Imap))
printf("fail to read Imap\n");
if(disk_read(2,Dmap))
printf("fail to read Dmap1\n");
if(disk_read(3,Dmap + (DMAP_SIZE) / 2))
printf("fail to read Dmap2\n");
//遍历imap和dmap得到freeblock
int mask_all = ~1 + 1; //全1掩码
int mask_one = 1<<31; //最高位为1的掩码
for(int i = 0; i < 1024; i++)
{
if(Imap[i]^mask_all) //如果Imap[i]没满
{
for(int j = 0; j < 32; j++)
{
if(Imap[i]^(mask_one>>j)) //该位为非空闲位
continue;
else
{
freeblock++; //空闲位数量+1
}
}
}
else
continue;
}
for(int i = 0; i < 2048; i++)
{
if(Dmap[i]^mask_all) //如果Dmap[i]没满
{
for(int j = 0; j < 32; j++)
{
if(Dmap[i]^(mask_one>>j))
continue;
else
{
freeblock++;
}
}
}
else
continue;
}
stat->f_bavail = freeblock;
stat->f_bfree = freeblock;
stat->f_files = super_block->file_count;
stat->f_ffree = FILE_NUM - stat->f_files;
stat->f_favail = FILE_NUM - stat->f_files;
free(Imap);
free(Dmap);
return 0;
}
int fs_open (const char *path, struct fuse_file_info *fi)
{
/*
当你需要访问或修改一个文件或目录时会进行调用。
主要判断当前用户是否有权限读/写这个文件/目录。
本次实验除fs_open外不需要修改。
*/
printf("Open is called:%s\n",path);
// 查询该文件信息
struct stat attr;
fs_getattr(path, &attr);
if(attr.st_mode == DIRMODE) //如果不是文件,则不能打开
return -EISDIR;
// 告知fi inumber
int ino = attr.st_ino;
fi->fh = ino;
int offset = 2;
if(getuid() != attr.st_uid)
{
offset = 1;
if(getgid() != attr.st_gid)
{
offset = 0;
}
}
offset *= 3;
int mask = 0x7;
int perm = (attr.st_mode >> offset) & mask;
int readOK = (perm >> 2) & 1;
int writeOK = (perm >> 1) & 1;
int execOK = perm & 1;
if(!readOK)
{
return -EACCES;
}
if(!writeOK)
{
if(fi->flags & O_WRONLY)
return -EACCES;
if(fi->flags & O_RDWR)
return -EACCES;
if(fi->flags & O_APPEND)
return -EACCES;
}
return 0;
}
//Functions you don't actually need to modify
int fs_release (const char *path, struct fuse_file_info *fi)
{
printf("Release is called:%s\n",path);
return 0;
}
int fs_opendir (const char *path, struct fuse_file_info *fi)
{
printf("Opendir is called:%s\n",path);
return 0;
}
int fs_releasedir (const char * path, struct fuse_file_info *fi)
{
printf("Releasedir is called:%s\n",path);
return 0;
}
static struct fuse_operations fs_operations = {
.getattr = fs_getattr,
.readdir = fs_readdir,
.read = fs_read,
.mkdir = fs_mkdir,
.rmdir = fs_rmdir,
.unlink = fs_unlink,
.rename = fs_rename,
.truncate = fs_truncate,
.utime = fs_utime,
.mknod = fs_mknod,
.write = fs_write,
.statfs = fs_statfs,
.open = fs_open,
.release = fs_release,
.opendir = fs_opendir,
.releasedir = fs_releasedir
};
int main(int argc, char *argv[])
{
if(disk_init())
{
printf("Can't open virtual disk!\n");
return -1;
}
if(mkfs())
{
printf("Mkfs failed!\n");
return -2;
}
if(!mkfs())
{
// char* path = "/dir1";
// mode_t mode = DIRMODE;
// fs_mkdir(path,mode);
}
return fuse_main(argc, argv, &fs_operations, NULL);
}