From f05cf635dabbc7811c26e7631390b83b14086c03 Mon Sep 17 00:00:00 2001 From: wangziao <1575538687@qq.com> Date: Sat, 23 Aug 2025 23:25:27 -0700 Subject: [PATCH] support statfs, check whether target directory is empty and fail on non-empty for rmdir --- include/files.h | 1 + include/fs.hpp | 4 +++- include/fs/fs_data_types.hpp | 3 +++ lib/files.cpp | 40 +++++++++++++++++++++++++++++++----- lib/fischl.cpp | 15 +++++++++++--- lib/fs/datablock_manager.cpp | 3 +++ lib/fs/fs.cpp | 15 ++++++++++++-- lib/fs/fs_data_types.cpp | 6 ++++++ lib/fs/inode_manager.cpp | 2 ++ 9 files changed, 78 insertions(+), 11 deletions(-) diff --git a/include/files.h b/include/files.h index 64c7101..a881bf9 100644 --- a/include/files.h +++ b/include/files.h @@ -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); diff --git a/include/fs.hpp b/include/fs.hpp index 59475c4..d154b7d 100644 --- a/include/fs.hpp +++ b/include/fs.hpp @@ -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, diff --git a/include/fs/fs_data_types.hpp b/include/fs/fs_data_types.hpp index 1305c2d..f165295 100644 --- a/include/fs/fs_data_types.hpp +++ b/include/fs/fs_data_types.hpp @@ -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[]); diff --git a/lib/files.cpp b/lib/files.cpp index a247da6..d019e3f 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -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; -} \ No newline at end of file +} diff --git a/lib/fischl.cpp b/lib/fischl.cpp index f400f32..e8f1c2d 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -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); @@ -315,4 +324,4 @@ int fischl(int argc, char *argv[]) ret = fuse_main(args.argc, args.argv, &fischl_oper, NULL); fuse_opt_free_args(&args); return ret; -} \ No newline at end of file +} diff --git a/lib/fs/datablock_manager.cpp b/lib/fs/datablock_manager.cpp index 2d8ff51..5c2d6a3 100644 --- a/lib/fs/datablock_manager.cpp +++ b/lib/fs/datablock_manager.cpp @@ -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 diff --git a/lib/fs/fs.cpp b/lib/fs/fs.cpp index 92b85cd..f9e3516 100644 --- a/lib/fs/fs.cpp +++ b/lib/fs/fs.cpp @@ -1,7 +1,7 @@ #include "fs.hpp" #include -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); @@ -77,4 +80,12 @@ int Fs::save_inode_list_head(u_int64_t new_inode_list_head) { return err; } 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; } \ No newline at end of file diff --git a/lib/fs/fs_data_types.cpp b/lib/fs/fs_data_types.cpp index 05fc38a..ba343f0 100644 --- a/lib/fs/fs_data_types.cpp +++ b/lib/fs/fs_data_types.cpp @@ -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) { diff --git a/lib/fs/inode_manager.cpp b/lib/fs/inode_manager.cpp index 33166ad..a24571f 100644 --- a/lib/fs/inode_manager.cpp +++ b/lib/fs/inode_manager.cpp @@ -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; }