support statfs, check whether target directory is empty and fail on non-empty for rmdir

This commit is contained in:
wangziao 2025-08-23 23:25:27 -07:00
parent 26b44b20ba
commit f05cf635da
9 changed files with 78 additions and 11 deletions

View File

@ -24,6 +24,7 @@ public:
void unlink_inode(u_int64_t inode_number);
u_int64_t disk_namei(const char* path);
u_int64_t namei(const char* path);
bool dir_empty(u_int64_t inode_number);
int fischl_mkdir(const char*, mode_t);
int fischl_mknod(const char*, mode_t, dev_t);//for special file
int fischl_access(const char* path, int mask);

View File

@ -12,7 +12,7 @@ class DatablockOperation;
class Fs {
public:
Fs(RawDisk *disk, bool load = false);
Fs(RawDisk *disk, bool load, u_int64_t user_inode_blocks = 0);
~Fs();
ssize_t read(INode_Data *inode_data, char buf[], size_t count, size_t offset);
@ -35,6 +35,8 @@ public:
int save_free_list_head(u_int64_t new_free_list_head);
int save_inode_list_head(u_int64_t new_inode_list_head);
void update_num_used_inodes(int delta);
void update_num_used_datablocks(int delta);
int sweep_inode_datablocks(INode_Data *inode_data,
u_int64_t start_block_index, bool allocate,

View File

@ -16,6 +16,9 @@ public:
u_int64_t free_list_head;
u_int64_t inode_list_head;
u_int64_t num_inode_blocks;
u_int64_t num_used_inodes;
u_int64_t num_data_blocks;
u_int64_t num_used_data_blocks;
SuperBlock_Data();
void serialize(char buf[]);
void deserialize(char buf[]);

View File

@ -501,6 +501,25 @@ int FilesOperation::fischl_readdir(const char *path, void *buf,
return 0;
}
bool FilesOperation::dir_empty(u_int64_t inode_number) {
INode_Data inode;
inode.inode_num = inode_number;
fs->inode_manager->load_inode(&inode);
char buffer[IO_BLOCK_SIZE] = {0};
for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) {
fs->read(&inode, buffer, IO_BLOCK_SIZE, idx * IO_BLOCK_SIZE);
DirectoryEntry ent;
for (int i = 0; i <= IO_BLOCK_SIZE - 264; i += 264) {
ent.deserialize(buffer + i);
if (ent.inode_number && strcmp(ent.file_name, ".") &&
strcmp(ent.file_name, "..")) {
return false;
}
}
}
return true;
}
int FilesOperation::fischl_releasedir(const char *path,
struct fuse_file_info *fi) {
if (fischl_load_entry(root_node, path) == NULL)
@ -559,6 +578,16 @@ int FilesOperation::fischl_opendir(const char *path,
}
int FilesOperation::fischl_rmdir(const char *path) {
u_int64_t fh = namei(path);
if (fh == -1) {
return -ENOENT;
}
printf("in rmdir\n");
if(!dir_empty(fh)){
return -ENOTEMPTY;
}
printf("rmdir: not empty\n");
char *pathdup = strdup(path);
char *lastSlash = strrchr(pathdup, '/');
*lastSlash = '\0';
@ -1324,10 +1353,11 @@ int FilesOperation::fischl_utimens(const char *path,
int FilesOperation::fischl_statfs(const char *path, struct statvfs *stbuf) {
stbuf->f_bsize = 4096;
stbuf->f_blocks = 0;
stbuf->f_bfree = 0;
stbuf->f_files = 0;
stbuf->f_ffree = 0;
stbuf->f_frsize = IO_BLOCK_SIZE;
stbuf->f_blocks = fs->superblock.num_data_blocks;
stbuf->f_bfree = fs->superblock.num_data_blocks - fs->superblock.num_used_data_blocks;
stbuf->f_files = fs->superblock.num_inode_blocks * 8;
stbuf->f_ffree = fs->superblock.num_inode_blocks * 8 - fs->superblock.num_used_inodes;
stbuf->f_namemax = 256;
return 0;
}

View File

@ -226,12 +226,21 @@ int fischl(int argc, char *argv[])
printf("WRONG l/n ARGUMENTS\n");
return 0;
}
options.fs = new Fs(options.H);
if(options.load){
options.fs = new Fs(options.H, true);
}
else{
options.fs = new Fs(options.H);
uint64_t total_blocks = options.H->diskSize / IO_BLOCK_SIZE;
uint64_t max_inode_blocks = options.H->diskSize / IO_BLOCK_SIZE - 2 - DATABLOCKS_PER_BITMAP_BLOCK;
printf("The block device contains %llu blocks\n", total_blocks);
printf("Choose the number of blocks to store inodes: 1 ~ %llu\n", max_inode_blocks);
uint64_t user_inode_blocks;
scanf("%llu", &user_inode_blocks);
if (user_inode_blocks < 1 || user_inode_blocks > max_inode_blocks) {
printf("Invalid number of blocks to store inodes\n");
return -1;
}
options.fs = new Fs(options.H, false, user_inode_blocks);
printf("FORMAT %d\n", options.fs->format());
}
options.fsop = new FilesOperation(*options.H, options.fs);

View File

@ -88,6 +88,8 @@ int DataBlock_Manager_Bitmap::new_datablock(u_int64_t *block_num) {
return err;
(*block_num) = block_num_;
fs->update_num_used_datablocks(1);
return 0;
}
@ -119,6 +121,7 @@ int DataBlock_Manager_Bitmap::free_datablock(u_int64_t block_num) {
if ((err = fs->save_free_list_head(bitmap_block_num)) < 0)
return err;
fs->update_num_used_datablocks(-1);
return 0;
// placing almost full bitmaps back at start of freelist is slow

View File

@ -1,7 +1,7 @@
#include "fs.hpp"
#include <assert.h>
Fs::Fs(RawDisk *disk, bool load) : disk(disk) {
Fs::Fs(RawDisk *disk, bool load, uint64_t user_inode_blocks) : disk(disk) {
superblock = SuperBlock_Data();
// Determine the num inode blocks
uint64_t num_inode_blocks = 0; // The superblock is not loaded from disk here; it is done in FilesOperation::initialize called by fischl_init
@ -9,8 +9,11 @@ Fs::Fs(RawDisk *disk, bool load) : disk(disk) {
load_superblock();
num_inode_blocks = superblock.num_inode_blocks;
} else {
num_inode_blocks = (disk->diskSize / IO_BLOCK_SIZE) / 8; // adaptive size
num_inode_blocks = user_inode_blocks;
superblock.num_inode_blocks = num_inode_blocks;
superblock.num_used_inodes = 0;
superblock.num_data_blocks = disk->diskSize / IO_BLOCK_SIZE - 1 - num_inode_blocks;
superblock.num_used_data_blocks = 0;
}
assert((disk->diskSize / IO_BLOCK_SIZE) >
2 + num_inode_blocks + DATABLOCKS_PER_BITMAP_BLOCK);
@ -78,3 +81,11 @@ int Fs::save_inode_list_head(u_int64_t new_inode_list_head) {
}
return 0;
}
void Fs::update_num_used_inodes(int delta) {
superblock.num_used_inodes += delta;
}
void Fs::update_num_used_datablocks(int delta) {
superblock.num_used_data_blocks += delta;
}

View File

@ -44,6 +44,9 @@ void SuperBlock_Data::serialize(char buf[]) {
i += write_u64(free_list_head, &buf[i]);
i += write_u64(inode_list_head, &buf[i]);
i += write_u64(num_inode_blocks, &buf[i]);
i += write_u64(num_used_inodes, &buf[i]);
i += write_u64(num_data_blocks, &buf[i]);
i += write_u64(num_used_data_blocks, &buf[i]);
}
void SuperBlock_Data::deserialize(char buf[]) {
@ -51,6 +54,9 @@ void SuperBlock_Data::deserialize(char buf[]) {
i += read_u64(&free_list_head, &buf[i]);
i += read_u64(&inode_list_head, &buf[i]);
i += read_u64(&num_inode_blocks, &buf[i]);
i += read_u64(&num_used_inodes, &buf[i]);
i += read_u64(&num_data_blocks, &buf[i]);
i += read_u64(&num_used_data_blocks, &buf[i]);
}
INode_Data::INode_Data(u_int64_t inode_num) : inode_num(inode_num) {

View File

@ -88,6 +88,7 @@ int INode_Manager_Freelist::new_inode(u_int64_t uid, u_int64_t gid,
inode_data->inode_num = 0xFFFFFFFFFFFFFFFF;
return err;
}
fs->update_num_used_inodes(1);
return 0;
}
@ -111,6 +112,7 @@ int INode_Manager_Freelist::free_inode(INode_Data *inode_data) {
if ((err = fs->save_inode_list_head(inode_data->inode_num)) < 0)
return err;
fs->update_num_used_inodes(-1);
return 0;
}