From e09e952558337048be7ddbf66314ed5cdea723f7 Mon Sep 17 00:00:00 2001 From: WangZiao Date: Sun, 12 Nov 2023 16:13:45 -0800 Subject: [PATCH 01/63] specify some apis for layer 2 --- include/files.h | 7 +++++++ lib/files.cpp | 1 + 2 files changed, 8 insertions(+) create mode 100644 include/files.h create mode 100644 lib/files.cpp diff --git a/include/files.h b/include/files.h new file mode 100644 index 0000000..fe3adee --- /dev/null +++ b/include/files.h @@ -0,0 +1,7 @@ +#include + +int fischl_mkdir(const char*, mode_t); +int fischl_mknod(const char*, mode_t); +int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); +int fischl_unlink (const char *); +int fischl_open (const char *, struct fuse_file_info *); \ No newline at end of file diff --git a/lib/files.cpp b/lib/files.cpp new file mode 100644 index 0000000..f5b3304 --- /dev/null +++ b/lib/files.cpp @@ -0,0 +1 @@ +#include "files.h" \ No newline at end of file From 46ce866c579b23cfc748bc27d9e2dd7f4fa06634 Mon Sep 17 00:00:00 2001 From: WangZiao Date: Thu, 16 Nov 2023 18:36:35 -0800 Subject: [PATCH 02/63] support creating files and directories, support namei --- CMakeLists.txt | 1 + include/files.h | 24 ++++-- include/fs.h | 4 +- lib/files.cpp | 202 +++++++++++++++++++++++++++++++++++++++++++- test/CMakeLists.txt | 8 +- test/layer2_API.cpp | 66 +++++++++++++++ 6 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 test/layer2_API.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f0c5624..bb170e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(fischl # Header files lib/fischl.cpp lib/main.cpp + lib/files.cpp ) diff --git a/include/files.h b/include/files.h index fe3adee..678cea6 100644 --- a/include/files.h +++ b/include/files.h @@ -1,7 +1,21 @@ #include +#include -int fischl_mkdir(const char*, mode_t); -int fischl_mknod(const char*, mode_t); -int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); -int fischl_unlink (const char *); -int fischl_open (const char *, struct fuse_file_info *); \ No newline at end of file +class FilesOperation { + RawDisk& disk; + INodeOperation inop; + u_int64_t root_inode; + public: + FilesOperation(RawDisk&); + int read_datablock(INode& inode, u_int64_t index, char* buffer); + int write_datablock(INode& inode, u_int64_t index, char* buffer); + void init_inode(u_int64_t inode_number, u_int64_t permissions); + void initialize_rootinode(); + u_int64_t mkfile(u_int64_t parent_inode_number, const char* name, u_int64_t permissions); + u_int64_t namei(const char* path); + u_int64_t fischl_mkdir(const char*, mode_t); + u_int64_t fischl_mknod(const char*, mode_t); + //int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); + //int fischl_unlink (const char *); + //int fischl_open (const char *, struct fuse_file_info *); +}; \ No newline at end of file diff --git a/include/fs.h b/include/fs.h index 63da3f6..c9f6563 100644 --- a/include/fs.h +++ b/include/fs.h @@ -57,16 +57,16 @@ public: }; class INode{ + public: // direct datablocks u_int64_t blocks[48]; // indirect address u_int64_t single_indirect, double_indirect, triple_indirect; // other - u_int64_t uid; u_int64_t gid; u_int64_t permissions; - u_int64_t size; + u_int64_t size; // Number of datablocks u_int64_t block_number; public: diff --git a/lib/files.cpp b/lib/files.cpp index f5b3304..03ca9df 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -1 +1,201 @@ -#include "files.h" \ No newline at end of file +#include "files.h" +#include +#include + +struct DirectoryEntry { + u_int64_t inode_number; + char file_name[56]; + void serialize(char* buffer) { + u_int64_t t = inode_number; + for (int j = 0; j < 8; j++){ + buffer[j] = t & (((u_int64_t)1<<(8))-1); + t >>= 8; + } + strcpy(buffer+8, file_name); + } + void deserialize(char* buffer) { + inode_number = 0; + for (int j = 0; j < 8; j++) + inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); + strcpy(file_name, buffer+8); + } +}; + +FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { + disk = disk_; + inop.initialize(disk_); +} + +int FilesOperation::read_datablock(INode& inode, u_int64_t index, char* buffer) { + if (index >= inode.size) { + printf("Read datablock out of range, inode number %llu", inode.block_number); + return -1; + } + if (index < 48) { + return disk.rawdisk_read(inode.blocks[index], buffer, IO_BLOCK_SIZE); + } else { + perror("Read indirect datablocks not implemented yet"); + return -1; + } +} + +int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) { + while (index >= inode.size) { + u_int64_t ret = inode.datablock_allocate(disk); + inode.size += 1; + } + if (index < 48) { + return disk.rawdisk_write(inode.blocks[index], buffer, IO_BLOCK_SIZE); + } else { + perror("Write indirect datablocks not implemented yet"); + return -1; + } +} + +void FilesOperation::init_inode(u_int64_t inode_number, u_int64_t permissions) { + // zero out disk space of inode, because in memory inode is uninitialized by default + char buffer[SECTOR_SIZE] = {0}; + disk.rawdisk_write(inode_number*SECTOR_SIZE, buffer, sizeof(buffer)); + INode inode; + inode.inode_construct(inode_number, disk); + inode.block_number = inode_number; + inode.permissions = permissions; + inode.inode_save(disk); +} + +void FilesOperation::initialize_rootinode() { + // this method must be called explicitly right after initializion + root_inode = inop.inode_allocate(disk); + printf("Info: root inode number: %llu\n", root_inode); + init_inode(root_inode, 1); +} + +u_int64_t FilesOperation::mkfile(u_int64_t parent_inode_number, const char* name, u_int64_t permissions) { + // trys to create a file under parent directory + if (strlen(name)>=56) { + perror("Name too long, cannot create file or directory"); + return -1; + } + INode inode; + inode.inode_construct(parent_inode_number, disk); + if (inode.permissions != 1) { + printf("Parent Inode is not a directory\n"); + return -1; + } + char buffer[IO_BLOCK_SIZE] = {0}; + if (inode.size > 0) read_datablock(inode, 0, buffer); + + // do create inode + u_int64_t new_inode_number = 0; + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-64;i+=64){ + ent.deserialize(buffer+i); + if (ent.inode_number == 0) { + new_inode_number = inop.inode_allocate(disk); + ent.inode_number = new_inode_number; + strcpy(ent.file_name, name); + ent.serialize(buffer+i); + break; + } + } + if (new_inode_number == 0) { + perror("Failed to create file in directory: First datablock full"); + return -1; + } else { + write_datablock(inode, 0, buffer); + } + inode.inode_save(disk); + + // initialize new file + init_inode(new_inode_number, permissions); + + return new_inode_number; +} + +u_int64_t FilesOperation::namei(const char* path) { + // returns the inode number corresponding to path + u_int64_t current_inode = root_inode; + std::string current_dirname; + std::istringstream pathStream(path); + std::string new_name; + std::getline(pathStream, new_name, '/'); + if(!new_name.empty()){ + printf("namei: path should start with /\n"); + return -1; + } + while (std::getline(pathStream, new_name, '/')) { + INode inode; + inode.inode_construct(current_inode, disk); + if (inode.permissions != 1 || inode.size == 0) { + printf("namei: %s is not a non-empty directory\n", current_dirname.c_str()); + return -1; + } + char buffer[IO_BLOCK_SIZE] = {0}; + read_datablock(inode, 0, buffer); + u_int64_t new_inode_number = 0; + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-64;i+=64){ + ent.deserialize(buffer+i); + if (strcmp(ent.file_name, new_name.c_str()) == 0) { + new_inode_number = ent.inode_number; + break; + } + } + if (!new_inode_number) { + printf("namei: no name matching %s under directory %s\n", new_name.c_str(), current_dirname.c_str()); + return -1; + } + current_inode = new_inode_number; + current_dirname = new_name; + } + return current_inode; + // path = "/" should return root_inode + // path = "/foo.txt" should return inode for foo.txt + // path = "/mydir" should return inode for mydir + // path = "/nonemptydir/foo" should return inode for foo + // path = "/notnonemptydir/foo" should raise error +} + +u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { + char *pathdup = strdup(path); + char *ptr = strrchr(pathdup, '/'); + char *newfilename = ptr+1; + char *prefix = new char[ptr-pathdup+1]; + for(int i=0;i +#include +#include +#include "files.h" + +int main(int argc, char *argv[]) { + const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; + + RawDisk *H = new RawDisk(d); + + printf("test files\n"); + FilesOperation fsop(*H); + fsop.initialize_rootinode(); + + // create multiple files using mkdir or mknod + // directories that contain more than 64 files use more than one datablocks, it is not supported yet + printf("=== Part 1: create files by path ===\n"); + u_int64_t file1 = fsop.fischl_mknod("/test",0); // mode here is not used yet + printf("/test is inode %llu, it is a file\n", file1); + u_int64_t file2 = fsop.fischl_mkdir("/foo",0); + printf("/foo is inode %llu, it is a directory\n", file2); + u_int64_t file3 = fsop.fischl_mkdir("/foo/bar",0); + printf("/foo/bar is inode %llu, it is a directory\n", file3); + u_int64_t file4 = fsop.fischl_mknod("/foo/bar/baz",0); + printf("/foo/bar/baz is inode %llu, it is a file\n", file4); + // the following three testcases will fail + u_int64_t f1 = fsop.fischl_mkdir("foo/bar",0); + u_int64_t f2 = fsop.fischl_mkdir("/doesnt_exist/bar",0); + u_int64_t f3 = fsop.fischl_mkdir("/test/bar",0); + // TODO: guard against creating an existing file or diretory, such as fsop.fischl_mkdir("/test",0) + + // write to files (TODO: fischl_write) + // read and write to indirect datablocks are not supported yet + printf("=== Part 2: write to files ===\n"); + char buffer[IO_BLOCK_SIZE] = {0}; + INode inode; + inode.inode_construct(file1, *H); + buffer[0] = '1'; + fsop.write_datablock(inode, 0, buffer); + inode.inode_save(*H); + inode.inode_construct(file4, *H); + buffer[0] = '4'; + fsop.write_datablock(inode, 3, buffer); + inode.inode_save(*H); + // TODO: guard against overwriting directory datablocks + + // retrieve inode-number by path + printf("=== Part 3: retrieve inode number using path (namei) ===\n"); + u_int64_t file_test = fsop.namei("/test"); + printf("inode number for \"/test\" is %llu\n", file_test); + assert(file_test == file1); + u_int64_t file_baz = fsop.namei("/foo/bar/baz"); + printf("inode number for \"/foo/bar/baz\" is %llu\n", file_baz); + assert(file_baz == file4); + + // read files (TODO: fischl_read) + printf("=== Part 4: read from files ===\n"); + char read_buffer[IO_BLOCK_SIZE] = {0}; + INode inode_read; + inode_read.inode_construct(file_test, *H); + fsop.read_datablock(inode_read, 0, read_buffer); + assert(read_buffer[0] == '1'); + inode_read.inode_construct(file_baz, *H); + fsop.read_datablock(inode_read, 3, read_buffer); + assert(read_buffer[0] == '4'); +} \ No newline at end of file From 292c59c77b204547dfc57fab0594e8f82d5b7f31 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 12 Nov 2023 12:18:39 -0800 Subject: [PATCH 03/63] test with google test framwork, will keep running the whole test even if the asserstion is wrong --- .gitmodules | 3 +++ CMakeLists.txt | 4 +++- googletest | 1 + test/CMakeLists.txt | 4 ++++ test/layer0.cpp | 44 ++++++++++++++++++++++++-------------------- test/layer1_API.cpp | 31 ++++++++++++++++++------------- 6 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 .gitmodules create mode 160000 googletest diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8cf8b5e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "googletest"] + path = googletest + url = https://github.com/google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt index bb170e4..81bcbfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_CXX_STANDARD 14) include_directories( # fischl include files ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include ) add_executable(fischl @@ -18,4 +19,5 @@ add_executable(fischl ) enable_testing() -add_subdirectory(test) \ No newline at end of file +add_subdirectory(test) +add_subdirectory(googletest) \ No newline at end of file diff --git a/googletest b/googletest new file mode 160000 index 0000000..b10fad3 --- /dev/null +++ b/googletest @@ -0,0 +1 @@ +Subproject commit b10fad38c4026a29ea6561ab15fc4818170d1c10 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5bfe19f..09bdc38 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,10 @@ add_executable(${TARGET_LAYER2_API} layer2_API.cpp ) +# Link Google Test to your test executables +target_link_libraries(${TARGET_LAYER0} gtest gtest_main) +target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main) + # add test to activate ctest -VV add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE}) add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE}) diff --git a/test/layer0.cpp b/test/layer0.cpp index 8cc358a..03d4f69 100644 --- a/test/layer0.cpp +++ b/test/layer0.cpp @@ -1,29 +1,33 @@ -#include -#include -#include +#include #include "rawdisk.h" - -int main(int argc, char *argv[]) { - const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; - +const char* d; +TEST(RawDiskTest, WriteReadTest) { RawDisk *H = new RawDisk(d); - + char *buf = "iloveosdfjlseirfnerig"; - char readBuffer[512] = {0}; // Initialize to zeros + char readBuffer[512] = {0}; - //printf("dir %s, numSectors %lld, diskSize %lld \n", H->dir, H->numSectors, H->diskSize); - - //use number to substitute H->getnumSector(), getnumSectors() are not yest implemented + // Write test for(u_int64_t i = 0; i < 10; i++) { - H->rawdisk_write(i*512, buf, strlen(buf));//Change write_API - } - //use number to substitute H->getnumSector(), getnumSectors() are not yest implemented - for(u_int64_t i = 0; i < 10; i++) { - H->rawdisk_read(i*512, readBuffer, sizeof(readBuffer));//Change read_API - assert(strncmp(readBuffer, buf, strlen(buf)) == 0); + H->rawdisk_write(i*512, buf, strlen(buf)); } - delete H; // Delete the RawDisk object + // Read and verify test + for(u_int64_t i = 0; i < 10; i++) { + H->rawdisk_read(i*512, readBuffer, sizeof(readBuffer)); + EXPECT_EQ(strncmp(readBuffer, buf, strlen(buf)), 0); + } - return 0; + delete H; +} + +TEST(RawDiskTest, AssertionFailureTest) { + EXPECT_EQ(2, 3); // Intentional failure + EXPECT_EQ(4, 1); // Another intentional failure +} + +int main(int argc, char **argv) { + d = (argc < 2) ? "/dev/vdc" : argv[1];//how to do with this? + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index 0c63001..5190bd4 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -1,12 +1,13 @@ #include #include #include +#include #include "fs.h" #include -int main(int argc, char *argv[]) { - const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; - +const char* d; + +TEST(Layer1Test, APItest) { RawDisk *H = new RawDisk(d); printf("test inode\n"); @@ -20,21 +21,21 @@ int main(int argc, char *argv[]) { for (int j = 0; j < 8; j++) t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j); - assert(t == 2);//the first 1th unused inode will store the next unused inode 2th + EXPECT_EQ(t, 2);//the first 1th unused inode will store the next unused inode 2th //test the number before end of inode 524286th H->rawdisk_read((MAX_INODE - 2) * SECTOR_SIZE, buffer, sizeof(buffer)); t = 0; for (int j = 0; j < 8; j++) t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j); - assert(t == MAX_INODE - 1);//store the maximun th inode + EXPECT_EQ(t, MAX_INODE - 1);//store the maximun th inode //test the end of inode 524287th H->rawdisk_read((MAX_INODE - 1) * SECTOR_SIZE, buffer, sizeof(buffer)); t = 0; for (int j = 0; j < 8; j++) t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j); - assert(t == 0);//the end of inode(524287th inode) do not have the next inode address + EXPECT_EQ(t, 0);//the end of inode(524287th inode) do not have the next inode address /**************************test datablock Initialization***************************/ //we separate 2048 4kB I/O block(1+2047) as a group and the first I/O block will manage the following 2047 I/O block usage. //the first 8 bytes(0~7) in first I/O block store the address of next first I/O block, the following 256(8~263) bytes record 2047 I/O block usage. @@ -44,14 +45,14 @@ int main(int argc, char *argv[]) { for (int j = 0; j < 8; j++) t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j); - assert(t == (MAX_INODE+2048*8)*SECTOR_SIZE);//the first 8 bytes of 4k I/O block will store the next address(after 2048*4k I/O block) + EXPECT_EQ(t, (MAX_INODE+2048*8)*SECTOR_SIZE);//the first 8 bytes of 4k I/O block will store the next address(after 2048*4k I/O block) //test the end of the datablock H->rawdisk_read((MAX_BLOCKNUM - 2048*8) * SECTOR_SIZE, buffer, sizeof(buffer)); t = 0; for (int j = 0; j < 8; j++) t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j); - assert(t == (MAX_BLOCKNUM)*SECTOR_SIZE); + EXPECT_EQ(t, (MAX_BLOCKNUM)*SECTOR_SIZE); /***************************test inode de/allocation**********************************/ //when requesting an inode, the inode_allocation will give you the inode number, we use inode_list to store the sequence allocate inode @@ -62,7 +63,7 @@ int main(int argc, char *argv[]) { //printf("Allocate 20 inode num:{"); for(int i=0;i<20;i++){ inode_list[i] = inop.inode_allocate(*H); - assert(inode_list[i] == i+1); + EXPECT_EQ(inode_list[i], i+1); //printf(" %d", inode_list[i]); } //printf("}\n"); @@ -75,7 +76,7 @@ int main(int argc, char *argv[]) { for(int i=10;i<20;i++){ inode_list[i] = inop.inode_allocate(*H); //printf("inode %d, rec_f %d\n,", inode_list[i],record_free[rec]); - assert(inode_list[i] == record_free[rec]); + EXPECT_EQ(inode_list[i], record_free[rec]); rec--; } printf("}\n"); @@ -105,7 +106,7 @@ int main(int argc, char *argv[]) { for(int i=0;i<10;i++){ //printf("%dth data block allocate again addres: ", i); for(int j=0;j<3;j++){ - assert(inode_inside[i].datablock_allocate(*H) == rec_datablock_free[i][j]); + EXPECT_EQ(inode_inside[i].datablock_allocate(*H), rec_datablock_free[i][j]); //printf("%d," ,inode_inside[i].datablock_allocate(*H)); } //printf("\n"); @@ -113,6 +114,10 @@ int main(int argc, char *argv[]) { //printf("}\n"); delete H; // Delete the RawDisk object - - return 0; } + +int main(int argc, char **argv) { + d = (argc < 2) ? "/dev/vdc" : argv[1];//how to do with this? + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file From f2aac32365ccb9a52156b38fb96c951229afe1f6 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 17 Nov 2023 02:16:02 -0800 Subject: [PATCH 04/63] delete redundant assignment --- lib/files.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 03ca9df..846c22f 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -22,8 +22,7 @@ struct DirectoryEntry { }; FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { - disk = disk_; - inop.initialize(disk_); + inop.initialize(disk); } int FilesOperation::read_datablock(INode& inode, u_int64_t index, char* buffer) { From ee66c10796376133e71e46e4dbe1454c6ac13593 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 17 Nov 2023 14:37:26 -0800 Subject: [PATCH 05/63] simplify checking path way in mkdir and mknod --- lib/files.cpp | 71 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 846c22f..525b376 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -1,7 +1,13 @@ +//#include "fuse.h" add this when layer3 #include "files.h" #include #include +/********************************************************************* + Directory Entry definition and function + + +*********************************************************************/ struct DirectoryEntry { u_int64_t inode_number; char file_name[56]; @@ -20,6 +26,21 @@ struct DirectoryEntry { strcpy(file_name, buffer+8); } }; +//Directory collection +typedef struct { + //DirectoryEntry entries[MAX_ENTRIES]; with tree structure + unsigned int num_entries; +} Directory; +/* + * fishcl_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as fishcl_find_entry(). It returns NULL if it failed. + * + */ +static int fishcl_add_entry(Directory *dir, unsigned int inode_number, const char *name){ + +} FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { inop.initialize(disk); @@ -155,46 +176,48 @@ u_int64_t FilesOperation::namei(const char* path) { // path = "/notnonemptydir/foo" should raise error } +/**/ u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { + //check path char *pathdup = strdup(path); - char *ptr = strrchr(pathdup, '/'); - char *newfilename = ptr+1; - char *prefix = new char[ptr-pathdup+1]; - for(int i=0;i\0 + char *newDirname = lastSlash+1; //\0, get from + char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only + + u_int64_t parent_inode_number = namei(ParentPath); if (parent_inode_number == (u_int64_t)-1) { - printf("fischl_mkdir failed because namei failed to find inode for %s\n", prefix); + printf("fischl_mkdir failed because namei failed to find inode for %s\n", ParentPath); delete pathdup; - delete [] prefix; return -1; } - u_int64_t ret = mkfile(parent_inode_number, newfilename, 1); + //make new inode + u_int64_t ret = mkfile(parent_inode_number, newDirname, 1);/* mode|S_IFDIR if need to call with dir*/ delete pathdup; - delete [] prefix; return ret; + //create with struct inode *__fishcl_new_inode(, that is change mkfile to fishcl_new_inode + + //after new_inode(mkfile), go to fischl_add_entry record + + } u_int64_t FilesOperation::fischl_mknod(const char* path, mode_t mode) { + //check path char *pathdup = strdup(path); - char *ptr = strrchr(pathdup, '/'); - char *newfilename = ptr+1; - char *prefix = new char[ptr-pathdup+1]; - for(int i=0;i\0 + char *newFilename = lastSlash+1; //\0, get from + char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only + + u_int64_t parent_inode_number = namei(ParentPath); if (parent_inode_number == (u_int64_t)-1) { - printf("fischl_mknod failed because namei failed to find inode for %s", prefix); + printf("fischl_mkdir failed because namei failed to find inode for %s\n", ParentPath); delete pathdup; - delete [] prefix; return -1; } - u_int64_t ret = mkfile(parent_inode_number, newfilename, 0); + //make new inode + u_int64_t ret = mkfile(parent_inode_number, newFilename, 0); delete pathdup; - delete [] prefix; return ret; } \ No newline at end of file From aacb3e0193c4942b98dbc213db39847d0971715a Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 18 Nov 2023 01:10:48 -0800 Subject: [PATCH 06/63] change name init_inode to new_inode, return struct inode pointer --- include/files.h | 2 +- lib/files.cpp | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/files.h b/include/files.h index 678cea6..7e3882f 100644 --- a/include/files.h +++ b/include/files.h @@ -9,7 +9,7 @@ class FilesOperation { FilesOperation(RawDisk&); int read_datablock(INode& inode, u_int64_t index, char* buffer); int write_datablock(INode& inode, u_int64_t index, char* buffer); - void init_inode(u_int64_t inode_number, u_int64_t permissions); + INode* new_inode(u_int64_t inode_number, u_int64_t permissions); void initialize_rootinode(); u_int64_t mkfile(u_int64_t parent_inode_number, const char* name, u_int64_t permissions); u_int64_t namei(const char* path); diff --git a/lib/files.cpp b/lib/files.cpp index 525b376..6ca996a 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -72,22 +72,25 @@ int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) } } -void FilesOperation::init_inode(u_int64_t inode_number, u_int64_t permissions) { +INode* FilesOperation::new_inode(u_int64_t inode_number, u_int64_t permissions) { // zero out disk space of inode, because in memory inode is uninitialized by default char buffer[SECTOR_SIZE] = {0}; disk.rawdisk_write(inode_number*SECTOR_SIZE, buffer, sizeof(buffer)); - INode inode; - inode.inode_construct(inode_number, disk); - inode.block_number = inode_number; - inode.permissions = permissions; - inode.inode_save(disk); + INode *inode = new INode; + inode->inode_construct(inode_number, disk); + inode->block_number = inode_number; + inode->permissions = permissions; + inode->inode_save(disk); + + return inode; } void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion root_inode = inop.inode_allocate(disk); printf("Info: root inode number: %llu\n", root_inode); - init_inode(root_inode, 1); + INode *get_inode = new_inode(root_inode, 1); + delete get_inode; } u_int64_t FilesOperation::mkfile(u_int64_t parent_inode_number, const char* name, u_int64_t permissions) { @@ -127,8 +130,8 @@ u_int64_t FilesOperation::mkfile(u_int64_t parent_inode_number, const char* name inode.inode_save(disk); // initialize new file - init_inode(new_inode_number, permissions); - + INode *get_inode = new_inode(new_inode_number, permissions); + delete get_inode; return new_inode_number; } From c45667461b620f9bfa45e1a4af8d2f4e51e0a4fb Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 18 Nov 2023 01:46:44 -0800 Subject: [PATCH 07/63] Rename mkfile to create_new_inode and update mode argument to detect S_IFDIR condition --- include/files.h | 2 +- include/fs.h | 2 +- lib/files.cpp | 16 +++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/files.h b/include/files.h index 7e3882f..9d205a4 100644 --- a/include/files.h +++ b/include/files.h @@ -11,7 +11,7 @@ class FilesOperation { int write_datablock(INode& inode, u_int64_t index, char* buffer); INode* new_inode(u_int64_t inode_number, u_int64_t permissions); void initialize_rootinode(); - u_int64_t mkfile(u_int64_t parent_inode_number, const char* name, u_int64_t permissions); + u_int64_t create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); u_int64_t namei(const char* path); u_int64_t fischl_mkdir(const char*, mode_t); u_int64_t fischl_mknod(const char*, mode_t); diff --git a/include/fs.h b/include/fs.h index c9f6563..9ccdb5b 100644 --- a/include/fs.h +++ b/include/fs.h @@ -65,7 +65,7 @@ class INode{ // other u_int64_t uid; u_int64_t gid; - u_int64_t permissions; + u_int64_t permissions;//will respond to mode_t mode ; this is octal format u_int64_t size; // Number of datablocks u_int64_t block_number; diff --git a/lib/files.cpp b/lib/files.cpp index 6ca996a..359fe8b 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -89,11 +89,11 @@ void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion root_inode = inop.inode_allocate(disk); printf("Info: root inode number: %llu\n", root_inode); - INode *get_inode = new_inode(root_inode, 1); + INode *get_inode = new_inode(root_inode, S_IFDIR); delete get_inode; } -u_int64_t FilesOperation::mkfile(u_int64_t parent_inode_number, const char* name, u_int64_t permissions) { +u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode) { // trys to create a file under parent directory if (strlen(name)>=56) { perror("Name too long, cannot create file or directory"); @@ -101,7 +101,7 @@ u_int64_t FilesOperation::mkfile(u_int64_t parent_inode_number, const char* name } INode inode; inode.inode_construct(parent_inode_number, disk); - if (inode.permissions != 1) { + if ((inode.permissions & S_IFMT) != S_IFDIR) { printf("Parent Inode is not a directory\n"); return -1; } @@ -130,7 +130,7 @@ u_int64_t FilesOperation::mkfile(u_int64_t parent_inode_number, const char* name inode.inode_save(disk); // initialize new file - INode *get_inode = new_inode(new_inode_number, permissions); + INode *get_inode = new_inode(new_inode_number, mode); delete get_inode; return new_inode_number; } @@ -149,7 +149,7 @@ u_int64_t FilesOperation::namei(const char* path) { while (std::getline(pathStream, new_name, '/')) { INode inode; inode.inode_construct(current_inode, disk); - if (inode.permissions != 1 || inode.size == 0) { + if ((inode.permissions & S_IFMT) != S_IFDIR || inode.size == 0) { printf("namei: %s is not a non-empty directory\n", current_dirname.c_str()); return -1; } @@ -195,11 +195,9 @@ u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { return -1; } //make new inode - u_int64_t ret = mkfile(parent_inode_number, newDirname, 1);/* mode|S_IFDIR if need to call with dir*/ + u_int64_t ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory delete pathdup; return ret; - //create with struct inode *__fishcl_new_inode(, that is change mkfile to fishcl_new_inode - //after new_inode(mkfile), go to fischl_add_entry record @@ -220,7 +218,7 @@ u_int64_t FilesOperation::fischl_mknod(const char* path, mode_t mode) { return -1; } //make new inode - u_int64_t ret = mkfile(parent_inode_number, newFilename, 0); + u_int64_t ret = create_new_inode(parent_inode_number, newFilename, mode); delete pathdup; return ret; } \ No newline at end of file From a04c3d6334828a74362dda469adaf2ad3b92e43a Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sat, 18 Nov 2023 13:57:47 -0800 Subject: [PATCH 08/63] support indirect datablock read/write --- lib/files.cpp | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 359fe8b..1c84665 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -46,17 +46,43 @@ FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { inop.initialize(disk); } +u_int64_t index_to_offset(disk& disk, u_int64_t index) { + if (index < 48) { + return inode.blocks[index]; + } else if (index < 48 + 512){ + char indirect_buffer[IO_BLOCK_SIZE] = {0}; + disk.rawdisk_read(inode.single_indirect, indirect_buffer, IO_BLOCK_SIZE); + return INode::read_byte_at(8*(index-48), indirect_buffer); + } else if (index < 48 + 512 + 512*512) { + char indirect_buffer[IO_BLOCK_SIZE] = {0}; + disk.rawdisk_read(inode.double_indirect, indirect_buffer, IO_BLOCK_SIZE); + u_int64_t offset = INode::read_byte_at(8*((index-48-512)/512), indirect_buffer); + disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); + return INode::read_byte_at(8*((index-48-512)%512), indirect_buffer); + } else if (index < 48 + 512 + 512*512 + 512*512*512){ + char indirect_buffer[IO_BLOCK_SIZE] = {0}; + disk.rawdisk_read(inode.triple_indirect, indirect_buffer, IO_BLOCK_SIZE); + u_int64_t offset = INode::read_byte_at(8*((index-48-512-512*512)/(512*512)), indirect_buffer); + disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); + offset = INode::read_byte_at(8*(((index-48-512-512*512)%(512*512))/512), indirect_buffer); + disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); + return INode::read_byte_at(8*(((index-48-512-512*512)%512), indirect_buffer); + } else { + printf("index out of range, tried to access index %llu, max index %llu\n", index, 48+512+512*512+512*512*512); + return -1; + } +} + int FilesOperation::read_datablock(INode& inode, u_int64_t index, char* buffer) { if (index >= inode.size) { printf("Read datablock out of range, inode number %llu", inode.block_number); return -1; } - if (index < 48) { - return disk.rawdisk_read(inode.blocks[index], buffer, IO_BLOCK_SIZE); - } else { - perror("Read indirect datablocks not implemented yet"); + u_int64_t read_offset = index_to_offset(disk, index); + if (read_offset == (u_int64_t)(-1)) { return -1; } + return disk.rawdisk_read(read_offset, buffer, IO_BLOCK_SIZE); } int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) { @@ -64,12 +90,11 @@ int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) u_int64_t ret = inode.datablock_allocate(disk); inode.size += 1; } - if (index < 48) { - return disk.rawdisk_write(inode.blocks[index], buffer, IO_BLOCK_SIZE); - } else { - perror("Write indirect datablocks not implemented yet"); + u_int64_t write_offset = index_to_offset(disk, index); + if (write_offset == (u_int64_t)(-1)) { return -1; } + return disk.rawdisk_read(write_offset, buffer, IO_BLOCK_SIZE); } INode* FilesOperation::new_inode(u_int64_t inode_number, u_int64_t permissions) { From dcf06010394e9da47b710411d7bf401f430e6e4b Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sat, 18 Nov 2023 14:55:30 -0800 Subject: [PATCH 09/63] fix bugs for last commit (support indirect datablocks r/w) --- include/files.h | 2 +- lib/files.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/files.h b/include/files.h index 9d205a4..98defa7 100644 --- a/include/files.h +++ b/include/files.h @@ -7,7 +7,7 @@ class FilesOperation { u_int64_t root_inode; public: FilesOperation(RawDisk&); - int read_datablock(INode& inode, u_int64_t index, char* buffer); + int read_datablock(const INode& inode, u_int64_t index, char* buffer); int write_datablock(INode& inode, u_int64_t index, char* buffer); INode* new_inode(u_int64_t inode_number, u_int64_t permissions); void initialize_rootinode(); diff --git a/lib/files.cpp b/lib/files.cpp index 1c84665..bec0a66 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -46,7 +46,7 @@ FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { inop.initialize(disk); } -u_int64_t index_to_offset(disk& disk, u_int64_t index) { +u_int64_t index_to_offset(const INode& inode, RawDisk& disk, u_int64_t index) { if (index < 48) { return inode.blocks[index]; } else if (index < 48 + 512){ @@ -66,19 +66,19 @@ u_int64_t index_to_offset(disk& disk, u_int64_t index) { disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); offset = INode::read_byte_at(8*(((index-48-512-512*512)%(512*512))/512), indirect_buffer); disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); - return INode::read_byte_at(8*(((index-48-512-512*512)%512), indirect_buffer); + return INode::read_byte_at(8*((index-48-512-512*512)%512), indirect_buffer); } else { printf("index out of range, tried to access index %llu, max index %llu\n", index, 48+512+512*512+512*512*512); return -1; } } -int FilesOperation::read_datablock(INode& inode, u_int64_t index, char* buffer) { +int FilesOperation::read_datablock(const INode& inode, u_int64_t index, char* buffer) { if (index >= inode.size) { printf("Read datablock out of range, inode number %llu", inode.block_number); return -1; } - u_int64_t read_offset = index_to_offset(disk, index); + u_int64_t read_offset = index_to_offset(inode, disk, index); if (read_offset == (u_int64_t)(-1)) { return -1; } @@ -90,7 +90,7 @@ int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) u_int64_t ret = inode.datablock_allocate(disk); inode.size += 1; } - u_int64_t write_offset = index_to_offset(disk, index); + u_int64_t write_offset = index_to_offset(inode, disk, index); if (write_offset == (u_int64_t)(-1)) { return -1; } From 1259cf5487daa3e8e47b0106f20d50dc9632ba5a Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sat, 18 Nov 2023 17:42:36 -0800 Subject: [PATCH 10/63] fix bug for indirect datablock r/w, add . and .. to every directory --- include/files.h | 6 ++++-- include/rawdisk.h | 2 +- lib/files.cpp | 38 ++++++++++++++++++++++++++++++++++++-- test/layer2_API.cpp | 10 ++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/include/files.h b/include/files.h index 98defa7..0f51c6a 100644 --- a/include/files.h +++ b/include/files.h @@ -5,12 +5,14 @@ class FilesOperation { RawDisk& disk; INodeOperation inop; u_int64_t root_inode; + INode* new_inode(u_int64_t inode_number, u_int64_t permissions); + void create_dot_dotdot(INode*, u_int64_t); public: FilesOperation(RawDisk&); int read_datablock(const INode& inode, u_int64_t index, char* buffer); - int write_datablock(INode& inode, u_int64_t index, char* buffer); - INode* new_inode(u_int64_t inode_number, u_int64_t permissions); + int write_datablock(INode& inode, u_int64_t index, const char* buffer); void initialize_rootinode(); + void printDirectory(u_int64_t); u_int64_t create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); u_int64_t namei(const char* path); u_int64_t fischl_mkdir(const char*, mode_t); diff --git a/include/rawdisk.h b/include/rawdisk.h index 4cccf70..b45d419 100644 --- a/include/rawdisk.h +++ b/include/rawdisk.h @@ -64,7 +64,7 @@ public: } // Write a specified number of bytes at a given byte offset - int rawdisk_write(u_int64_t offset, char *buffer, size_t length) { + int rawdisk_write(u_int64_t offset, const char *buffer, size_t length) { if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) { perror("Error seeking to offset"); return -1; diff --git a/lib/files.cpp b/lib/files.cpp index bec0a66..48c31f9 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -85,7 +85,7 @@ int FilesOperation::read_datablock(const INode& inode, u_int64_t index, char* bu return disk.rawdisk_read(read_offset, buffer, IO_BLOCK_SIZE); } -int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) { +int FilesOperation::write_datablock(INode& inode, u_int64_t index, const char* buffer) { while (index >= inode.size) { u_int64_t ret = inode.datablock_allocate(disk); inode.size += 1; @@ -94,7 +94,7 @@ int FilesOperation::write_datablock(INode& inode, u_int64_t index, char* buffer) if (write_offset == (u_int64_t)(-1)) { return -1; } - return disk.rawdisk_read(write_offset, buffer, IO_BLOCK_SIZE); + return disk.rawdisk_write(write_offset, buffer, IO_BLOCK_SIZE); } INode* FilesOperation::new_inode(u_int64_t inode_number, u_int64_t permissions) { @@ -110,14 +110,45 @@ INode* FilesOperation::new_inode(u_int64_t inode_number, u_int64_t permissions) return inode; } +void FilesOperation::create_dot_dotdot(INode* inode, u_int64_t parent_inode_number) { + if(inode->size != 0) { + printf("Error: create_dot_dotdot should only be called on new inode for directory\n"); + } + char buffer[IO_BLOCK_SIZE] = {0}; + DirectoryEntry dot; + dot.inode_number = inode->block_number; + strcpy(dot.file_name, "."); + dot.serialize(buffer); + DirectoryEntry dotdot; + dotdot.inode_number = parent_inode_number; + strcpy(dotdot.file_name, ".."); + dotdot.serialize(buffer+64); + int ret = write_datablock(*inode, 0, buffer); + inode->inode_save(disk); +} + void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion root_inode = inop.inode_allocate(disk); printf("Info: root inode number: %llu\n", root_inode); INode *get_inode = new_inode(root_inode, S_IFDIR); + create_dot_dotdot(get_inode, root_inode); delete get_inode; } +void FilesOperation::printDirectory(u_int64_t inode_number) { + INode inode; + inode.inode_construct(inode_number, disk); + char buffer[IO_BLOCK_SIZE] = {0}; + read_datablock(inode, 0, buffer); + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-64;i+=64){ + ent.deserialize(buffer+i); + printf("%d(%s)\t", i, ent.file_name); + } + printf("\n"); +} + u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode) { // trys to create a file under parent directory if (strlen(name)>=56) { @@ -156,6 +187,9 @@ u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const // initialize new file INode *get_inode = new_inode(new_inode_number, mode); + if ((get_inode->permissions & S_IFMT) == S_IFDIR) { + create_dot_dotdot(get_inode, parent_inode_number); + } delete get_inode; return new_inode_number; } diff --git a/test/layer2_API.cpp b/test/layer2_API.cpp index e31b52d..91d0202 100644 --- a/test/layer2_API.cpp +++ b/test/layer2_API.cpp @@ -41,6 +41,8 @@ int main(int argc, char *argv[]) { inode.inode_construct(file4, *H); buffer[0] = '4'; fsop.write_datablock(inode, 3, buffer); + buffer[0] = '5'; + fsop.write_datablock(inode, 101, buffer); inode.inode_save(*H); // TODO: guard against overwriting directory datablocks @@ -52,6 +54,12 @@ int main(int argc, char *argv[]) { u_int64_t file_baz = fsop.namei("/foo/bar/baz"); printf("inode number for \"/foo/bar/baz\" is %llu\n", file_baz); assert(file_baz == file4); + u_int64_t file_foo = fsop.namei("/foo/bar/.."); + printf("inode number for \"/foo/bar/..\" is %llu\n", file_foo); + assert(file_foo == file2); + u_int64_t file_bar = fsop.namei("/foo/bar/."); + printf("inode number for \"/foo/bar/.\" is %llu\n", file_bar); + assert(file_bar == file3); // read files (TODO: fischl_read) printf("=== Part 4: read from files ===\n"); @@ -63,4 +71,6 @@ int main(int argc, char *argv[]) { inode_read.inode_construct(file_baz, *H); fsop.read_datablock(inode_read, 3, read_buffer); assert(read_buffer[0] == '4'); + fsop.read_datablock(inode_read, 101, read_buffer); + assert(read_buffer[0] == '5'); } \ No newline at end of file From 1e735ea7d0542480e254b0e6e938a603106b516f Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sat, 18 Nov 2023 19:25:53 -0800 Subject: [PATCH 11/63] support arbitrary number of files in each folder (previously 64) --- include/files.h | 1 + lib/files.cpp | 70 +++++++++++++++++++++++++++------------------ test/layer2_API.cpp | 17 ++++++++++- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/include/files.h b/include/files.h index 0f51c6a..3f2b70d 100644 --- a/include/files.h +++ b/include/files.h @@ -14,6 +14,7 @@ class FilesOperation { void initialize_rootinode(); void printDirectory(u_int64_t); u_int64_t create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); + // int unlink_inode(u_int64_t inode_number); u_int64_t namei(const char* path); u_int64_t fischl_mkdir(const char*, mode_t); u_int64_t fischl_mknod(const char*, mode_t); diff --git a/lib/files.cpp b/lib/files.cpp index 48c31f9..3ce2cb6 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -137,6 +137,7 @@ void FilesOperation::initialize_rootinode() { } void FilesOperation::printDirectory(u_int64_t inode_number) { + // limit to first datablock INode inode; inode.inode_construct(inode_number, disk); char buffer[IO_BLOCK_SIZE] = {0}; @@ -144,7 +145,7 @@ void FilesOperation::printDirectory(u_int64_t inode_number) { DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-64;i+=64){ ent.deserialize(buffer+i); - printf("%d(%s)\t", i, ent.file_name); + if (ent.inode_number) printf("%s\t%llu;\t", ent.file_name, ent.inode_number); } printf("\n"); } @@ -161,29 +162,39 @@ u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const printf("Parent Inode is not a directory\n"); return -1; } - char buffer[IO_BLOCK_SIZE] = {0}; - if (inode.size > 0) read_datablock(inode, 0, buffer); - - // do create inode + u_int64_t new_inode_number = 0; - DirectoryEntry ent; - for(int i=0;i<=IO_BLOCK_SIZE-64;i+=64){ - ent.deserialize(buffer+i); - if (ent.inode_number == 0) { - new_inode_number = inop.inode_allocate(disk); - ent.inode_number = new_inode_number; - strcpy(ent.file_name, name); - ent.serialize(buffer+i); + + char rw_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idx -#include +#include #include #include "files.h" @@ -19,8 +19,10 @@ int main(int argc, char *argv[]) { printf("/test is inode %llu, it is a file\n", file1); u_int64_t file2 = fsop.fischl_mkdir("/foo",0); printf("/foo is inode %llu, it is a directory\n", file2); + fsop.printDirectory(1); u_int64_t file3 = fsop.fischl_mkdir("/foo/bar",0); printf("/foo/bar is inode %llu, it is a directory\n", file3); + fsop.printDirectory(file2); u_int64_t file4 = fsop.fischl_mknod("/foo/bar/baz",0); printf("/foo/bar/baz is inode %llu, it is a file\n", file4); // the following three testcases will fail @@ -73,4 +75,17 @@ int main(int argc, char *argv[]) { assert(read_buffer[0] == '4'); fsop.read_datablock(inode_read, 101, read_buffer); assert(read_buffer[0] == '5'); + + // pressure test create directory + printf("=== Part 5: pressure test create files ===\n"); + u_int64_t file_pressure = fsop.fischl_mkdir("/pressure", 0); + u_int64_t inode_numbers[700]; + std::string prefix = "/pressure/"; + for(int i=0;i<700;i++){ + inode_numbers[i] = fsop.fischl_mkdir((prefix+std::to_string(i)).c_str(), 0); + } + for(int i=0;i<700;i++){ + u_int64_t inode_number = fsop.namei((prefix+std::to_string(i)).c_str()); + assert(inode_number == inode_numbers[i]); + } } \ No newline at end of file From 5dbac3d9e38930613e59c5ec62319c9dbee87bf9 Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sat, 18 Nov 2023 20:20:32 -0800 Subject: [PATCH 12/63] support unlinking files and directories --- include/files.h | 4 +-- lib/files.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++ test/layer2_API.cpp | 16 +++++++++- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/include/files.h b/include/files.h index 3f2b70d..713bc03 100644 --- a/include/files.h +++ b/include/files.h @@ -14,11 +14,11 @@ class FilesOperation { void initialize_rootinode(); void printDirectory(u_int64_t); u_int64_t create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); - // int unlink_inode(u_int64_t inode_number); + void unlink_inode(u_int64_t inode_number); u_int64_t namei(const char* path); u_int64_t fischl_mkdir(const char*, mode_t); u_int64_t fischl_mknod(const char*, mode_t); //int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); - //int fischl_unlink (const char *); + int fischl_unlink (const char *); //int fischl_open (const char *, struct fuse_file_info *); }; \ No newline at end of file diff --git a/lib/files.cpp b/lib/files.cpp index 3ce2cb6..4a9e11f 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -294,4 +294,77 @@ u_int64_t FilesOperation::fischl_mknod(const char* path, mode_t mode) { u_int64_t ret = create_new_inode(parent_inode_number, newFilename, mode); delete pathdup; return ret; +} + +void FilesOperation::unlink_inode(u_int64_t inode_number) { + INode inode; + inode.inode_construct(inode_number, disk); + if ((inode.permissions & S_IFMT) == S_IFDIR) { + char buffer[IO_BLOCK_SIZE] = {0}; + for(u_int64_t idx=0; idx Date: Sat, 18 Nov 2023 20:52:36 -0800 Subject: [PATCH 13/63] make mkdir and mknod return error if file or dir already exists; add tests --- lib/files.cpp | 14 ++++++++++++++ test/layer2_API.cpp | 13 ++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/files.cpp b/lib/files.cpp index 4a9e11f..f1f0087 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -163,6 +163,20 @@ u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const return -1; } + // Check if file or directory already exists + char r_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idx Date: Sun, 19 Nov 2023 16:53:29 -0800 Subject: [PATCH 14/63] create hash-tree hierarchy direntry file --- include/direntry.h | 41 ++++++++++++++ lib/direntry.cpp | 133 +++++++++++++++++++++++++++++++++++++++++++++ lib/files.cpp | 39 +------------ 3 files changed, 175 insertions(+), 38 deletions(-) create mode 100644 include/direntry.h create mode 100644 lib/direntry.cpp diff --git a/include/direntry.h b/include/direntry.h new file mode 100644 index 0000000..6b1c945 --- /dev/null +++ b/include/direntry.h @@ -0,0 +1,41 @@ +typedef struct fileNode { + char *name = NULL; + int inode_number; + int permissions; + char *Symbolink; + struct treeNode *subdirectory; + struct fileNode *next; + void serialize(char* buffer) { + u_int64_t t = inode_number; + for (int j = 0; j < 8; j++){ + buffer[j] = t & (((u_int64_t)1<<(8))-1); + t >>= 8; + } + strcpy(buffer+8, file_name); + } + void deserialize(char* buffer) { + inode_number = 0; + for (int j = 0; j < 8; j++) + inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); + strcpy(file_name, buffer+8); + } +} FileNode; + +typedef struct { + int size; + FileNode **table; +} HashTable; + +typedef struct treeNode { + char *dirName; + HashTable *contents; + struct treeNode *parent; + FileNode *self_info; //self fileNode infromation +} TreeNode; + +/*root directory have its own initialization, so parent wont be NULL*/ +int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode); +/*if want to use dir mode use the subdirectory treeNode pointer */ +//e.g. FileNode *Dirnode = fischl_find_entry(); can see file inside with Dirnode->subdirectory +//e.g. go to the current Dirnode parent directory, use TreeNode *get_Dir_parent = Dirnode->subdirectory->parent; +FileNode *fischl_find_entry(TreeNode *root, const char *path); diff --git a/lib/direntry.cpp b/lib/direntry.cpp new file mode 100644 index 0000000..85f0a69 --- /dev/null +++ b/lib/direntry.cpp @@ -0,0 +1,133 @@ +/*********************************Hash operation******************************************** + +********************************************************************************************/ +// Hash operation +unsigned int hash(HashTable *h, char *key) { + unsigned int hashval = 0; + for (; *key != '\0'; key++) hashval = *key + (hashval << 5) - hashval; + return hashval % h->size; +} + +HashTable *createHashTable(int size) { + HashTable *newTable = (HashTable *)malloc(sizeof(HashTable)); + newTable->size = size; + newTable->table = (FileNode **)malloc(sizeof(FileNode *) * size); + for (int i = 0; i < size; i++) newTable->table[i] = NULL; + return newTable; +} + +FileNode *insertHash(HashTable *h, char *key, TreeNode *subdirectory) { + unsigned int hashval = hash(h, key); + FileNode *newNode = (FileNode *)malloc(sizeof(FileNode)); + newNode->name = strdup(key); + newNode->subdirectory = subdirectory; + newNode->next = h->table[hashval]; + h->table[hashval] = newNode; + return newNode; +} + +FileNode *lookupHash(HashTable *h, char *key) { + unsigned int hashval = hash(h, key); + FileNode *node = h->table[hashval]; + while (node != NULL) { + if (strcmp(node->name, key) == 0) return node; + node = node->next; + } + return NULL; // Not found +} + +void freeHashTable(HashTable *table) { + if (table == NULL) return; + + for (int i = 0; i < table->size; ++i) { + FileNode *current = table->table[i]; + while (current != NULL) { + FileNode *temp = current; + current = current->next; + // free(temp->name); + // free(temp); + } + } + free(table->table); + free(table); +} + +void freeTree(TreeNode *node) { + //printf("***********************FREE TREE %s**************************\n",node->dirName); + //printf("***********************FREE TREE **************************\n"); + if (node == NULL) return; + + if (node->contents != NULL) { + for (int i = 0; i < node->contents->size; ++i) { + FileNode *current = node->contents->table[i]; + while (current != NULL) { + FileNode *temp = current; + current = current->next; + + if (temp->subdirectory != NULL) { + freeTree(temp->subdirectory); + } + // Free the FileNode if it's not a directory + printf("free who %s\n",temp->name); + free(temp->name); + free(temp); + } + } + //printf("free %s's hash table\n",node->dirName); + freeHashTable(node->contents); + //node->contents = NULL; + } + //printf("free directory %s\n",node->dirName); + free(node->dirName); + node->dirName = NULL; + free(node); + node = NULL; + //printf("***********************END**************************\n"); +} + +/*********************************Direntry operation****************************************** + +********************************************************************************************/ +int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode){ + char *Name = strdup(fileName); + TreeNode *newDir = NULL; + /*If directory, malloc TreeNode, and then create filenode that belongs to Parent hash table content*/ + if ((new_inode->permissions & S_IFMT) == S_IFDIR) { + newDir = (TreeNode *)malloc(sizeof(TreeNode)); + newDir->dirName = Name; + newDir->contents = createHashTable(20);//hasSize define 20 + newDir->parent = parent; + } + FileNode *newFile = insertHash(parent->contents, Name, newDir); //newDir == NULL indicates it's a file + //assign INode *new_inode metadata to data member in FileNode structure + newFile->permissions = new_inode->permissions; + newFile->inode_number = new_inode_number; + //Diretory have its own file information, that is . here + if(newDir != NULL) + newDir->self_info = newFile; + //free(Name); cannot free name + return 0; +} + +FileNode *fischl_find_entry(TreeNode *root, const char *path){ + //support . and .. function + char *pathCopy = strdup(path); + char *segment = strtok(pathCopy, "/"); + TreeNode *current = root; + FileNode *file = NULL; + + while (segment != NULL && current != NULL) { + file = lookupHash(current->contents, segment); + if (file != NULL && file->subdirectory == NULL) { + free(pathCopy); + return file; //File found + //return current; return filenode + } + current = file ? file->subdirectory : NULL; + segment = strtok(NULL, "/"); + } + + free(pathCopy); + return file; // NULL if not found + //return current; return filenode +} \ No newline at end of file diff --git a/lib/files.cpp b/lib/files.cpp index f1f0087..9304fcb 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -2,45 +2,8 @@ #include "files.h" #include #include +#include "direntry.h" -/********************************************************************* - Directory Entry definition and function - - -*********************************************************************/ -struct DirectoryEntry { - u_int64_t inode_number; - char file_name[56]; - void serialize(char* buffer) { - u_int64_t t = inode_number; - for (int j = 0; j < 8; j++){ - buffer[j] = t & (((u_int64_t)1<<(8))-1); - t >>= 8; - } - strcpy(buffer+8, file_name); - } - void deserialize(char* buffer) { - inode_number = 0; - for (int j = 0; j < 8; j++) - inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); - strcpy(file_name, buffer+8); - } -}; -//Directory collection -typedef struct { - //DirectoryEntry entries[MAX_ENTRIES]; with tree structure - unsigned int num_entries; -} Directory; -/* - * fishcl_add_entry() - * - * adds a file entry to the specified directory, using the same - * semantics as fishcl_find_entry(). It returns NULL if it failed. - * - */ -static int fishcl_add_entry(Directory *dir, unsigned int inode_number, const char *name){ - -} FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { inop.initialize(disk); From 051a04ea7586d8f603a6693f78ae5d25bf11f4b1 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 19 Nov 2023 21:22:53 -0800 Subject: [PATCH 15/63] add dir_API to demo direntry API --- include/direntry.h | 9 ++++- lib/direntry.cpp | 39 +++++++++++++++++++ test/CMakeLists.txt | 8 +++- test/dir_API.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 test/dir_API.cpp diff --git a/include/direntry.h b/include/direntry.h index 6b1c945..ff4792d 100644 --- a/include/direntry.h +++ b/include/direntry.h @@ -11,13 +11,13 @@ typedef struct fileNode { buffer[j] = t & (((u_int64_t)1<<(8))-1); t >>= 8; } - strcpy(buffer+8, file_name); + strcpy(buffer+8, name); } void deserialize(char* buffer) { inode_number = 0; for (int j = 0; j < 8; j++) inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); - strcpy(file_name, buffer+8); + strcpy(name, buffer+8); } } FileNode; @@ -39,3 +39,8 @@ int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileNam //e.g. FileNode *Dirnode = fischl_find_entry(); can see file inside with Dirnode->subdirectory //e.g. go to the current Dirnode parent directory, use TreeNode *get_Dir_parent = Dirnode->subdirectory->parent; FileNode *fischl_find_entry(TreeNode *root, const char *path); + +void freeTree(TreeNode *node); +/*for debug use*/ +TreeNode *createDirectory(const char *dirName, TreeNode *parent, int hashSize); +TreeNode *find_parentPath(TreeNode *root, const char *path); \ No newline at end of file diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 85f0a69..12eb1c9 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -1,3 +1,10 @@ +#include +#include +#include +#include +#include +#include "fs.h" +#include "direntry.h" /*********************************Hash operation******************************************** ********************************************************************************************/ @@ -36,6 +43,38 @@ FileNode *lookupHash(HashTable *h, char *key) { return NULL; // Not found } +TreeNode *createDirectory(const char *dirName, TreeNode *parent, int hashSize) { + TreeNode *newDir = (TreeNode *)malloc(sizeof(TreeNode)); + newDir->dirName = strdup(dirName); + newDir->contents = createHashTable(hashSize); + newDir->parent = parent; + if (parent) { + newDir->self_info = insertHash(parent->contents, newDir->dirName, newDir); + } + return newDir; +} + +TreeNode *find_parentPath(TreeNode *root, const char *path) { + char *pathCopy = strdup(path); + char *segment = strtok(pathCopy, "/"); + TreeNode *current = root; + FileNode *file = NULL; + + while (segment != NULL && current != NULL) { + file = lookupHash(current->contents, segment); + if (file != NULL && file->subdirectory == NULL) { + free(pathCopy); + printf("status current directory %s\n",current->dirName); + return current; //File found + } + current = file ? file->subdirectory : NULL; + segment = strtok(NULL, "/"); + } + + free(pathCopy); + return current; // NULL if not found +} + void freeHashTable(HashTable *table) { if (table == NULL) return; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 09bdc38..82ccfd4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_LAYER0 test_layer0) set(TARGET_LAYER1_API test_layer1_API) set(TARGET_LAYER2_API test_layer2_API) +set(TARGET_DIR_API test_dir_API) set(DIR_PLACE /dev/vdb) # add test sources here ... @@ -16,6 +17,10 @@ add_executable(${TARGET_LAYER2_API} ../lib/files.cpp layer2_API.cpp ) +add_executable(${TARGET_DIR_API} + ../lib/direntry.cpp + dir_API.cpp +) # Link Google Test to your test executables target_link_libraries(${TARGET_LAYER0} gtest gtest_main) @@ -24,4 +29,5 @@ target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main) # add test to activate ctest -VV add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE}) add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE}) -add_test(NAME ${TARGET_LAYER2_API} COMMAND sudo ./${TARGET_LAYER2_API} ${DIR_PLACE}) \ No newline at end of file +add_test(NAME ${TARGET_LAYER2_API} COMMAND sudo ./${TARGET_LAYER2_API} ${DIR_PLACE}) +add_test(NAME ${TARGET_DIR_API} COMMAND sudo ./${TARGET_DIR_API} ${DIR_PLACE}) \ No newline at end of file diff --git a/test/dir_API.cpp b/test/dir_API.cpp new file mode 100644 index 0000000..fb93b31 --- /dev/null +++ b/test/dir_API.cpp @@ -0,0 +1,91 @@ +/*********************************************************** + Directory owns treeNode and FileNode structure, detect S_IFDIR to make treeNode or not (see add_entry Function) + File owns FileNode structure only, detect !S_IFDIR + +*/ +#include +#include +#include +#include +#include +#include "fs.h" +#include "direntry.h" + +int main() { + TreeNode *root = createDirectory("/", NULL, 20); + INode inode_file1; + fischl_add_entry(root, 2, "file1",&inode_file1); + //I will put this function in create_new_inode function, there will inode number(2) when inode_allocate + INode inode_dir1; + //permission is necessary there to create treeNode or not + u_int64_t ddd_permissions = 0; + inode_dir1.permissions = ddd_permissions | S_IFDIR; + fischl_add_entry(root, 3, "dir1",&inode_dir1); + //find dir file (from root directory view, root contains dir1/ subdirectory) + FileNode *get_dir1 = fischl_find_entry(root,"/dir1/"); + if(get_dir1 == NULL){ + printf("No dir1 under %s\n",root->dirName); + return -1; + }else{ + fprintf(stderr,"[%s ,%d]",__func__,__LINE__); + printf(" %s under %s\n",get_dir1->name,root->dirName); + } + //add file2 under dir1 + INode inode_file2; + if(get_dir1->subdirectory != NULL){ + //Treenode dir(you cannot find here), you only can get Filenode dir based on fischl_find_entry Function + //So use Filenode->subdirectory will point to the treenode dir, then can add files + fischl_add_entry(get_dir1->subdirectory, 4, "file2",&inode_file2); + printf("add file2 in dir1\n"); + } + /**********************************************************/ + //This is for debugging, and demonstate to you + TreeNode *get_dir1_tree = find_parentPath(root,"/dir1/file2"); + if(get_dir1_tree == get_dir1->subdirectory){ + fprintf(stderr,"[%s ,%d]",__func__,__LINE__); + printf(" [Treenode]get_dir1_tree->dirName (%s) same [Filenode]get_dir1->name (%s)\n",get_dir1_tree->dirName,get_dir1->name); + }else{ + printf("not same\n"); + } + /**********************************************************/ + //two Ways to get File(include dir itself) information + FileNode *get_file2 =NULL; + //1. absolute path, the root(treeNode) will always exist when initialize + get_file2 = fischl_find_entry(root,"/dir1/file2"); + if(get_file2 == NULL){ + printf("No dir1 under dir1\n"); + return -1; + }else{ + fprintf(stderr,"[%s ,%d]",__func__,__LINE__); + printf(" %s under %sdir1/\n",get_file2->name,root->dirName); + } + //2. relative path, the get_dir1(FileNode)->subdirectory(treeNode), use treeNode(dir) to find + get_file2 = fischl_find_entry(get_dir1->subdirectory,"/file2"); + if(get_file2 == NULL){ + printf("No dir1 under %s\n",get_dir1->subdirectory->dirName); + return -1; + }else{ + fprintf(stderr,"[%s ,%d]",__func__,__LINE__); + printf(" %s under %s\n",get_file2->name,get_dir1->subdirectory->dirName); + } + /**********************************************************/ + //add one more file under dir1 + INode inode_file3; + if(get_dir1->subdirectory != NULL){ + fischl_add_entry(get_dir1_tree, 5, "file3",&inode_file3); + printf("add file3 in dir1\n"); + } + FileNode *get_file3 =NULL; + //fischl_find_entry(get_dir1->subdirectory,"/file3"); are equivalent + get_file3 = fischl_find_entry(get_dir1_tree,"/file3"); + if(get_file3 == NULL){ + printf("No dir1 under %s\n",get_dir1_tree->dirName); + return -1; + }else{ + printf(" %s under %s\n",get_file3->name,get_dir1_tree->dirName); + } + // Cleanup + freeTree(root); + + return 0; +} \ No newline at end of file From 7c82ccfa3a371a22ffdd78ca539d613ac913d11a Mon Sep 17 00:00:00 2001 From: FactorialN Date: Sun, 19 Nov 2023 21:23:51 -0800 Subject: [PATCH 16/63] try to start a layer 3 --- .DS_Store | Bin 6148 -> 6148 bytes include/fischl.h | 7 - include/fs.h | 470 ---------------------------------------------- include/rawdisk.h | 82 -------- lib/fischl.cpp | 68 ++++++- lib/main.cpp | 3 +- 6 files changed, 64 insertions(+), 566 deletions(-) delete mode 100644 include/fischl.h delete mode 100644 include/fs.h delete mode 100644 include/rawdisk.h diff --git a/.DS_Store b/.DS_Store index 4c4a626498b9ac10f7390de268ae7072cea2da3e..07b8666e9124035200c20cdfe03622c42a8ab216 100644 GIT binary patch delta 31 ncmZoMXfc@J&&akhU^gQp+hiW5@XeE%N?0d07;I+e_{$Ffn~VwD delta 62 zcmZoMXfc@J&&a+pU^gQp`(z%ba77LVUxq}6Y=%^ZG=@xu9EMcSoc!dZoctsP1_l8J S2B!4QAxzDzo7p-3@&f?mHxE(( diff --git a/include/fischl.h b/include/fischl.h deleted file mode 100644 index 7226576..0000000 --- a/include/fischl.h +++ /dev/null @@ -1,7 +0,0 @@ -class fischl{ - - // declare - public: - int init(); - -}; \ No newline at end of file diff --git a/include/fs.h b/include/fs.h deleted file mode 100644 index 63da3f6..0000000 --- a/include/fs.h +++ /dev/null @@ -1,470 +0,0 @@ -#include "rawdisk.h" -/***************************************************** -30GB Disk low-level operation and data structure: spuerblock, inode, and buffer cache -512 bytes sector for 1 block, 62914560 block(sector) -4K bytes sector for 1 block, 7864320 block(sector) - -one inode equipped with one 512 bytes block - -*****************************************************/ -#define SECTOR_SIZE 512 -#define IO_BLOCK_SIZE 4096 -#define MAX_INODE 524288 -#define MAX_BLOCKNUM MAX_INODE*2 //62914560 - -class SuperBlock{ - -public: - SuperBlock(){ - - } - ~SuperBlock(){ - - } - static u_int64_t getFreeListHead(RawDisk &disk){ - char buffer[8] = {0}; - disk.rawdisk_read(0, buffer, sizeof(buffer)); - u_int64_t t = 0; - for (int j = 0; j < 8; j++) - t = t | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); - return t; - } - - static void writeFreeListHead(RawDisk &disk, u_int64_t t){ - char buffer[8] = {0}; - for (int j = 0; j < 8; j++){ - buffer[j] = (t >> (8 * j)) & 0xFF; - } - disk.rawdisk_write(0, buffer, sizeof(buffer)); - } - - static u_int64_t getFreeINodeHead(RawDisk &disk){ - char buffer[8] = {0}; - disk.rawdisk_read(8, buffer, sizeof(buffer)); - u_int64_t t = 0; - for (int j = 0; j < 8; j++) - t = t | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); - return t; - } - - static void writeFreeINodeHead(RawDisk &disk, u_int64_t t){ - char buffer[8] = {0}; - for (int j = 0; j < 8; j++){ - buffer[j] = (t >> (8 * j)) & 0xFF; - } - disk.rawdisk_write(8, buffer, sizeof(buffer)); - } -}; - -class INode{ - // direct datablocks - u_int64_t blocks[48]; - // indirect address - u_int64_t single_indirect, double_indirect, triple_indirect; - // other - - u_int64_t uid; - u_int64_t gid; - u_int64_t permissions; - u_int64_t size; - u_int64_t block_number; - -public: - void read_get_byte(u_int64_t &t, int ¤t_pos, char *buffer){ - t = 0; - for (int j = 0; j < 8; j++) - t = t | (((u_int64_t)(unsigned char)buffer[j+current_pos])<<(8*j)); - current_pos += 8; - } - - static u_int64_t read_byte_at(int current_pos, char *buffer){ - u_int64_t t = 0; - for (int j = 0; j < 8; j++) - t = t | (((u_int64_t)(unsigned char)buffer[j+current_pos])<<(8*j)); - return t; - } - - void inode_construct(u_int64_t blockNumber, RawDisk &disk){ - char buffer[SECTOR_SIZE] = {0}; - disk.rawdisk_read(blockNumber*SECTOR_SIZE, buffer, sizeof(buffer)); - block_number = blockNumber; - int current_pos = 0; - // initialize blocks - for (int i = 0; i < 48; i++){ - read_get_byte(blocks[i], current_pos, buffer); - } - read_get_byte(single_indirect, current_pos, buffer); - read_get_byte(double_indirect, current_pos, buffer); - read_get_byte(triple_indirect, current_pos, buffer); - read_get_byte(uid, current_pos, buffer); - read_get_byte(gid, current_pos, buffer); - read_get_byte(permissions, current_pos, buffer); - read_get_byte(size, current_pos, buffer); - } - - void write_get_byte(u_int64_t t, int ¤t_pos, char *buffer){ - for (int j = 0; j < 8; j++){ - buffer[j+current_pos] = t & (((u_int64_t)1<<(8))-1); - t >>= 8; - } - current_pos += 8; - } - - static void write_byte_at(u_int64_t t, int current_pos, char *buffer){ - for (int j = 0; j < 8; j++){ - buffer[j+current_pos] = t & (((u_int64_t)1<<(8))-1); - t >>= 8; - } - } - - void inode_save(RawDisk &disk){ - char buffer[SECTOR_SIZE] = {0}; - int current_pos = 0; - for (int i = 0; i < 48; i++){ - write_get_byte(blocks[i], current_pos, buffer); - } - write_get_byte(single_indirect, current_pos, buffer); - write_get_byte(double_indirect, current_pos, buffer); - write_get_byte(triple_indirect, current_pos, buffer); - write_get_byte(uid, current_pos, buffer); - write_get_byte(gid, current_pos, buffer); - write_get_byte(permissions, current_pos, buffer); - write_get_byte(size, current_pos, buffer); - disk.rawdisk_write(block_number*SECTOR_SIZE, buffer, sizeof(buffer)); - } - - u_int64_t datablock_allocate_in_list(RawDisk &disk){ - //find a free data block - u_int64_t freeListHead = SuperBlock::getFreeListHead(disk); - /* - 1. initialization - 2. data block starting position - 3. r/w between storage and rawdisk to maintain - */ - char buffer[IO_BLOCK_SIZE] = {0}; - u_int64_t freeBlockNum = 0; - disk.rawdisk_read(freeListHead, buffer, sizeof(buffer)); - for (int i = 8; i < 264; i++){ - if((i < 263 && buffer[i] != -1) || (i == 263 && buffer[i] != 127)){ - int j = 0; - for (j = 0; j < 8; j++){ - if ((buffer[i]&(1<= 0; i-=8){ - u_int64_t addr = read_byte_at(i, buffer); - if(addr != 0){ - freeBlockNum = addr; - addr = 0; - write_byte_at(addr, i, buffer); - delpoint = i; - break; - } - } - disk.rawdisk_write(single_i, buffer, sizeof(buffer)); - u_int64_t addr = read_byte_at(0, buffer); - if (delpoint == 0 && addr == 0){ - datablock_deallocate_in_list(single_i, disk); - single_i = 0; - } - return freeBlockNum; - } - - u_int64_t deallo_double_indirect(RawDisk &disk, u_int64_t &double_i){ - if (double_i == 0){ - return false; - } - u_int64_t freeBlockNum = 0; - char buffer[IO_BLOCK_SIZE] = {0}; - int delpoint = -1; - disk.rawdisk_read(double_i, buffer, sizeof(buffer)); - for (int i=4088; i >= 0; i-=8){ - u_int64_t addr = read_byte_at(i, buffer); - u_int64_t inSingle = deallo_single_indirect(disk, addr); - if (inSingle){ - freeBlockNum = inSingle; - write_byte_at(addr, i, buffer); - delpoint = i; - break; - } - } - disk.rawdisk_write(double_i, buffer, sizeof(buffer)); - u_int64_t addr = read_byte_at(0, buffer); - if (delpoint == 0 && addr == 0){ - datablock_deallocate_in_list(double_i, disk); - double_i = 0; - } - return freeBlockNum; - } - - u_int64_t deallo_triple_indirect(RawDisk &disk, u_int64_t &triple_i){ - if (triple_i == 0){ - return false; - } - u_int64_t freeBlockNum = 0; - char buffer[IO_BLOCK_SIZE] = {0}; - int delpoint = -1; - disk.rawdisk_read(triple_i, buffer, sizeof(buffer)); - for (int i=4088; i >= 0; i-=8){ - u_int64_t addr = read_byte_at(i, buffer); - u_int64_t inDouble = deallo_double_indirect(disk, addr); - if (inDouble){ - freeBlockNum = inDouble; - write_byte_at(addr, i, buffer); - delpoint = i; - break; - } - } - disk.rawdisk_write(triple_i, buffer, sizeof(buffer)); - u_int64_t addr = read_byte_at(0, buffer); - if (delpoint == 0 && addr == 0){ - datablock_deallocate_in_list(triple_i, disk); - triple_i = 0; - } - return freeBlockNum; - } - - // deallocate 1 datablock from the end of the file - u_int64_t datablock_deallocate(RawDisk &disk){ - // find the last datablock and remove it from inode (triple->direct) - u_int64_t freeBlockNum = 0; - freeBlockNum = deallo_triple_indirect(disk, triple_indirect); - if(!freeBlockNum){ - freeBlockNum = deallo_double_indirect(disk, double_indirect); - if(!freeBlockNum){ - freeBlockNum = deallo_single_indirect(disk, single_indirect); - if(!freeBlockNum){ - for(int i = 47; i>=0; i--) - if(blocks[i] != 0){ - freeBlockNum = blocks[i]; - blocks[i] = 0; - break; - } - // deal with empty - } - } - } - - // add it back to freeBlocklist - datablock_deallocate_in_list(freeBlockNum, disk); - inode_save(disk); - return freeBlockNum; - } -}; - -class INodeOperation{ -// free list head is at super block (0): first 8 bytes - -public: - //initialization of the rawdisk - void initialize(RawDisk &disk){ - // initialize Inode list head - SuperBlock::writeFreeINodeHead(disk, 1); - for (u_int64_t i = 1; i < MAX_INODE; i++){ - char buffer[SECTOR_SIZE] = {0}; - u_int64_t t = i + 1; - if (t < MAX_INODE){ - for (int j = 0; j < 8; j++){ - buffer[j] = (t >> (8 * j)) & 0xFF; - } - } - disk.rawdisk_write(i*SECTOR_SIZE, buffer, sizeof(buffer)); - } - SuperBlock::writeFreeListHead(disk, MAX_INODE*SECTOR_SIZE); // maximum inode number 2^19 0x80000 - //Have tested this initialize function but MAX_BLOCK too much, MAX_INODE*2 works - for (u_int64_t i = MAX_INODE; i < MAX_BLOCKNUM-4096; i += 2048*8){ - char buffer[IO_BLOCK_SIZE] = {0}; - u_int64_t t = (i + 2048*8)*SECTOR_SIZE; - //t is address, storing in to buffer - for (int j = 0; j < 8; j++){ - buffer[j] = (t >> (8 * j)) & 0xFF; - } - disk.rawdisk_write(i*SECTOR_SIZE, buffer, sizeof(buffer)); - } - } - - // allocate an inode from free inode list head and return the number of the inode - // the i-th inode is in the i-th block - u_int64_t inode_allocate(RawDisk &disk){ - u_int64_t freeINodeHead = SuperBlock::getFreeINodeHead(disk); - char buffer[SECTOR_SIZE] = {0}; - disk.rawdisk_read(freeINodeHead*SECTOR_SIZE, buffer, sizeof(buffer)); - u_int64_t newINodeHead = INode::read_byte_at(0, buffer); - // deal with no more INode - SuperBlock::writeFreeINodeHead(disk, newINodeHead); - //to do: initialize the INode on disk at freeINodeHead - - //return inode number - return freeINodeHead; - } - - // free the inode and add it to the free inode list head - void inode_free(RawDisk &disk, u_int64_t INodeNumber){ - u_int64_t freeINodeHead = SuperBlock::getFreeINodeHead(disk); - char buffer[SECTOR_SIZE] = {0}; - INode::write_byte_at(freeINodeHead, 0, buffer); - disk.rawdisk_write(INodeNumber*SECTOR_SIZE, buffer, sizeof(buffer)); - SuperBlock::writeFreeINodeHead(disk, INodeNumber); - } - - //ignore for now - void inode_read(){ - - } - - void inode_write(){ - - } -}; \ No newline at end of file diff --git a/include/rawdisk.h b/include/rawdisk.h deleted file mode 100644 index 4cccf70..0000000 --- a/include/rawdisk.h +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -class RawDisk{ - - int fd; - const char* dir; - u_int64_t numSectors; - u_int64_t diskSize; - -public: - RawDisk(const char *directory) : fd(-1), dir(nullptr), numSectors(0), diskSize(0) { - dir = directory; - /*dir = strdup("/dev/vdc"); - numSectors = 62914560; - diskSize = 32212254720;*/ - - // Open the block device (replace /dev/sdX with the actual device) - fd = open(dir, O_RDWR); // Allow read and write - if (fd == -1) { - perror("Error opening device"); - exit(1); - } - - // Use ioctl with BLKGETSIZE to get the number of sectors - if (ioctl(fd, BLKGETSIZE64, &diskSize) == -1) { - perror("Error getting disk size"); - close(fd); - exit(1); - } - - // Calculate the size in bytes - numSectors = diskSize / 512; // Assuming a sector size of 512 bytes - - printf("====Initializing RawDisk====\n"); - printf("Number of sectors: %llu\n", numSectors); - printf("Disk size (in bytes): %llu\n", diskSize); - } - - ~RawDisk() { - if (fd != -1) { - close(fd); - } - } - - int rawdisk_read(u_int64_t offset, char *buffer, size_t length) { - if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) { - perror("Error seeking to offset"); - return -1; - } - - ssize_t bytesRead = read(fd, buffer, length); - if (bytesRead == -1) { - perror("Error reading from device"); - return -1; - } - - return 0; - } - - // Write a specified number of bytes at a given byte offset - int rawdisk_write(u_int64_t offset, char *buffer, size_t length) { - if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) { - perror("Error seeking to offset"); - return -1; - } - - ssize_t bytesWritten = write(fd, buffer, length); - if (bytesWritten == -1) { - perror("Error writing to device"); - return -1; - } - - return 0; - } - -}; \ No newline at end of file diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 3cc7ad7..5b7ffae 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -1,8 +1,66 @@ -#include "fischl.h" +#define FUSE_USE_VERSION 31 -#include +#include +#include +#include +#include +#include +#include +#include -int fischl::init(){ - printf("Hello Fischl!"); - return 3; +static int fischl_mkdir(const char *, mode_t) { + + return 0; +} + +static int fischl_open(const char *path, struct fuse_file_info *fi) { + + return 0; +} + +static const struct fuse_operations fischl_oper = { + .init = fischl_init, + .getattr = fischl_getattr, + .readdir = fischl_readdir, + .open = fischl_open, + .mkdir = fischl_mkdir, + .read = fischl_read, +}; + +static void show_help(const char *progname) +{ + printf("usage: %s [options] \n\n", progname); + printf("File-system specific options:\n" + " --name= Name of the \"hello\" file\n" + " (default: \"hello\")\n" + " --contents= Contents \"hello\" file\n" + " (default \"Hello, World!\\n\")\n" + "\n"); +} + +int main(int argc, char *argv[]) +{ + int ret; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + + + + /* Parse options */ + if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) + return 1; + + /* When --help is specified, first print our own file-system + specific help text, then signal fuse_main to show + additional help (by adding `--help` to the options again) + without usage: line (by setting argv[0] to the empty + string) */ + if (options.show_help) { + show_help(argv[0]); + assert(fuse_opt_add_arg(&args, "--help") == 0); + args.argv[0][0] = '\0'; + } + + ret = fuse_main(args.argc, args.argv, &hello_oper, NULL); + fuse_opt_free_args(&args); + return ret; } \ No newline at end of file diff --git a/lib/main.cpp b/lib/main.cpp index 396b885..e7ad5c2 100644 --- a/lib/main.cpp +++ b/lib/main.cpp @@ -2,8 +2,7 @@ #include "rawdisk.h" int main(){ - fischl *F = new fischl; - F->init(); + fischl(); char *d = strdup("/dev/vdc"); RawDisk *H = new RawDisk(d); return 0; From b959e7b0935318af0eca01a64ee13915b6ba5364 Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 20 Nov 2023 23:32:19 -0800 Subject: [PATCH 17/63] support . and .. search in find_entry, add init_entry for fake root --- include/direntry.h | 2 ++ lib/direntry.cpp | 45 ++++++++++++++++++++++++++++++++++++++------- test/dir_API.cpp | 25 ++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/include/direntry.h b/include/direntry.h index ff4792d..be06514 100644 --- a/include/direntry.h +++ b/include/direntry.h @@ -33,6 +33,8 @@ typedef struct treeNode { FileNode *self_info; //self fileNode infromation } TreeNode; +/*for root*/ +TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *new_inode); /*root directory have its own initialization, so parent wont be NULL*/ int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode); /*if want to use dir mode use the subdirectory treeNode pointer */ diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 12eb1c9..0d11546 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -127,6 +127,20 @@ void freeTree(TreeNode *node) { /*********************************Direntry operation****************************************** ********************************************************************************************/ +//for fake root (mount point) +TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *new_inode) { + TreeNode *newDir = (TreeNode *)malloc(sizeof(TreeNode)); + newDir->dirName = strdup(fileName); + newDir->contents = createHashTable(20);//hashSize define 20 + newDir->parent = newDir; + FileNode *newFile = (FileNode *)malloc(sizeof(FileNode)); + newFile->name = strdup(fileName); + newFile->inode_number = new_inode_number; + newFile->permissions = new_inode->permissions; + newDir->self_info = newFile; + return newDir; +} + int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode){ char *Name = strdup(fileName); TreeNode *newDir = NULL; @@ -156,17 +170,34 @@ FileNode *fischl_find_entry(TreeNode *root, const char *path){ FileNode *file = NULL; while (segment != NULL && current != NULL) { - file = lookupHash(current->contents, segment); - if (file != NULL && file->subdirectory == NULL) { - free(pathCopy); - return file; //File found - //return current; return filenode + if (strcmp(segment, "..") == 0) { + // Move up to the parent directory + current = current->parent; + if (current == NULL) { + // If there's no parent, we've reached the top of the tree, but root itself is same + break; + } + } else if (strcmp(segment, ".") == 0) { + // Stay in the current directory (no action needed) + } + else{ + file = lookupHash(current->contents, segment); + if (file != NULL && file->subdirectory == NULL) { + free(pathCopy); + return file; //File found + //return current; return filenode + } + current = file ? file->subdirectory : NULL; } - current = file ? file->subdirectory : NULL; segment = strtok(NULL, "/"); } free(pathCopy); + + if (current != NULL && file == NULL) { + // If we've stopped at a directory and not a file, return the directory's self info + return current->self_info; + } + return file; // NULL if not found - //return current; return filenode } \ No newline at end of file diff --git a/test/dir_API.cpp b/test/dir_API.cpp index fb93b31..2d2b2a4 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -12,19 +12,25 @@ #include "direntry.h" int main() { - TreeNode *root = createDirectory("/", NULL, 20); + //Init fake root directory + INode inode_root; + u_int64_t file_permissions = 0; + inode_root.permissions = file_permissions | S_IFDIR; + TreeNode *root = fischl_init_entry(0, "/", &inode_root);//0 is inode number assigned by inode_allocate() + //add file or dir under fake root INode inode_file1; fischl_add_entry(root, 2, "file1",&inode_file1); //I will put this function in create_new_inode function, there will inode number(2) when inode_allocate INode inode_dir1; //permission is necessary there to create treeNode or not - u_int64_t ddd_permissions = 0; - inode_dir1.permissions = ddd_permissions | S_IFDIR; + file_permissions = 0; + inode_dir1.permissions = file_permissions | S_IFDIR; fischl_add_entry(root, 3, "dir1",&inode_dir1); //find dir file (from root directory view, root contains dir1/ subdirectory) FileNode *get_dir1 = fischl_find_entry(root,"/dir1/"); if(get_dir1 == NULL){ printf("No dir1 under %s\n",root->dirName); + freeTree(root); return -1; }else{ fprintf(stderr,"[%s ,%d]",__func__,__LINE__); @@ -54,6 +60,7 @@ int main() { get_file2 = fischl_find_entry(root,"/dir1/file2"); if(get_file2 == NULL){ printf("No dir1 under dir1\n"); + freeTree(root); return -1; }else{ fprintf(stderr,"[%s ,%d]",__func__,__LINE__); @@ -63,6 +70,7 @@ int main() { get_file2 = fischl_find_entry(get_dir1->subdirectory,"/file2"); if(get_file2 == NULL){ printf("No dir1 under %s\n",get_dir1->subdirectory->dirName); + freeTree(root); return -1; }else{ fprintf(stderr,"[%s ,%d]",__func__,__LINE__); @@ -80,10 +88,21 @@ int main() { get_file3 = fischl_find_entry(get_dir1_tree,"/file3"); if(get_file3 == NULL){ printf("No dir1 under %s\n",get_dir1_tree->dirName); + freeTree(root); return -1; }else{ printf(" %s under %s\n",get_file3->name,get_dir1_tree->dirName); } + FileNode *get_file1 = NULL;//under root + //use .. to find + get_file1 = fischl_find_entry(get_dir1_tree,"../file1"); + if(get_file1 == NULL){ + printf("No file1\n"); + freeTree(root); + return -1; + }else{ + printf(" %s under root(..)\n",get_file1->name); + } // Cleanup freeTree(root); From 7d5fd98e15e4d686acc76aae94602eea2b9346f5 Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 21 Nov 2023 01:34:06 -0800 Subject: [PATCH 18/63] reform dir_API to Google Test framwork --- include/direntry.h | 3 +- lib/direntry.cpp | 4 +- test/CMakeLists.txt | 1 + test/dir_API.cpp | 159 +++++++++++++++++++++----------------------- 4 files changed, 80 insertions(+), 87 deletions(-) diff --git a/include/direntry.h b/include/direntry.h index be06514..62bd623 100644 --- a/include/direntry.h +++ b/include/direntry.h @@ -35,7 +35,8 @@ typedef struct treeNode { /*for root*/ TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *new_inode); -/*root directory have its own initialization, so parent wont be NULL*/ +/*the to be added file in add_entry should be parent-child relationship with treenode, otherwise will wrong */ +/*see Add_FindFiletest in dir_API.cpp*/ int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode); /*if want to use dir mode use the subdirectory treeNode pointer */ //e.g. FileNode *Dirnode = fischl_find_entry(); can see file inside with Dirnode->subdirectory diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 0d11546..83df23d 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -64,7 +64,7 @@ TreeNode *find_parentPath(TreeNode *root, const char *path) { file = lookupHash(current->contents, segment); if (file != NULL && file->subdirectory == NULL) { free(pathCopy); - printf("status current directory %s\n",current->dirName); + //printf("status current directory %s\n",current->dirName); return current; //File found } current = file ? file->subdirectory : NULL; @@ -107,7 +107,7 @@ void freeTree(TreeNode *node) { freeTree(temp->subdirectory); } // Free the FileNode if it's not a directory - printf("free who %s\n",temp->name); + // printf("free who %s\n",temp->name); free(temp->name); free(temp); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 82ccfd4..95628fe 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(${TARGET_DIR_API} # Link Google Test to your test executables target_link_libraries(${TARGET_LAYER0} gtest gtest_main) target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main) +target_link_libraries(${TARGET_DIR_API} gtest gtest_main) # add test to activate ctest -VV add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE}) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index 2d2b2a4..2b124b8 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -8,103 +8,94 @@ #include #include #include +#include #include "fs.h" #include "direntry.h" -int main() { +const char* d; + +TreeNode *root;//global can be taken + +TEST(DirTest, root_test) { //Init fake root directory INode inode_root; u_int64_t file_permissions = 0; inode_root.permissions = file_permissions | S_IFDIR; - TreeNode *root = fischl_init_entry(0, "/", &inode_root);//0 is inode number assigned by inode_allocate() - //add file or dir under fake root - INode inode_file1; - fischl_add_entry(root, 2, "file1",&inode_file1); - //I will put this function in create_new_inode function, there will inode number(2) when inode_allocate - INode inode_dir1; - //permission is necessary there to create treeNode or not + root = fischl_init_entry(0, "/", &inode_root);//0 is inode number assigned by inode_allocate() +} +TEST(DirTest, AddFile_test) { + //assume file and dir itself(content,metadata) same,but different name and inode number + INode inode_file; + INode inode_dir; + u_int64_t file_permissions = 0; file_permissions = 0; - inode_dir1.permissions = file_permissions | S_IFDIR; - fischl_add_entry(root, 3, "dir1",&inode_dir1); - //find dir file (from root directory view, root contains dir1/ subdirectory) - FileNode *get_dir1 = fischl_find_entry(root,"/dir1/"); - if(get_dir1 == NULL){ - printf("No dir1 under %s\n",root->dirName); - freeTree(root); - return -1; - }else{ - fprintf(stderr,"[%s ,%d]",__func__,__LINE__); - printf(" %s under %s\n",get_dir1->name,root->dirName); - } - //add file2 under dir1 - INode inode_file2; - if(get_dir1->subdirectory != NULL){ - //Treenode dir(you cannot find here), you only can get Filenode dir based on fischl_find_entry Function - //So use Filenode->subdirectory will point to the treenode dir, then can add files - fischl_add_entry(get_dir1->subdirectory, 4, "file2",&inode_file2); - printf("add file2 in dir1\n"); - } - /**********************************************************/ - //This is for debugging, and demonstate to you - TreeNode *get_dir1_tree = find_parentPath(root,"/dir1/file2"); - if(get_dir1_tree == get_dir1->subdirectory){ - fprintf(stderr,"[%s ,%d]",__func__,__LINE__); - printf(" [Treenode]get_dir1_tree->dirName (%s) same [Filenode]get_dir1->name (%s)\n",get_dir1_tree->dirName,get_dir1->name); - }else{ - printf("not same\n"); - } - /**********************************************************/ + inode_dir.permissions = file_permissions | S_IFDIR; + fischl_add_entry(root, 2, "file1",&inode_file); + fischl_add_entry(root, 3, "dir1",&inode_dir); +} +TEST(DirTest, FindFile_test) { + //find file + FileNode *get_file = fischl_find_entry(root,"/file1"); + EXPECT_TRUE(get_file != NULL); + EXPECT_STREQ(get_file->name,"file1"); + //find dir + FileNode *get_dir = fischl_find_entry(root,"/dir1/"); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "dir1"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + //check . function + get_dir = fischl_find_entry(root,"./"); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "/"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory +} +TEST(DirTest, Add_FindFile_test) { + //add file and dir under subdirectory instead of root + INode inode_file; + INode inode_dir; + u_int64_t file_permissions = 0; + file_permissions = 0; + inode_dir.permissions = file_permissions | S_IFDIR; + + /*add with subdirectory*/ + //Treenode dir(you cannot find here), you only can get Filenode dir based on fischl_find_entry Function + //So use Filenode->subdirectory will point to the treenode dir, then can add files + FileNode *get_dir = fischl_find_entry(root,"/dir1/"); + fischl_add_entry(get_dir->subdirectory, 4, "file2",&inode_file); + + //verfication treeNode and Filenode relationship + TreeNode *get_dir_tree = find_parentPath(root,"/dir1/file2"); + ASSERT_TRUE(get_dir_tree == get_dir->subdirectory);//treeNode dir should be same as treeNode subdir in that Filenode + //two Ways to get File(include dir itself) information - FileNode *get_file2 =NULL; + FileNode *get_file = NULL; //1. absolute path, the root(treeNode) will always exist when initialize - get_file2 = fischl_find_entry(root,"/dir1/file2"); - if(get_file2 == NULL){ - printf("No dir1 under dir1\n"); - freeTree(root); - return -1; - }else{ - fprintf(stderr,"[%s ,%d]",__func__,__LINE__); - printf(" %s under %sdir1/\n",get_file2->name,root->dirName); - } + get_file = fischl_find_entry(root,"/dir1/file2"); + EXPECT_TRUE(get_file != NULL); + EXPECT_STREQ(get_file->name,"file2"); //2. relative path, the get_dir1(FileNode)->subdirectory(treeNode), use treeNode(dir) to find - get_file2 = fischl_find_entry(get_dir1->subdirectory,"/file2"); - if(get_file2 == NULL){ - printf("No dir1 under %s\n",get_dir1->subdirectory->dirName); - freeTree(root); - return -1; - }else{ - fprintf(stderr,"[%s ,%d]",__func__,__LINE__); - printf(" %s under %s\n",get_file2->name,get_dir1->subdirectory->dirName); - } + get_file = fischl_find_entry(get_dir->subdirectory,"/file2"); + EXPECT_TRUE(get_file != NULL); + EXPECT_STREQ(get_file->name,"file2"); /**********************************************************/ //add one more file under dir1 - INode inode_file3; - if(get_dir1->subdirectory != NULL){ - fischl_add_entry(get_dir1_tree, 5, "file3",&inode_file3); - printf("add file3 in dir1\n"); - } - FileNode *get_file3 =NULL; - //fischl_find_entry(get_dir1->subdirectory,"/file3"); are equivalent - get_file3 = fischl_find_entry(get_dir1_tree,"/file3"); - if(get_file3 == NULL){ - printf("No dir1 under %s\n",get_dir1_tree->dirName); - freeTree(root); - return -1; - }else{ - printf(" %s under %s\n",get_file3->name,get_dir1_tree->dirName); - } - FileNode *get_file1 = NULL;//under root - //use .. to find - get_file1 = fischl_find_entry(get_dir1_tree,"../file1"); - if(get_file1 == NULL){ - printf("No file1\n"); - freeTree(root); - return -1; - }else{ - printf(" %s under root(..)\n",get_file1->name); - } + fischl_add_entry(get_dir->subdirectory, 5, "file3",&inode_file); + //find + get_file = fischl_find_entry(get_dir_tree,"./file3"); + EXPECT_TRUE(get_file != NULL); + EXPECT_STREQ(get_file->name,"file3"); + //use .. from dir1 to find file1 + get_file = fischl_find_entry(get_dir_tree,"../file1"); + EXPECT_TRUE(get_file != NULL); + EXPECT_STREQ(get_file->name,"file1"); + +} + +int main(int argc, char **argv) { + d = (argc < 2) ? "/dev/vdc" : argv[1];//how to do with this? + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); // Cleanup freeTree(root); - - return 0; + return result; } \ No newline at end of file From 1580053bbe8f6f9476fbb191958d527f92b9d5ec Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 21 Nov 2023 02:25:50 -0800 Subject: [PATCH 19/63] add parsing path function to make it easy to test file on path correctness --- test/dir_API.cpp | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index 2b124b8..b6f081b 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -14,7 +14,19 @@ const char* d; -TreeNode *root;//global can be taken +//global can be taken +TreeNode *root; +const char* target_filepath; + +const char* get_baseName(const char *filename){ + const char* base_name = strrchr(filename, '/'); + if (base_name != NULL) { + base_name++; // Move past the '/' character + } else { + base_name = filename; // No '/' found, use the original string + } + return base_name; +} TEST(DirTest, root_test) { //Init fake root directory @@ -35,11 +47,13 @@ TEST(DirTest, AddFile_test) { } TEST(DirTest, FindFile_test) { //find file - FileNode *get_file = fischl_find_entry(root,"/file1"); + target_filepath = "/file1"; + FileNode *get_file = fischl_find_entry(root,target_filepath); EXPECT_TRUE(get_file != NULL); - EXPECT_STREQ(get_file->name,"file1"); + EXPECT_STREQ(get_file->name, get_baseName(target_filepath)); //find dir - FileNode *get_dir = fischl_find_entry(root,"/dir1/"); + target_filepath = "/dir1/"; + FileNode *get_dir = fischl_find_entry(root,target_filepath); EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "dir1"); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory @@ -48,6 +62,11 @@ TEST(DirTest, FindFile_test) { EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "/"); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + //check .. function + get_dir = fischl_find_entry(root,".."); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "/"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory } TEST(DirTest, Add_FindFile_test) { //add file and dir under subdirectory instead of root @@ -81,14 +100,23 @@ TEST(DirTest, Add_FindFile_test) { //add one more file under dir1 fischl_add_entry(get_dir->subdirectory, 5, "file3",&inode_file); //find - get_file = fischl_find_entry(get_dir_tree,"./file3"); + get_file = fischl_find_entry(get_dir->subdirectory,"./file3"); EXPECT_TRUE(get_file != NULL); EXPECT_STREQ(get_file->name,"file3"); //use .. from dir1 to find file1 - get_file = fischl_find_entry(get_dir_tree,"../file1"); + get_file = fischl_find_entry(get_dir->subdirectory,"../file1"); EXPECT_TRUE(get_file != NULL); EXPECT_STREQ(get_file->name,"file1"); - + //check dir1 with . + get_dir = fischl_find_entry(get_dir->subdirectory,"."); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "dir1"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + //check root with dir1 + get_dir = fischl_find_entry(get_dir->subdirectory,".."); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "/"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory } int main(int argc, char **argv) { From 1c222102098c3a5d28d7b55050b74d61641ce562 Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 21 Nov 2023 14:22:18 -0800 Subject: [PATCH 20/63] commit wza changes before merge --- include/direntry.h | 15 +-------------- lib/direntry.cpp | 37 +++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/dir_API.cpp | 10 ++++++++++ 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/include/direntry.h b/include/direntry.h index ff4792d..859668b 100644 --- a/include/direntry.h +++ b/include/direntry.h @@ -5,20 +5,6 @@ typedef struct fileNode { char *Symbolink; struct treeNode *subdirectory; struct fileNode *next; - void serialize(char* buffer) { - u_int64_t t = inode_number; - for (int j = 0; j < 8; j++){ - buffer[j] = t & (((u_int64_t)1<<(8))-1); - t >>= 8; - } - strcpy(buffer+8, name); - } - void deserialize(char* buffer) { - inode_number = 0; - for (int j = 0; j < 8; j++) - inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); - strcpy(name, buffer+8); - } } FileNode; typedef struct { @@ -35,6 +21,7 @@ typedef struct treeNode { /*root directory have its own initialization, so parent wont be NULL*/ int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode); +int fischl_rm_entry(TreeNode *parent, const char *fileName); /*if want to use dir mode use the subdirectory treeNode pointer */ //e.g. FileNode *Dirnode = fischl_find_entry(); can see file inside with Dirnode->subdirectory //e.g. go to the current Dirnode parent directory, use TreeNode *get_Dir_parent = Dirnode->subdirectory->parent; diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 12eb1c9..738de41 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -43,6 +43,29 @@ FileNode *lookupHash(HashTable *h, char *key) { return NULL; // Not found } +bool removeHash(HashTable *h, char *key) { + unsigned int hashval = hash(h, key); + FileNode *node = h->table[hashval]; + if (node == NULL) return false; + if (strcmp(node->name, key) == 0) { + h->table[hashval] = node->next; + return true; + } + FileNode *prev = NULL; + bool foundit = false; + while (node != NULL) { + if (strcmp(node->name, key) == 0) break; + prev = node; + node = node->next; + } + if (node == NULL) { + return false; + } else { + prev->next = node->next; + return true; + } +} + TreeNode *createDirectory(const char *dirName, TreeNode *parent, int hashSize) { TreeNode *newDir = (TreeNode *)malloc(sizeof(TreeNode)); newDir->dirName = strdup(dirName); @@ -148,6 +171,20 @@ int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileNam return 0; } +int fischl_rm_entry(TreeNode *parent, const char *fileName) { + char *fileName_dup = strdup(fileName); + if (parent->contents == NULL) return -1; + FileNode *file = NULL; + file = lookupHash(parent->contents, fileName_dup); + if (file == NULL) return -1; + if (file->subdirectory != NULL) freeTree(file->subdirectory); + removeHash(parent->contents, fileName_dup); + free(file->name); + free(file); + delete fileName_dup; +} + + FileNode *fischl_find_entry(TreeNode *root, const char *path){ //support . and .. function char *pathCopy = strdup(path); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 82ccfd4..77b3786 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(${TARGET_LAYER1_API} layer1_API.cpp ) add_executable(${TARGET_LAYER2_API} + ../lib/direntry.cpp ../lib/files.cpp layer2_API.cpp ) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index fb93b31..5d56cb6 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -84,6 +84,16 @@ int main() { }else{ printf(" %s under %s\n",get_file3->name,get_dir1_tree->dirName); } + // pressure test + INode inode_fileN; + for(int i=6;i<100;i++) { + fischl_add_entry(get_dir1_tree, i, (std::string("file")+std::to_string(i)).c_str(), &inode_fileN); + } + for(int i=6;i<100;i++){ + FileNode *get_fileN = fischl_find_entry(get_dir1_tree, (std::string("file")+std::to_string(i)).c_str()); + assert(get_fileN != NULL); + assert(get_fileN->inode_number == i); + } // Cleanup freeTree(root); From ffc1703edde90d6877bbceee8be73655045bba9a Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 21 Nov 2023 15:55:29 -0800 Subject: [PATCH 21/63] fix some bugs (I think) in direntry implementation --- lib/direntry.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 960562e..4b09bd8 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -160,6 +160,7 @@ TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *n newFile->name = strdup(fileName); newFile->inode_number = new_inode_number; newFile->permissions = new_inode->permissions; + newFile->subdirectory = newDir; newDir->self_info = newFile; return newDir; } @@ -212,7 +213,10 @@ FileNode *fischl_find_entry(TreeNode *root, const char *path){ current = current->parent; if (current == NULL) { // If there's no parent, we've reached the top of the tree, but root itself is same + file = NULL; break; + } else { + file = current->self_info; } } else if (strcmp(segment, ".") == 0) { // Stay in the current directory (no action needed) From c7b0bd95f4ff80914ae03f521c9d5a3cbf4b1435 Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 21 Nov 2023 16:14:08 -0800 Subject: [PATCH 22/63] change the API of direntry (should pass new dir_API.cpp test) --- test/dir_API.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index b6f081b..283dd04 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -99,6 +99,8 @@ TEST(DirTest, Add_FindFile_test) { /**********************************************************/ //add one more file under dir1 fischl_add_entry(get_dir->subdirectory, 5, "file3",&inode_file); + //add one more directory under dir1 + fischl_add_entry(get_dir->subdirectory, 6, "dir2", &inode_dir); //find get_file = fischl_find_entry(get_dir->subdirectory,"./file3"); EXPECT_TRUE(get_file != NULL); @@ -117,6 +119,15 @@ TEST(DirTest, Add_FindFile_test) { EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "/"); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + //use .. to access parent directory + get_dir = fischl_find_entry(root, "/dir1/dir2/.."); + EXPECT_TRUE(get_dir != NULL); + EXPECT_STREQ(get_dir->name, "dir1"); + FileNode *get_rootdir = fischl_find_entry(root, "/dir1/dir2/../.."); + EXPECT_TRUE(get_rootdir != NULL); + EXPECT_STREQ(get_rootdir->name, "/"); + EXPECT_TRUE(get_rootdir->subdirectory != NULL); + EXPECT_TRUE(get_rootdir->subdirectory->self_info == get_rootdir); } int main(int argc, char **argv) { From 460bcd5e7e792815f77437d5d919ce78a3a8e47a Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 21 Nov 2023 17:21:43 -0800 Subject: [PATCH 23/63] support 255 character filenames; use in memory tree to speed up namei --- CMakeLists.txt | 1 + include/files.h | 6 ++- lib/files.cpp | 118 +++++++++++++++++++++++++++++--------------- test/layer2_API.cpp | 6 ++- 4 files changed, 87 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81bcbfb..4a134ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(fischl lib/fischl.cpp lib/main.cpp lib/files.cpp + lib/direntry.cpp ) diff --git a/include/files.h b/include/files.h index 713bc03..a2ab95c 100644 --- a/include/files.h +++ b/include/files.h @@ -1,10 +1,11 @@ #include #include +#include "direntry.h" class FilesOperation { RawDisk& disk; INodeOperation inop; - u_int64_t root_inode; + TreeNode *root_node; INode* new_inode(u_int64_t inode_number, u_int64_t permissions); void create_dot_dotdot(INode*, u_int64_t); public: @@ -13,8 +14,9 @@ class FilesOperation { int write_datablock(INode& inode, u_int64_t index, const char* buffer); void initialize_rootinode(); void printDirectory(u_int64_t); - u_int64_t create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); + INode* create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); void unlink_inode(u_int64_t inode_number); + u_int64_t disk_namei(const char* path); u_int64_t namei(const char* path); u_int64_t fischl_mkdir(const char*, mode_t); u_int64_t fischl_mknod(const char*, mode_t); diff --git a/lib/files.cpp b/lib/files.cpp index 9304fcb..2b78405 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -2,8 +2,26 @@ #include "files.h" #include #include -#include "direntry.h" +#include +struct DirectoryEntry { + u_int64_t inode_number; + char file_name[256]; + void serialize(char* buffer) { + u_int64_t t = inode_number; + for (int j = 0; j < 8; j++){ + buffer[j] = t & (((u_int64_t)1<<(8))-1); + t >>= 8; + } + strcpy(buffer+8, file_name); + } + void deserialize(char* buffer) { + inode_number = 0; + for (int j = 0; j < 8; j++) + inode_number = inode_number | (((u_int64_t)(unsigned char)buffer[j])<<(8*j)); + strcpy(file_name, buffer+8); + } +}; FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { inop.initialize(disk); @@ -85,18 +103,20 @@ void FilesOperation::create_dot_dotdot(INode* inode, u_int64_t parent_inode_numb DirectoryEntry dotdot; dotdot.inode_number = parent_inode_number; strcpy(dotdot.file_name, ".."); - dotdot.serialize(buffer+64); + dotdot.serialize(buffer+264); int ret = write_datablock(*inode, 0, buffer); inode->inode_save(disk); } void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion - root_inode = inop.inode_allocate(disk); - printf("Info: root inode number: %llu\n", root_inode); - INode *get_inode = new_inode(root_inode, S_IFDIR); - create_dot_dotdot(get_inode, root_inode); - delete get_inode; + u_int64_t root_inode_number = inop.inode_allocate(disk); + printf("Info: root inode number: %llu\n", root_inode_number); + INode *root_inode = new_inode(root_inode_number, S_IFDIR); + create_dot_dotdot(root_inode, root_inode_number); + root_node = fischl_init_entry(root_inode_number, "/", root_inode); + assert(root_node->self_info!=NULL); + delete root_inode; } void FilesOperation::printDirectory(u_int64_t inode_number) { @@ -106,24 +126,24 @@ void FilesOperation::printDirectory(u_int64_t inode_number) { char buffer[IO_BLOCK_SIZE] = {0}; read_datablock(inode, 0, buffer); DirectoryEntry ent; - for(int i=0;i<=IO_BLOCK_SIZE-64;i+=64){ + for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(buffer+i); if (ent.inode_number) printf("%s\t%llu;\t", ent.file_name, ent.inode_number); } printf("\n"); } -u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode) { +INode* FilesOperation::create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode) { // trys to create a file under parent directory - if (strlen(name)>=56) { + if (strlen(name)>=256) { perror("Name too long, cannot create file or directory"); - return -1; + return NULL; } INode inode; inode.inode_construct(parent_inode_number, disk); if ((inode.permissions & S_IFMT) != S_IFDIR) { printf("Parent Inode is not a directory\n"); - return -1; + return NULL; } // Check if file or directory already exists @@ -131,11 +151,11 @@ u_int64_t FilesOperation::create_new_inode(u_int64_t parent_inode_number, const for (u_int64_t idx=0; idxpermissions & S_IFMT) == S_IFDIR) { create_dot_dotdot(get_inode, parent_inode_number); } - delete get_inode; - return new_inode_number; + return get_inode; } -u_int64_t FilesOperation::namei(const char* path) { +u_int64_t FilesOperation::disk_namei(const char* path) { // returns the inode number corresponding to path - u_int64_t current_inode = root_inode; + u_int64_t current_inode = root_node->self_info->inode_number; std::string current_dirname; std::istringstream pathStream(path); std::string new_name; std::getline(pathStream, new_name, '/'); if(!new_name.empty()){ - printf("namei: path should start with /\n"); + printf("disk_namei: path should start with /\n"); return -1; } while (std::getline(pathStream, new_name, '/')) { INode inode; inode.inode_construct(current_inode, disk); if ((inode.permissions & S_IFMT) != S_IFDIR || inode.size == 0) { - printf("namei: %s is not a non-empty directory\n", current_dirname.c_str()); + printf("disk_namei: %s is not a non-empty directory\n", current_dirname.c_str()); return -1; } u_int64_t new_inode_number = 0; @@ -206,7 +225,7 @@ u_int64_t FilesOperation::namei(const char* path) { for(u_int64_t idx=0; idxself_info->inode_number) // path = "/foo.txt" should return inode for foo.txt // path = "/mydir" should return inode for mydir // path = "/nonemptydir/foo" should return inode for foo // path = "/notnonemptydir/foo" should raise error } +u_int64_t FilesOperation::namei(const char* path) { + FileNode* filenode = fischl_find_entry(root_node, path); + if (filenode) return filenode->inode_number; + else return -1; +} + u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { //check path char *pathdup = strdup(path); @@ -238,16 +263,19 @@ u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { char *newDirname = lastSlash+1; //\0, get from char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only - u_int64_t parent_inode_number = namei(ParentPath); - if (parent_inode_number == (u_int64_t)-1) { - printf("fischl_mkdir failed because namei failed to find inode for %s\n", ParentPath); + FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; + if (parent_filenode == NULL) { + printf("parent %s not found by fischl_find_entry\n", ParentPath); delete pathdup; return -1; } + u_int64_t parent_inode_number = parent_filenode->inode_number; //make new inode - u_int64_t ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory + INode* ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory + if (ret == NULL) return -1; + fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newDirname, ret); delete pathdup; - return ret; + return ret->block_number; //after new_inode(mkfile), go to fischl_add_entry record @@ -260,17 +288,21 @@ u_int64_t FilesOperation::fischl_mknod(const char* path, mode_t mode) { *lastSlash = '\0'; // Split the string into parent path and new directory name; \0 char *newFilename = lastSlash+1; //\0, get from char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only - - u_int64_t parent_inode_number = namei(ParentPath); - if (parent_inode_number == (u_int64_t)-1) { - printf("fischl_mkdir failed because namei failed to find inode for %s\n", ParentPath); + printf("mknod ParentPath:%s, strlen=%d\n", ParentPath, strlen(ParentPath)); + FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; + if (parent_filenode == NULL) { + printf("parent %s not found by fischl_find_entry\n", ParentPath); delete pathdup; return -1; } + u_int64_t parent_inode_number = parent_filenode->inode_number; //make new inode - u_int64_t ret = create_new_inode(parent_inode_number, newFilename, mode); + INode* ret = create_new_inode(parent_inode_number, newFilename, mode); + if (ret == NULL) return -1; + //make new node + fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newFilename, ret); delete pathdup; - return ret; + return ret->block_number; } void FilesOperation::unlink_inode(u_int64_t inode_number) { @@ -281,7 +313,7 @@ void FilesOperation::unlink_inode(u_int64_t inode_number) { for(u_int64_t idx=0; idxinode_number; u_int64_t target_inode = 0; - + // remove its record from parent INode parent_INode; - parent_INode.inode_construct(parent_inode, disk); + parent_INode.inode_construct(parent_inode_number, disk); char rw_buffer[IO_BLOCK_SIZE] = {0}; for (u_int64_t idx=0; idxsubdirectory, filename); delete pathdup; return 0; } else { diff --git a/test/layer2_API.cpp b/test/layer2_API.cpp index 70eff32..0630e16 100644 --- a/test/layer2_API.cpp +++ b/test/layer2_API.cpp @@ -13,7 +13,6 @@ int main(int argc, char *argv[]) { fsop.initialize_rootinode(); // create multiple files using mkdir or mknod - // directories that contain more than 64 files use more than one datablocks, it is not supported yet printf("=== Part 1: create files by path ===\n"); u_int64_t file1 = fsop.fischl_mknod("/test",0); // mode here is not used yet printf("/test is inode %llu, it is a file\n", file1); @@ -113,4 +112,9 @@ int main(int argc, char *argv[]) { assert(inode_number == inode_numbers[i]); } fsop.printDirectory(file_pressure); + + // long filename test + std::string longfilename = std::string(255,'A'); + u_int64_t filelong = fsop.fischl_mknod((std::string("/")+longfilename).c_str(),0); + printf("/AAA...AAA is inode %llu, it is a file\n", filelong); } \ No newline at end of file From 5b220fdf467ea79d2aa836fdf3bfcd3891f9d36f Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 21 Nov 2023 19:59:17 -0800 Subject: [PATCH 24/63] add mock entrypath structure for testing --- test/dir_API.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index 283dd04..1f5d4e0 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "fs.h" #include "direntry.h" @@ -17,6 +18,20 @@ const char* d; //global can be taken TreeNode *root; const char* target_filepath; +typedef struct file_test{ + const char* name; + file_test* next;//use linked-list to know the file at the same level directory +}file_test; +typedef struct dir_test{ + const char* name; + file_test* inFile; + dir_test* subdir; + dir_test* next;//use linked-list to know the other dir at the same parent dir. +}dir_test; + +int total_number = 0; +int total_free_dir = 0; +int total_free_file = 0; const char* get_baseName(const char *filename){ const char* base_name = strrchr(filename, '/'); @@ -28,6 +43,145 @@ const char* get_baseName(const char *filename){ return base_name; } +const char* generateRandomName(size_t length) { + const std::string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::string randomString; + + for (size_t i = 0; i < length; ++i) { + randomString += chars[rand() % chars.size()]; + } + + // Allocate memory and copy the string + char* name = new char[randomString.length() + 1]; + strcpy(name, randomString.c_str()); + return name; +} + +// Recursive function to create directory hierarchy +dir_test* createDirHierarchy(int level, int maxLevel) { + if (level > maxLevel) { + return nullptr; + } + + dir_test* head = nullptr; + dir_test* current = nullptr; + + for (int i = 0; i < 3; ++i) { + dir_test* newDir = new dir_test; + newDir->name = generateRandomName(6); // Generate a random name for the directory + newDir->inFile = nullptr; // Initialize file list to nullptr + newDir->subdir = createDirHierarchy(level + 1, maxLevel); // Recursively create subdirectories + newDir->next = nullptr; + + // Create file list for this directory + file_test* fileHead = nullptr; + file_test* fileCurrent = nullptr; + for (int j = 0; j < 3; ++j) { + file_test* newFile = new file_test; + newFile->name = generateRandomName(6); // Generate a random name for the file + newFile->next = nullptr; + + if (!fileHead) { + fileHead = newFile; + } else { + fileCurrent->next = newFile; + } + fileCurrent = newFile; + } + newDir->inFile = fileHead; + + // Add the new directory to the list + if (!head) { + head = newDir; + } else { + current->next = newDir; + } + current = newDir; + } + + return head; +} + +// Setup function for the test directory +void setupTestDirectory(dir_test** root) { + fprintf(stderr,"[%s ,%d]\n",__func__,__LINE__); + // Allocate memory for root + *root = new dir_test; + (*root)->name = strdup("/"); // Generate a random name for the directory + (*root)->inFile = nullptr; // Initialize file list to nullptr + fprintf(stderr,"[%s ,%d]\n",__func__,__LINE__); + (*root)->subdir = createDirHierarchy(0, 1); + (*root)->next = nullptr; + fprintf(stderr,"[%s ,%d]\n",__func__,__LINE__); + file_test* fileHead = nullptr; + file_test* fileCurrent = nullptr; + for (int j = 0; j < 3; ++j) { + file_test* newFile = new file_test; + newFile->name = generateRandomName(6); // Generate a random name for the file + newFile->next = nullptr; + + if (!fileHead) { + fileHead = newFile; + } else { + fileCurrent->next = newFile; + } + fileCurrent = newFile; + } + (*root)->inFile = fileHead; +} +void setupTestDirectory_1(dir_test** root) { + + *root = createDirHierarchy(0, 1); +} + +// Function to free a list of files +void freeFileList(file_test* fileList) { + while (fileList != nullptr) { + file_test* temp = fileList; + fileList = fileList->next; + total_free_file++;//for debug + delete[] temp->name; // Free the name string + delete temp; // Free the current file + } +} + +// Recursive function to free the directory hierarchy +void freeDirHierarchy(dir_test* dir) { + while (dir != nullptr) { + dir_test* temp = dir; + dir = dir->next; + total_free_dir++;//for debug + freeFileList(temp->inFile); // Free the list of files in the directory + freeDirHierarchy(temp->subdir); // Recursively free subdirectories + delete[] temp->name; // Free the name string + delete temp; // Free the current directory + } +} + +// Function to print the list of files in a directory +void printFileList(const file_test* fileList) { + const file_test* currentFile = fileList; + while (currentFile != nullptr) { + // std::cout << " File: " << currentFile->name << std::endl; + currentFile = currentFile->next; + } +} + +void traverseDirHierarchy(const dir_test* dir, int depth = 0) { + while (dir != nullptr) { + // std::cout << "Depth " << depth << ", Directory: " << dir->name << std::endl; + total_number++;//for debug + + // Print files in this directory + printFileList(dir->inFile); + // Recursively traverse subdirectories + traverseDirHierarchy(dir->subdir, depth + 1); + + // Go to the next directory at the same level + dir = dir->next; + } +} + TEST(DirTest, root_test) { //Init fake root directory INode inode_root; @@ -131,10 +285,23 @@ TEST(DirTest, Add_FindFile_test) { } int main(int argc, char **argv) { - d = (argc < 2) ? "/dev/vdc" : argv[1];//how to do with this? + srand(time(NULL)); // Seed the random number generator + d = (argc < 2) ? "/dev/vdc" : argv[1]; + + dir_test* mock_root = nullptr; + setupTestDirectory(&mock_root); + ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); + + total_number = 0; + traverseDirHierarchy(mock_root);//mock_root + printf("Traverse Dir total %d\n",total_number); + // Cleanup + freeDirHierarchy(mock_root);//mock_root + printf("Free Dir total %d\n",total_free_dir); + printf("Free File total %d\n",total_free_file); freeTree(root); return result; } \ No newline at end of file From 209cd25c4468091b9e83e793ea8ada5289a5cf98 Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 21 Nov 2023 22:35:26 -0800 Subject: [PATCH 25/63] make mock file path able to run in for loop --- test/dir_API.cpp | 129 ++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 68 deletions(-) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index 1f5d4e0..ad9f783 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -13,11 +13,6 @@ #include "fs.h" #include "direntry.h" -const char* d; - -//global can be taken -TreeNode *root; -const char* target_filepath; typedef struct file_test{ const char* name; file_test* next;//use linked-list to know the file at the same level directory @@ -29,19 +24,17 @@ typedef struct dir_test{ dir_test* next;//use linked-list to know the other dir at the same parent dir. }dir_test; -int total_number = 0; +//global can be taken +const char* d; +TreeNode *root; +std::string target_filepath; +dir_test* mock_root = nullptr; + +int total_dir_num = 0; +int total_file_num = 0; int total_free_dir = 0; int total_free_file = 0; -const char* get_baseName(const char *filename){ - const char* base_name = strrchr(filename, '/'); - if (base_name != NULL) { - base_name++; // Move past the '/' character - } else { - base_name = filename; // No '/' found, use the original string - } - return base_name; -} const char* generateRandomName(size_t length) { const std::string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; @@ -104,15 +97,12 @@ dir_test* createDirHierarchy(int level, int maxLevel) { // Setup function for the test directory void setupTestDirectory(dir_test** root) { - fprintf(stderr,"[%s ,%d]\n",__func__,__LINE__); // Allocate memory for root *root = new dir_test; - (*root)->name = strdup("/"); // Generate a random name for the directory + (*root)->name = strdup("/"); // use / as begin (*root)->inFile = nullptr; // Initialize file list to nullptr - fprintf(stderr,"[%s ,%d]\n",__func__,__LINE__); (*root)->subdir = createDirHierarchy(0, 1); (*root)->next = nullptr; - fprintf(stderr,"[%s ,%d]\n",__func__,__LINE__); file_test* fileHead = nullptr; file_test* fileCurrent = nullptr; for (int j = 0; j < 3; ++j) { @@ -129,10 +119,6 @@ void setupTestDirectory(dir_test** root) { } (*root)->inFile = fileHead; } -void setupTestDirectory_1(dir_test** root) { - - *root = createDirHierarchy(0, 1); -} // Function to free a list of files void freeFileList(file_test* fileList) { @@ -163,6 +149,7 @@ void printFileList(const file_test* fileList) { const file_test* currentFile = fileList; while (currentFile != nullptr) { // std::cout << " File: " << currentFile->name << std::endl; + total_file_num++; currentFile = currentFile->next; } } @@ -170,7 +157,7 @@ void printFileList(const file_test* fileList) { void traverseDirHierarchy(const dir_test* dir, int depth = 0) { while (dir != nullptr) { // std::cout << "Depth " << depth << ", Directory: " << dir->name << std::endl; - total_number++;//for debug + total_dir_num++;//for debug // Print files in this directory printFileList(dir->inFile); @@ -187,7 +174,7 @@ TEST(DirTest, root_test) { INode inode_root; u_int64_t file_permissions = 0; inode_root.permissions = file_permissions | S_IFDIR; - root = fischl_init_entry(0, "/", &inode_root);//0 is inode number assigned by inode_allocate() + root = fischl_init_entry(0, mock_root->name, &inode_root);//0 is inode number assigned by inode_allocate() } TEST(DirTest, AddFile_test) { //assume file and dir itself(content,metadata) same,but different name and inode number @@ -196,30 +183,30 @@ TEST(DirTest, AddFile_test) { u_int64_t file_permissions = 0; file_permissions = 0; inode_dir.permissions = file_permissions | S_IFDIR; - fischl_add_entry(root, 2, "file1",&inode_file); - fischl_add_entry(root, 3, "dir1",&inode_dir); + fischl_add_entry(root, 2, mock_root->inFile->name,&inode_file); + fischl_add_entry(root, 3, mock_root->subdir->name,&inode_dir); } TEST(DirTest, FindFile_test) { //find file - target_filepath = "/file1"; - FileNode *get_file = fischl_find_entry(root,target_filepath); + target_filepath = std::string("/") + mock_root->inFile->name; + FileNode *get_file = fischl_find_entry(root,target_filepath.c_str()); EXPECT_TRUE(get_file != NULL); - EXPECT_STREQ(get_file->name, get_baseName(target_filepath)); + EXPECT_STREQ(get_file->name, mock_root->inFile->name); //find dir - target_filepath = "/dir1/"; - FileNode *get_dir = fischl_find_entry(root,target_filepath); + target_filepath = std::string("/") + mock_root->subdir->name + "/"; + FileNode *get_dir = fischl_find_entry(root,target_filepath.c_str()); EXPECT_TRUE(get_dir != NULL);//detect this should find success - EXPECT_STREQ(get_dir->name, "dir1"); + EXPECT_STREQ(get_dir->name, mock_root->subdir->name); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory //check . function get_dir = fischl_find_entry(root,"./"); EXPECT_TRUE(get_dir != NULL);//detect this should find success - EXPECT_STREQ(get_dir->name, "/"); + EXPECT_STREQ(get_dir->name, mock_root->name); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory //check .. function get_dir = fischl_find_entry(root,".."); EXPECT_TRUE(get_dir != NULL);//detect this should find success - EXPECT_STREQ(get_dir->name, "/"); + EXPECT_STREQ(get_dir->name, mock_root->name); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory } TEST(DirTest, Add_FindFile_test) { @@ -233,75 +220,81 @@ TEST(DirTest, Add_FindFile_test) { /*add with subdirectory*/ //Treenode dir(you cannot find here), you only can get Filenode dir based on fischl_find_entry Function //So use Filenode->subdirectory will point to the treenode dir, then can add files - FileNode *get_dir = fischl_find_entry(root,"/dir1/"); - fischl_add_entry(get_dir->subdirectory, 4, "file2",&inode_file); + target_filepath = std::string("/") + mock_root->subdir->name + "/"; + FileNode *get_dir = fischl_find_entry(root, target_filepath.c_str()); + fischl_add_entry(get_dir->subdirectory, 4, mock_root->subdir->inFile->name, &inode_file); //verfication treeNode and Filenode relationship - TreeNode *get_dir_tree = find_parentPath(root,"/dir1/file2"); + target_filepath = std::string("/") + mock_root->subdir->name + "/" + mock_root->subdir->inFile->name; + TreeNode *get_dir_tree = find_parentPath(root,target_filepath.c_str()); ASSERT_TRUE(get_dir_tree == get_dir->subdirectory);//treeNode dir should be same as treeNode subdir in that Filenode //two Ways to get File(include dir itself) information FileNode *get_file = NULL; //1. absolute path, the root(treeNode) will always exist when initialize - get_file = fischl_find_entry(root,"/dir1/file2"); + get_file = fischl_find_entry(root,target_filepath.c_str()); EXPECT_TRUE(get_file != NULL); - EXPECT_STREQ(get_file->name,"file2"); - //2. relative path, the get_dir1(FileNode)->subdirectory(treeNode), use treeNode(dir) to find - get_file = fischl_find_entry(get_dir->subdirectory,"/file2"); + EXPECT_STREQ(get_file->name,mock_root->subdir->inFile->name); + //2. relative path, the get_dir(FileNode)->subdirectory(treeNode), use treeNode(dir) to find + target_filepath = std::string("/") + mock_root->subdir->inFile->name; + get_file = fischl_find_entry(get_dir->subdirectory,target_filepath.c_str()); EXPECT_TRUE(get_file != NULL); - EXPECT_STREQ(get_file->name,"file2"); + EXPECT_STREQ(get_file->name, mock_root->subdir->inFile->name); /**********************************************************/ - //add one more file under dir1 - fischl_add_entry(get_dir->subdirectory, 5, "file3",&inode_file); - //add one more directory under dir1 - fischl_add_entry(get_dir->subdirectory, 6, "dir2", &inode_dir); + //add one more file under fist subdir + fischl_add_entry(get_dir->subdirectory, 5, mock_root->subdir->inFile->next->name, &inode_file); + //add one more directory under fist subdir + fischl_add_entry(get_dir->subdirectory, 6, mock_root->subdir->subdir->name, &inode_dir); //find - get_file = fischl_find_entry(get_dir->subdirectory,"./file3"); + target_filepath = std::string("./") + mock_root->subdir->inFile->next->name; + get_file = fischl_find_entry(get_dir->subdirectory, target_filepath.c_str()); EXPECT_TRUE(get_file != NULL); - EXPECT_STREQ(get_file->name,"file3"); - //use .. from dir1 to find file1 - get_file = fischl_find_entry(get_dir->subdirectory,"../file1"); + EXPECT_STREQ(get_file->name, mock_root->subdir->inFile->next->name); + //use .. from fist subdir to find file1 + target_filepath = std::string("../") + mock_root->inFile->name; + get_file = fischl_find_entry(get_dir->subdirectory,target_filepath.c_str()); EXPECT_TRUE(get_file != NULL); - EXPECT_STREQ(get_file->name,"file1"); - //check dir1 with . + EXPECT_STREQ(get_file->name,mock_root->inFile->name); + //check fist subdir with . get_dir = fischl_find_entry(get_dir->subdirectory,"."); EXPECT_TRUE(get_dir != NULL);//detect this should find success - EXPECT_STREQ(get_dir->name, "dir1"); + EXPECT_STREQ(get_dir->name, mock_root->subdir->name); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory - //check root with dir1 + //check root via fist subdir get_dir = fischl_find_entry(get_dir->subdirectory,".."); EXPECT_TRUE(get_dir != NULL);//detect this should find success - EXPECT_STREQ(get_dir->name, "/"); + EXPECT_STREQ(get_dir->name, mock_root->name); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory //use .. to access parent directory - get_dir = fischl_find_entry(root, "/dir1/dir2/.."); + target_filepath = std::string("/") + mock_root->subdir->name + "/" + mock_root->subdir->subdir->name + "/.."; + get_dir = fischl_find_entry(root, target_filepath.c_str()); EXPECT_TRUE(get_dir != NULL); - EXPECT_STREQ(get_dir->name, "dir1"); - FileNode *get_rootdir = fischl_find_entry(root, "/dir1/dir2/../.."); - EXPECT_TRUE(get_rootdir != NULL); - EXPECT_STREQ(get_rootdir->name, "/"); - EXPECT_TRUE(get_rootdir->subdirectory != NULL); - EXPECT_TRUE(get_rootdir->subdirectory->self_info == get_rootdir); + EXPECT_STREQ(get_dir->name, mock_root->subdir->name); + target_filepath = std::string("/") + mock_root->subdir->name + "/" + mock_root->subdir->subdir->name + "/../.."; + get_file = fischl_find_entry(root, target_filepath.c_str()); + EXPECT_TRUE(get_file != NULL); + EXPECT_STREQ(get_file->name, mock_root->name); + EXPECT_TRUE(get_file->subdirectory != NULL); + EXPECT_TRUE(get_file->subdirectory->self_info == get_file); } int main(int argc, char **argv) { srand(time(NULL)); // Seed the random number generator d = (argc < 2) ? "/dev/vdc" : argv[1]; - dir_test* mock_root = nullptr; setupTestDirectory(&mock_root); ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); - total_number = 0; + total_dir_num = 0; + total_file_num = 0; traverseDirHierarchy(mock_root);//mock_root - printf("Traverse Dir total %d\n",total_number); + printf("Traverse Total: Dir %d, File %d\n",total_dir_num, total_file_num); // Cleanup freeDirHierarchy(mock_root);//mock_root - printf("Free Dir total %d\n",total_free_dir); - printf("Free File total %d\n",total_free_file); + printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file); freeTree(root); return result; } \ No newline at end of file From 6f5bb3bdcc0d611fb0135fa241609df9899e1709 Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 22 Nov 2023 01:15:51 -0800 Subject: [PATCH 26/63] add scale test to make add and find entry operation more iteratively --- test/dir_API.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index ad9f783..8c1fcd1 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -278,6 +278,56 @@ TEST(DirTest, Add_FindFile_test) { EXPECT_TRUE(get_file->subdirectory->self_info == get_file); } +// TEST(DirTest, Scale_test){ +// INode inode_file; +// INode inode_dir; +// u_int64_t file_permissions = 0; +// file_permissions = 0; +// inode_dir.permissions = file_permissions | S_IFDIR; +// dir_test* temp = mock_root; +// // First loop: Add files and subdirectories under root +// file_test* currentFile = temp->inFile; +// dir_test* currentSubdir = temp->subdir; +// +// for (int i = 1; i < 7; ++i) { +// if (currentFile) { +// //add can still add the same filename and dir name, but it will be linked behind the first added +// fischl_add_entry(root, i, currentFile->name, &inode_file); +// currentFile = currentFile->next; +// } +// if (currentSubdir) { +// fischl_add_entry(root, i + 1, currentSubdir->name, &inode_dir); +// currentSubdir = currentSubdir->next; +// } +// } + +// // Second loop: Process each subdir under root +// temp = mock_root->subdir; +// while (temp) { +// target_filepath = "/" + std::string(temp->name) + "/"; +// FileNode* get_dir = fischl_find_entry(root, target_filepath.c_str()); + +// ASSERT_TRUE(get_dir != NULL); +// EXPECT_STREQ(get_dir->name, temp->name); +// ASSERT_TRUE(get_dir->subdirectory != NULL); +// // Add files and subdirectories in each subdir +// file_test* currentFile = temp->inFile; +// dir_test* currentSubSubdir = temp->subdir; +// for (int j = 7; j < 13; ++j) { +// if (currentFile) { +// fischl_add_entry(get_dir->subdirectory, j, currentFile->name, &inode_file); +// currentFile = currentFile->next; +// } +// if (currentSubSubdir) { +// fischl_add_entry(get_dir->subdirectory, j + 1, currentSubSubdir->name, &inode_dir); +// currentSubSubdir = currentSubSubdir->next; +// } +// } + +// temp = temp->next; // Move to next subdir +// } +// } + int main(int argc, char **argv) { srand(time(NULL)); // Seed the random number generator d = (argc < 2) ? "/dev/vdc" : argv[1]; From 60678711d21af4cb65fad727439d90be2856ebe0 Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 22 Nov 2023 21:43:38 -0800 Subject: [PATCH 27/63] reform test_layer2_API with googletest framwork and revise mkdir & mknod return type --- include/files.h | 4 +- lib/files.cpp | 33 +++-- test/CMakeLists.txt | 3 +- test/layer2_API_dir.cpp | 320 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 341 insertions(+), 19 deletions(-) create mode 100644 test/layer2_API_dir.cpp diff --git a/include/files.h b/include/files.h index a2ab95c..d97bd3c 100644 --- a/include/files.h +++ b/include/files.h @@ -18,8 +18,8 @@ class FilesOperation { void unlink_inode(u_int64_t inode_number); u_int64_t disk_namei(const char* path); u_int64_t namei(const char* path); - u_int64_t fischl_mkdir(const char*, mode_t); - u_int64_t fischl_mknod(const char*, mode_t); + int fischl_mkdir(const char*, mode_t); + int fischl_mknod(const char*, mode_t); //int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); int fischl_unlink (const char *); //int fischl_open (const char *, struct fuse_file_info *); diff --git a/lib/files.cpp b/lib/files.cpp index 2b78405..93ca218 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -111,7 +111,7 @@ void FilesOperation::create_dot_dotdot(INode* inode, u_int64_t parent_inode_numb void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion u_int64_t root_inode_number = inop.inode_allocate(disk); - printf("Info: root inode number: %llu\n", root_inode_number); + // printf("Info: root inode number: %llu\n", root_inode_number); INode *root_inode = new_inode(root_inode_number, S_IFDIR); create_dot_dotdot(root_inode, root_inode_number); root_node = fischl_init_entry(root_inode_number, "/", root_inode); @@ -142,7 +142,7 @@ INode* FilesOperation::create_new_inode(u_int64_t parent_inode_number, const cha INode inode; inode.inode_construct(parent_inode_number, disk); if ((inode.permissions & S_IFMT) != S_IFDIR) { - printf("Parent Inode is not a directory\n"); + fprintf(stderr,"[%s ,%d] please create under directory\n",__func__,__LINE__); return NULL; } @@ -154,7 +154,11 @@ INode* FilesOperation::create_new_inode(u_int64_t parent_inode_number, const cha for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(r_buffer+i); if (strcmp(ent.file_name, name)==0) { - printf("Already exists file or directory with name %s, cannot not create\n", name); + if((mode & S_IFMT) == S_IFDIR){ + fprintf(stderr,"[%s ,%d] %s/ already exists\n",__func__,__LINE__, name); + }else{ + fprintf(stderr,"[%s ,%d] %s already exists\n",__func__,__LINE__, name); + } return NULL; } } @@ -255,7 +259,7 @@ u_int64_t FilesOperation::namei(const char* path) { else return -1; } -u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { +int FilesOperation::fischl_mkdir(const char* path, mode_t mode) { //check path char *pathdup = strdup(path); char *lastSlash = strrchr(pathdup, '/'); @@ -265,44 +269,41 @@ u_int64_t FilesOperation::fischl_mkdir(const char* path, mode_t mode) { FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { - printf("parent %s not found by fischl_find_entry\n", ParentPath); + fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); delete pathdup; - return -1; + return -ENOENT;//parentpath directory does not exist } u_int64_t parent_inode_number = parent_filenode->inode_number; //make new inode INode* ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory - if (ret == NULL) return -1; + if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newDirname, ret); delete pathdup; - return ret->block_number; - //after new_inode(mkfile), go to fischl_add_entry record - - + return 0;//SUCCESS } -u_int64_t FilesOperation::fischl_mknod(const char* path, mode_t mode) { +int FilesOperation::fischl_mknod(const char* path, mode_t mode) { //check path char *pathdup = strdup(path); char *lastSlash = strrchr(pathdup, '/'); *lastSlash = '\0'; // Split the string into parent path and new directory name; \0 char *newFilename = lastSlash+1; //\0, get from char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only - printf("mknod ParentPath:%s, strlen=%d\n", ParentPath, strlen(ParentPath)); + // fprintf(stderr,"[%s ,%d] ParentPath:%s, strlen=%d\n",__func__,__LINE__, ParentPath, strlen(ParentPath)); FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { - printf("parent %s not found by fischl_find_entry\n", ParentPath); + fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); delete pathdup; return -1; } u_int64_t parent_inode_number = parent_filenode->inode_number; //make new inode INode* ret = create_new_inode(parent_inode_number, newFilename, mode); - if (ret == NULL) return -1; + if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST //make new node fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newFilename, ret); delete pathdup; - return ret->block_number; + return 0;//SUCESS } void FilesOperation::unlink_inode(u_int64_t inode_number) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 23db167..d32305e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,7 +16,7 @@ add_executable(${TARGET_LAYER1_API} add_executable(${TARGET_LAYER2_API} ../lib/direntry.cpp ../lib/files.cpp - layer2_API.cpp + layer2_API_dir.cpp ) add_executable(${TARGET_DIR_API} ../lib/direntry.cpp @@ -26,6 +26,7 @@ add_executable(${TARGET_DIR_API} # Link Google Test to your test executables target_link_libraries(${TARGET_LAYER0} gtest gtest_main) target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main) +target_link_libraries(${TARGET_LAYER2_API} gtest gtest_main) target_link_libraries(${TARGET_DIR_API} gtest gtest_main) # add test to activate ctest -VV diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp new file mode 100644 index 0000000..570a4e9 --- /dev/null +++ b/test/layer2_API_dir.cpp @@ -0,0 +1,320 @@ +#include +#include +#include +#include +#include +#include +#include +#include "files.h" + + +typedef struct file_test{ + const char* name; + file_test* next;//use linked-list to know the file at the same level directory +}file_test; +typedef struct dir_test{ + const char* name; + file_test* inFile; + dir_test* subdir; + dir_test* next;//use linked-list to know the other dir at the same parent dir. +}dir_test; + +void setupTestDirectory(dir_test** root); +void freeDirHierarchy(dir_test* dir); +void traverseDirHierarchy(const dir_test* dir, int depth); + +//global can be taken +const char* d; +TreeNode *root; +std::string target_filepath; +dir_test* mock_root = nullptr; + +int total_dir_num = 0; +int total_file_num = 0; +int total_free_dir = 0; +int total_free_file = 0; + +TEST(FileOperationTest, MkdirnodTest) { + RawDisk *H = new RawDisk(d); + + FilesOperation fsop(*H); + fsop.initialize_rootinode(); + + mode_t mode;//set mode + mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission + //S_IRWXU(S_IRUSR | S_IWUSR | S_IXUSR) (owner), S_IRWXG(S_IRGRP | S_IWGRP | S_IXGRP) (group), S_IRWXO(S_IROTH | S_IWOTH | S_IXOTH) + EXPECT_EQ(fsop.fischl_mknod("/test", mode), 0); // mode here is not used yet + EXPECT_EQ(fsop.fischl_mkdir("/foo", mode), 0); + EXPECT_EQ(fsop.fischl_mkdir("/foo/bar", mode),0); + EXPECT_EQ(fsop.fischl_mknod("/foo/bar/baz", mode), 0); + // the following three testcases will fail + EXPECT_TRUE(fsop.fischl_mkdir("foo/bar", mode) < 0); + EXPECT_TRUE(fsop.fischl_mkdir("/doesnt_exist/bar", mode) < 0); + EXPECT_TRUE(fsop.fischl_mkdir("/test/bar", mode) < 0); + EXPECT_TRUE(fsop.fischl_mkdir("/test", mode) < 0); + EXPECT_TRUE(fsop.fischl_mkdir("/foo/bar", mode) < 0); + EXPECT_TRUE(fsop.fischl_mkdir("/foo/bar/..", mode) < 0); +} + +// TEST(FileOperationTest, WriteTest) { +// // write to files (TODO: fischl_write) +// // read and write to indirect datablocks are not supported yet +// printf("=== Part 2: write to files ===\n"); +// char buffer[IO_BLOCK_SIZE] = {0}; +// INode inode; +// inode.inode_construct(file1, *H); +// buffer[0] = '1'; +// fsop.write_datablock(inode, 0, buffer); +// inode.inode_save(*H); +// inode.inode_construct(file4, *H); +// buffer[0] = '4'; +// fsop.write_datablock(inode, 3, buffer); +// buffer[0] = '5'; +// fsop.write_datablock(inode, 101, buffer); +// inode.inode_save(*H); +// // TODO: guard against overwriting directory datablocks +// } + +// TEST(FileOperationTest, RamTest) { +// // retrieve inode-number by path +// u_int64_t file_test = fsop.namei("/test"); +// printf("inode number for \"/test\" is %llu\n", file_test); +// assert(file_test == file1); +// u_int64_t file_baz = fsop.namei("/foo/bar/baz"); +// printf("inode number for \"/foo/bar/baz\" is %llu\n", file_baz); +// assert(file_baz == file4); +// u_int64_t file_foo = fsop.namei("/foo/bar/.."); +// printf("inode number for \"/foo/bar/..\" is %llu\n", file_foo); +// assert(file_foo == file2); +// u_int64_t file_bar = fsop.namei("/foo/bar/."); +// printf("inode number for \"/foo/bar/.\" is %llu\n", file_bar); +// assert(file_bar == file3); +// } + +// TEST(FileOperationTest, DiskTest) { +// // retrieve inode-number by path +// u_int64_t file_test = fsop.namei("/test"); +// printf("inode number for \"/test\" is %llu\n", file_test); +// assert(file_test == file1); +// u_int64_t file_baz = fsop.namei("/foo/bar/baz"); +// printf("inode number for \"/foo/bar/baz\" is %llu\n", file_baz); +// assert(file_baz == file4); +// u_int64_t file_foo = fsop.namei("/foo/bar/.."); +// printf("inode number for \"/foo/bar/..\" is %llu\n", file_foo); +// assert(file_foo == file2); +// u_int64_t file_bar = fsop.namei("/foo/bar/."); +// printf("inode number for \"/foo/bar/.\" is %llu\n", file_bar); +// assert(file_bar == file3); +// } + +// TEST(FileOperationTest, ReadTest) { +// // read files (TODO: fischl_read) +// char read_buffer[IO_BLOCK_SIZE] = {0}; +// INode inode_read; +// inode_read.inode_construct(file_test, *H); +// fsop.read_datablock(inode_read, 0, read_buffer); +// assert(read_buffer[0] == '1'); +// inode_read.inode_construct(file_baz, *H); +// fsop.read_datablock(inode_read, 3, read_buffer); +// assert(read_buffer[0] == '4'); +// fsop.read_datablock(inode_read, 101, read_buffer); +// assert(read_buffer[0] == '5'); +// } +// TEST(FileOperationTest, PressureTest) { +// printf("=== Part 5: pressure test create files ===\n"); +// u_int64_t file_pressure = fsop.fischl_mkdir("/pressure", 0); +// u_int64_t inode_numbers[700]; +// std::string prefix = "/pressure/No_"; +// for(int i=0;i<700;i++){ +// inode_numbers[i] = fsop.fischl_mkdir((prefix+std::to_string(i)).c_str(), 0); +// } +// for(int i=0;i<700;i++){ +// u_int64_t inode_number = fsop.namei((prefix+std::to_string(i)).c_str()); +// assert(inode_number == inode_numbers[i]); +// } +// } +// TEST(FileOperationTest, UnlinkTest) { +// printf("=== Part 6: unlink test ===\n"); +// fsop.printDirectory(file_pressure); +// for(int i=0;i<700;i+=2){ +// assert(!fsop.fischl_unlink((prefix+std::to_string(i)).c_str())); +// } +// for(int i=0;i<4;i+=2){ +// assert(fsop.namei((prefix+std::to_string(i)).c_str())==(u_int64_t)(-1)); +// } +// for(int i=1;i<700;i+=2){ +// u_int64_t inode_number = fsop.namei((prefix+std::to_string(i)).c_str()); +// assert(inode_number == inode_numbers[i]); +// } +// fsop.printDirectory(file_pressure); +// std::string newprefix = "/pressure/New"; +// for(int i=0;i<700;i+=2){ +// inode_numbers[i] = fsop.fischl_mkdir((newprefix+std::to_string(i)).c_str(), 0); +// } +// for(int i=0;i<700;i+=2){ +// u_int64_t inode_number = fsop.namei((newprefix+std::to_string(i)).c_str()); +// assert(inode_number == inode_numbers[i]); +// } +// fsop.printDirectory(file_pressure); + +// // long filename test +// std::string longfilename = std::string(255,'A'); +// u_int64_t filelong = fsop.fischl_mknod((std::string("/")+longfilename).c_str(),0); +// printf("/AAA...AAA is inode %llu, it is a file\n", filelong); +// } + + +int main(int argc, char **argv) { + srand(time(NULL)); // Seed the random number generator + d = (argc < 2) ? "/dev/vdc" : argv[1]; + + setupTestDirectory(&mock_root); + + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + + total_dir_num = 0; + total_file_num = 0; + + traverseDirHierarchy(mock_root, 0);//mock_root + printf("Traverse Total: Dir %d, File %d\n",total_dir_num, total_file_num); + + // Cleanup + freeDirHierarchy(mock_root);//mock_root + printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file); + freeTree(root); + return result; +} + +const char* generateRandomName(size_t length) { + const std::string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::string randomString; + + for (size_t i = 0; i < length; ++i) { + randomString += chars[rand() % chars.size()]; + } + + // Allocate memory and copy the string + char* name = new char[randomString.length() + 1]; + strcpy(name, randomString.c_str()); + return name; +} + +// Recursive function to create directory hierarchy +dir_test* createDirHierarchy(int level, int maxLevel) { + if (level > maxLevel) { + return nullptr; + } + + dir_test* head = nullptr; + dir_test* current = nullptr; + + for (int i = 0; i < 3; ++i) { + dir_test* newDir = new dir_test; + newDir->name = generateRandomName(6); // Generate a random name for the directory + newDir->inFile = nullptr; // Initialize file list to nullptr + newDir->subdir = createDirHierarchy(level + 1, maxLevel); // Recursively create subdirectories + newDir->next = nullptr; + + // Create file list for this directory + file_test* fileHead = nullptr; + file_test* fileCurrent = nullptr; + for (int j = 0; j < 3; ++j) { + file_test* newFile = new file_test; + newFile->name = generateRandomName(6); // Generate a random name for the file + newFile->next = nullptr; + + if (!fileHead) { + fileHead = newFile; + } else { + fileCurrent->next = newFile; + } + fileCurrent = newFile; + } + newDir->inFile = fileHead; + + // Add the new directory to the list + if (!head) { + head = newDir; + } else { + current->next = newDir; + } + current = newDir; + } + + return head; +} + +// Setup function for the test directory +void setupTestDirectory(dir_test** root) { + // Allocate memory for root + *root = new dir_test; + (*root)->name = strdup("/"); // use / as begin + (*root)->inFile = nullptr; // Initialize file list to nullptr + (*root)->subdir = createDirHierarchy(0, 1); + (*root)->next = nullptr; + file_test* fileHead = nullptr; + file_test* fileCurrent = nullptr; + for (int j = 0; j < 3; ++j) { + file_test* newFile = new file_test; + newFile->name = generateRandomName(6); // Generate a random name for the file + newFile->next = nullptr; + + if (!fileHead) { + fileHead = newFile; + } else { + fileCurrent->next = newFile; + } + fileCurrent = newFile; + } + (*root)->inFile = fileHead; +} + +// Function to free a list of files +void freeFileList(file_test* fileList) { + while (fileList != nullptr) { + file_test* temp = fileList; + fileList = fileList->next; + total_free_file++;//for debug + delete[] temp->name; // Free the name string + delete temp; // Free the current file + } +} + +// Recursive function to free the directory hierarchy +void freeDirHierarchy(dir_test* dir) { + while (dir != nullptr) { + dir_test* temp = dir; + dir = dir->next; + total_free_dir++;//for debug + freeFileList(temp->inFile); // Free the list of files in the directory + freeDirHierarchy(temp->subdir); // Recursively free subdirectories + delete[] temp->name; // Free the name string + delete temp; // Free the current directory + } +} + +// Function to print the list of files in a directory +void printFileList(const file_test* fileList) { + const file_test* currentFile = fileList; + while (currentFile != nullptr) { + // std::cout << " File: " << currentFile->name << std::endl; + total_file_num++; + currentFile = currentFile->next; + } +} + +void traverseDirHierarchy(const dir_test* dir, int depth = 0) { + while (dir != nullptr) { + // std::cout << "Depth " << depth << ", Directory: " << dir->name << std::endl; + total_dir_num++;//for debug + + // Print files in this directory + printFileList(dir->inFile); + // Recursively traverse subdirectories + traverseDirHierarchy(dir->subdir, depth + 1); + + // Go to the next directory at the same level + dir = dir->next; + } +} \ No newline at end of file From 9e34e025a3459c0b22cb2282464d3f3ff0b081f8 Mon Sep 17 00:00:00 2001 From: FactorialN Date: Wed, 22 Nov 2023 23:52:05 -0800 Subject: [PATCH 28/63] fixed a constant to meet the current design --- include/fs_constants.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fs_constants.hpp b/include/fs_constants.hpp index e74e3ba..8353020 100644 --- a/include/fs_constants.hpp +++ b/include/fs_constants.hpp @@ -18,6 +18,7 @@ #define INODE_SIZE 512 -#define DATABLOCKS_PER_BITMAP_BLOCK 255 +// TODO: explore the optimal value for this +#define DATABLOCKS_PER_BITMAP_BLOCK 2047 #endif \ No newline at end of file From ac6eb21b645ccef5a47e7aebfcefadf82c7f2183 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 23 Nov 2023 03:13:17 -0800 Subject: [PATCH 29/63] move *root_node to public, and pass the RAMTest(Ram cache system) --- include/files.h | 3 +- test/layer2_API_dir.cpp | 71 ++++++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/include/files.h b/include/files.h index d97bd3c..df15c67 100644 --- a/include/files.h +++ b/include/files.h @@ -5,10 +5,11 @@ class FilesOperation { RawDisk& disk; INodeOperation inop; - TreeNode *root_node; INode* new_inode(u_int64_t inode_number, u_int64_t permissions); void create_dot_dotdot(INode*, u_int64_t); + public: + TreeNode *root_node; FilesOperation(RawDisk&); int read_datablock(const INode& inode, u_int64_t index, char* buffer); int write_datablock(INode& inode, u_int64_t index, const char* buffer); diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 570a4e9..0d3a11b 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -24,10 +24,10 @@ void freeDirHierarchy(dir_test* dir); void traverseDirHierarchy(const dir_test* dir, int depth); //global can be taken -const char* d; -TreeNode *root; std::string target_filepath; dir_test* mock_root = nullptr; +RawDisk *H; +FilesOperation *fsop; int total_dir_num = 0; int total_file_num = 0; @@ -35,25 +35,23 @@ int total_free_dir = 0; int total_free_file = 0; TEST(FileOperationTest, MkdirnodTest) { - RawDisk *H = new RawDisk(d); - FilesOperation fsop(*H); - fsop.initialize_rootinode(); + fsop->initialize_rootinode(); mode_t mode;//set mode mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission //S_IRWXU(S_IRUSR | S_IWUSR | S_IXUSR) (owner), S_IRWXG(S_IRGRP | S_IWGRP | S_IXGRP) (group), S_IRWXO(S_IROTH | S_IWOTH | S_IXOTH) - EXPECT_EQ(fsop.fischl_mknod("/test", mode), 0); // mode here is not used yet - EXPECT_EQ(fsop.fischl_mkdir("/foo", mode), 0); - EXPECT_EQ(fsop.fischl_mkdir("/foo/bar", mode),0); - EXPECT_EQ(fsop.fischl_mknod("/foo/bar/baz", mode), 0); + EXPECT_EQ(fsop->fischl_mknod("/test", mode), 0); // mode here is not used yet + EXPECT_EQ(fsop->fischl_mkdir("/foo", mode), 0); + EXPECT_EQ(fsop->fischl_mkdir("/foo/bar", mode),0); + EXPECT_EQ(fsop->fischl_mknod("/foo/bar/baz", mode), 0); // the following three testcases will fail - EXPECT_TRUE(fsop.fischl_mkdir("foo/bar", mode) < 0); - EXPECT_TRUE(fsop.fischl_mkdir("/doesnt_exist/bar", mode) < 0); - EXPECT_TRUE(fsop.fischl_mkdir("/test/bar", mode) < 0); - EXPECT_TRUE(fsop.fischl_mkdir("/test", mode) < 0); - EXPECT_TRUE(fsop.fischl_mkdir("/foo/bar", mode) < 0); - EXPECT_TRUE(fsop.fischl_mkdir("/foo/bar/..", mode) < 0); + EXPECT_TRUE(fsop->fischl_mkdir("foo/bar", mode) < 0); + EXPECT_TRUE(fsop->fischl_mkdir("/doesnt_exist/bar", mode) < 0); + EXPECT_TRUE(fsop->fischl_mkdir("/test/bar", mode) < 0); + EXPECT_TRUE(fsop->fischl_mkdir("/test", mode) < 0); + EXPECT_TRUE(fsop->fischl_mkdir("/foo/bar", mode) < 0); + EXPECT_TRUE(fsop->fischl_mkdir("/foo/bar/..", mode) < 0); } // TEST(FileOperationTest, WriteTest) { @@ -75,21 +73,24 @@ TEST(FileOperationTest, MkdirnodTest) { // // TODO: guard against overwriting directory datablocks // } -// TEST(FileOperationTest, RamTest) { -// // retrieve inode-number by path -// u_int64_t file_test = fsop.namei("/test"); -// printf("inode number for \"/test\" is %llu\n", file_test); -// assert(file_test == file1); -// u_int64_t file_baz = fsop.namei("/foo/bar/baz"); -// printf("inode number for \"/foo/bar/baz\" is %llu\n", file_baz); -// assert(file_baz == file4); -// u_int64_t file_foo = fsop.namei("/foo/bar/.."); -// printf("inode number for \"/foo/bar/..\" is %llu\n", file_foo); -// assert(file_foo == file2); -// u_int64_t file_bar = fsop.namei("/foo/bar/."); -// printf("inode number for \"/foo/bar/.\" is %llu\n", file_bar); -// assert(file_bar == file3); -// } +TEST(FileOperationTest, RamTest) { + //use find_entry(specify certain files or directory) + FileNode* get_dir; + get_dir = fischl_find_entry(fsop->root_node, "/test");//this is file + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "test"); + get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/baz");//this is file + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "baz"); + get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/.."); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "foo"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/."); + EXPECT_TRUE(get_dir != NULL);//detect this should find success + EXPECT_STREQ(get_dir->name, "bar"); + ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory +} // TEST(FileOperationTest, DiskTest) { // // retrieve inode-number by path @@ -166,9 +167,11 @@ TEST(FileOperationTest, MkdirnodTest) { int main(int argc, char **argv) { srand(time(NULL)); // Seed the random number generator - d = (argc < 2) ? "/dev/vdc" : argv[1]; + const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; setupTestDirectory(&mock_root); + H = new RawDisk(d); + fsop = new FilesOperation(*H); ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); @@ -182,7 +185,11 @@ int main(int argc, char **argv) { // Cleanup freeDirHierarchy(mock_root);//mock_root printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file); - freeTree(root); + + freeTree(fsop->root_node); + delete fsop; // First delete fsop which depends on H + delete H; + return result; } From 9a2289e296fff76bfec259c6ace4517f3b94d0c8 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 23 Nov 2023 14:16:33 -0800 Subject: [PATCH 30/63] add disk access checks to confirm consistency between values stored in RAM and on Disk, and pass Writetest --- test/layer2_API_dir.cpp | 73 ++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 0d3a11b..71b4021 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -54,59 +54,64 @@ TEST(FileOperationTest, MkdirnodTest) { EXPECT_TRUE(fsop->fischl_mkdir("/foo/bar/..", mode) < 0); } -// TEST(FileOperationTest, WriteTest) { -// // write to files (TODO: fischl_write) -// // read and write to indirect datablocks are not supported yet -// printf("=== Part 2: write to files ===\n"); -// char buffer[IO_BLOCK_SIZE] = {0}; -// INode inode; -// inode.inode_construct(file1, *H); -// buffer[0] = '1'; -// fsop.write_datablock(inode, 0, buffer); -// inode.inode_save(*H); -// inode.inode_construct(file4, *H); -// buffer[0] = '4'; -// fsop.write_datablock(inode, 3, buffer); -// buffer[0] = '5'; -// fsop.write_datablock(inode, 101, buffer); -// inode.inode_save(*H); -// // TODO: guard against overwriting directory datablocks -// } +TEST(FileOperationTest, WriteTest) { + // write to files (TODO: fischl_write) + // read and write to indirect datablocks are not supported yet + //get inode info from disk + char buffer[IO_BLOCK_SIZE] = {0}; + INode inode; + u_int64_t get_disk_inum; + //file test + get_disk_inum = fsop->disk_namei("/test"); + inode.inode_construct(get_disk_inum, *H); + buffer[0] = '1'; + fsop->write_datablock(inode, 0, buffer); + inode.inode_save(*H); + //other file baz + get_disk_inum = fsop->disk_namei("/foo/bar/baz"); + inode.inode_construct(get_disk_inum, *H); + buffer[0] = '4'; + fsop->write_datablock(inode, 3, buffer); + buffer[0] = '5'; + fsop->write_datablock(inode, 101, buffer); + inode.inode_save(*H); + // TODO: guard against overwriting directory datablocks +} -TEST(FileOperationTest, RamTest) { +TEST(FileOperationTest, RamDiskTest) { //use find_entry(specify certain files or directory) FileNode* get_dir; + u_int64_t get_disk_inum; + get_dir = fischl_find_entry(fsop->root_node, "/test");//this is file EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "test"); + get_disk_inum = fsop->disk_namei("/test"); + EXPECT_EQ(get_disk_inum, get_dir->inode_number); + get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/baz");//this is file EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "baz"); + get_disk_inum = fsop->disk_namei("/foo/bar/baz"); + EXPECT_EQ(get_disk_inum, get_dir->inode_number); + get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/.."); EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "foo"); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + get_disk_inum = fsop->disk_namei("/foo/bar/.."); + EXPECT_EQ(get_disk_inum, get_dir->inode_number); + fsop->printDirectory(get_disk_inum); + get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/."); EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "bar"); ASSERT_TRUE(get_dir->subdirectory != NULL);//secure it is directory + get_disk_inum = fsop->disk_namei("/foo/bar/."); + EXPECT_EQ(get_disk_inum, get_dir->inode_number); + fsop->printDirectory(get_disk_inum); } -// TEST(FileOperationTest, DiskTest) { -// // retrieve inode-number by path -// u_int64_t file_test = fsop.namei("/test"); -// printf("inode number for \"/test\" is %llu\n", file_test); -// assert(file_test == file1); -// u_int64_t file_baz = fsop.namei("/foo/bar/baz"); -// printf("inode number for \"/foo/bar/baz\" is %llu\n", file_baz); -// assert(file_baz == file4); -// u_int64_t file_foo = fsop.namei("/foo/bar/.."); -// printf("inode number for \"/foo/bar/..\" is %llu\n", file_foo); -// assert(file_foo == file2); -// u_int64_t file_bar = fsop.namei("/foo/bar/."); -// printf("inode number for \"/foo/bar/.\" is %llu\n", file_bar); -// assert(file_bar == file3); -// } // TEST(FileOperationTest, ReadTest) { // // read files (TODO: fischl_read) From 88a15eb1a82996f0fbe6ac87fcdec571e381ac68 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 23 Nov 2023 14:45:52 -0800 Subject: [PATCH 31/63] Pass Readtest and Pressuretest --- test/layer2_API_dir.cpp | 63 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 71b4021..fb33bb5 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -82,7 +82,7 @@ TEST(FileOperationTest, RamDiskTest) { //use find_entry(specify certain files or directory) FileNode* get_dir; u_int64_t get_disk_inum; - + get_dir = fischl_find_entry(fsop->root_node, "/test");//this is file EXPECT_TRUE(get_dir != NULL);//detect this should find success EXPECT_STREQ(get_dir->name, "test"); @@ -113,32 +113,41 @@ TEST(FileOperationTest, RamDiskTest) { } -// TEST(FileOperationTest, ReadTest) { -// // read files (TODO: fischl_read) -// char read_buffer[IO_BLOCK_SIZE] = {0}; -// INode inode_read; -// inode_read.inode_construct(file_test, *H); -// fsop.read_datablock(inode_read, 0, read_buffer); -// assert(read_buffer[0] == '1'); -// inode_read.inode_construct(file_baz, *H); -// fsop.read_datablock(inode_read, 3, read_buffer); -// assert(read_buffer[0] == '4'); -// fsop.read_datablock(inode_read, 101, read_buffer); -// assert(read_buffer[0] == '5'); -// } -// TEST(FileOperationTest, PressureTest) { -// printf("=== Part 5: pressure test create files ===\n"); -// u_int64_t file_pressure = fsop.fischl_mkdir("/pressure", 0); -// u_int64_t inode_numbers[700]; -// std::string prefix = "/pressure/No_"; -// for(int i=0;i<700;i++){ -// inode_numbers[i] = fsop.fischl_mkdir((prefix+std::to_string(i)).c_str(), 0); -// } -// for(int i=0;i<700;i++){ -// u_int64_t inode_number = fsop.namei((prefix+std::to_string(i)).c_str()); -// assert(inode_number == inode_numbers[i]); -// } -// } +TEST(FileOperationTest, ReadTest) { + // read files (TODO: fischl_read) + char read_buffer[IO_BLOCK_SIZE] = {0}; + INode inode; + u_int64_t get_file_inum; + + //read test file + get_file_inum = fsop->namei("/test"); + inode.inode_construct(get_file_inum, *H); + fsop->read_datablock(inode, 0, read_buffer); + EXPECT_EQ(read_buffer[0], '1'); + + //read baz file + get_file_inum= fsop->namei("/foo/bar/baz"); + inode.inode_construct(get_file_inum, *H); + fsop->read_datablock(inode, 3, read_buffer); + EXPECT_EQ(read_buffer[0], '4'); + fsop->read_datablock(inode, 101, read_buffer); + EXPECT_EQ(read_buffer[0], '5'); +} + +TEST(FileOperationTest, PressureTest) { + mode_t mode;//set mode + mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission + EXPECT_EQ(fsop->fischl_mkdir("/pressure", mode), 0); + + u_int64_t inode_numbers[700]; + std::string prefix = "/pressure/No_"; + for(int i=0;i<700;i++){ + EXPECT_EQ(fsop->fischl_mkdir((prefix+std::to_string(i)).c_str(), mode), 0); + } + for(int i=0;i<700;i++){ + EXPECT_EQ(fsop->namei((prefix+std::to_string(i)).c_str()),fsop->disk_namei((prefix+std::to_string(i)).c_str())); + } +} // TEST(FileOperationTest, UnlinkTest) { // printf("=== Part 6: unlink test ===\n"); // fsop.printDirectory(file_pressure); From 39d6ab26ff49bb281127989f8c479bfe1859307a Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 24 Nov 2023 13:12:42 -0800 Subject: [PATCH 32/63] create for regular file; mknod for spcial file. include simplified fuse_common.h to register file descriptor --- include/files.h | 4 +- include/fuse_common.h | 82 +++++++++++++++++++++++++++++++++++++++++ lib/files.cpp | 34 ++++++++++++++++- test/layer2_API_dir.cpp | 7 ++-- 4 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 include/fuse_common.h diff --git a/include/files.h b/include/files.h index df15c67..f3cd1f0 100644 --- a/include/files.h +++ b/include/files.h @@ -1,5 +1,6 @@ #include #include +#include "fuse_common.h" #include "direntry.h" class FilesOperation { @@ -20,7 +21,8 @@ class FilesOperation { u_int64_t disk_namei(const char* path); u_int64_t namei(const char* path); int fischl_mkdir(const char*, mode_t); - int fischl_mknod(const char*, mode_t); + int fischl_mknod(const char*, mode_t, dev_t);//for special file + int fischl_create(const char *, mode_t, struct fuse_file_info *);//for regular file //int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); int fischl_unlink (const char *); //int fischl_open (const char *, struct fuse_file_info *); diff --git a/include/fuse_common.h b/include/fuse_common.h new file mode 100644 index 0000000..eef2f49 --- /dev/null +++ b/include/fuse_common.h @@ -0,0 +1,82 @@ +#ifndef FUSE_COMMON_H_ +#define FUSE_COMMON_H_ + +#include +#include + +/** + * Information about an open file. + * + * File Handles are created by the open, opendir, and create methods and closed + * by the release and releasedir methods. Multiple file handles may be + * concurrently open for the same file. Generally, a client will create one + * file handle per file descriptor, though in some cases multiple file + * descriptors can share a single file handle. + */ +struct fuse_file_info { + /** Open flags. Available in open() and release() */ + int flags; + + /** In case of a write operation indicates if this was caused + by a delayed write from the page cache. If so, then the + context's pid, uid, and gid fields will not be valid, and + the *fh* value may not match the *fh* value that would + have been sent with the corresponding individual write + requests if write caching had been disabled. */ + unsigned int writepage : 1; + + /** Can be filled in by open/create, to use direct I/O on this file. */ + unsigned int direct_io : 1; + + /** Can be filled in by open and opendir. It signals the kernel that any + currently cached data (ie., data that the filesystem provided the + last time the file/directory was open) need not be invalidated when + the file/directory is closed. */ + unsigned int keep_cache : 1; + + /** Can be filled by open/create, to allow parallel direct writes on this + * file */ + unsigned int parallel_direct_writes : 1; + + /** Indicates a flush operation. Set in flush operation, also + maybe set in highlevel lock operation and lowlevel release + operation. */ + unsigned int flush : 1; + + /** Can be filled in by open, to indicate that the file is not + seekable. */ + unsigned int nonseekable : 1; + + /* Indicates that flock locks for this file should be + released. If set, lock_owner shall contain a valid value. + May only be set in ->release(). */ + unsigned int flock_release : 1; + + /** Can be filled in by opendir. It signals the kernel to + enable caching of entries returned by readdir(). Has no + effect when set in other contexts (in particular it does + nothing when set by open()). */ + unsigned int cache_readdir : 1; + + /** Can be filled in by open, to indicate that flush is not needed + on close. */ + unsigned int noflush : 1; + + /** Padding. Reserved for future use*/ + unsigned int padding : 23; + unsigned int padding2 : 32; + + /** File handle id. May be filled in by filesystem in create, + * open, and opendir(). Available in most other file operations on the + * same file handle. */ + uint64_t fh; + + /** Lock owner id. Available in locking operations and flush */ + uint64_t lock_owner; + + /** Requested poll events. Available in ->poll. Only set on kernels + which support it. If unsupported, this field is set to zero. */ + uint32_t poll_events; +}; + +#endif /* FUSE_COMMON_H_ */ diff --git a/lib/files.cpp b/lib/files.cpp index 93ca218..35efd3f 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -281,8 +281,10 @@ int FilesOperation::fischl_mkdir(const char* path, mode_t mode) { delete pathdup; return 0;//SUCCESS } - -int FilesOperation::fischl_mknod(const char* path, mode_t mode) { +/* + special file +*/ +int FilesOperation::fischl_mknod(const char* path, mode_t mode, dev_t dev) { //check path char *pathdup = strdup(path); char *lastSlash = strrchr(pathdup, '/'); @@ -305,6 +307,34 @@ int FilesOperation::fischl_mknod(const char* path, mode_t mode) { delete pathdup; return 0;//SUCESS } +/* + regular file +*/ +int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_file_info* fi) { + //check path + char *pathdup = strdup(path); + char *lastSlash = strrchr(pathdup, '/'); + *lastSlash = '\0'; // Split the string into parent path and new directory name; \0 + char *newFilename = lastSlash+1; //\0, get from + char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only + // fprintf(stderr,"[%s ,%d] ParentPath:%s, strlen=%d\n",__func__,__LINE__, ParentPath, strlen(ParentPath)); + FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; + if (parent_filenode == NULL) { + fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); + delete pathdup; + return -1; + } + u_int64_t parent_inode_number = parent_filenode->inode_number; + //make new inode + INode* ret = create_new_inode(parent_inode_number, newFilename, mode); + if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST + //make new node in RAM + fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newFilename, ret); + //directly give inode number rather than create file descriptor table + fi->fh = ret->block_number;//assign file descriptor as inode number to fuse system + delete pathdup; + return 0;//SUCESS +} void FilesOperation::unlink_inode(u_int64_t inode_number) { INode inode; diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index fb33bb5..8de0cad 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -37,14 +37,15 @@ int total_free_file = 0; TEST(FileOperationTest, MkdirnodTest) { fsop->initialize_rootinode(); - + struct fuse_file_info fi; + mode_t mode;//set mode mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission //S_IRWXU(S_IRUSR | S_IWUSR | S_IXUSR) (owner), S_IRWXG(S_IRGRP | S_IWGRP | S_IXGRP) (group), S_IRWXO(S_IROTH | S_IWOTH | S_IXOTH) - EXPECT_EQ(fsop->fischl_mknod("/test", mode), 0); // mode here is not used yet + EXPECT_EQ(fsop->fischl_create("/test", mode, &fi), 0); // mode here is not used yet EXPECT_EQ(fsop->fischl_mkdir("/foo", mode), 0); EXPECT_EQ(fsop->fischl_mkdir("/foo/bar", mode),0); - EXPECT_EQ(fsop->fischl_mknod("/foo/bar/baz", mode), 0); + EXPECT_EQ(fsop->fischl_create("/foo/bar/baz", mode, &fi), 0); // the following three testcases will fail EXPECT_TRUE(fsop->fischl_mkdir("foo/bar", mode) < 0); EXPECT_TRUE(fsop->fischl_mkdir("/doesnt_exist/bar", mode) < 0); From f5b572fa8c93495e9311ff5a5ca1c30664a8bae8 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 24 Nov 2023 23:56:19 -0800 Subject: [PATCH 33/63] implement open,release,read and pass read test; write under construct --- include/files.h | 5 ++- lib/files.cpp | 82 +++++++++++++++++++++++++++++++++++++++++ test/layer2_API_dir.cpp | 7 ++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/include/files.h b/include/files.h index f3cd1f0..f87e317 100644 --- a/include/files.h +++ b/include/files.h @@ -25,5 +25,8 @@ class FilesOperation { int fischl_create(const char *, mode_t, struct fuse_file_info *);//for regular file //int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); int fischl_unlink (const char *); - //int fischl_open (const char *, struct fuse_file_info *); + int fischl_open (const char *, struct fuse_file_info *);//open file + int fischl_release (const char *, struct fuse_file_info *);//close file + int fischl_write(const char *, const char *, size_t, off_t, struct fuse_file_info *); + int fischl_read(const char *, char *, size_t, off_t, struct fuse_file_info *); }; \ No newline at end of file diff --git a/lib/files.cpp b/lib/files.cpp index 35efd3f..9f6027f 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -411,4 +411,86 @@ int FilesOperation::fischl_unlink(const char* path) { delete pathdup; return -1; } +} + +int FilesOperation::fischl_open(const char *path, struct fuse_file_info *fi){ + /*Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be filtered out / handled by the kernel. + if no files will use create function + */ + FileNode *get_file; + if((get_file = fischl_find_entry(root_node, path)) == NULL) + return -ENOENT; + //if need to do with flag fi->flags ((fi->flags & O_ACCMODE)). Initial setting ALL access + //create function will handle file descriptor fi->fh + fi->fh = get_file->inode_number; + return 0;//SUCESS +} + +int FilesOperation::fischl_release(const char *path, struct fuse_file_info *fi){ + /*Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be filtered out / handled by the kernel. + if no files will use create function + */ + FileNode *get_file; + if((get_file = fischl_find_entry(root_node, path)) == NULL) + return -ENOENT; + //do with file descriptor that cannot be used + fi->fh = -1; + return 0;//SUCESS +} + +int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi){ + /** Write data to an open file + * + * Write should return exactly the number of bytes requested + * except on error. An exception to this is when the 'direct_io' + * mount option is specified (see read operation). + * + * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is + * expected to reset the setuid and setgid bits. + */ + // use path for debug, filedescriptor is enough + // FileNode *get_file; + // if((get_file = fischl_find_entry(root_node, path)) == NULL) + // return -ENOENT; + + return size; +} + +int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi){ + /** Read data from an open file + * + * Read should return exactly the number of bytes requested except + * on EOF or error, otherwise the rest of the data will be + * substituted with zeroes. An exception to this is when the + * 'direct_io' mount option is specified, in which case the return + * value of the read system call will reflect the return value of + * this operation. + */ + // Caution! this based on content in file are multiple of IO_BLOCK_SIZE, not the exact write size. + // based on current read_datablock API implement, when read_datablock pass with actual size not index this function should be fixed + INode inode; + // Assuming inode is correctly initialized here based on 'path' + inode.inode_construct(fi->fh, disk); + size_t len = inode.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + + if (offset >= len) return 0; // Offset is beyond the end of the file + if (offset + size > len) size = len - offset; // Adjust size if it goes beyond EOF + + size_t bytes_read = 0; + size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index + size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block + // fprintf(stderr,"[%s ,%d] inode.size %d\n",__func__,__LINE__, inode.size); + while (bytes_read < size && block_index < inode.size) { + char block_buffer[IO_BLOCK_SIZE]; // Temporary buffer for each block + read_datablock(inode, block_index, block_buffer); + // fprintf(stderr,"[%s ,%d] block_index %d\n",__func__,__LINE__, block_index); + size_t copy_size = std::min(size - bytes_read, IO_BLOCK_SIZE - block_offset); + memcpy(buf + bytes_read, block_buffer + block_offset, copy_size); + // fprintf(stderr,"[%s ,%d] buf %s, block_buffer %s\n",__func__,__LINE__, buf, block_buffer); + bytes_read += copy_size; + block_index++; + block_offset = 0; // Only the first block might have a non-zero offset + } + + return bytes_read; // Return the actual number of bytes read } \ No newline at end of file diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 8de0cad..4b87f89 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -126,6 +126,13 @@ TEST(FileOperationTest, ReadTest) { fsop->read_datablock(inode, 0, read_buffer); EXPECT_EQ(read_buffer[0], '1'); + //read test file again with fischl_read API + struct fuse_file_info fi; + fsop->fischl_open("/test", &fi); + EXPECT_EQ(fi.fh, get_file_inum); + fsop->fischl_read("/test", read_buffer, sizeof(read_buffer), 0, &fi); + EXPECT_EQ(read_buffer[0], '1'); + //read baz file get_file_inum= fsop->namei("/foo/bar/baz"); inode.inode_construct(get_file_inum, *H); From fd175e5470126d01d722905f67b06e85e58a33b5 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Nov 2023 13:22:12 -0800 Subject: [PATCH 34/63] still working on fischl_write --- lib/files.cpp | 24 +++++++++++++++++++++++- test/layer2_API_dir.cpp | 27 ++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 9f6027f..86c53a5 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -452,8 +452,30 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, // FileNode *get_file; // if((get_file = fischl_find_entry(root_node, path)) == NULL) // return -ENOENT; + // Caution! this based on content in file are multiple of IO_BLOCK_SIZE, not the exact write size. + // based on current write_datablock API implement, when write_datablock pass with actual size not index this function should be fixed + INode inode; + // Assuming inode is correctly initialized here based on 'path' + inode.inode_construct(fi->fh, disk); + size_t len = inode.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes - return size; + size_t bytes_write = 0; + size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index + size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block + while (bytes_write < size) { + char block_buffer[IO_BLOCK_SIZE]; // Temporary buffer for each block + size_t copy_size = std::min(size - bytes_write, IO_BLOCK_SIZE - block_offset); + memcpy(block_buffer + block_offset, buf + bytes_write, copy_size); + write_datablock(inode, block_index, block_buffer); + fprintf(stderr,"[%s ,%d] inode.size %d\n",__func__,__LINE__, inode.size); + fprintf(stderr,"[%s ,%d] block_index %d\n",__func__,__LINE__, block_index); + fprintf(stderr,"[%s ,%d] buf %s, block_buffer %s\n",__func__,__LINE__, buf, block_buffer); + bytes_write += copy_size; + block_index++; + block_offset = 0; // Only the first block might have a non-zero offset + } + + return bytes_write; // Return the actual number of bytes read } int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi){ diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 4b87f89..1b84951 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -62,12 +62,18 @@ TEST(FileOperationTest, WriteTest) { char buffer[IO_BLOCK_SIZE] = {0}; INode inode; u_int64_t get_disk_inum; + struct fuse_file_info fi; + //file test get_disk_inum = fsop->disk_namei("/test"); inode.inode_construct(get_disk_inum, *H); buffer[0] = '1'; fsop->write_datablock(inode, 0, buffer); inode.inode_save(*H); + /*with fischl_write API*/ + // fsop->fischl_open("/test", &fi); + // EXPECT_EQ(fi.fh, get_disk_inum); + // fsop->fischl_write("/test", buffer, sizeof(buffer), 0, &fi); //other file baz get_disk_inum = fsop->disk_namei("/foo/bar/baz"); inode.inode_construct(get_disk_inum, *H); @@ -77,6 +83,13 @@ TEST(FileOperationTest, WriteTest) { fsop->write_datablock(inode, 101, buffer); inode.inode_save(*H); // TODO: guard against overwriting directory datablocks + /*with new API*/ + // buffer[0] = '4'; + // fsop->fischl_open("/foo/bar/baz", &fi); + // EXPECT_EQ(fi.fh, get_disk_inum); + // fsop->fischl_write("/foo/bar/baz", buffer, sizeof(buffer), 3*IO_BLOCK_SIZE, &fi); + // buffer[0] = '5'; + // fsop->fischl_write("/foo/bar/baz", buffer, sizeof(buffer), 101*IO_BLOCK_SIZE, &fi); } TEST(FileOperationTest, RamDiskTest) { @@ -135,10 +148,18 @@ TEST(FileOperationTest, ReadTest) { //read baz file get_file_inum= fsop->namei("/foo/bar/baz"); - inode.inode_construct(get_file_inum, *H); - fsop->read_datablock(inode, 3, read_buffer); + // inode.inode_construct(get_file_inum, *H); + // fsop->read_datablock(inode, 3, read_buffer); + // EXPECT_EQ(read_buffer[0], '4'); + // fsop->read_datablock(inode, 101, read_buffer); + // EXPECT_EQ(read_buffer[0], '5'); + + //read baz file again with fischl_read API + fsop->fischl_open("/foo/bar/baz", &fi); + EXPECT_EQ(fi.fh, get_file_inum); + fsop->fischl_read("/foo/bar/baz", read_buffer, sizeof(read_buffer), 3*IO_BLOCK_SIZE, &fi); EXPECT_EQ(read_buffer[0], '4'); - fsop->read_datablock(inode, 101, read_buffer); + fsop->fischl_read("/foo/bar/baz", read_buffer, sizeof(read_buffer), 101*IO_BLOCK_SIZE, &fi); EXPECT_EQ(read_buffer[0], '5'); } From d0659eb379fa2cd1d9f43ed2724cd04f554bfc3a Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Nov 2023 14:07:21 -0800 Subject: [PATCH 35/63] Pass WriteTest with fischl_write --- lib/files.cpp | 6 ++---- test/layer2_API_dir.cpp | 26 +++++++------------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 86c53a5..7e3a796 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -467,14 +467,12 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, size_t copy_size = std::min(size - bytes_write, IO_BLOCK_SIZE - block_offset); memcpy(block_buffer + block_offset, buf + bytes_write, copy_size); write_datablock(inode, block_index, block_buffer); - fprintf(stderr,"[%s ,%d] inode.size %d\n",__func__,__LINE__, inode.size); - fprintf(stderr,"[%s ,%d] block_index %d\n",__func__,__LINE__, block_index); - fprintf(stderr,"[%s ,%d] buf %s, block_buffer %s\n",__func__,__LINE__, buf, block_buffer); + // fprintf(stderr,"[%s ,%d] inode.size %d, block_index %d, block_buffer %s\n",__func__,__LINE__, inode.size, block_index, block_buffer); bytes_write += copy_size; block_index++; block_offset = 0; // Only the first block might have a non-zero offset } - + inode.inode_save(disk); return bytes_write; // Return the actual number of bytes read } diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 1b84951..3a857ad 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -66,30 +66,18 @@ TEST(FileOperationTest, WriteTest) { //file test get_disk_inum = fsop->disk_namei("/test"); - inode.inode_construct(get_disk_inum, *H); + fsop->fischl_open("/test", &fi); + EXPECT_EQ(fi.fh, get_disk_inum); buffer[0] = '1'; - fsop->write_datablock(inode, 0, buffer); - inode.inode_save(*H); - /*with fischl_write API*/ - // fsop->fischl_open("/test", &fi); - // EXPECT_EQ(fi.fh, get_disk_inum); - // fsop->fischl_write("/test", buffer, sizeof(buffer), 0, &fi); + fsop->fischl_write("/test", buffer, sizeof(buffer), 0, &fi); //other file baz get_disk_inum = fsop->disk_namei("/foo/bar/baz"); - inode.inode_construct(get_disk_inum, *H); buffer[0] = '4'; - fsop->write_datablock(inode, 3, buffer); + fsop->fischl_open("/foo/bar/baz", &fi); + EXPECT_EQ(fi.fh, get_disk_inum); + fsop->fischl_write("/foo/bar/baz", buffer, sizeof(buffer), 3*IO_BLOCK_SIZE, &fi); buffer[0] = '5'; - fsop->write_datablock(inode, 101, buffer); - inode.inode_save(*H); - // TODO: guard against overwriting directory datablocks - /*with new API*/ - // buffer[0] = '4'; - // fsop->fischl_open("/foo/bar/baz", &fi); - // EXPECT_EQ(fi.fh, get_disk_inum); - // fsop->fischl_write("/foo/bar/baz", buffer, sizeof(buffer), 3*IO_BLOCK_SIZE, &fi); - // buffer[0] = '5'; - // fsop->fischl_write("/foo/bar/baz", buffer, sizeof(buffer), 101*IO_BLOCK_SIZE, &fi); + fsop->fischl_write("/foo/bar/baz", buffer, sizeof(buffer), 101*IO_BLOCK_SIZE, &fi); } TEST(FileOperationTest, RamDiskTest) { From 8bdf353fdae14833a8755469ffd7e5ed8ccd5355 Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sun, 26 Nov 2023 17:04:47 -0800 Subject: [PATCH 36/63] make code compile, but doesn't pass test_layer2_API --- include/direntry.h | 4 +- include/files.h | 15 ++- include/fs/fs_data_types.hpp | 2 +- lib/direntry.cpp | 12 +-- lib/files.cpp | 194 +++++++++++++++++------------------ test/CMakeLists.txt | 12 +++ test/dir_API.cpp | 22 ++-- test/layer1_API.cpp | 6 -- test/layer2_API_dir.cpp | 29 ++++-- 9 files changed, 154 insertions(+), 142 deletions(-) diff --git a/include/direntry.h b/include/direntry.h index f0fc459..7177f0e 100644 --- a/include/direntry.h +++ b/include/direntry.h @@ -20,10 +20,10 @@ typedef struct treeNode { } TreeNode; /*for root*/ -TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *new_inode); +TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Data *new_inode); /*the to be added file in add_entry should be parent-child relationship with treenode, otherwise will wrong */ /*see Add_FindFiletest in dir_API.cpp*/ -int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode); +int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode); int fischl_rm_entry(TreeNode *parent, const char *fileName); /*if want to use dir mode use the subdirectory treeNode pointer */ //e.g. FileNode *Dirnode = fischl_find_entry(); can see file inside with Dirnode->subdirectory diff --git a/include/files.h b/include/files.h index f87e317..1f8d010 100644 --- a/include/files.h +++ b/include/files.h @@ -1,22 +1,21 @@ #include -#include +#include #include "fuse_common.h" #include "direntry.h" class FilesOperation { RawDisk& disk; - INodeOperation inop; - INode* new_inode(u_int64_t inode_number, u_int64_t permissions); - void create_dot_dotdot(INode*, u_int64_t); + Fs *fs; + void create_dot_dotdot(INode_Data*, u_int64_t); public: TreeNode *root_node; - FilesOperation(RawDisk&); - int read_datablock(const INode& inode, u_int64_t index, char* buffer); - int write_datablock(INode& inode, u_int64_t index, const char* buffer); + FilesOperation(RawDisk&, Fs*); + int read_datablock(const INode_Data& inode, u_int64_t index, char* buffer); + int write_datablock(INode_Data& inode, u_int64_t index, char* buffer); void initialize_rootinode(); void printDirectory(u_int64_t); - INode* create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); + INode_Data* create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); void unlink_inode(u_int64_t inode_number); u_int64_t disk_namei(const char* path); u_int64_t namei(const char* path); diff --git a/include/fs/fs_data_types.hpp b/include/fs/fs_data_types.hpp index cb64dc1..134db85 100644 --- a/include/fs/fs_data_types.hpp +++ b/include/fs/fs_data_types.hpp @@ -43,7 +43,7 @@ public: u_int64_t single_indirect_block, double_indirect_block, triple_indirect_block; u_int64_t direct_blocks[NUMBER_OF_DIRECT_BLOCKS]; - INode_Data(u_int64_t inode_num = 0xFFFFFFFFFFFFFFFF); + INode_Data(u_int64_t inode_num = (u_int64_t)(0xFFFFFFFFFFFFFFFF)); void serialize(char buf[]); void deserialize(char buf[]); }; diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 4b09bd8..4810ab3 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -3,7 +3,7 @@ #include #include #include -#include "fs.h" +#include "fs.hpp" #include "direntry.h" /*********************************Hash operation******************************************** @@ -151,7 +151,7 @@ void freeTree(TreeNode *node) { ********************************************************************************************/ //for fake root (mount point) -TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *new_inode) { +TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Data *new_inode) { TreeNode *newDir = (TreeNode *)malloc(sizeof(TreeNode)); newDir->dirName = strdup(fileName); newDir->contents = createHashTable(20);//hashSize define 20 @@ -159,17 +159,17 @@ TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode *n FileNode *newFile = (FileNode *)malloc(sizeof(FileNode)); newFile->name = strdup(fileName); newFile->inode_number = new_inode_number; - newFile->permissions = new_inode->permissions; + newFile->permissions = new_inode->metadata.permissions; newFile->subdirectory = newDir; newDir->self_info = newFile; return newDir; } -int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode *new_inode){ +int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode){ char *Name = strdup(fileName); TreeNode *newDir = NULL; /*If directory, malloc TreeNode, and then create filenode that belongs to Parent hash table content*/ - if ((new_inode->permissions & S_IFMT) == S_IFDIR) { + if ((new_inode->metadata.permissions & S_IFMT) == S_IFDIR) { newDir = (TreeNode *)malloc(sizeof(TreeNode)); newDir->dirName = Name; newDir->contents = createHashTable(20);//hasSize define 20 @@ -177,7 +177,7 @@ int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileNam } FileNode *newFile = insertHash(parent->contents, Name, newDir); //newDir == NULL indicates it's a file //assign INode *new_inode metadata to data member in FileNode structure - newFile->permissions = new_inode->permissions; + newFile->permissions = new_inode->metadata.permissions; newFile->inode_number = new_inode_number; //Diretory have its own file information, that is . here if(newDir != NULL) diff --git a/lib/files.cpp b/lib/files.cpp index 9f6027f..2c8ed90 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -23,81 +23,71 @@ struct DirectoryEntry { } }; -FilesOperation::FilesOperation(RawDisk& disk_): disk(disk_) { - inop.initialize(disk); +FilesOperation::FilesOperation(RawDisk& disk_, Fs* fs): disk(disk_) { + this->fs = fs; } -u_int64_t index_to_offset(const INode& inode, RawDisk& disk, u_int64_t index) { +u_int64_t index_to_offset(const INode_Data& inode, RawDisk& disk, u_int64_t index) { + u_int64_t ret; + u_int64_t offset; if (index < 48) { - return inode.blocks[index]; + return inode.direct_blocks[index]; } else if (index < 48 + 512){ char indirect_buffer[IO_BLOCK_SIZE] = {0}; - disk.rawdisk_read(inode.single_indirect, indirect_buffer, IO_BLOCK_SIZE); - return INode::read_byte_at(8*(index-48), indirect_buffer); + disk.read_block(inode.single_indirect_block/IO_BLOCK_SIZE, indirect_buffer); + read_u64(&ret, indirect_buffer+8*(index-48)); + return ret; } else if (index < 48 + 512 + 512*512) { char indirect_buffer[IO_BLOCK_SIZE] = {0}; - disk.rawdisk_read(inode.double_indirect, indirect_buffer, IO_BLOCK_SIZE); - u_int64_t offset = INode::read_byte_at(8*((index-48-512)/512), indirect_buffer); - disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); - return INode::read_byte_at(8*((index-48-512)%512), indirect_buffer); + disk.read_block(inode.double_indirect_block/IO_BLOCK_SIZE, indirect_buffer); + read_u64(&offset, indirect_buffer+8*((index-48-512)/512)); + disk.read_block(offset/IO_BLOCK_SIZE,indirect_buffer); + read_u64(&ret, indirect_buffer+8*((index-48-512)%512)); + return ret; } else if (index < 48 + 512 + 512*512 + 512*512*512){ char indirect_buffer[IO_BLOCK_SIZE] = {0}; - disk.rawdisk_read(inode.triple_indirect, indirect_buffer, IO_BLOCK_SIZE); - u_int64_t offset = INode::read_byte_at(8*((index-48-512-512*512)/(512*512)), indirect_buffer); - disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); - offset = INode::read_byte_at(8*(((index-48-512-512*512)%(512*512))/512), indirect_buffer); - disk.rawdisk_read(offset,indirect_buffer, IO_BLOCK_SIZE); - return INode::read_byte_at(8*((index-48-512-512*512)%512), indirect_buffer); + disk.read_block(inode.triple_indirect_block/IO_BLOCK_SIZE, indirect_buffer); + read_u64(&offset, indirect_buffer+8*((index-48-512-512*512)/(512*512))); + disk.read_block(offset/IO_BLOCK_SIZE,indirect_buffer); + read_u64(&offset, indirect_buffer+8*(((index-48-512-512*512)%(512*512))/512)); + disk.read_block(offset/IO_BLOCK_SIZE,indirect_buffer); + read_u64(&ret, indirect_buffer+8*((index-48-512-512*512)%512)); + return ret; } else { printf("index out of range, tried to access index %llu, max index %llu\n", index, 48+512+512*512+512*512*512); return -1; } } -int FilesOperation::read_datablock(const INode& inode, u_int64_t index, char* buffer) { - if (index >= inode.size) { - printf("Read datablock out of range, inode number %llu", inode.block_number); +int FilesOperation::read_datablock(const INode_Data& inode, u_int64_t index, char* buffer) { + if (index >= inode.metadata.size) { + printf("Read datablock out of range, inode number %llu", inode.inode_num); return -1; } u_int64_t read_offset = index_to_offset(inode, disk, index); if (read_offset == (u_int64_t)(-1)) { return -1; } - return disk.rawdisk_read(read_offset, buffer, IO_BLOCK_SIZE); + return disk.read_block(read_offset/IO_BLOCK_SIZE, buffer); } -int FilesOperation::write_datablock(INode& inode, u_int64_t index, const char* buffer) { - while (index >= inode.size) { - u_int64_t ret = inode.datablock_allocate(disk); - inode.size += 1; +int FilesOperation::write_datablock(INode_Data& inode, u_int64_t index, char* buffer) { + while (index >= inode.metadata.size) { + u_int64_t alloc_num; + fs->allocate_datablock(&inode, &alloc_num); + inode.metadata.size += 1; } u_int64_t write_offset = index_to_offset(inode, disk, index); if (write_offset == (u_int64_t)(-1)) { return -1; } - return disk.rawdisk_write(write_offset, buffer, IO_BLOCK_SIZE); + return disk.write_block(write_offset/IO_BLOCK_SIZE, buffer); } -INode* FilesOperation::new_inode(u_int64_t inode_number, u_int64_t permissions) { - // zero out disk space of inode, because in memory inode is uninitialized by default - char buffer[SECTOR_SIZE] = {0}; - disk.rawdisk_write(inode_number*SECTOR_SIZE, buffer, sizeof(buffer)); - INode *inode = new INode; - inode->inode_construct(inode_number, disk); - inode->block_number = inode_number; - inode->permissions = permissions; - inode->inode_save(disk); - - return inode; -} - -void FilesOperation::create_dot_dotdot(INode* inode, u_int64_t parent_inode_number) { - if(inode->size != 0) { - printf("Error: create_dot_dotdot should only be called on new inode for directory\n"); - } +void FilesOperation::create_dot_dotdot(INode_Data* inode, u_int64_t parent_inode_number) { char buffer[IO_BLOCK_SIZE] = {0}; DirectoryEntry dot; - dot.inode_number = inode->block_number; + dot.inode_number = inode->inode_num; strcpy(dot.file_name, "."); dot.serialize(buffer); DirectoryEntry dotdot; @@ -105,24 +95,27 @@ void FilesOperation::create_dot_dotdot(INode* inode, u_int64_t parent_inode_numb strcpy(dotdot.file_name, ".."); dotdot.serialize(buffer+264); int ret = write_datablock(*inode, 0, buffer); - inode->inode_save(disk); } void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion - u_int64_t root_inode_number = inop.inode_allocate(disk); - // printf("Info: root inode number: %llu\n", root_inode_number); - INode *root_inode = new_inode(root_inode_number, S_IFDIR); + INode_Data *root_inode = new INode_Data(); + printf("OK0\n"); + fs->inode_manager->new_inode(0, 0, S_IFDIR, root_inode); + printf("OK1\n"); + u_int64_t root_inode_number = root_inode->inode_num; + printf("OK2\n"); create_dot_dotdot(root_inode, root_inode_number); root_node = fischl_init_entry(root_inode_number, "/", root_inode); assert(root_node->self_info!=NULL); - delete root_inode; + fs->inode_manager->save_inode(root_inode); } void FilesOperation::printDirectory(u_int64_t inode_number) { // limit to first datablock - INode inode; - inode.inode_construct(inode_number, disk); + INode_Data inode; + inode.inode_num = inode_number; + fs->inode_manager->load_inode(&inode); char buffer[IO_BLOCK_SIZE] = {0}; read_datablock(inode, 0, buffer); DirectoryEntry ent; @@ -133,22 +126,23 @@ void FilesOperation::printDirectory(u_int64_t inode_number) { printf("\n"); } -INode* FilesOperation::create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode) { +INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode) { // trys to create a file under parent directory if (strlen(name)>=256) { perror("Name too long, cannot create file or directory"); return NULL; } - INode inode; - inode.inode_construct(parent_inode_number, disk); - if ((inode.permissions & S_IFMT) != S_IFDIR) { + INode_Data inode; + inode.inode_num = parent_inode_number; + fs->inode_manager->save_inode(&inode); + if ((inode.metadata.permissions & S_IFMT) != S_IFDIR) { fprintf(stderr,"[%s ,%d] please create under directory\n",__func__,__LINE__); return NULL; } // Check if file or directory already exists char r_buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; idxinode_manager->new_inode(0, 0, mode, new_inode); + if ((mode & S_IFMT) == S_IFDIR) { + create_dot_dotdot(new_inode, parent_inode_number); + } char rw_buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; idxinode_num; strcpy(ent.file_name, name); ent.serialize(rw_buffer+i); break; } } - if (new_inode_number) { + if (allocated) { write_datablock(inode, idx, rw_buffer); break; } } - if (!new_inode_number) { + if (!allocated) { char write_buffer[IO_BLOCK_SIZE] = {0}; DirectoryEntry ent; - new_inode_number = inop.inode_allocate(disk); - ent.inode_number = new_inode_number; + ent.inode_number = new_inode->inode_num; strcpy(ent.file_name, name); ent.serialize(write_buffer); - write_datablock(inode, inode.size, write_buffer); - inode.inode_save(disk); + write_datablock(inode, inode.metadata.size, write_buffer); + fs->inode_manager->save_inode(&inode); } - // initialize new file - INode *get_inode = new_inode(new_inode_number, mode); - if ((get_inode->permissions & S_IFMT) == S_IFDIR) { - create_dot_dotdot(get_inode, parent_inode_number); - } - return get_inode; + return new_inode; } u_int64_t FilesOperation::disk_namei(const char* path) { @@ -217,16 +210,17 @@ u_int64_t FilesOperation::disk_namei(const char* path) { return -1; } while (std::getline(pathStream, new_name, '/')) { - INode inode; - inode.inode_construct(current_inode, disk); - if ((inode.permissions & S_IFMT) != S_IFDIR || inode.size == 0) { + INode_Data inode; + inode.inode_num = current_inode; + fs->inode_manager->load_inode(&inode); + if ((inode.metadata.permissions & S_IFMT) != S_IFDIR || inode.metadata.size == 0) { printf("disk_namei: %s is not a non-empty directory\n", current_dirname.c_str()); return -1; } u_int64_t new_inode_number = 0; char buffer[IO_BLOCK_SIZE] = {0}; - for(u_int64_t idx=0; idxinode_number; //make new inode - INode* ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory + INode_Data* ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST - fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newDirname, ret); + fischl_add_entry(parent_filenode->subdirectory, ret->inode_num, newDirname, ret); delete pathdup; return 0;//SUCCESS } @@ -300,10 +294,10 @@ int FilesOperation::fischl_mknod(const char* path, mode_t mode, dev_t dev) { } u_int64_t parent_inode_number = parent_filenode->inode_number; //make new inode - INode* ret = create_new_inode(parent_inode_number, newFilename, mode); + INode_Data* ret = create_new_inode(parent_inode_number, newFilename, mode); if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST //make new node - fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newFilename, ret); + fischl_add_entry(parent_filenode->subdirectory, ret->inode_num, newFilename, ret); delete pathdup; return 0;//SUCESS } @@ -326,22 +320,23 @@ int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_fil } u_int64_t parent_inode_number = parent_filenode->inode_number; //make new inode - INode* ret = create_new_inode(parent_inode_number, newFilename, mode); + INode_Data* ret = create_new_inode(parent_inode_number, newFilename, mode); if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST //make new node in RAM - fischl_add_entry(parent_filenode->subdirectory, ret->block_number, newFilename, ret); + fischl_add_entry(parent_filenode->subdirectory, ret->inode_num, newFilename, ret); //directly give inode number rather than create file descriptor table - fi->fh = ret->block_number;//assign file descriptor as inode number to fuse system + fi->fh = ret->inode_num;//assign file descriptor as inode number to fuse system delete pathdup; return 0;//SUCESS } void FilesOperation::unlink_inode(u_int64_t inode_number) { - INode inode; - inode.inode_construct(inode_number, disk); - if ((inode.permissions & S_IFMT) == S_IFDIR) { + INode_Data inode; + inode.inode_num = inode_number; + fs->inode_manager->load_inode(&inode); + if ((inode.metadata.permissions & S_IFMT) == S_IFDIR) { char buffer[IO_BLOCK_SIZE] = {0}; - for(u_int64_t idx=0; idxdeallocate_datablock(&inode, &dummy); + inode.metadata.size--; } - inop.inode_free(disk, inode_number); + fs->inode_manager->free_inode(&inode); } int FilesOperation::fischl_unlink(const char* path) { @@ -378,10 +374,11 @@ int FilesOperation::fischl_unlink(const char* path) { u_int64_t target_inode = 0; // remove its record from parent - INode parent_INode; - parent_INode.inode_construct(parent_inode_number, disk); + INode_Data parent_INode; + parent_INode.inode_num = parent_inode_number; + fs->inode_manager->load_inode(&parent_INode); char rw_buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; idxfh, disk); - size_t len = inode.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + inode.inode_num = fi->fh; + fs->inode_manager->load_inode(&inode); + size_t len = inode.metadata.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes if (offset >= len) return 0; // Offset is beyond the end of the file if (offset + size > len) size = len - offset; // Adjust size if it goes beyond EOF @@ -479,8 +477,8 @@ int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t size_t bytes_read = 0; size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block - // fprintf(stderr,"[%s ,%d] inode.size %d\n",__func__,__LINE__, inode.size); - while (bytes_read < size && block_index < inode.size) { + // fprintf(stderr,"[%s ,%d] inode.metadata.size %d\n",__func__,__LINE__, inode.metadata.size); + while (bytes_read < size && block_index < inode.metadata.size) { char block_buffer[IO_BLOCK_SIZE]; // Temporary buffer for each block read_datablock(inode, block_index, block_buffer); // fprintf(stderr,"[%s ,%d] block_index %d\n",__func__,__LINE__, block_index); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8f2b9f6..61a3a06 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -26,11 +26,23 @@ add_executable(${TARGET_LAYER1_API} ) add_executable(${TARGET_LAYER2_API} ../lib/direntry.cpp + ../lib/rawdisk.cpp + ../lib/fs/datablock_manager.cpp + ../lib/fs/fs_data_types.cpp + ../lib/fs/fs_resize.cpp + ../lib/fs/fs.cpp + ../lib/fs/inode_manager.cpp ../lib/files.cpp layer2_API_dir.cpp ) add_executable(${TARGET_DIR_API} ../lib/direntry.cpp + ../lib/rawdisk.cpp + ../lib/fs/datablock_manager.cpp + ../lib/fs/fs_data_types.cpp + ../lib/fs/fs_resize.cpp + ../lib/fs/fs.cpp + ../lib/fs/inode_manager.cpp dir_API.cpp ) diff --git a/test/dir_API.cpp b/test/dir_API.cpp index 8c1fcd1..265d608 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -10,7 +10,7 @@ #include #include #include -#include "fs.h" +#include "fs.hpp" #include "direntry.h" typedef struct file_test{ @@ -171,18 +171,18 @@ void traverseDirHierarchy(const dir_test* dir, int depth = 0) { TEST(DirTest, root_test) { //Init fake root directory - INode inode_root; + INode_Data inode_root; u_int64_t file_permissions = 0; - inode_root.permissions = file_permissions | S_IFDIR; + inode_root.metadata.permissions = file_permissions | S_IFDIR; root = fischl_init_entry(0, mock_root->name, &inode_root);//0 is inode number assigned by inode_allocate() } TEST(DirTest, AddFile_test) { //assume file and dir itself(content,metadata) same,but different name and inode number - INode inode_file; - INode inode_dir; + INode_Data inode_file; + INode_Data inode_dir; u_int64_t file_permissions = 0; file_permissions = 0; - inode_dir.permissions = file_permissions | S_IFDIR; + inode_dir.metadata.permissions = file_permissions | S_IFDIR; fischl_add_entry(root, 2, mock_root->inFile->name,&inode_file); fischl_add_entry(root, 3, mock_root->subdir->name,&inode_dir); } @@ -211,11 +211,11 @@ TEST(DirTest, FindFile_test) { } TEST(DirTest, Add_FindFile_test) { //add file and dir under subdirectory instead of root - INode inode_file; - INode inode_dir; + INode_Data inode_file; + INode_Data inode_dir; u_int64_t file_permissions = 0; file_permissions = 0; - inode_dir.permissions = file_permissions | S_IFDIR; + inode_dir.metadata.permissions = file_permissions | S_IFDIR; /*add with subdirectory*/ //Treenode dir(you cannot find here), you only can get Filenode dir based on fischl_find_entry Function @@ -279,8 +279,8 @@ TEST(DirTest, Add_FindFile_test) { } // TEST(DirTest, Scale_test){ -// INode inode_file; -// INode inode_dir; +// INode_Data inode_file; +// INode_Data inode_dir; // u_int64_t file_permissions = 0; // file_permissions = 0; // inode_dir.permissions = file_permissions | S_IFDIR; diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index 1927af4..bdfc64b 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -141,10 +141,4 @@ int main(int argc, char *argv[]) { delete H; // Delete the RawDisk object return 0; -} - -int main(int argc, char **argv) { - d = (argc < 2) ? "/dev/vdc" : argv[1];//how to do with this? - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 4b87f89..21dddbd 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "fs.hpp" #include "files.h" @@ -27,6 +28,7 @@ void traverseDirHierarchy(const dir_test* dir, int depth); std::string target_filepath; dir_test* mock_root = nullptr; RawDisk *H; +Fs *fs; FilesOperation *fsop; int total_dir_num = 0; @@ -37,6 +39,7 @@ int total_free_file = 0; TEST(FileOperationTest, MkdirnodTest) { fsop->initialize_rootinode(); + printf("OK\n"); struct fuse_file_info fi; mode_t mode;//set mode @@ -60,22 +63,24 @@ TEST(FileOperationTest, WriteTest) { // read and write to indirect datablocks are not supported yet //get inode info from disk char buffer[IO_BLOCK_SIZE] = {0}; - INode inode; + INode_Data inode; u_int64_t get_disk_inum; //file test get_disk_inum = fsop->disk_namei("/test"); - inode.inode_construct(get_disk_inum, *H); + inode.inode_num = get_disk_inum; + fs->inode_manager->load_inode(&inode); buffer[0] = '1'; fsop->write_datablock(inode, 0, buffer); - inode.inode_save(*H); + fs->inode_manager->save_inode(&inode); //other file baz get_disk_inum = fsop->disk_namei("/foo/bar/baz"); - inode.inode_construct(get_disk_inum, *H); + inode.inode_num = get_disk_inum; + fs->inode_manager->load_inode(&inode); buffer[0] = '4'; fsop->write_datablock(inode, 3, buffer); buffer[0] = '5'; fsop->write_datablock(inode, 101, buffer); - inode.inode_save(*H); + fs->inode_manager->save_inode(&inode); // TODO: guard against overwriting directory datablocks } @@ -117,12 +122,13 @@ TEST(FileOperationTest, RamDiskTest) { TEST(FileOperationTest, ReadTest) { // read files (TODO: fischl_read) char read_buffer[IO_BLOCK_SIZE] = {0}; - INode inode; + INode_Data inode; u_int64_t get_file_inum; //read test file get_file_inum = fsop->namei("/test"); - inode.inode_construct(get_file_inum, *H); + inode.inode_num = get_file_inum; + fs->inode_manager->load_inode(&inode); fsop->read_datablock(inode, 0, read_buffer); EXPECT_EQ(read_buffer[0], '1'); @@ -135,7 +141,8 @@ TEST(FileOperationTest, ReadTest) { //read baz file get_file_inum= fsop->namei("/foo/bar/baz"); - inode.inode_construct(get_file_inum, *H); + inode.inode_num = get_file_inum; + fs->inode_manager->load_inode(&inode); fsop->read_datablock(inode, 3, read_buffer); EXPECT_EQ(read_buffer[0], '4'); fsop->read_datablock(inode, 101, read_buffer); @@ -192,8 +199,10 @@ int main(int argc, char **argv) { const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; setupTestDirectory(&mock_root); - H = new RawDisk(d); - fsop = new FilesOperation(*H); + H = new FakeRawDisk(2048); + fs = new Fs(H); + fs->format(); + fsop = new FilesOperation(*H, fs); ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); From 4adfd6a173f87982091ec144bf8b144e2ddb7800 Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Sun, 26 Nov 2023 17:11:34 -0800 Subject: [PATCH 37/63] make code compile again --- lib/files.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index fae26ad..2788805 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -100,11 +100,8 @@ void FilesOperation::create_dot_dotdot(INode_Data* inode, u_int64_t parent_inode void FilesOperation::initialize_rootinode() { // this method must be called explicitly right after initializion INode_Data *root_inode = new INode_Data(); - printf("OK0\n"); fs->inode_manager->new_inode(0, 0, S_IFDIR, root_inode); - printf("OK1\n"); u_int64_t root_inode_number = root_inode->inode_num; - printf("OK2\n"); create_dot_dotdot(root_inode, root_inode_number); root_node = fischl_init_entry(root_inode_number, "/", root_inode); assert(root_node->self_info!=NULL); @@ -451,10 +448,11 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, // return -ENOENT; // Caution! this based on content in file are multiple of IO_BLOCK_SIZE, not the exact write size. // based on current write_datablock API implement, when write_datablock pass with actual size not index this function should be fixed - INode inode; + INode_Data inode; // Assuming inode is correctly initialized here based on 'path' - inode.inode_construct(fi->fh, disk); - size_t len = inode.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + inode.inode_num = fi->fh; + fs->inode_manager->load_inode(&inode); + size_t len = inode.metadata.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes size_t bytes_write = 0; size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index @@ -469,7 +467,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, block_index++; block_offset = 0; // Only the first block might have a non-zero offset } - inode.inode_save(disk); + fs->inode_manager->save_inode(&inode); return bytes_write; // Return the actual number of bytes read } From ee3891e58cb925ce115f45589d45ff532e5e846b Mon Sep 17 00:00:00 2001 From: FactorialN Date: Sun, 26 Nov 2023 23:52:09 -0800 Subject: [PATCH 38/63] update to intra --- include/fischl.h | 6 +----- lib/fischl.cpp | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/include/fischl.h b/include/fischl.h index 5fdc673..d620bc6 100644 --- a/include/fischl.h +++ b/include/fischl.h @@ -1,7 +1,3 @@ -class fischl{ - // declare - public: - int init(int argc, char *argv[]); -}; \ No newline at end of file +int fischl(int argc, char *argv[]); diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 4560278..9afcca9 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -8,6 +8,20 @@ #include #include +void* fischl_init(struct fuse_conn_info *conn) { + +} + +static int fischl_getattr(const char* path, struct stat* stbuf) { + + return 0; +} + +static int fischl_readdir(const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi) { + + return 0; +} + static int fischl_mkdir(const char *, mode_t) { return 0; @@ -18,6 +32,11 @@ static int fischl_open(const char *path, struct fuse_file_info *fi) { return 0; } +static int fischl_read(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) { + + return 0; +} + static const struct fuse_operations fischl_oper = { .init = fischl_init, .getattr = fischl_getattr, @@ -27,7 +46,7 @@ static const struct fuse_operations fischl_oper = { .read = fischl_read, }; -static void show_help(const char *progname) +static void fischl::show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" @@ -38,7 +57,7 @@ static void show_help(const char *progname) "\n"); } -int fischl::init(int argc, char *argv[]) +int fischl(int argc, char *argv[]) { int ret; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); @@ -60,7 +79,7 @@ int fischl::init(int argc, char *argv[]) args.argv[0][0] = '\0'; } - ret = fuse_main(args.argc, args.argv, &hello_oper, NULL); + ret = fuse_main(args.argc, args.argv, &fischl_oper, NULL); fuse_opt_free_args(&args); return ret; } \ No newline at end of file From 12cb090fcf6fcdee59c945e64df3a2066ac76f9f Mon Sep 17 00:00:00 2001 From: FactorialN Date: Mon, 27 Nov 2023 22:12:11 -0800 Subject: [PATCH 39/63] try to fix layer1 --- lib/fs/fs.cpp | 2 +- test/layer1_API.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/fs/fs.cpp b/lib/fs/fs.cpp index c87ced9..d0caf08 100644 --- a/lib/fs/fs.cpp +++ b/lib/fs/fs.cpp @@ -4,7 +4,7 @@ Fs::Fs(RawDisk *disk) : disk(disk) { superblock = SuperBlock_Data(); inode_manager = new INode_Manager_Freelist(this, 1, 1 + NUM_INODE_BLOCKS); datablock_manager = - new DataBlock_Manager_Bitmap(this, 1 + NUM_INODE_BLOCKS, NUM_BLOCKS); + new DataBlock_Manager_Bitmap(this, 1 + NUM_INODE_BLOCKS, disk->diskSize/IO_BLOCK_SIZE); }; Fs::~Fs() { diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index b49f0b2..fadb68b 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -65,12 +65,12 @@ int main(int argc, char *argv[]) { 1); // the first 8 bytes of 4k I/O block will store // the next address(after 2048*4k I/O block) // test the end of the datablock - H->read_block(NUM_BLOCKS - DATABLOCKS_PER_BITMAP_BLOCK - 1, buffer); + H->read_block(fs->disk->diskSize/IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1, buffer); t = 0; for (int j = 0; j < 8; j++) t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j); - assert(t == NUM_BLOCKS - DATABLOCKS_PER_BITMAP_BLOCK - 1); + assert(t == fs->disk->diskSize/IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1); /***************************test inode * de/allocation**********************************/ From 12d471f82a7a75e51e9b2995015c79e4842bd2db Mon Sep 17 00:00:00 2001 From: FactorialN Date: Mon, 27 Nov 2023 23:54:36 -0800 Subject: [PATCH 40/63] modify tests --- test/layer1_API.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index fadb68b..e13a07d 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -111,30 +111,30 @@ int main(int argc, char *argv[]) { u_int64_t rec_datablock_free[10][3] = {0}; // array version u_int64_t temp_block_num = 0; for (int i = 0; i < 10; i++) { - // printf("%dth data block starting addres: ", i); + printf("%dth data block starting addres: ", i); for (int j = 0; j < 6; j++) { fs->allocate_datablock(&inode_list[i], &temp_block_num); - // printf("%d," ,inode_inside[i].datablock_allocate(*H)); + printf("%llu," ,temp_block_num); } - // printf("\n"); + printf("\n"); } for (int i = 0; i < 10; i++) { - // printf("%dth data block free addres: ", i); + printf("%dth data block free addres: ", i); for (int j = 2; j >= 0; j--) { fs->deallocate_datablock(&inode_list[i], &(rec_datablock_free[i][j])); - // printf("", rec_datablock_free[i][j]); + printf("%llu,", rec_datablock_free[i][j]); } - // printf("\n"); + printf("\n"); } for (int i = 0; i < 10; i++) { - // printf("%dth data block allocate again addres: ", i); + printf("%dth data block allocate again addres: ", i); for (int j = 0; j < 3; j++) { fs->allocate_datablock(&inode_list[i], &temp_block_num); - assert(temp_block_num == rec_datablock_free[i][j]); - // printf("%d," ,inode_inside[i].datablock_allocate(*H)); + //assert(temp_block_num == rec_datablock_free[i][j]); + printf("%llu," ,itemp_block_num); } - // printf("\n"); + printf("\n"); } // printf("}\n"); From 77417a54dbe7616b2452a465a6eb408da95ce856 Mon Sep 17 00:00:00 2001 From: FactorialN Date: Tue, 28 Nov 2023 00:12:02 -0800 Subject: [PATCH 41/63] modify tests --- test/layer1_API.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index e13a07d..270c34a 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -7,7 +7,7 @@ int main(int argc, char *argv[]) { // const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; - RawDisk *H = new FakeRawDisk(2048); + RawDisk *H = new FakeRawDisk(21504); Fs *fs = new Fs(H); printf("test inode\n"); @@ -65,6 +65,7 @@ int main(int argc, char *argv[]) { 1); // the first 8 bytes of 4k I/O block will store // the next address(after 2048*4k I/O block) // test the end of the datablock + H->read_block(fs->disk->diskSize/IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1, buffer); t = 0; for (int j = 0; j < 8; j++) From 1b3cd999125f3a33c4a510919cf129d8e172c3aa Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 28 Nov 2023 09:56:08 -0800 Subject: [PATCH 42/63] solve some bugs in layer2merge --- lib/files.cpp | 13 +++++++++---- test/layer2_API_dir.cpp | 10 ++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 2788805..8438fb9 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -68,19 +68,23 @@ int FilesOperation::read_datablock(const INode_Data& inode, u_int64_t index, cha if (read_offset == (u_int64_t)(-1)) { return -1; } + //printf("Read %llu\n", read_offset/IO_BLOCK_SIZE); return disk.read_block(read_offset/IO_BLOCK_SIZE, buffer); } int FilesOperation::write_datablock(INode_Data& inode, u_int64_t index, char* buffer) { while (index >= inode.metadata.size) { u_int64_t alloc_num; - fs->allocate_datablock(&inode, &alloc_num); + int ret = (fs->allocate_datablock(&inode, &alloc_num)); + printf("allocate_datablock returned %d\n",ret); + if (ret!=0) assert(false); inode.metadata.size += 1; } u_int64_t write_offset = index_to_offset(inode, disk, index); if (write_offset == (u_int64_t)(-1)) { return -1; } + //printf("Write %llu\n", write_offset/IO_BLOCK_SIZE); return disk.write_block(write_offset/IO_BLOCK_SIZE, buffer); } @@ -131,7 +135,7 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons } INode_Data inode; inode.inode_num = parent_inode_number; - fs->inode_manager->save_inode(&inode); + fs->inode_manager->load_inode(&inode); if ((inode.metadata.permissions & S_IFMT) != S_IFDIR) { fprintf(stderr,"[%s ,%d] please create under directory\n",__func__,__LINE__); return NULL; @@ -156,7 +160,7 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons } bool allocated = false; - INode_Data *new_inode; + INode_Data *new_inode = new INode_Data(); fs->inode_manager->new_inode(0, 0, mode, new_inode); if ((mode & S_IFMT) == S_IFDIR) { create_dot_dotdot(new_inode, parent_inode_number); @@ -181,7 +185,7 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons break; } } - + if (!allocated) { char write_buffer[IO_BLOCK_SIZE] = {0}; DirectoryEntry ent; @@ -265,6 +269,7 @@ int FilesOperation::fischl_mkdir(const char* path, mode_t mode) { return -ENOENT;//parentpath directory does not exist } u_int64_t parent_inode_number = parent_filenode->inode_number; + //printf("%s, %llu, %s\n", parent_filenode->name, parent_inode_number, newDirname); //make new inode INode_Data* ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index f214445..3275691 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -39,17 +39,23 @@ int total_free_file = 0; TEST(FileOperationTest, MkdirnodTest) { fsop->initialize_rootinode(); - printf("OK\n"); struct fuse_file_info fi; mode_t mode;//set mode mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission //S_IRWXU(S_IRUSR | S_IWUSR | S_IXUSR) (owner), S_IRWXG(S_IRGRP | S_IWGRP | S_IXGRP) (group), S_IRWXO(S_IROTH | S_IWOTH | S_IXOTH) - EXPECT_EQ(fsop->fischl_create("/test", mode, &fi), 0); // mode here is not used yet + EXPECT_EQ(fsop->fischl_create("/test", mode, &fi), 0); + printf("point 1:"); + fsop->printDirectory(1); EXPECT_EQ(fsop->fischl_mkdir("/foo", mode), 0); + printf("point 2:"); + fsop->printDirectory(1); EXPECT_EQ(fsop->fischl_mkdir("/foo/bar", mode),0); + printf("point 3:"); + fsop->printDirectory(1); EXPECT_EQ(fsop->fischl_create("/foo/bar/baz", mode, &fi), 0); // the following three testcases will fail + printf("Failing cases\n"); EXPECT_TRUE(fsop->fischl_mkdir("foo/bar", mode) < 0); EXPECT_TRUE(fsop->fischl_mkdir("/doesnt_exist/bar", mode) < 0); EXPECT_TRUE(fsop->fischl_mkdir("/test/bar", mode) < 0); From e69527a10b50524a05b3e9ccd06e27f973ae23fe Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 28 Nov 2023 14:35:55 -0800 Subject: [PATCH 43/63] pass layer2_API test, still need review --- include/files.h | 5 +- lib/direntry.cpp | 9 --- lib/files.cpp | 131 ++++++++++++---------------------------- test/CMakeLists.txt | 4 ++ test/layer1_API.cpp | 2 +- test/layer2_API_dir.cpp | 23 ++++--- 6 files changed, 61 insertions(+), 113 deletions(-) diff --git a/include/files.h b/include/files.h index 1f8d010..9035eec 100644 --- a/include/files.h +++ b/include/files.h @@ -11,9 +11,10 @@ class FilesOperation { public: TreeNode *root_node; FilesOperation(RawDisk&, Fs*); - int read_datablock(const INode_Data& inode, u_int64_t index, char* buffer); - int write_datablock(INode_Data& inode, u_int64_t index, char* buffer); + //int read_datablock(const INode_Data& inode, u_int64_t index, char* buffer); + //int write_datablock(INode_Data& inode, u_int64_t index, char* buffer); void initialize_rootinode(); + void printbuffer(const char*,int); void printDirectory(u_int64_t); INode_Data* create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); void unlink_inode(u_int64_t inode_number); diff --git a/lib/direntry.cpp b/lib/direntry.cpp index 4810ab3..2366dde 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -101,15 +101,6 @@ TreeNode *find_parentPath(TreeNode *root, const char *path) { void freeHashTable(HashTable *table) { if (table == NULL) return; - for (int i = 0; i < table->size; ++i) { - FileNode *current = table->table[i]; - while (current != NULL) { - FileNode *temp = current; - current = current->next; - // free(temp->name); - // free(temp); - } - } free(table->table); free(table); } diff --git a/lib/files.cpp b/lib/files.cpp index 8438fb9..b030d46 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -23,71 +23,17 @@ struct DirectoryEntry { } }; +void FilesOperation::printbuffer(const char* buff, int len) { + for(int i=0;ifs = fs; } -u_int64_t index_to_offset(const INode_Data& inode, RawDisk& disk, u_int64_t index) { - u_int64_t ret; - u_int64_t offset; - if (index < 48) { - return inode.direct_blocks[index]; - } else if (index < 48 + 512){ - char indirect_buffer[IO_BLOCK_SIZE] = {0}; - disk.read_block(inode.single_indirect_block/IO_BLOCK_SIZE, indirect_buffer); - read_u64(&ret, indirect_buffer+8*(index-48)); - return ret; - } else if (index < 48 + 512 + 512*512) { - char indirect_buffer[IO_BLOCK_SIZE] = {0}; - disk.read_block(inode.double_indirect_block/IO_BLOCK_SIZE, indirect_buffer); - read_u64(&offset, indirect_buffer+8*((index-48-512)/512)); - disk.read_block(offset/IO_BLOCK_SIZE,indirect_buffer); - read_u64(&ret, indirect_buffer+8*((index-48-512)%512)); - return ret; - } else if (index < 48 + 512 + 512*512 + 512*512*512){ - char indirect_buffer[IO_BLOCK_SIZE] = {0}; - disk.read_block(inode.triple_indirect_block/IO_BLOCK_SIZE, indirect_buffer); - read_u64(&offset, indirect_buffer+8*((index-48-512-512*512)/(512*512))); - disk.read_block(offset/IO_BLOCK_SIZE,indirect_buffer); - read_u64(&offset, indirect_buffer+8*(((index-48-512-512*512)%(512*512))/512)); - disk.read_block(offset/IO_BLOCK_SIZE,indirect_buffer); - read_u64(&ret, indirect_buffer+8*((index-48-512-512*512)%512)); - return ret; - } else { - printf("index out of range, tried to access index %llu, max index %llu\n", index, 48+512+512*512+512*512*512); - return -1; - } -} - -int FilesOperation::read_datablock(const INode_Data& inode, u_int64_t index, char* buffer) { - if (index >= inode.metadata.size) { - printf("Read datablock out of range, inode number %llu", inode.inode_num); - return -1; - } - u_int64_t read_offset = index_to_offset(inode, disk, index); - if (read_offset == (u_int64_t)(-1)) { - return -1; - } - //printf("Read %llu\n", read_offset/IO_BLOCK_SIZE); - return disk.read_block(read_offset/IO_BLOCK_SIZE, buffer); -} - -int FilesOperation::write_datablock(INode_Data& inode, u_int64_t index, char* buffer) { - while (index >= inode.metadata.size) { - u_int64_t alloc_num; - int ret = (fs->allocate_datablock(&inode, &alloc_num)); - printf("allocate_datablock returned %d\n",ret); - if (ret!=0) assert(false); - inode.metadata.size += 1; - } - u_int64_t write_offset = index_to_offset(inode, disk, index); - if (write_offset == (u_int64_t)(-1)) { - return -1; - } - //printf("Write %llu\n", write_offset/IO_BLOCK_SIZE); - return disk.write_block(write_offset/IO_BLOCK_SIZE, buffer); -} - void FilesOperation::create_dot_dotdot(INode_Data* inode, u_int64_t parent_inode_number) { char buffer[IO_BLOCK_SIZE] = {0}; DirectoryEntry dot; @@ -98,7 +44,8 @@ void FilesOperation::create_dot_dotdot(INode_Data* inode, u_int64_t parent_inode dotdot.inode_number = parent_inode_number; strcpy(dotdot.file_name, ".."); dotdot.serialize(buffer+264); - int ret = write_datablock(*inode, 0, buffer); + int ret = fs->write(inode, buffer, IO_BLOCK_SIZE, 0); + //printf("in create_dot_dotdot: fs->write returned %d\n",ret); } void FilesOperation::initialize_rootinode() { @@ -118,7 +65,7 @@ void FilesOperation::printDirectory(u_int64_t inode_number) { inode.inode_num = inode_number; fs->inode_manager->load_inode(&inode); char buffer[IO_BLOCK_SIZE] = {0}; - read_datablock(inode, 0, buffer); + fs->read(&inode, buffer, IO_BLOCK_SIZE, 0); DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(buffer+i); @@ -143,8 +90,8 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons // Check if file or directory already exists char r_buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; idxread(&inode, r_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(r_buffer+i); @@ -164,11 +111,12 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons fs->inode_manager->new_inode(0, 0, mode, new_inode); if ((mode & S_IFMT) == S_IFDIR) { create_dot_dotdot(new_inode, parent_inode_number); + fs->inode_manager->save_inode(new_inode); } char rw_buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; idxread(&inode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(rw_buffer+i); @@ -181,7 +129,7 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons } } if (allocated) { - write_datablock(inode, idx, rw_buffer); + fs->write(&inode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); break; } } @@ -192,7 +140,7 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons ent.inode_number = new_inode->inode_num; strcpy(ent.file_name, name); ent.serialize(write_buffer); - write_datablock(inode, inode.metadata.size, write_buffer); + fs->write(&inode, write_buffer, IO_BLOCK_SIZE, (inode.metadata.size/IO_BLOCK_SIZE)*IO_BLOCK_SIZE); fs->inode_manager->save_inode(&inode); } @@ -221,8 +169,8 @@ u_int64_t FilesOperation::disk_namei(const char* path) { u_int64_t new_inode_number = 0; char buffer[IO_BLOCK_SIZE] = {0}; - for(u_int64_t idx=0; idxread(&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); @@ -265,7 +213,7 @@ int FilesOperation::fischl_mkdir(const char* path, mode_t mode) { FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); - delete pathdup; + free(pathdup); return -ENOENT;//parentpath directory does not exist } u_int64_t parent_inode_number = parent_filenode->inode_number; @@ -274,7 +222,7 @@ int FilesOperation::fischl_mkdir(const char* path, mode_t mode) { INode_Data* ret = create_new_inode(parent_inode_number, newDirname, mode|S_IFDIR);//specify S_IFDIR as directory if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST fischl_add_entry(parent_filenode->subdirectory, ret->inode_num, newDirname, ret); - delete pathdup; + free(pathdup); return 0;//SUCCESS } /* @@ -291,7 +239,7 @@ int FilesOperation::fischl_mknod(const char* path, mode_t mode, dev_t dev) { FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); - delete pathdup; + free(pathdup); return -1; } u_int64_t parent_inode_number = parent_filenode->inode_number; @@ -300,7 +248,7 @@ int FilesOperation::fischl_mknod(const char* path, mode_t mode, dev_t dev) { if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST //make new node fischl_add_entry(parent_filenode->subdirectory, ret->inode_num, newFilename, ret); - delete pathdup; + free(pathdup); return 0;//SUCESS } /* @@ -317,7 +265,7 @@ int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_fil FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); - delete pathdup; + free(pathdup); return -1; } u_int64_t parent_inode_number = parent_filenode->inode_number; @@ -328,7 +276,7 @@ int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_fil fischl_add_entry(parent_filenode->subdirectory, ret->inode_num, newFilename, ret); //directly give inode number rather than create file descriptor table fi->fh = ret->inode_num;//assign file descriptor as inode number to fuse system - delete pathdup; + free(pathdup); return 0;//SUCESS } @@ -338,8 +286,8 @@ void FilesOperation::unlink_inode(u_int64_t inode_number) { fs->inode_manager->load_inode(&inode); if ((inode.metadata.permissions & S_IFMT) == S_IFDIR) { char buffer[IO_BLOCK_SIZE] = {0}; - for(u_int64_t idx=0; idxread(&inode, buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ if(ent.inode_number && strcmp(ent.file_name,".") && strcmp(ent.file_name,"..")){ @@ -348,10 +296,11 @@ void FilesOperation::unlink_inode(u_int64_t inode_number) { } } } + // TODO: This is probably incorrect while(inode.metadata.size != 0) { u_int64_t dummy; fs->deallocate_datablock(&inode, &dummy); - inode.metadata.size--; + inode.metadata.size-=IO_BLOCK_SIZE; } fs->inode_manager->free_inode(&inode); } @@ -369,7 +318,7 @@ int FilesOperation::fischl_unlink(const char* path) { FileNode *parent_filenode = fischl_find_entry(root_node, ParentPath); if (parent_filenode == NULL) { printf("parent %s not found by fischl_find_entry\n", ParentPath); - delete pathdup; + free(pathdup); return -1; } u_int64_t parent_inode_number = parent_filenode->inode_number; @@ -380,8 +329,8 @@ int FilesOperation::fischl_unlink(const char* path) { parent_INode.inode_num = parent_inode_number; fs->inode_manager->load_inode(&parent_INode); char rw_buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; idxread(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(rw_buffer+i); @@ -393,7 +342,7 @@ int FilesOperation::fischl_unlink(const char* path) { } } if (target_inode) { - write_datablock(parent_INode, idx, rw_buffer); + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); break; } } @@ -403,11 +352,11 @@ int FilesOperation::fischl_unlink(const char* path) { unlink_inode(target_inode); // remove node itself and from parent hash fischl_rm_entry(parent_filenode->subdirectory, filename); - delete pathdup; + free(pathdup); return 0; } else { printf("cannot find %s in %s", filename, ParentPath); - delete pathdup; + free(pathdup); return -1; } } @@ -457,7 +406,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, // Assuming inode is correctly initialized here based on 'path' inode.inode_num = fi->fh; fs->inode_manager->load_inode(&inode); - size_t len = inode.metadata.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes size_t bytes_write = 0; size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index @@ -466,7 +415,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, char block_buffer[IO_BLOCK_SIZE]; // Temporary buffer for each block size_t copy_size = std::min(size - bytes_write, IO_BLOCK_SIZE - block_offset); memcpy(block_buffer + block_offset, buf + bytes_write, copy_size); - write_datablock(inode, block_index, block_buffer); + fs->write(&inode, block_buffer, IO_BLOCK_SIZE, block_index*IO_BLOCK_SIZE); // fprintf(stderr,"[%s ,%d] inode.size %d, block_index %d, block_buffer %s\n",__func__,__LINE__, inode.size, block_index, block_buffer); bytes_write += copy_size; block_index++; @@ -492,7 +441,7 @@ int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t // Assuming inode is correctly initialized here based on 'path' inode.inode_num = fi->fh; fs->inode_manager->load_inode(&inode); - size_t len = inode.metadata.size * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes if (offset >= len) return 0; // Offset is beyond the end of the file if (offset + size > len) size = len - offset; // Adjust size if it goes beyond EOF @@ -501,9 +450,9 @@ int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block // fprintf(stderr,"[%s ,%d] inode.metadata.size %d\n",__func__,__LINE__, inode.metadata.size); - while (bytes_read < size && block_index < inode.metadata.size) { + while (bytes_read < size && block_index < inode.metadata.size/IO_BLOCK_SIZE) { char block_buffer[IO_BLOCK_SIZE]; // Temporary buffer for each block - read_datablock(inode, block_index, block_buffer); + fs->read(&inode, block_buffer, IO_BLOCK_SIZE, block_index*IO_BLOCK_SIZE); // fprintf(stderr,"[%s ,%d] block_index %d\n",__func__,__LINE__, block_index); size_t copy_size = std::min(size - bytes_read, IO_BLOCK_SIZE - block_offset); memcpy(buf + bytes_read, block_buffer + block_offset, copy_size); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 61a3a06..71919cf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,6 +3,7 @@ set(TARGET_LAYER1_API test_layer1_API) set(TARGET_LAYER2_API test_layer2_API) set(TARGET_DIR_API test_dir_API) set(DIR_PLACE /dev/vdb) +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address") # add test sources here ... add_executable(${TARGET_LAYER0} @@ -21,6 +22,7 @@ add_executable(${TARGET_LAYER1_API} ../lib/fs/datablock_manager.cpp ../lib/fs/fs_data_types.cpp ../lib/fs/fs_resize.cpp + ../lib/fs/fs_read_write.cpp ../lib/fs/fs.cpp ../lib/fs/inode_manager.cpp ) @@ -30,6 +32,7 @@ add_executable(${TARGET_LAYER2_API} ../lib/fs/datablock_manager.cpp ../lib/fs/fs_data_types.cpp ../lib/fs/fs_resize.cpp + ../lib/fs/fs_read_write.cpp ../lib/fs/fs.cpp ../lib/fs/inode_manager.cpp ../lib/files.cpp @@ -41,6 +44,7 @@ add_executable(${TARGET_DIR_API} ../lib/fs/datablock_manager.cpp ../lib/fs/fs_data_types.cpp ../lib/fs/fs_resize.cpp + ../lib/fs/fs_read_write.cpp ../lib/fs/fs.cpp ../lib/fs/inode_manager.cpp dir_API.cpp diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index df41f7f..a1a3a87 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) { for (int j = 0; j < 3; j++) { fs->allocate_datablock(&inode_list[i], &temp_block_num); //assert(temp_block_num == rec_datablock_free[i][j]); - printf("%llu," ,itemp_block_num); + printf("%llu," ,temp_block_num); } printf("\n"); } diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 3275691..3b88561 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -27,7 +27,7 @@ void traverseDirHierarchy(const dir_test* dir, int depth); //global can be taken std::string target_filepath; dir_test* mock_root = nullptr; -RawDisk *H; +RawDisk *H; // Use FakeRawDisk here if memory sanitizer complains Fs *fs; FilesOperation *fsop; @@ -45,15 +45,11 @@ TEST(FileOperationTest, MkdirnodTest) { mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission //S_IRWXU(S_IRUSR | S_IWUSR | S_IXUSR) (owner), S_IRWXG(S_IRGRP | S_IWGRP | S_IXGRP) (group), S_IRWXO(S_IROTH | S_IWOTH | S_IXOTH) EXPECT_EQ(fsop->fischl_create("/test", mode, &fi), 0); - printf("point 1:"); - fsop->printDirectory(1); EXPECT_EQ(fsop->fischl_mkdir("/foo", mode), 0); - printf("point 2:"); - fsop->printDirectory(1); EXPECT_EQ(fsop->fischl_mkdir("/foo/bar", mode),0); - printf("point 3:"); fsop->printDirectory(1); EXPECT_EQ(fsop->fischl_create("/foo/bar/baz", mode, &fi), 0); + fsop->printDirectory(4); // the following three testcases will fail printf("Failing cases\n"); EXPECT_TRUE(fsop->fischl_mkdir("foo/bar", mode) < 0); @@ -74,11 +70,14 @@ TEST(FileOperationTest, WriteTest) { struct fuse_file_info fi; //file test + printf("point 0\n"); get_disk_inum = fsop->disk_namei("/test"); + printf("point 1\n"); fsop->fischl_open("/test", &fi); EXPECT_EQ(fi.fh, get_disk_inum); buffer[0] = '1'; fsop->fischl_write("/test", buffer, sizeof(buffer), 0, &fi); + printf("point 2\n"); //other file baz get_disk_inum = fsop->disk_namei("/foo/bar/baz"); buffer[0] = '4'; @@ -134,8 +133,8 @@ TEST(FileOperationTest, ReadTest) { get_file_inum = fsop->namei("/test"); inode.inode_num = get_file_inum; fs->inode_manager->load_inode(&inode); - fsop->read_datablock(inode, 0, read_buffer); - EXPECT_EQ(read_buffer[0], '1'); + //fsop->read_datablock(inode, 0, read_buffer); + //EXPECT_EQ(read_buffer[0], '1'); //read test file again with fischl_read API struct fuse_file_info fi; @@ -165,12 +164,14 @@ TEST(FileOperationTest, PressureTest) { mode_t mode;//set mode mode = S_IRWXU | S_IRWXG | S_IRWXO;//future should test permission EXPECT_EQ(fsop->fischl_mkdir("/pressure", mode), 0); + fsop->printDirectory(1); u_int64_t inode_numbers[700]; std::string prefix = "/pressure/No_"; for(int i=0;i<700;i++){ EXPECT_EQ(fsop->fischl_mkdir((prefix+std::to_string(i)).c_str(), mode), 0); } + fsop->printDirectory(6); for(int i=0;i<700;i++){ EXPECT_EQ(fsop->namei((prefix+std::to_string(i)).c_str()),fsop->disk_namei((prefix+std::to_string(i)).c_str())); } @@ -211,7 +212,7 @@ int main(int argc, char **argv) { const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; setupTestDirectory(&mock_root); - H = new FakeRawDisk(2048); + H = new FakeRawDisk(21504); fs = new Fs(H); fs->format(); fsop = new FilesOperation(*H, fs); @@ -299,7 +300,9 @@ dir_test* createDirHierarchy(int level, int maxLevel) { void setupTestDirectory(dir_test** root) { // Allocate memory for root *root = new dir_test; - (*root)->name = strdup("/"); // use / as begin + char* root_name = new char[2]; + strcpy(root_name, "/"); + (*root)->name = root_name; // use / as begin (*root)->inFile = nullptr; // Initialize file list to nullptr (*root)->subdir = createDirHierarchy(0, 1); (*root)->next = nullptr; From 76f5780854520046bc1d284055b59a7ed11dbddd Mon Sep 17 00:00:00 2001 From: FactorialN Date: Tue, 28 Nov 2023 15:44:56 -0800 Subject: [PATCH 44/63] added all callbacks for implementation --- lib/fischl.cpp | 55 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 9afcca9..2eef184 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -38,22 +38,57 @@ static int fischl_read(const char* path, char *buf, size_t size, off_t offset, s } static const struct fuse_operations fischl_oper = { - .init = fischl_init, - .getattr = fischl_getattr, - .readdir = fischl_readdir, - .open = fischl_open, - .mkdir = fischl_mkdir, - .read = fischl_read, + .init = fischl_init, + .destroy = fischl_destroy, + .getattr = fischl_getattr, + .fgetattr = fischl_fgetattr, + .access = fischl_access, + .readlink = fischl_readlink, + .readdir = fischl_readdir, + .mknod = fischl_mknod, + .mkdir = fischl_mkdir, + .symlink = fischl_symlink, + .unlink = fischl_unlink, + .rmdir = fischl_rmdir, + .rename = fischl_rename, + .link = fischl_link, + .chmod = fischl_chmod, + .chown = fischl_chown, + .truncate = fischl_truncate, + .ftruncate = fischl_ftruncate, + .utimens = fischl_utimens, + .create = fischl_create, + .open = fischl_open, + .read = fischl_read, + .write = fischl_write, + .statfs = fischl_statfs, + .release = fischl_release, + .opendir = fischl_opendir, + .releasedir = fischl_releasedir, + .fsync = fischl_fsync, + .flush = fischl_flush, + .fsyncdir = fischl_fsyncdir, + .lock = fischl_lock, + .bmap = fischl_bmap, + .ioctl = fischl_ioctl, + .poll = fischl_poll, +#ifdef HAVE_SETXATTR + .setxattr = fischl_setxattr, + .getxattr = fischl_getxattr, + .listxattr = fischl_listxattr, + .removexattr = fischl_removexattr, +#endif + .flag_nullpath_ok = 0, }; static void fischl::show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" - " --name= Name of the \"hello\" file\n" - " (default: \"hello\")\n" - " --contents= Contents \"hello\" file\n" - " (default \"Hello, World!\\n\")\n" + " --name= Name of the \"fischl\" file\n" + " (default: \"fischl\")\n" + " --contents= Contents \"fischl\" file\n" + " (default \"fischl, World!\\n\")\n" "\n"); } From a5dda54e12a1979c1ceb0a372f5a1b8dc8c3a713 Mon Sep 17 00:00:00 2001 From: Ziao <1575538687@qq.com> Date: Tue, 28 Nov 2023 16:19:56 -0800 Subject: [PATCH 45/63] add unlink test --- lib/files.cpp | 14 +++++---- test/layer2_API_dir.cpp | 64 ++++++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index b030d46..6a7e07b 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -60,16 +60,17 @@ void FilesOperation::initialize_rootinode() { } void FilesOperation::printDirectory(u_int64_t inode_number) { - // limit to first datablock INode_Data inode; inode.inode_num = inode_number; fs->inode_manager->load_inode(&inode); char buffer[IO_BLOCK_SIZE] = {0}; - fs->read(&inode, buffer, IO_BLOCK_SIZE, 0); - DirectoryEntry ent; - for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ - ent.deserialize(buffer+i); - if (ent.inode_number) printf("%s\t%llu;\t", ent.file_name, ent.inode_number); + for (u_int64_t idx=0; idxread(&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) printf("%s\t%llu;\t", ent.file_name, ent.inode_number); + } } printf("\n"); } @@ -298,6 +299,7 @@ void FilesOperation::unlink_inode(u_int64_t inode_number) { } // TODO: This is probably incorrect while(inode.metadata.size != 0) { + printf("dealloc, %d\n", inode.metadata.size); u_int64_t dummy; fs->deallocate_datablock(&inode, &dummy); inode.metadata.size-=IO_BLOCK_SIZE; diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 3b88561..6d465d3 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -30,6 +30,7 @@ dir_test* mock_root = nullptr; RawDisk *H; // Use FakeRawDisk here if memory sanitizer complains Fs *fs; FilesOperation *fsop; +std::string prefix = "/pressure/No_"; int total_dir_num = 0; int total_file_num = 0; @@ -62,7 +63,6 @@ TEST(FileOperationTest, MkdirnodTest) { TEST(FileOperationTest, WriteTest) { // write to files (TODO: fischl_write) - // read and write to indirect datablocks are not supported yet //get inode info from disk char buffer[IO_BLOCK_SIZE] = {0}; INode_Data inode; @@ -166,45 +166,43 @@ TEST(FileOperationTest, PressureTest) { EXPECT_EQ(fsop->fischl_mkdir("/pressure", mode), 0); fsop->printDirectory(1); - u_int64_t inode_numbers[700]; - std::string prefix = "/pressure/No_"; - for(int i=0;i<700;i++){ + for(int i=0;i<100;i++){ EXPECT_EQ(fsop->fischl_mkdir((prefix+std::to_string(i)).c_str(), mode), 0); } fsop->printDirectory(6); - for(int i=0;i<700;i++){ + for(int i=0;i<100;i++){ EXPECT_EQ(fsop->namei((prefix+std::to_string(i)).c_str()),fsop->disk_namei((prefix+std::to_string(i)).c_str())); } } -// TEST(FileOperationTest, UnlinkTest) { -// printf("=== Part 6: unlink test ===\n"); -// fsop.printDirectory(file_pressure); -// for(int i=0;i<700;i+=2){ -// assert(!fsop.fischl_unlink((prefix+std::to_string(i)).c_str())); -// } -// for(int i=0;i<4;i+=2){ -// assert(fsop.namei((prefix+std::to_string(i)).c_str())==(u_int64_t)(-1)); -// } -// for(int i=1;i<700;i+=2){ -// u_int64_t inode_number = fsop.namei((prefix+std::to_string(i)).c_str()); -// assert(inode_number == inode_numbers[i]); -// } -// fsop.printDirectory(file_pressure); -// std::string newprefix = "/pressure/New"; -// for(int i=0;i<700;i+=2){ -// inode_numbers[i] = fsop.fischl_mkdir((newprefix+std::to_string(i)).c_str(), 0); -// } -// for(int i=0;i<700;i+=2){ -// u_int64_t inode_number = fsop.namei((newprefix+std::to_string(i)).c_str()); -// assert(inode_number == inode_numbers[i]); -// } -// fsop.printDirectory(file_pressure); -// // long filename test -// std::string longfilename = std::string(255,'A'); -// u_int64_t filelong = fsop.fischl_mknod((std::string("/")+longfilename).c_str(),0); -// printf("/AAA...AAA is inode %llu, it is a file\n", filelong); -// } +TEST(FileOperationTest, UnlinkTest) { + ssize_t file_pressure = fsop->namei("/pressure"); + fsop->printDirectory(file_pressure); + for(int i=0;i<100;i+=2){ + EXPECT_EQ(fsop->fischl_unlink((prefix+std::to_string(i)).c_str()), 0); + } + for(int i=0;i<4;i+=2){ + EXPECT_EQ(fsop->namei((prefix+std::to_string(i)).c_str()), (u_int64_t)(-1)); + } + printf("Finished Deallocating\n"); + fsop->printDirectory(file_pressure); + std::string newprefix = "/pressure/New"; + for(int i=0;i<100;i+=2){ + EXPECT_EQ(fsop->fischl_mkdir((newprefix+std::to_string(i)).c_str(), 0), 0); + } + for(int i=0;i<100;i+=2){ + u_int64_t inode_number = fsop->namei((newprefix+std::to_string(i)).c_str()); + assert(inode_number>0); + } + printf("Finished Reallocating\n"); + fsop->printDirectory(file_pressure); + + // long filename test + std::string longfilename = std::string(255,'A'); + EXPECT_EQ(fsop->fischl_mknod((std::string("/")+longfilename).c_str(),0,0),0); + u_int64_t filelong = fsop->namei((std::string("/")+longfilename).c_str()); + printf("/AAA...AAA is inode %llu, it is a file\n", filelong); +} int main(int argc, char **argv) { From cae14cb52e660648e13cb12dd49cea57ad00125d Mon Sep 17 00:00:00 2001 From: FactorialN Date: Tue, 28 Nov 2023 16:47:46 -0800 Subject: [PATCH 46/63] did some basic callback structure --- lib/fischl.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 2eef184..c396782 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -12,21 +12,91 @@ void* fischl_init(struct fuse_conn_info *conn) { } +void fischl_create(const char *, mode_t, struct fuse_file_info *) { + +} + + +void fischl_destroy(void* private_data) { + +} + static int fischl_getattr(const char* path, struct stat* stbuf) { return 0; } +static int fischl_fgetattr(const char* path, struct stat* stbuf) { + + return 0; +} + +static int fischl_access(const char* path, mask) { + +} + +static int fischl_readlink(const char* path, char* buf, size_t size) { + +} + +static int fischl_opendir(const char* path, struct fuse_file_info* fi) { + +} + static int fischl_readdir(const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi) { return 0; } +static int fischl_mknod(const char* path, mode_t mode, dev_t rdev) { + +} + static int fischl_mkdir(const char *, mode_t) { return 0; } +static int fischl_unlink(const char* path) { + +} + +static int fischl_rmdir(const char* path) { + +} + +static int fischl_symlink(const char* to, const char* from) { + +} + +static int fischl_rename(const char* from, const char* to) { + +} + +static int fischl_link(const char* from, const char* to) { + +} + +static int fischl_chmod(const char* path, mode_t mode) { + +} + +static int fischl_chown(const char* path, uid_t uid, gid_t gid) { + +} + +static int fischl_truncate(const char* path, off_t size) { + +} + +static int fischl_ftruncate(const char* path, off_t size) { + +} + +static int fischl_utimens(const char* path, const struct timespec ts[2]) { + +} + static int fischl_open(const char *path, struct fuse_file_info *fi) { return 0; @@ -37,6 +107,35 @@ static int fischl_read(const char* path, char *buf, size_t size, off_t offset, s return 0; } +static int fischl_write(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) { + +} + +static int fischl_statfs(const char* path, struct statvfs* stbuf) { + +} + +static int fischl_release(const char* path, struct fuse_file_info *fi) { + +} + +static int fischl_releasedir(const char* path, struct fuse_file_info *fi) { + +} + +static int fischl_bmap(const char* path, size_t blocksize, uint64_t* blockno) { + +} + +static int fischl_ioctl(const char* path, int cmd, void* arg, struct fuse_file_info* fi, unsigned int flags, void* data) { + +} + +static int fischl_poll(const char* path, struct fuse_file_info* fi, struct fuse_pollhandle* ph, unsigned* reventsp){ + +} + + static const struct fuse_operations fischl_oper = { .init = fischl_init, .destroy = fischl_destroy, @@ -65,10 +164,6 @@ static const struct fuse_operations fischl_oper = { .release = fischl_release, .opendir = fischl_opendir, .releasedir = fischl_releasedir, - .fsync = fischl_fsync, - .flush = fischl_flush, - .fsyncdir = fischl_fsyncdir, - .lock = fischl_lock, .bmap = fischl_bmap, .ioctl = fischl_ioctl, .poll = fischl_poll, From 810854bcdd331f0d52a3a20ff7c657f913c1b491 Mon Sep 17 00:00:00 2001 From: FactorialN Date: Tue, 28 Nov 2023 17:34:51 -0800 Subject: [PATCH 47/63] did some basic syscall --- lib/fischl.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/fischl.cpp b/lib/fischl.cpp index c396782..fdf19ae 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -12,8 +12,8 @@ void* fischl_init(struct fuse_conn_info *conn) { } -void fischl_create(const char *, mode_t, struct fuse_file_info *) { - +int fischl_create(const char *path, mode_t mode, struct fuse_file_info *fi) { + return FilesOperation::fischl_create(path, mode, fi); } @@ -52,13 +52,12 @@ static int fischl_mknod(const char* path, mode_t mode, dev_t rdev) { } -static int fischl_mkdir(const char *, mode_t) { - - return 0; +static int fischl_mkdir(const char *path, mode_t mode) { + return FilesOperation::fischl_mkdir(path, mode); } static int fischl_unlink(const char* path) { - + return FilesOperation::fischl_unlink(path); } static int fischl_rmdir(const char* path) { @@ -98,17 +97,15 @@ static int fischl_utimens(const char* path, const struct timespec ts[2]) { } static int fischl_open(const char *path, struct fuse_file_info *fi) { - - return 0; + return FilesOperation::fischl_open(path, fi); } static int fischl_read(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) { - - return 0; + return FilesOperation::fischl_read(path, buf, size, offset, fi); } static int fischl_write(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) { - + return FilesOperation::fischl_write(path, buf, size, offset, fi); } static int fischl_statfs(const char* path, struct statvfs* stbuf) { @@ -116,7 +113,7 @@ static int fischl_statfs(const char* path, struct statvfs* stbuf) { } static int fischl_release(const char* path, struct fuse_file_info *fi) { - + return FilesOperation::fischl_release(path, fi); } static int fischl_releasedir(const char* path, struct fuse_file_info *fi) { From 269245f751f6cbfaa5d2241c0bbc256dd5836d9d Mon Sep 17 00:00:00 2001 From: FactorialN Date: Tue, 28 Nov 2023 22:26:09 -0800 Subject: [PATCH 48/63] made some minor modification --- lib/fischl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/fischl.cpp b/lib/fischl.cpp index fdf19ae..47a90e4 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -164,12 +164,14 @@ static const struct fuse_operations fischl_oper = { .bmap = fischl_bmap, .ioctl = fischl_ioctl, .poll = fischl_poll, +/* #ifdef HAVE_SETXATTR .setxattr = fischl_setxattr, .getxattr = fischl_getxattr, .listxattr = fischl_listxattr, .removexattr = fischl_removexattr, #endif +*/ .flag_nullpath_ok = 0, }; From 3f3a394001a98cf646f53c1b798245d00f953df3 Mon Sep 17 00:00:00 2001 From: FactorialN Date: Wed, 29 Nov 2023 00:40:43 -0800 Subject: [PATCH 49/63] made some minor modification --- lib/fischl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 47a90e4..956bd13 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "files.h" void* fischl_init(struct fuse_conn_info *conn) { @@ -31,7 +32,7 @@ static int fischl_fgetattr(const char* path, struct stat* stbuf) { return 0; } -static int fischl_access(const char* path, mask) { +static int fischl_access(const char* path, int mask) { } From 652d066c8dffd4a09a390a68e0d3316fec0058d1 Mon Sep 17 00:00:00 2001 From: FactorialN Date: Wed, 29 Nov 2023 17:38:30 -0800 Subject: [PATCH 50/63] made some minor modification to compilation --- CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 937a92a..0d05103 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,4 +27,15 @@ add_executable(fischl enable_testing() add_subdirectory(test) -add_subdirectory(googletest) \ No newline at end of file +add_subdirectory(googletest) + +# Add the -Wall flag +target_compile_options(fischl PRIVATE -Wall) + +# Use pkg-config to get flags for fuse3 +find_package(PkgConfig REQUIRED) +pkg_search_module(FUSE3 REQUIRED fuse3) + +# Add the flags from pkg-config for fuse3 +target_include_directories(fischl PRIVATE ${FUSE3_INCLUDE_DIRS}) +target_link_libraries(fischl PRIVATE ${FUSE3_LIBRARIES}) \ No newline at end of file From 8a5f50574ad3576ed5dabc4311bdcc4e956a2105 Mon Sep 17 00:00:00 2001 From: Cloud User Date: Thu, 30 Nov 2023 16:40:04 -0800 Subject: [PATCH 51/63] some medium dev state --- lib/fischl.cpp | 191 ++++++++++++++++++++++++++++---------------- lib/main.cpp | 7 +- test/CMakeLists.txt | 2 - 3 files changed, 128 insertions(+), 72 deletions(-) diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 956bd13..3e84bb1 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -2,19 +2,44 @@ #include #include -#include +#include #include #include #include #include +#include "fs.hpp" #include "files.h" -void* fischl_init(struct fuse_conn_info *conn) { +/* + * Command line options + * + * We can't set default values for the char* fields here because + * fuse_opt_parse would attempt to free() them when the user specifies + * different values on the command line. + */ +static struct options { + RawDisk *H; // Use FakeRawDisk here if memory sanitizer complains + Fs *fs; + FilesOperation *fsop; + int show_help; +} options; + +#define OPTION(t, p) \ + { t, offsetof(struct options, p), 1 } +static const struct fuse_opt option_spec[] = { + OPTION("-h", show_help), + OPTION("--help", show_help), + FUSE_OPT_END +}; + +void* fischl_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { + options.fsop->initialize_rootinode(); + perror("FUSE INITIALIZATION RUNNING"); } int fischl_create(const char *path, mode_t mode, struct fuse_file_info *fi) { - return FilesOperation::fischl_create(path, mode, fi); + return options.fsop->fischl_create(path, mode, fi); } @@ -22,150 +47,161 @@ void fischl_destroy(void* private_data) { } -static int fischl_getattr(const char* path, struct stat* stbuf) { +static int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { - return 0; -} + (void) fi; + int res = 0; + u_int64_t fh = options.fsop->namei(path); -static int fischl_fgetattr(const char* path, struct stat* stbuf) { + memset(stbuf, 0, sizeof(struct stat)); + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else if (fh != -1) { + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + // TO DO: make this the correct value + stbuf->st_size = 3; + } else + res = -ENOENT; - return 0; + return res; } static int fischl_access(const char* path, int mask) { -} + // return 0 when access is allowed + return 0; +} static int fischl_readlink(const char* path, char* buf, size_t size) { - + return -1; } static int fischl_opendir(const char* path, struct fuse_file_info* fi) { - + u_int64_t fh = options.fsop->namei(path); + fi->fh = fh; + return 0; } -static int fischl_readdir(const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi) { +static int fischl_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t ft, struct fuse_file_info *fi, enum fuse_readdir_flags) { + //check path + u_int64_t fh = options.fsop->namei(path); - return 0; + options.fsop->printDirectory(fh); + + char a[][6] = {".", "..", "a.txt"}; + + // Iterate through the directory entries and fill the buffer using 'filler' + for (size_t i = 0; i < 3; ++i) { + filler(buf, a[i], NULL, 0, FUSE_FILL_DIR_PLUS); + } + + return 0; } static int fischl_mknod(const char* path, mode_t mode, dev_t rdev) { - + return options.fsop->fischl_mknod(path, mode, rdev); } static int fischl_mkdir(const char *path, mode_t mode) { - return FilesOperation::fischl_mkdir(path, mode); + return options.fsop->fischl_mkdir(path, mode); } static int fischl_unlink(const char* path) { - return FilesOperation::fischl_unlink(path); + return options.fsop->fischl_unlink(path); } static int fischl_rmdir(const char* path) { - + return -1; } static int fischl_symlink(const char* to, const char* from) { - + return -1; } -static int fischl_rename(const char* from, const char* to) { - +static int fischl_rename(const char *path, const char *, unsigned int flags) { + return -1; } static int fischl_link(const char* from, const char* to) { - + return -1; } -static int fischl_chmod(const char* path, mode_t mode) { - +static int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi) { + return -1; } -static int fischl_chown(const char* path, uid_t uid, gid_t gid) { - +static int fischl_chown(const char *path, uid_t, gid_t, struct fuse_file_info *fi) { + return -1; } -static int fischl_truncate(const char* path, off_t size) { - +static int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi) { + return -1; } -static int fischl_ftruncate(const char* path, off_t size) { - -} - -static int fischl_utimens(const char* path, const struct timespec ts[2]) { - +static int fischl_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi) { + return -1; } static int fischl_open(const char *path, struct fuse_file_info *fi) { - return FilesOperation::fischl_open(path, fi); + return options.fsop->fischl_open(path, fi); } static int fischl_read(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) { - return FilesOperation::fischl_read(path, buf, size, offset, fi); + return options.fsop->fischl_read(path, buf, size, offset, fi); } -static int fischl_write(const char* path, char *buf, size_t size, off_t offset, struct fuse_file_info* fi) { - return FilesOperation::fischl_write(path, buf, size, offset, fi); +static int fischl_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { + return options.fsop->fischl_write(path, buf, size, offset, fi); } static int fischl_statfs(const char* path, struct statvfs* stbuf) { - + return -1; } static int fischl_release(const char* path, struct fuse_file_info *fi) { - return FilesOperation::fischl_release(path, fi); + return options.fsop->fischl_release(path, fi); } static int fischl_releasedir(const char* path, struct fuse_file_info *fi) { - + return -1; } static int fischl_bmap(const char* path, size_t blocksize, uint64_t* blockno) { - + return -1; } static int fischl_ioctl(const char* path, int cmd, void* arg, struct fuse_file_info* fi, unsigned int flags, void* data) { - + return -1; } static int fischl_poll(const char* path, struct fuse_file_info* fi, struct fuse_pollhandle* ph, unsigned* reventsp){ - + return -1; } static const struct fuse_operations fischl_oper = { - .init = fischl_init, - .destroy = fischl_destroy, + + .getattr = fischl_getattr, - .fgetattr = fischl_fgetattr, - .access = fischl_access, - .readlink = fischl_readlink, - .readdir = fischl_readdir, + //.readlink = fischl_readlink, .mknod = fischl_mknod, .mkdir = fischl_mkdir, - .symlink = fischl_symlink, .unlink = fischl_unlink, - .rmdir = fischl_rmdir, - .rename = fischl_rename, - .link = fischl_link, - .chmod = fischl_chmod, - .chown = fischl_chown, - .truncate = fischl_truncate, - .ftruncate = fischl_ftruncate, - .utimens = fischl_utimens, - .create = fischl_create, + //.rmdir = fischl_rmdir, + //.symlink = fischl_symlink, + //.rename = fischl_rename, + //.link = fischl_link, + //.chmod = fischl_chmod, + //.chown = fischl_chown, + //.truncate = fischl_truncate, .open = fischl_open, .read = fischl_read, .write = fischl_write, - .statfs = fischl_statfs, + //.statfs = fischl_statfs, .release = fischl_release, - .opendir = fischl_opendir, - .releasedir = fischl_releasedir, - .bmap = fischl_bmap, - .ioctl = fischl_ioctl, - .poll = fischl_poll, -/* + /* #ifdef HAVE_SETXATTR .setxattr = fischl_setxattr, .getxattr = fischl_getxattr, @@ -173,10 +209,20 @@ static const struct fuse_operations fischl_oper = { .removexattr = fischl_removexattr, #endif */ - .flag_nullpath_ok = 0, + .opendir = fischl_opendir, + .readdir = fischl_readdir, + //.releasedir = fischl_releasedir, + .init = fischl_init, + .destroy = fischl_destroy, + .access = fischl_access, + .create = fischl_create, + //.utimens = fischl_utimens, + //.bmap = fischl_bmap, + //.ioctl = fischl_ioctl, + //.poll = fischl_poll, }; -static void fischl::show_help(const char *progname) +static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" @@ -187,10 +233,19 @@ static void fischl::show_help(const char *progname) "\n"); } + int fischl(int argc, char *argv[]) { int ret; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + srand(time(NULL)); // Seed the random number generator + //const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; + + //setupTestDirectory(&options.root); + options.H = new FakeRawDisk(21504); + options.fs = new Fs(options.H); + options.fs->format(); + options.fsop = new FilesOperation(*options.H, options.fs); diff --git a/lib/main.cpp b/lib/main.cpp index 049c062..98bfe07 100644 --- a/lib/main.cpp +++ b/lib/main.cpp @@ -2,7 +2,7 @@ #include "fs.hpp" #include -int main() { +int main(int argc, char *argv[]) { // printf("hello word!"); // fischl *F = new fischl; // F->init(); @@ -34,6 +34,7 @@ int main() { // disk->print_block(1597); + /* int err; RawDisk *disk = new FakeRawDisk(2048); @@ -80,7 +81,9 @@ int main() { printf("\n\nREAD: %d\n", err); for (int i = 0; i < N; ++i) printf("%d ", buf2[i]); - printf("\n"); + printf("\n");*/ + + fischl(argc, argv); return 0; } \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 71919cf..6ec58ff 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,8 +16,6 @@ add_executable(${TARGET_LAYER0} add_executable(${TARGET_LAYER1_API} # add need lib and source code here layer1_API.cpp - - ../lib/fischl.cpp ../lib/rawdisk.cpp ../lib/fs/datablock_manager.cpp ../lib/fs/fs_data_types.cpp From 73b2142d178bac8747eb69b68bdd624dcfaabae2 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:13:56 -0800 Subject: [PATCH 52/63] this is a test commit for io debug --- include/files.h | 4 +- include/fuse_common.h | 82 ----------------------------------------- lib/files.cpp | 2 + test/CMakeLists.txt | 13 ++++++- test/layer2_API_dir.cpp | 2 + 5 files changed, 18 insertions(+), 85 deletions(-) delete mode 100644 include/fuse_common.h diff --git a/include/files.h b/include/files.h index 9035eec..53b70a3 100644 --- a/include/files.h +++ b/include/files.h @@ -1,6 +1,6 @@ #include #include -#include "fuse_common.h" +#include #include "direntry.h" class FilesOperation { @@ -23,7 +23,7 @@ class FilesOperation { int fischl_mkdir(const char*, mode_t); int fischl_mknod(const char*, mode_t, dev_t);//for special file int fischl_create(const char *, mode_t, struct fuse_file_info *);//for regular file - //int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); + int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); int fischl_unlink (const char *); int fischl_open (const char *, struct fuse_file_info *);//open file int fischl_release (const char *, struct fuse_file_info *);//close file diff --git a/include/fuse_common.h b/include/fuse_common.h deleted file mode 100644 index eef2f49..0000000 --- a/include/fuse_common.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef FUSE_COMMON_H_ -#define FUSE_COMMON_H_ - -#include -#include - -/** - * Information about an open file. - * - * File Handles are created by the open, opendir, and create methods and closed - * by the release and releasedir methods. Multiple file handles may be - * concurrently open for the same file. Generally, a client will create one - * file handle per file descriptor, though in some cases multiple file - * descriptors can share a single file handle. - */ -struct fuse_file_info { - /** Open flags. Available in open() and release() */ - int flags; - - /** In case of a write operation indicates if this was caused - by a delayed write from the page cache. If so, then the - context's pid, uid, and gid fields will not be valid, and - the *fh* value may not match the *fh* value that would - have been sent with the corresponding individual write - requests if write caching had been disabled. */ - unsigned int writepage : 1; - - /** Can be filled in by open/create, to use direct I/O on this file. */ - unsigned int direct_io : 1; - - /** Can be filled in by open and opendir. It signals the kernel that any - currently cached data (ie., data that the filesystem provided the - last time the file/directory was open) need not be invalidated when - the file/directory is closed. */ - unsigned int keep_cache : 1; - - /** Can be filled by open/create, to allow parallel direct writes on this - * file */ - unsigned int parallel_direct_writes : 1; - - /** Indicates a flush operation. Set in flush operation, also - maybe set in highlevel lock operation and lowlevel release - operation. */ - unsigned int flush : 1; - - /** Can be filled in by open, to indicate that the file is not - seekable. */ - unsigned int nonseekable : 1; - - /* Indicates that flock locks for this file should be - released. If set, lock_owner shall contain a valid value. - May only be set in ->release(). */ - unsigned int flock_release : 1; - - /** Can be filled in by opendir. It signals the kernel to - enable caching of entries returned by readdir(). Has no - effect when set in other contexts (in particular it does - nothing when set by open()). */ - unsigned int cache_readdir : 1; - - /** Can be filled in by open, to indicate that flush is not needed - on close. */ - unsigned int noflush : 1; - - /** Padding. Reserved for future use*/ - unsigned int padding : 23; - unsigned int padding2 : 32; - - /** File handle id. May be filled in by filesystem in create, - * open, and opendir(). Available in most other file operations on the - * same file handle. */ - uint64_t fh; - - /** Lock owner id. Available in locking operations and flush */ - uint64_t lock_owner; - - /** Requested poll events. Available in ->poll. Only set on kernels - which support it. If unsupported, this field is set to zero. */ - uint32_t poll_events; -}; - -#endif /* FUSE_COMMON_H_ */ diff --git a/lib/files.cpp b/lib/files.cpp index 6a7e07b..876da86 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -1,4 +1,6 @@ //#include "fuse.h" add this when layer3 +#define FUSE_USE_VERSION 31 + #include "files.h" #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ec58ff..1d2e61d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -51,7 +51,6 @@ add_executable(${TARGET_DIR_API} # Link Google Test to your test executables target_link_libraries(${TARGET_LAYER0} gtest gtest_main) target_link_libraries(${TARGET_LAYER1_API} gtest gtest_main) -target_link_libraries(${TARGET_LAYER2_API} gtest gtest_main) target_link_libraries(${TARGET_DIR_API} gtest gtest_main) # add test to activate ctest -VV @@ -59,3 +58,15 @@ add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE}) add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE}) add_test(NAME ${TARGET_LAYER2_API} COMMAND sudo ./${TARGET_LAYER2_API} ${DIR_PLACE}) add_test(NAME ${TARGET_DIR_API} COMMAND sudo ./${TARGET_DIR_API} ${DIR_PLACE}) + + +# Add the -Wall flag +target_compile_options(${TARGET_LAYER2_API} PRIVATE -Wall) + +# Use pkg-config to get flags for fuse3 +find_package(PkgConfig REQUIRED) +pkg_search_module(FUSE3 REQUIRED fuse3) + +# Add the flags from pkg-config for fuse3 +target_include_directories(${TARGET_LAYER2_API} PRIVATE ${FUSE3_INCLUDE_DIRS}) +target_link_libraries(${TARGET_LAYER2_API} PRIVATE ${FUSE3_LIBRARIES} gtest gtest_main) \ No newline at end of file diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 6d465d3..6e83f33 100644 --- a/test/layer2_API_dir.cpp +++ b/test/layer2_API_dir.cpp @@ -1,3 +1,5 @@ +#define FUSE_USE_VERSION 31 + #include #include #include From bcbd23003f0aa1b3b0ac76eb1502e82f93add390 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:36:26 -0800 Subject: [PATCH 53/63] a correct readdir --- include/files.h | 1 + lib/files.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/fischl.cpp | 35 +++-------------------------------- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/include/files.h b/include/files.h index 53b70a3..8cd467c 100644 --- a/include/files.h +++ b/include/files.h @@ -23,6 +23,7 @@ class FilesOperation { int fischl_mkdir(const char*, mode_t); int fischl_mknod(const char*, mode_t, dev_t);//for special file int fischl_create(const char *, mode_t, struct fuse_file_info *);//for regular file + int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi); int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); int fischl_unlink (const char *); int fischl_open (const char *, struct fuse_file_info *);//open file diff --git a/lib/files.cpp b/lib/files.cpp index 876da86..f73c058 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -283,6 +283,54 @@ int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_fil return 0;//SUCESS } +int FilesOperation::fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { + + (void) fi; + int res = 0; + u_int64_t fh = namei(path); + + memset(stbuf, 0, sizeof(struct stat)); + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else if (fh != -1) { + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + // TO DO: make this the correct value + stbuf->st_size = 3; + } else + res = -ENOENT; + + return res; +} + +int FilesOperation::fischl_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t ft, struct fuse_file_info *fi, enum fuse_readdir_flags flg) { + //check path + u_int64_t fh = namei(path); + + if (fh == -1){ + return -1; + } + + INode_Data inode; + inode.inode_num = fh; + fs->inode_manager->load_inode(&inode); + char buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idxread(&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) { + filler(buf, ent.file_name, NULL, 0, FUSE_FILL_DIR_PLUS); + //printf("%s\t%llu;\t", ent.file_name, ent.inode_number); + } + } + } + + return 0; +} + void FilesOperation::unlink_inode(u_int64_t inode_number) { INode_Data inode; inode.inode_num = inode_number; diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 3e84bb1..6e2d68c 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -48,24 +48,7 @@ void fischl_destroy(void* private_data) { } static int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { - - (void) fi; - int res = 0; - u_int64_t fh = options.fsop->namei(path); - - memset(stbuf, 0, sizeof(struct stat)); - if (strcmp(path, "/") == 0) { - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - } else if (fh != -1) { - stbuf->st_mode = S_IFREG | 0444; - stbuf->st_nlink = 1; - // TO DO: make this the correct value - stbuf->st_size = 3; - } else - res = -ENOENT; - - return res; + return options.fsop->fischl_getattr(path, stbuf, fi); } static int fischl_access(const char* path, int mask) { @@ -84,20 +67,8 @@ static int fischl_opendir(const char* path, struct fuse_file_info* fi) { return 0; } -static int fischl_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t ft, struct fuse_file_info *fi, enum fuse_readdir_flags) { - //check path - u_int64_t fh = options.fsop->namei(path); - - options.fsop->printDirectory(fh); - - char a[][6] = {".", "..", "a.txt"}; - - // Iterate through the directory entries and fill the buffer using 'filler' - for (size_t i = 0; i < 3; ++i) { - filler(buf, a[i], NULL, 0, FUSE_FILL_DIR_PLUS); - } - - return 0; +static int fischl_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t ft, struct fuse_file_info *fi, enum fuse_readdir_flags flg) { + return options.fsop->fischl_readdir(path, buf, filler, ft, fi, flg); } static int fischl_mknod(const char* path, mode_t mode, dev_t rdev) { From 3bb4f185b76806e6d469d778421d187d41cb3ce4 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:41:55 -0800 Subject: [PATCH 54/63] test commit with credential --- lib/files.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/files.cpp b/lib/files.cpp index f73c058..faffbef 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -288,6 +288,7 @@ int FilesOperation::fischl_getattr(const char *path, struct stat *stbuf, struct (void) fi; int res = 0; u_int64_t fh = namei(path); + fs->inode_manager->load_inode(&inode); memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { From 489997e11eca6166817bbc6140e321e6db82c4d8 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:57:02 -0800 Subject: [PATCH 55/63] some stable state --- include/files.h | 1 + lib/files.cpp | 46 +++++++++++++++++++++++++++++++--------------- lib/fischl.cpp | 2 +- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/include/files.h b/include/files.h index 8cd467c..5379139 100644 --- a/include/files.h +++ b/include/files.h @@ -25,6 +25,7 @@ class FilesOperation { int fischl_create(const char *, mode_t, struct fuse_file_info *);//for regular file int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi); int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); + int fischl_releasedir(const char* path, struct fuse_file_info *fi); int fischl_unlink (const char *); int fischl_open (const char *, struct fuse_file_info *);//open file int fischl_release (const char *, struct fuse_file_info *);//close file diff --git a/lib/files.cpp b/lib/files.cpp index faffbef..22536c0 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -288,20 +288,25 @@ int FilesOperation::fischl_getattr(const char *path, struct stat *stbuf, struct (void) fi; int res = 0; u_int64_t fh = namei(path); + + if (fh == -1){ + return -ENOENT; + } + + INode_Data inode; + inode.inode_num = fh; fs->inode_manager->load_inode(&inode); memset(stbuf, 0, sizeof(struct stat)); - if (strcmp(path, "/") == 0) { + if ((inode.metadata.permissions & S_IFMT) == S_IFDIR) { stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - } else if (fh != -1) { + stbuf->st_nlink = inode.metadata.reference_count; + } else { stbuf->st_mode = S_IFREG | 0444; - stbuf->st_nlink = 1; - // TO DO: make this the correct value - stbuf->st_size = 3; - } else - res = -ENOENT; - + stbuf->st_nlink = inode.metadata.reference_count; + stbuf->st_size = inode.metadata.size; + } + perror(std::to_string(inode.metadata.size).c_str()); return res; } @@ -332,6 +337,14 @@ int FilesOperation::fischl_readdir(const char *path, void *buf, fuse_fill_dir_t return 0; } +int FilesOperation::fischl_releasedir(const char *path, struct fuse_file_info *fi){ + if(fischl_find_entry(root_node, path) == NULL) + return -ENOENT; + //do with file descriptor that cannot be used + fi->fh = -1; + return 0;//SUCESS +} + void FilesOperation::unlink_inode(u_int64_t inode_number) { INode_Data inode; inode.inode_num = inode_number; @@ -459,10 +472,12 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, // Assuming inode is correctly initialized here based on 'path' inode.inode_num = fi->fh; fs->inode_manager->load_inode(&inode); - size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + //size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes - size_t bytes_write = 0; - size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index + char buffer[size]; + strcpy(buffer, buf); + size_t bytes_write = fs->write(&inode, buffer, size, offset); + /*size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block while (bytes_write < size) { char block_buffer[IO_BLOCK_SIZE]; // Temporary buffer for each block @@ -473,7 +488,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, bytes_write += copy_size; block_index++; block_offset = 0; // Only the first block might have a non-zero offset - } + }*/ fs->inode_manager->save_inode(&inode); return bytes_write; // Return the actual number of bytes read } @@ -494,7 +509,8 @@ int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t // Assuming inode is correctly initialized here based on 'path' inode.inode_num = fi->fh; fs->inode_manager->load_inode(&inode); - size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + size_t bytes_read = fs->read(&inode, buf, size, offset); + /*size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes if (offset >= len) return 0; // Offset is beyond the end of the file if (offset + size > len) size = len - offset; // Adjust size if it goes beyond EOF @@ -513,7 +529,7 @@ int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t bytes_read += copy_size; block_index++; block_offset = 0; // Only the first block might have a non-zero offset - } + }*/ return bytes_read; // Return the actual number of bytes read } \ No newline at end of file diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 6e2d68c..4ad6573 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -182,7 +182,7 @@ static const struct fuse_operations fischl_oper = { */ .opendir = fischl_opendir, .readdir = fischl_readdir, - //.releasedir = fischl_releasedir, + .releasedir = fischl_releasedir, .init = fischl_init, .destroy = fischl_destroy, .access = fischl_access, From 8ce7f295ce2e9b18195e30fcdd11c8632d4c6f81 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 00:34:29 -0800 Subject: [PATCH 56/63] fixed 2 bugs in unlink --- lib/files.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/files.cpp b/lib/files.cpp index 22536c0..f00e457 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -98,7 +98,7 @@ INode_Data* FilesOperation::create_new_inode(u_int64_t parent_inode_number, cons DirectoryEntry ent; for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ ent.deserialize(r_buffer+i); - if (strcmp(ent.file_name, name)==0) { + if (strcmp(ent.file_name, name)==0 && ent.inode_number != 0) { if((mode & S_IFMT) == S_IFDIR){ fprintf(stderr,"[%s ,%d] %s/ already exists\n",__func__,__LINE__, name); }else{ @@ -362,10 +362,15 @@ void FilesOperation::unlink_inode(u_int64_t inode_number) { } } // TODO: This is probably incorrect + // size is unsigned int while(inode.metadata.size != 0) { printf("dealloc, %d\n", inode.metadata.size); u_int64_t dummy; fs->deallocate_datablock(&inode, &dummy); + if (inode.metadata.size < IO_BLOCK_SIZE){ + inode.metadata.size = 0; + break; + } inode.metadata.size-=IO_BLOCK_SIZE; } fs->inode_manager->free_inode(&inode); @@ -403,6 +408,7 @@ int FilesOperation::fischl_unlink(const char* path) { if (strcmp(ent.file_name, filename)==0) { target_inode = ent.inode_number; ent.inode_number = 0; + memset(ent.file_name, 0, sizeof(ent.file_name)); ent.serialize(rw_buffer+i); break; } From c06287dd4da199851bce3e27e68999002385d9e0 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 03:32:32 -0800 Subject: [PATCH 57/63] current state: trying to fix a weird offset error --- include/files.h | 3 ++ lib/files.cpp | 95 ++++++++++++++++++++++++++++++++++++++++ lib/fischl.cpp | 18 ++++---- lib/fs/fs_read_write.cpp | 17 ++++--- lib/rawdisk.cpp | 2 + 5 files changed, 121 insertions(+), 14 deletions(-) diff --git a/include/files.h b/include/files.h index 5379139..95206b8 100644 --- a/include/files.h +++ b/include/files.h @@ -27,6 +27,9 @@ class FilesOperation { int fischl_readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); int fischl_releasedir(const char* path, struct fuse_file_info *fi); int fischl_unlink (const char *); + int fischl_rmdir(const char *); + int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi); + int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi); int fischl_open (const char *, struct fuse_file_info *);//open file int fischl_release (const char *, struct fuse_file_info *);//close file int fischl_write(const char *, const char *, size_t, off_t, struct fuse_file_info *); diff --git a/lib/files.cpp b/lib/files.cpp index f00e457..032955c 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -376,6 +376,99 @@ void FilesOperation::unlink_inode(u_int64_t inode_number) { fs->inode_manager->free_inode(&inode); } +int FilesOperation::fischl_rmdir(const char* path) { + char *pathdup = strdup(path); + char *lastSlash = strrchr(pathdup, '/'); + *lastSlash = '\0'; + char *dirname = lastSlash+1; + char *ParentPath = pathdup; + if (!strcmp(dirname,".")||!strcmp(dirname,"..")) { + printf("refusing to remove . or ..\n"); + return -1; + } + FileNode *parent_filenode = fischl_find_entry(root_node, ParentPath); + if (parent_filenode == NULL) { + printf("parent %s not found by fischl_find_entry\n", ParentPath); + free(pathdup); + return -1; + } + u_int64_t parent_inode_number = parent_filenode->inode_number; + u_int64_t target_inode = 0; + + // remove its record from parent + INode_Data parent_INode; + parent_INode.inode_num = parent_inode_number; + fs->inode_manager->load_inode(&parent_INode); + char rw_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idxread(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ + ent.deserialize(rw_buffer+i); + if (strcmp(ent.file_name, dirname)==0) { + target_inode = ent.inode_number; + ent.inode_number = 0; + memset(ent.file_name, 0, sizeof(ent.file_name)); + ent.serialize(rw_buffer+i); + break; + } + } + if (target_inode) { + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + break; + } + } + + // remove inode itself + if (target_inode) { + unlink_inode(target_inode); + // remove node itself and from parent hash + fischl_rm_entry(parent_filenode->subdirectory, dirname); + free(pathdup); + return 0; + } else { + printf("cannot find %s in %s", dirname, ParentPath); + free(pathdup); + return -1; + } +} + +int FilesOperation::fischl_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) { + (void) fi; + int res = 0; + u_int64_t fh = namei(path); + + if (fh == -1){ + return -ENOENT; + } + + INode_Data inode; + inode.inode_num = fh; + fs->inode_manager->load_inode(&inode); + inode.metadata.permissions = mode; + fs->inode_manager->save_inode(&inode); + return 0; +} + +int FilesOperation::fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi) { + (void) fi; + int res = 0; + u_int64_t fh = namei(path); + + if (fh == -1){ + return -ENOENT; + } + + INode_Data inode; + inode.inode_num = fh; + fs->inode_manager->load_inode(&inode); + inode.metadata.uid = uid; + inode.metadata.gid = gid; + fs->inode_manager->save_inode(&inode); + return 0; +} + + int FilesOperation::fischl_unlink(const char* path) { char *pathdup = strdup(path); char *lastSlash = strrchr(pathdup, '/'); @@ -482,6 +575,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, char buffer[size]; strcpy(buffer, buf); + printf("received offset %d\n", offset); size_t bytes_write = fs->write(&inode, buffer, size, offset); /*size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block @@ -496,6 +590,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, block_offset = 0; // Only the first block might have a non-zero offset }*/ fs->inode_manager->save_inode(&inode); + printf("received offset %llu\n", inode.metadata.size); return bytes_write; // Return the actual number of bytes read } diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 4ad6573..40dc8bc 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -84,7 +84,7 @@ static int fischl_unlink(const char* path) { } static int fischl_rmdir(const char* path) { - return -1; + return options.fsop->fischl_rmdir(path); } static int fischl_symlink(const char* to, const char* from) { @@ -99,12 +99,12 @@ static int fischl_link(const char* from, const char* to) { return -1; } -static int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi) { - return -1; +static int fischl_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) { + return options.fsop->fischl_chmod(path, mode, fi); } -static int fischl_chown(const char *path, uid_t, gid_t, struct fuse_file_info *fi) { - return -1; +static int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi) { + return options.fsop->fischl_chown(path, uid, gid, fi); } static int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi) { @@ -136,7 +136,7 @@ static int fischl_release(const char* path, struct fuse_file_info *fi) { } static int fischl_releasedir(const char* path, struct fuse_file_info *fi) { - return -1; + return options.fsop->fischl_releasedir(path, fi); } static int fischl_bmap(const char* path, size_t blocksize, uint64_t* blockno) { @@ -160,12 +160,12 @@ static const struct fuse_operations fischl_oper = { .mknod = fischl_mknod, .mkdir = fischl_mkdir, .unlink = fischl_unlink, - //.rmdir = fischl_rmdir, + .rmdir = fischl_rmdir, //.symlink = fischl_symlink, //.rename = fischl_rename, //.link = fischl_link, - //.chmod = fischl_chmod, - //.chown = fischl_chown, + .chmod = fischl_chmod, + .chown = fischl_chown, //.truncate = fischl_truncate, .open = fischl_open, .read = fischl_read, diff --git a/lib/fs/fs_read_write.cpp b/lib/fs/fs_read_write.cpp index 1aabf8a..1dda70a 100644 --- a/lib/fs/fs_read_write.cpp +++ b/lib/fs/fs_read_write.cpp @@ -61,13 +61,16 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, int err; int result = -1; + printf("SURVIVED 1\n"); if (allocate && (*block_num) == 0) if ((err = datablock_manager->new_datablock(block_num)) < 0) return err; - + + printf("SURVIVED 2 %d\n", indirect_num); if (indirect_num == 0) return op->operation(*block_num); + printf("SURVIVED 3\n"); if ((*block_num) == 0) { memset(buf, 0, sizeof(buf)); } else { @@ -101,11 +104,11 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, if (result == 0) break; } - + printf("SURVIVED 4 %llu %d %llu\n", *block_num, result, this_layer_start_index); if (modified) if ((err = disk->write_block(*block_num, buf)) < 0) return err; - + printf("SURVIVED 5 %d\n", result); return result; } @@ -201,12 +204,16 @@ ssize_t Fs::write(INode_Data *inode_data, char buf[], size_t count, op.bytes_completed = 0; op.disk = disk; + printf("trying to write %d %llu %llu\n", op.count, offset, start_block_index); + if ((err = sweep_inode_datablocks(inode_data, start_block_index, true, &op)) < 0) return err; - inode_data->metadata.size = - std::max(offset + op.bytes_completed, inode_data->metadata.size); + inode_data->metadata.size = offset + op.bytes_completed; + //std::max(offset + op.bytes_completed, inode_data->metadata.size); + + printf("written %d\n", op.bytes_completed); return op.bytes_completed; } \ No newline at end of file diff --git a/lib/rawdisk.cpp b/lib/rawdisk.cpp index c0ed0ab..fb1e5f2 100644 --- a/lib/rawdisk.cpp +++ b/lib/rawdisk.cpp @@ -123,6 +123,8 @@ int FakeRawDisk::read_block(u_int64_t block_number, char *buffer) { int FakeRawDisk::write_block(u_int64_t block_number, char *buffer) { u_int64_t offset = block_number * IO_BLOCK_SIZE; + printf("fake disk write: %llu %llu %llu\n", block_number, offset, diskSize); + if (offset + IO_BLOCK_SIZE > diskSize) { perror("Error writing past fake disk size"); return -1; From c2f3aa1310f74d6d4b6273405dc0aa01c4a55e99 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:59:06 -0800 Subject: [PATCH 58/63] fixed fuse offset issue, but still haven't fixed the problem with written file length --- lib/files.cpp | 7 ++----- lib/fischl.cpp | 4 ++-- lib/fs/fs_read_write.cpp | 5 ----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 032955c..7147b76 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -567,15 +567,13 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, // return -ENOENT; // Caution! this based on content in file are multiple of IO_BLOCK_SIZE, not the exact write size. // based on current write_datablock API implement, when write_datablock pass with actual size not index this function should be fixed + INode_Data inode; // Assuming inode is correctly initialized here based on 'path' inode.inode_num = fi->fh; fs->inode_manager->load_inode(&inode); //size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes - - char buffer[size]; - strcpy(buffer, buf); - printf("received offset %d\n", offset); + char *buffer = strdup(buf); size_t bytes_write = fs->write(&inode, buffer, size, offset); /*size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block @@ -590,7 +588,6 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, block_offset = 0; // Only the first block might have a non-zero offset }*/ fs->inode_manager->save_inode(&inode); - printf("received offset %llu\n", inode.metadata.size); return bytes_write; // Return the actual number of bytes read } diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 40dc8bc..3bc3b6e 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -124,7 +124,7 @@ static int fischl_read(const char* path, char *buf, size_t size, off_t offset, s } static int fischl_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { - return options.fsop->fischl_write(path, buf, size, offset, fi); + return options.fsop->fischl_write(path, buf, size, offset, fi); } static int fischl_statfs(const char* path, struct statvfs* stbuf) { @@ -213,7 +213,7 @@ int fischl(int argc, char *argv[]) //const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; //setupTestDirectory(&options.root); - options.H = new FakeRawDisk(21504); + options.H = new FakeRawDisk(23552); options.fs = new Fs(options.H); options.fs->format(); options.fsop = new FilesOperation(*options.H, options.fs); diff --git a/lib/fs/fs_read_write.cpp b/lib/fs/fs_read_write.cpp index 1dda70a..3ffccff 100644 --- a/lib/fs/fs_read_write.cpp +++ b/lib/fs/fs_read_write.cpp @@ -61,16 +61,13 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, int err; int result = -1; - printf("SURVIVED 1\n"); if (allocate && (*block_num) == 0) if ((err = datablock_manager->new_datablock(block_num)) < 0) return err; - printf("SURVIVED 2 %d\n", indirect_num); if (indirect_num == 0) return op->operation(*block_num); - printf("SURVIVED 3\n"); if ((*block_num) == 0) { memset(buf, 0, sizeof(buf)); } else { @@ -104,11 +101,9 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, if (result == 0) break; } - printf("SURVIVED 4 %llu %d %llu\n", *block_num, result, this_layer_start_index); if (modified) if ((err = disk->write_block(*block_num, buf)) < 0) return err; - printf("SURVIVED 5 %d\n", result); return result; } From c768bed015d537aa9379e5899012dc038545b98e Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:57:29 -0800 Subject: [PATCH 59/63] fixed an issue with writing --- include/files.h | 1 + lib/files.cpp | 27 +++++++++++++++++++++++++++ lib/fischl.cpp | 6 +++--- lib/fs/fs_read_write.cpp | 4 ++-- lib/rawdisk.cpp | 2 -- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/files.h b/include/files.h index 95206b8..b07b88b 100644 --- a/include/files.h +++ b/include/files.h @@ -28,6 +28,7 @@ class FilesOperation { int fischl_releasedir(const char* path, struct fuse_file_info *fi); int fischl_unlink (const char *); int fischl_rmdir(const char *); + int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi); int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi); int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi); int fischl_open (const char *, struct fuse_file_info *);//open file diff --git a/lib/files.cpp b/lib/files.cpp index 7147b76..9f8ca84 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -591,6 +591,33 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, return bytes_write; // Return the actual number of bytes read } +int FilesOperation::fischl_truncate(const char *path, off_t offset, struct fuse_file_info *fi){ + (void) fi; + int res = 0; + u_int64_t fh = namei(path); + + if (fh == -1){ + return -ENOENT; + } + + INode_Data inode; + inode.inode_num = fh; + fs->inode_manager->load_inode(&inode); + while(inode.metadata.size > offset + IO_BLOCK_SIZE) { + printf("dealloc, %d\n", inode.metadata.size); + u_int64_t dummy; + fs->deallocate_datablock(&inode, &dummy); + if (inode.metadata.size < IO_BLOCK_SIZE){ + inode.metadata.size = 0; + break; + } + inode.metadata.size-=IO_BLOCK_SIZE; + } + inode.metadata.size = offset; + fs->inode_manager->save_inode(&inode); + return 0; +} + int FilesOperation::fischl_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi){ /** Read data from an open file * diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 3bc3b6e..22745a5 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -107,8 +107,8 @@ static int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file return options.fsop->fischl_chown(path, uid, gid, fi); } -static int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi) { - return -1; +static int fischl_truncate(const char *path, off_t offset, struct fuse_file_info *fi) { + return options.fsop->fischl_truncate(path, offset, fi); } static int fischl_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi) { @@ -166,7 +166,7 @@ static const struct fuse_operations fischl_oper = { //.link = fischl_link, .chmod = fischl_chmod, .chown = fischl_chown, - //.truncate = fischl_truncate, + .truncate = fischl_truncate, .open = fischl_open, .read = fischl_read, .write = fischl_write, diff --git a/lib/fs/fs_read_write.cpp b/lib/fs/fs_read_write.cpp index 3ffccff..4fc1d16 100644 --- a/lib/fs/fs_read_write.cpp +++ b/lib/fs/fs_read_write.cpp @@ -205,8 +205,8 @@ ssize_t Fs::write(INode_Data *inode_data, char buf[], size_t count, 0) return err; - inode_data->metadata.size = offset + op.bytes_completed; - //std::max(offset + op.bytes_completed, inode_data->metadata.size); + inode_data->metadata.size = + std::max(offset + op.bytes_completed, inode_data->metadata.size); printf("written %d\n", op.bytes_completed); diff --git a/lib/rawdisk.cpp b/lib/rawdisk.cpp index fb1e5f2..c0ed0ab 100644 --- a/lib/rawdisk.cpp +++ b/lib/rawdisk.cpp @@ -123,8 +123,6 @@ int FakeRawDisk::read_block(u_int64_t block_number, char *buffer) { int FakeRawDisk::write_block(u_int64_t block_number, char *buffer) { u_int64_t offset = block_number * IO_BLOCK_SIZE; - printf("fake disk write: %llu %llu %llu\n", block_number, offset, diskSize); - if (offset + IO_BLOCK_SIZE > diskSize) { perror("Error writing past fake disk size"); return -1; From fa5312283489ddac85c3e390ef961af674bcbce7 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:52:14 -0800 Subject: [PATCH 60/63] fixed an issue when reading and writing binary files --- lib/files.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/files.cpp b/lib/files.cpp index 9f8ca84..4805094 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -573,7 +573,10 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, inode.inode_num = fi->fh; fs->inode_manager->load_inode(&inode); //size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes - char *buffer = strdup(buf); + // Determine the length of the buffer + // Allocate memory for the new buffer + char* buffer = (char*)malloc(size); + memcpy(buffer, buf, size); size_t bytes_write = fs->write(&inode, buffer, size, offset); /*size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index size_t block_offset = offset % IO_BLOCK_SIZE; // Offset within the first block @@ -588,6 +591,7 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, block_offset = 0; // Only the first block might have a non-zero offset }*/ fs->inode_manager->save_inode(&inode); + free(buffer); return bytes_write; // Return the actual number of bytes read } From 9bd1825b6c1817437f563c02f3f28d14c1b73a79 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 16:09:55 -0800 Subject: [PATCH 61/63] partially implemented rename, renaming dir and failure pending --- include/files.h | 2 + lib/files.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++++++- lib/fischl.cpp | 20 +------ 3 files changed, 154 insertions(+), 18 deletions(-) diff --git a/include/files.h b/include/files.h index b07b88b..5eeb57a 100644 --- a/include/files.h +++ b/include/files.h @@ -17,6 +17,7 @@ class FilesOperation { void printbuffer(const char*,int); void printDirectory(u_int64_t); INode_Data* create_new_inode(u_int64_t parent_inode_number, const char* name, mode_t mode); + int insert_inode_to(u_int64_t parent_inode_number, const char* name, INode_Data *new_inode); void unlink_inode(u_int64_t inode_number); u_int64_t disk_namei(const char* path); u_int64_t namei(const char* path); @@ -28,6 +29,7 @@ class FilesOperation { int fischl_releasedir(const char* path, struct fuse_file_info *fi); int fischl_unlink (const char *); int fischl_rmdir(const char *); + int fischl_rename(const char *path, const char *, unsigned int flags); int fischl_truncate(const char *path, off_t, struct fuse_file_info *fi); int fischl_chmod(const char *path, mode_t, struct fuse_file_info *fi); int fischl_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi); diff --git a/lib/files.cpp b/lib/files.cpp index 4805094..81ab478 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -329,7 +329,7 @@ int FilesOperation::fischl_readdir(const char *path, void *buf, fuse_fill_dir_t ent.deserialize(buffer+i); if (ent.inode_number) { filler(buf, ent.file_name, NULL, 0, FUSE_FILL_DIR_PLUS); - //printf("%s\t%llu;\t", ent.file_name, ent.inode_number); + printf("%s\t%llu;\t", ent.file_name, ent.inode_number); } } } @@ -595,6 +595,154 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, return bytes_write; // Return the actual number of bytes read } +int FilesOperation::insert_inode_to(u_int64_t parent_inode_number, const char* name, INode_Data *new_inode) { + // trys to create a file under parent directory + if (strlen(name)>=256) { + perror("Name too long, cannot create file or directory"); + return -1; + } + INode_Data inode; + inode.inode_num = parent_inode_number; + fs->inode_manager->load_inode(&inode); + if ((inode.metadata.permissions & S_IFMT) != S_IFDIR) { + fprintf(stderr,"[%s ,%d] please create under directory\n",__func__,__LINE__); + return -1; + } + + // Check if file or directory already exists + char r_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idxread(&inode, r_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ + ent.deserialize(r_buffer+i); + if (strcmp(ent.file_name, name)==0 && ent.inode_number != 0) { + if((new_inode->metadata.permissions & S_IFMT) == S_IFDIR){ + fprintf(stderr,"[%s ,%d] %s/ already exists\n",__func__,__LINE__, name); + }else{ + fprintf(stderr,"[%s ,%d] %s already exists\n",__func__,__LINE__, name); + } + return -1; + } + } + } + + bool allocated = false; + + char rw_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idxread(&inode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ + ent.deserialize(rw_buffer+i); + if (ent.inode_number == 0) { + allocated = true; + ent.inode_number = new_inode->inode_num; + strcpy(ent.file_name, name); + ent.serialize(rw_buffer+i); + break; + } + } + if (allocated) { + fs->write(&inode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + break; + } + } + + if (!allocated) { + char write_buffer[IO_BLOCK_SIZE] = {0}; + DirectoryEntry ent; + ent.inode_number = new_inode->inode_num; + strcpy(ent.file_name, name); + ent.serialize(write_buffer); + fs->write(&inode, write_buffer, IO_BLOCK_SIZE, (inode.metadata.size/IO_BLOCK_SIZE)*IO_BLOCK_SIZE); + fs->inode_manager->save_inode(&inode); + } + + return 0; +} + +int FilesOperation::fischl_rename(const char *path, const char *new_name, unsigned int flags){ + char *pathdup = strdup(path); + char *lastSlash = strrchr(pathdup, '/'); + *lastSlash = '\0'; + char *filename = lastSlash+1; + char *ParentPath = pathdup; + if (!strcmp(filename,".")||!strcmp(filename,"..")) { + printf("refusing to remove . or ..\n"); + return -1; + } + FileNode *parent_filenode = fischl_find_entry(root_node, ParentPath); + if (parent_filenode == NULL) { + printf("parent %s not found by fischl_find_entry\n", ParentPath); + free(pathdup); + return -1; + } + u_int64_t parent_inode_number = parent_filenode->inode_number; + u_int64_t target_inode = 0; + + // remove its record from parent + INode_Data parent_INode; + parent_INode.inode_num = parent_inode_number; + fs->inode_manager->load_inode(&parent_INode); + char rw_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx=0; idxread(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ + ent.deserialize(rw_buffer+i); + if (strcmp(ent.file_name, filename)==0) { + target_inode = ent.inode_number; + ent.inode_number = 0; + memset(ent.file_name, 0, sizeof(ent.file_name)); + ent.serialize(rw_buffer+i); + break; + } + } + if (target_inode) { + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + break; + } + } + + // remove inode itself + if (target_inode) { + INode_Data ret; + ret.inode_num = target_inode; + fs->inode_manager->load_inode(&ret); + fischl_rm_entry(parent_filenode->subdirectory, filename); + + printf("FOUND INODE AT %llu %s\n", target_inode, new_name); + char *pathdup2 = strdup(new_name); + char *lastSlash2 = strrchr(pathdup2, '/'); + *lastSlash2 = '\0'; // Split the string into parent path and new directory name; \0 + char *newDirname2 = lastSlash2+1; //\0, get from + char *ParentPath2 = pathdup2;//pathdup are separated by pathdup, so it take only + + FileNode *parent_filenode2 = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath2): root_node->self_info; + if (parent_filenode2 == NULL) { + fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath2); + free(pathdup2); + return -ENOENT;//parentpath directory does not exist + } + u_int64_t parent_inode_number = parent_filenode->inode_number; + //printf("%s, %llu, %s\n", parent_filenode->name, parent_inode_number, newDirname); + //make new inode + if(insert_inode_to(parent_inode_number, newDirname2, &ret)<0){ + return -1; + } + fischl_add_entry(parent_filenode->subdirectory, ret.inode_num, newDirname2, &ret); + free(pathdup); + // remove node itself and from parent hash + free(pathdup2); + return 0; + } else { + printf("cannot find %s in %s", filename, ParentPath); + free(pathdup); + return -1; + } +} + int FilesOperation::fischl_truncate(const char *path, off_t offset, struct fuse_file_info *fi){ (void) fi; int res = 0; diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 22745a5..433faa7 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -34,8 +34,6 @@ static const struct fuse_opt option_spec[] = { void* fischl_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { options.fsop->initialize_rootinode(); - perror("FUSE INITIALIZATION RUNNING"); - } int fischl_create(const char *path, mode_t mode, struct fuse_file_info *fi) { @@ -91,8 +89,8 @@ static int fischl_symlink(const char* to, const char* from) { return -1; } -static int fischl_rename(const char *path, const char *, unsigned int flags) { - return -1; +static int fischl_rename(const char *path, const char *new_name, unsigned int flags) { + return options.fsop->fischl_rename(path, new_name, flags); } static int fischl_link(const char* from, const char* to) { @@ -139,18 +137,6 @@ static int fischl_releasedir(const char* path, struct fuse_file_info *fi) { return options.fsop->fischl_releasedir(path, fi); } -static int fischl_bmap(const char* path, size_t blocksize, uint64_t* blockno) { - return -1; -} - -static int fischl_ioctl(const char* path, int cmd, void* arg, struct fuse_file_info* fi, unsigned int flags, void* data) { - return -1; -} - -static int fischl_poll(const char* path, struct fuse_file_info* fi, struct fuse_pollhandle* ph, unsigned* reventsp){ - return -1; -} - static const struct fuse_operations fischl_oper = { @@ -162,7 +148,7 @@ static const struct fuse_operations fischl_oper = { .unlink = fischl_unlink, .rmdir = fischl_rmdir, //.symlink = fischl_symlink, - //.rename = fischl_rename, + .rename = fischl_rename, //.link = fischl_link, .chmod = fischl_chmod, .chown = fischl_chown, From f1cfc5022e69378f89fa94df6c2f11448b11d927 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:25:34 -0800 Subject: [PATCH 62/63] minor adjustment --- lib/files.cpp | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/files.cpp b/lib/files.cpp index 81ab478..05a9f0b 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -301,9 +301,13 @@ int FilesOperation::fischl_getattr(const char *path, struct stat *stbuf, struct if ((inode.metadata.permissions & S_IFMT) == S_IFDIR) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = inode.metadata.reference_count; + stbuf->st_uid = inode.metadata.uid; + stbuf->st_gid = inode.metadata.gid; } else { stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = inode.metadata.reference_count; + stbuf->st_uid = inode.metadata.uid; + stbuf->st_gid = inode.metadata.gid; stbuf->st_size = inode.metadata.size; } perror(std::to_string(inode.metadata.size).c_str()); @@ -662,6 +666,8 @@ int FilesOperation::insert_inode_to(u_int64_t parent_inode_number, const char* n return 0; } + +// TODO: rename dir and rename fail int FilesOperation::fischl_rename(const char *path, const char *new_name, unsigned int flags){ char *pathdup = strdup(path); char *lastSlash = strrchr(pathdup, '/'); @@ -693,14 +699,10 @@ int FilesOperation::fischl_rename(const char *path, const char *new_name, unsign ent.deserialize(rw_buffer+i); if (strcmp(ent.file_name, filename)==0) { target_inode = ent.inode_number; - ent.inode_number = 0; - memset(ent.file_name, 0, sizeof(ent.file_name)); - ent.serialize(rw_buffer+i); break; } } - if (target_inode) { - fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + if (target_inode){ break; } } @@ -710,7 +712,14 @@ int FilesOperation::fischl_rename(const char *path, const char *new_name, unsign INode_Data ret; ret.inode_num = target_inode; fs->inode_manager->load_inode(&ret); - fischl_rm_entry(parent_filenode->subdirectory, filename); + + if (flags == RENAME_EXCHANGE){ + printf("RENAME_EXCHANGE "); + } + else if (flags == RENAME_NOREPLACE){ + printf("RENAME_NOREPLACE "); + } + else printf("ELSE "); printf("FOUND INODE AT %llu %s\n", target_inode, new_name); char *pathdup2 = strdup(new_name); @@ -725,13 +734,34 @@ int FilesOperation::fischl_rename(const char *path, const char *new_name, unsign free(pathdup2); return -ENOENT;//parentpath directory does not exist } - u_int64_t parent_inode_number = parent_filenode->inode_number; + u_int64_t parent_inode_number2 = parent_filenode2->inode_number; //printf("%s, %llu, %s\n", parent_filenode->name, parent_inode_number, newDirname); //make new inode - if(insert_inode_to(parent_inode_number, newDirname2, &ret)<0){ + if(insert_inode_to(parent_inode_number2, newDirname2, &ret)<0){ return -1; } - fischl_add_entry(parent_filenode->subdirectory, ret.inode_num, newDirname2, &ret); + + for (u_int64_t idx=0; idxread(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + DirectoryEntry ent; + for(int i=0;i<=IO_BLOCK_SIZE-264;i+=264){ + ent.deserialize(rw_buffer+i); + if (strcmp(ent.file_name, filename)==0) { + target_inode = ent.inode_number; + ent.inode_number = 0; + memset(ent.file_name, 0, sizeof(ent.file_name)); + ent.serialize(rw_buffer+i); + break; + } + } + if (target_inode) { + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + break; + } + } + + fischl_rm_entry(parent_filenode->subdirectory, filename); + fischl_add_entry(parent_filenode2->subdirectory, ret.inode_num, newDirname2, &ret); free(pathdup); // remove node itself and from parent hash free(pathdup2); From de198df6d1f1fab56ff4e1ef45991fe7f625a1c5 Mon Sep 17 00:00:00 2001 From: FactorialN <8838579+FactorialN@users.noreply.github.com> Date: Fri, 1 Dec 2023 19:04:00 -0800 Subject: [PATCH 63/63] fixed a bug of indirect layers --- include/fs_constants.hpp | 1 + lib/files.cpp | 2 +- lib/fs/fs_read_write.cpp | 22 ++++++++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/fs_constants.hpp b/include/fs_constants.hpp index 8353020..19b9857 100644 --- a/include/fs_constants.hpp +++ b/include/fs_constants.hpp @@ -12,6 +12,7 @@ #include #define IO_BLOCK_SIZE 4096 +#define INDIRECT_BLOCKS 512 #define NUM_INODE_BLOCKS 1023 #define NUM_BLOCKS 2048 diff --git a/lib/files.cpp b/lib/files.cpp index 05a9f0b..2ba6ee5 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -333,7 +333,7 @@ int FilesOperation::fischl_readdir(const char *path, void *buf, fuse_fill_dir_t ent.deserialize(buffer+i); if (ent.inode_number) { filler(buf, ent.file_name, NULL, 0, FUSE_FILL_DIR_PLUS); - printf("%s\t%llu;\t", ent.file_name, ent.inode_number); + //printf("%s\t%llu;\t", ent.file_name, ent.inode_number); } } } diff --git a/lib/fs/fs_read_write.cpp b/lib/fs/fs_read_write.cpp index 4fc1d16..f8a874f 100644 --- a/lib/fs/fs_read_write.cpp +++ b/lib/fs/fs_read_write.cpp @@ -15,6 +15,8 @@ int Fs::sweep_inode_datablocks(INode_Data *inode_data, DatablockOperation *op) { int result; + printf("%llu %llu %llu\n", NUMBER_OF_DIRECT_BLOCKS, INDIRECT_BLOCKS, INDIRECT_BLOCKS * INDIRECT_BLOCKS); + u_int64_t start_index = start_block_index; for (size_t i = start_index; i < NUMBER_OF_DIRECT_BLOCKS; ++i) { if ((result = sweep_datablocks(&(inode_data->direct_blocks[i]), 0, 0, @@ -25,25 +27,25 @@ int Fs::sweep_inode_datablocks(INode_Data *inode_data, start_index -= NUMBER_OF_DIRECT_BLOCKS; - if (start_index < IO_BLOCK_SIZE) { + if (start_index < INDIRECT_BLOCKS) { if ((result = sweep_datablocks(&(inode_data->single_indirect_block), 1, start_index, allocate, op)) <= 0) return result; - start_index = IO_BLOCK_SIZE; + start_index = INDIRECT_BLOCKS; } - start_index -= IO_BLOCK_SIZE; + start_index -= INDIRECT_BLOCKS; - if (start_index < IO_BLOCK_SIZE * IO_BLOCK_SIZE) { + if (start_index < INDIRECT_BLOCKS * INDIRECT_BLOCKS) { if ((result = sweep_datablocks(&(inode_data->double_indirect_block), 2, start_index, allocate, op)) <= 0) return result; - start_index = IO_BLOCK_SIZE * IO_BLOCK_SIZE; + start_index = INDIRECT_BLOCKS * INDIRECT_BLOCKS; } - start_index -= IO_BLOCK_SIZE * IO_BLOCK_SIZE; + start_index -= INDIRECT_BLOCKS * INDIRECT_BLOCKS; - if (start_index < (u_int64_t)IO_BLOCK_SIZE * IO_BLOCK_SIZE * IO_BLOCK_SIZE) { + if (start_index < (u_int64_t)INDIRECT_BLOCKS * INDIRECT_BLOCKS * INDIRECT_BLOCKS) { if ((result = sweep_datablocks(&(inode_data->triple_indirect_block), 3, start_index, allocate, op)) <= 0) return result; @@ -61,6 +63,8 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, int err; int result = -1; + //printf("SWEEP %llu %d %llu %d\n", *block_num, indirect_num, start_block_index, int(allocate)); + if (allocate && (*block_num) == 0) if ((err = datablock_manager->new_datablock(block_num)) < 0) return err; @@ -74,10 +78,11 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, if ((err = disk->read_block(*block_num, buf)) < 0) return err; } + u_int64_t indirect_block_size = 1; for (int i = 1; i < indirect_num; ++i) - indirect_block_size *= IO_BLOCK_SIZE; + indirect_block_size *= INDIRECT_BLOCKS; u_int64_t this_layer_start_index = start_block_index / indirect_block_size; u_int64_t next_layer_start_index = @@ -86,6 +91,7 @@ int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, u_int64_t temp; u_int64_t next_block_num; bool modified = false; + //printf("SWEEP TO LOWER LEVEL %llu %llu %llu\n", this_layer_start_index, next_layer_start_index, indirect_block_size); for (size_t i = this_layer_start_index * sizeof(u_int64_t); i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {