diff --git a/.DS_Store b/.DS_Store index 4c4a626..07b8666 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/CMakeLists.txt b/CMakeLists.txt index 937a92a..0ecb1d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14) include_directories( # fischl include files ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include + # ${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include ) add_executable(fischl @@ -16,8 +16,7 @@ add_executable(fischl lib/rawdisk.cpp 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_file_io.cpp lib/fs/fs.cpp lib/fs/inode_manager.cpp lib/files.cpp @@ -27,4 +26,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 diff --git a/README.md b/README.md index 43d625f..3d24def 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,29 @@ cmake .. make # cmake --build . is same ``` +## mount and test +normal usage: +```bash +./fischl diskpath n -s mountpoint +``` +diskpath must be provided following ./fischl +l/n must be provided following diskpath indicating whether to load the exisiting file system or create a new one. +for loading: +```bash +./fischl diskpath l -s mountpoint +``` +-s is also required because our fs doesn't support multi-threading. + +if the diskpath need to be accessed by root: +```bash +sudo ./fischl diskpath n -o allow_other -s mountpoint +``` + +for debugging: +```bash +sudo ./fischl diskpath n -o allow_other -d -s mountpoint +``` + ## run test ### add your own test file on test/CMakeList.txt ``` diff --git a/include/direntry.h b/include/direntry.h index 7177f0e..a4c6cbb 100644 --- a/include/direntry.h +++ b/include/direntry.h @@ -19,18 +19,48 @@ typedef struct treeNode { FileNode *self_info; //self fileNode infromation } TreeNode; + +typedef struct RenameInfo { + FileNode *oldFileNode; // The file node being renamed. + FileNode *oldParentNode; // The parent directory of the file node being renamed. + FileNode *newParentNode; // The target parent directory where the file node will be moved. + char *newName; // The new name of the file node after the rename. + FileNode *newFileNode; // The new file node, if one already exists at the target location. + bool exchangeExist; // Flag to indicate if the rename should replace an existing file node. +} RenameInfo; + /*for root*/ 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*/ +FileNode* fischl_add_entry_for_cache(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *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 //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); +FileNode *fischl_find_entry(Fs *fs, 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 +TreeNode *find_parentPath(TreeNode *root, const char *path); + +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); + } +}; diff --git a/include/files.h b/include/files.h index 9035eec..64c7101 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 { @@ -8,25 +8,44 @@ class FilesOperation { Fs *fs; void create_dot_dotdot(INode_Data*, u_int64_t); - public: +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); void initialize_rootinode(); + void initialize(bool load); void printbuffer(const char*,int); void printDirectory(u_int64_t); + bool permission_check(int, INode_Data*); + bool permission_check_by_inode_num(int, 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, bool check_replace); void unlink_inode(u_int64_t inode_number); 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, dev_t);//for special file + int fischl_access(const char* path, int mask); 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_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_opendir(const char* path, struct fuse_file_info* fi); + int fischl_rmdir(const char *); + int fischl_readlink(const char* path, char* buf, size_t size); + int fischl_symlink(const char* from, const char* to); + int fischl_link(const char* from, const char* to); + 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); 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 + int fischl_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi); + int fischl_statfs(const char* path, struct statvfs* stbuf); + FileNode *fischl_load_entry(TreeNode *root, const char *path); +}; diff --git a/include/fischl.h b/include/fischl.h index 94113c2..d620bc6 100644 --- a/include/fischl.h +++ b/include/fischl.h @@ -1,7 +1,3 @@ -class fischl{ - // declare - public: - int init(); -}; \ No newline at end of file +int fischl(int argc, char *argv[]); diff --git a/include/fs.hpp b/include/fs.hpp index 7a0cd7f..3a420aa 100644 --- a/include/fs.hpp +++ b/include/fs.hpp @@ -15,20 +15,12 @@ public: Fs(RawDisk *disk); ~Fs(); - int allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num); - int deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num); - ssize_t read(INode_Data *inode_data, char buf[], size_t count, size_t offset); - ssize_t write(INode_Data *inode_data, char buf[], size_t count, + ssize_t write(INode_Data *inode_data, const char buf[], size_t count, size_t offset); - - int sweep_inode_datablocks(INode_Data *inode_data, - u_int64_t start_block_index, bool allocate, - DatablockOperation *op); - - int sweep_datablocks(u_int64_t *block_num, int indirect_num, - u_int64_t start_block_index, bool allocate, - DatablockOperation *op); + int truncate(INode_Data *inode_data, size_t length); + ssize_t lseek_next_data(INode_Data *inode_data, size_t offset); + ssize_t lseek_next_hole(INode_Data *inode_data, size_t offset); int format(); @@ -44,8 +36,13 @@ public: int save_free_list_head(u_int64_t new_free_list_head); int save_inode_list_head(u_int64_t new_inode_list_head); - int allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num); - int deallocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num); + int sweep_inode_datablocks(INode_Data *inode_data, + u_int64_t start_block_index, bool allocate, + DatablockOperation *op); + + int sweep_datablocks(u_int64_t *block_num, int indirect_num, + u_int64_t start_block_index, bool allocate, + DatablockOperation *op); }; #endif \ No newline at end of file diff --git a/include/fs/fs_data_types.hpp b/include/fs/fs_data_types.hpp index 134db85..9242c0c 100644 --- a/include/fs/fs_data_types.hpp +++ b/include/fs/fs_data_types.hpp @@ -25,12 +25,14 @@ public: u_int64_t inode_num; #define NUMBER_OF_METADATA_BYTES \ - (4 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t))) + (6 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t))) struct INode_MetaData { u_int64_t uid; u_int64_t gid; u_int64_t permissions; u_int64_t size; // not yet implemented + u_int64_t access_time; + u_int64_t modification_time; u_int32_t reference_count; u_int32_t flags; } metadata; diff --git a/include/fs_constants.hpp b/include/fs_constants.hpp index 8353020..fb3a53c 100644 --- a/include/fs_constants.hpp +++ b/include/fs_constants.hpp @@ -12,9 +12,9 @@ #include #define IO_BLOCK_SIZE 4096 +#define INDIRECT_BLOCKS 512 #define NUM_INODE_BLOCKS 1023 -#define NUM_BLOCKS 2048 #define INODE_SIZE 512 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/direntry.cpp b/lib/direntry.cpp index 2366dde..3b765b0 100644 --- a/lib/direntry.cpp +++ b/lib/direntry.cpp @@ -156,6 +156,26 @@ TreeNode *fischl_init_entry(int new_inode_number, const char *fileName, INode_Da return newDir; } +FileNode* fischl_add_entry_for_cache(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->metadata.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->metadata.permissions; + newFile->inode_number = new_inode_number; + //Diretory have its own file information, that is . here + if(newDir != NULL) + newDir->self_info = newFile; + return newFile; +} + int fischl_add_entry(TreeNode *parent, int new_inode_number, const char *fileName, INode_Data *new_inode){ char *Name = strdup(fileName); TreeNode *newDir = NULL; @@ -191,13 +211,15 @@ int fischl_rm_entry(TreeNode *parent, const char *fileName) { } -FileNode *fischl_find_entry(TreeNode *root, const char *path){ +FileNode *fischl_find_entry(Fs *fs, TreeNode *root, const char *path){ //support . and .. function char *pathCopy = strdup(path); char *segment = strtok(pathCopy, "/"); TreeNode *current = root; FileNode *file = NULL; + printf("FINDING %s %s %llu\n", path, segment, current->self_info->inode_number); + while (segment != NULL && current != NULL) { if (strcmp(segment, "..") == 0) { // Move up to the parent directory @@ -214,8 +236,29 @@ FileNode *fischl_find_entry(TreeNode *root, const char *path){ } else{ file = lookupHash(current->contents, segment); + if (file == NULL) { + // find on disk whether this exists + INode_Data inode; + inode.inode_num = current->self_info->inode_number; + 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); + //printf("WARNING:%d %llu %llu %s %s\n",__LINE__,inode.inode_num, ent.inode_number, ent.file_name, segment); + if (ent.inode_number && strcmp(ent.file_name, segment)==0) { + file = fischl_add_entry_for_cache(current, ent.inode_number, ent.file_name, &inode); + //printf("DONE !! %llu\n", file->inode_number); + break; + } + } + } + } if (file != NULL && file->subdirectory == NULL) { free(pathCopy); + printf("FOUND !! %llu\n", file->inode_number); return file; //File found //return current; return filenode } diff --git a/lib/files.cpp b/lib/files.cpp index 6a7e07b..7fb34b5 100644 --- a/lib/files.cpp +++ b/lib/files.cpp @@ -1,57 +1,45 @@ //#include "fuse.h" add this when layer3 +#define FUSE_USE_VERSION 31 + #include "files.h" -#include -#include #include +#include +#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); - } -}; - -void FilesOperation::printbuffer(const char* buff, int len) { - for(int i=0;ifs = fs; +void FilesOperation::printbuffer(const char *buff, int len) { + for (int i = 0; i < len; i++) { + printf("%x ", buff[i]); + } + printf("\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->inode_num; - strcpy(dot.file_name, "."); - dot.serialize(buffer); - DirectoryEntry dotdot; - dotdot.inode_number = parent_inode_number; - strcpy(dotdot.file_name, ".."); - dotdot.serialize(buffer+264); - int ret = fs->write(inode, buffer, IO_BLOCK_SIZE, 0); - //printf("in create_dot_dotdot: fs->write returned %d\n",ret); +FilesOperation::FilesOperation(RawDisk &disk_, Fs *fs) : disk(disk_) { + this->fs = fs; +} + +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->inode_num; + strcpy(dot.file_name, "."); + dot.serialize(buffer); + DirectoryEntry dotdot; + dotdot.inode_number = parent_inode_number; + strcpy(dotdot.file_name, ".."); + dotdot.serialize(buffer + 264); + 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() { // this method must be called explicitly right after initializion INode_Data *root_inode = new INode_Data(); - fs->inode_manager->new_inode(0, 0, S_IFDIR, root_inode); + fs->inode_manager->new_inode(getuid(), getgid(), S_IFDIR|0755, root_inode); u_int64_t root_inode_number = root_inode->inode_num; create_dot_dotdot(root_inode, root_inode_number); root_node = fischl_init_entry(root_inode_number, "/", root_inode); @@ -59,165 +47,272 @@ void FilesOperation::initialize_rootinode() { fs->inode_manager->save_inode(root_inode); } -void FilesOperation::printDirectory(u_int64_t inode_number) { - INode_Data inode; - inode.inode_num = inode_number; - fs->inode_manager->load_inode(&inode); - char buffer[IO_BLOCK_SIZE] = {0}; - for (u_int64_t idx=0; 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); - } +void FilesOperation::initialize(bool load) { + if (load){ + INode_Data *root_inode = new INode_Data(); + root_inode->inode_num = 1; + fs->inode_manager->load_inode(root_inode); + root_node = fischl_init_entry(1, "/", root_inode); + assert(root_node->self_info!=NULL); + fs->load_superblock(); + } + else{ + initialize_rootinode(); } - printf("\n"); } -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_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 NULL; +void FilesOperation::printDirectory(u_int64_t inode_number) { + INode_Data inode; + inode.inode_num = inode_number; + fs->inode_manager->load_inode(&inode); + char buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) { + fs->read(&inode, buffer, IO_BLOCK_SIZE, idx * IO_BLOCK_SIZE); + DirectoryEntry ent; + for (int i = 0; i <= IO_BLOCK_SIZE - 264; i += 264) { + ent.deserialize(buffer + i); + if (ent.inode_number) + printf("%s\t%llu;\t", ent.file_name, ent.inode_number); } + } + printf("\n"); +} - // 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) { - 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; - } +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_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 NULL; + } + + // Check if file or directory already exists + char r_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) { + fs->read(&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 ((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; + } } + } bool allocated = false; INode_Data *new_inode = new INode_Data(); - fs->inode_manager->new_inode(0, 0, mode, new_inode); + fs->inode_manager->new_inode(getuid(), getgid(), mode, new_inode); + //printf("%llu\n",new_inode->inode_num); 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); - 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; + char rw_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) { + fs->read(&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(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); + ent.serialize(rw_buffer + i); + break; + } } + if (allocated) { + fs->write(&inode, rw_buffer, IO_BLOCK_SIZE, idx * IO_BLOCK_SIZE); + break; + } + } - return new_inode; + 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 new_inode; } -u_int64_t FilesOperation::disk_namei(const char* path) { - // returns the inode number corresponding to path - 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("disk_namei: path should start with /\n"); - return -1; - } - while (std::getline(pathStream, new_name, '/')) { - 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; +u_int64_t FilesOperation::disk_namei(const char *path) { + // returns the inode number corresponding to path + 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("disk_namei: path should start with /\n"); + return -1; + } + while (std::getline(pathStream, new_name, '/')) { + 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; 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 (strcmp(ent.file_name, new_name.c_str()) == 0) { - new_inode_number = ent.inode_number; - break; - } - } - if (new_inode_number) break; + char buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) { + fs->read(&inode, buffer, IO_BLOCK_SIZE, idx * IO_BLOCK_SIZE); + DirectoryEntry ent; + for (int i = 0; i <= IO_BLOCK_SIZE - 264; i += 264) { + ent.deserialize(buffer + i); + if (strcmp(ent.file_name, new_name.c_str()) == 0) { + new_inode_number = ent.inode_number; + break; } - if (!new_inode_number) { - printf("disk_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_number (root_node->self_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 + } + if (new_inode_number) + break; + } + if (!new_inode_number) { + printf("disk_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_number + // (root_node->self_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); + FileNode* filenode = fischl_load_entry(root_node, path); if (filenode) return filenode->inode_number; else return -1; } -int FilesOperation::fischl_mkdir(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 *newDirname = lastSlash+1; //\0, get from - char *ParentPath = pathdup;//pathdup are separated by pathdup, so it take only +bool FilesOperation::permission_check(int mask, INode_Data *inode) { + mode_t per = (mode_t)inode->metadata.permissions; + uid_t uid = (uid_t)inode->metadata.uid; + gid_t gid = (gid_t)inode->metadata.gid; + //printf("PERMISSION CHECK %d %llu %llu %o\n", mask, uid, gid, per); + if(getuid() == uid){ + if ((mask & R_OK) && !(per & S_IRUSR)) { + return false; // Permission denied for reading + } - FileNode *parent_filenode = strlen(ParentPath)? fischl_find_entry(root_node, ParentPath): root_node->self_info; + if ((mask & W_OK) && !(per & S_IWUSR)) { + return false; // Permission denied for writing + } + + if ((mask & X_OK) && !(per & S_IXUSR)) { + return false; // Permission denied for executing + } + return true; + } + else if(getgid() == gid){ + if ((mask & R_OK) && !(per & S_IRGRP)) { + return false; // Permission denied for reading + } + + if ((mask & W_OK) && !(per & S_IWGRP)) { + return false; // Permission denied for writing + } + + if ((mask & X_OK) && !(per & S_IXGRP)) { + return false; // Permission denied for executing + } + return true; + } + else{ + if ((mask & R_OK) && !(per & S_IROTH)) { + return false; // Permission denied for reading + } + + if ((mask & W_OK) && !(per & S_IWOTH)) { + return false; // Permission denied for writing + } + + if ((mask & X_OK) && !(per & S_IXOTH)) { + return false; // Permission denied for executing + } + return true; + } +} + +bool FilesOperation::permission_check_by_inode_num(int mask, u_int64_t inode_num) { + INode_Data inode; + inode.inode_num = inode_num; + + fs->inode_manager->load_inode(&inode); + if(!permission_check(mask, &inode)){ + return false; + } + return true; +} + +int FilesOperation::fischl_access(const char* path, int mask) { + + u_int64_t fh = namei(path); + + if (fh == -1){ + return -ENOENT; + } + + if(!permission_check_by_inode_num(mask, fh)){ + return -EACCES; + } + // return 0 when access is allowed + return 0; +} + +int FilesOperation::fischl_mkdir(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 *newDirname = + lastSlash + 1; //\0, get from + char *ParentPath = pathdup; // pathdup are separated by pathdup, so it take + // only + + FileNode *parent_filenode = strlen(ParentPath)? fischl_load_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); free(pathdup); return -ENOENT;//parentpath directory does not exist } u_int64_t parent_inode_number = parent_filenode->inode_number; + if(!permission_check_by_inode_num(W_OK, parent_inode_number)){ + return -EACCES; + } + //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 @@ -237,13 +332,16 @@ int FilesOperation::fischl_mknod(const char* path, mode_t mode, dev_t dev) { 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; + FileNode *parent_filenode = strlen(ParentPath)? fischl_load_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); free(pathdup); return -1; } u_int64_t parent_inode_number = parent_filenode->inode_number; + if(!permission_check_by_inode_num(W_OK, parent_inode_number)){ + return -EACCES; + } //make new inode INode_Data* ret = create_new_inode(parent_inode_number, newFilename, mode); if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST @@ -263,13 +361,16 @@ int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_fil 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; + FileNode *parent_filenode = strlen(ParentPath)? fischl_load_entry(root_node, ParentPath): root_node->self_info; if (parent_filenode == NULL) { fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); free(pathdup); return -1; } u_int64_t parent_inode_number = parent_filenode->inode_number; + if(!permission_check_by_inode_num(W_OK, parent_inode_number)){ + return -EACCES; + } //make new inode INode_Data* ret = create_new_inode(parent_inode_number, newFilename, mode); if (ret == NULL) return -1;//ENOSPC but create_new_inode handle ENAMETOOLONG EEXIST @@ -281,45 +382,156 @@ int FilesOperation::fischl_create(const char* path, mode_t mode, struct fuse_fil return 0;//SUCESS } -void FilesOperation::unlink_inode(u_int64_t inode_number) { +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); + + if (fh == -1) { + return -ENOENT; + } + + INode_Data inode; + inode.inode_num = fh; + fs->inode_manager->load_inode(&inode); + + //printf("GETATTR PERM %o\n", (mode_t)inode.metadata.permissions); + + //memset(stbuf, 0, sizeof(struct stat)); + if ((inode.metadata.permissions & S_IFMT) == S_IFDIR) { + stbuf->st_mode = (mode_t)inode.metadata.permissions;//S_IFDIR | 0755; + stbuf->st_nlink = 2;//inode.metadata.reference_count; + stbuf->st_uid = inode.metadata.uid; + stbuf->st_gid = inode.metadata.gid; + stbuf->st_atime = (time_t)(inode.metadata.access_time / 1000000000ULL); + stbuf->st_mtime = (time_t)(inode.metadata.modification_time / 1000000000ULL); + stbuf->st_size = IO_BLOCK_SIZE; + stbuf->st_ino = inode.inode_num; + } else if(S_ISLNK(inode.metadata.permissions)){ + stbuf->st_mode = (mode_t)inode.metadata.permissions; + stbuf->st_nlink = 1;//inode.metadata.reference_count; + stbuf->st_uid = inode.metadata.uid; + stbuf->st_gid = inode.metadata.gid; + stbuf->st_atime = (time_t)(inode.metadata.access_time / 1000000000ULL); + stbuf->st_mtime = (time_t)(inode.metadata.modification_time / 1000000000ULL); + stbuf->st_size = inode.metadata.size; + stbuf->st_ino = inode.inode_num; + } else { + stbuf->st_mode = (mode_t)inode.metadata.permissions; + stbuf->st_nlink = inode.metadata.reference_count; + stbuf->st_uid = inode.metadata.uid; + stbuf->st_gid = inode.metadata.gid; + stbuf->st_atime = (time_t)(inode.metadata.access_time / 1000000000ULL); + stbuf->st_mtime = (time_t)(inode.metadata.modification_time / 1000000000ULL); + stbuf->st_size = inode.metadata.size; + stbuf->st_ino = inode.inode_num; + } + //perror(std::to_string(inode.inode_num).c_str()); + 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 = inode_number; + inode.inode_num = fh; 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,"..")){ - unlink_inode(ent.inode_number); - } + if(!permission_check(R_OK, &inode)){ + return -EACCES; + } + 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\n", ent.file_name, ent.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; - } - fs->inode_manager->free_inode(&inode); + + return 0; } -int FilesOperation::fischl_unlink(const char* path) { +int FilesOperation::fischl_releasedir(const char *path, struct fuse_file_info *fi){ + if(fischl_load_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; + fs->inode_manager->load_inode(&inode); + if (inode.metadata.reference_count > 1 && (inode.metadata.permissions & S_IFMT) != S_IFDIR){ + inode.metadata.reference_count -= 1; + fs->inode_manager->save_inode(&inode); + return; + } + if ((inode.metadata.permissions & S_IFMT) == S_IFDIR) { + char buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) { + fs->read(&inode, buffer, IO_BLOCK_SIZE, idx * IO_BLOCK_SIZE); + DirectoryEntry ent; + for (int i = 0; i <= IO_BLOCK_SIZE - 264; i += 264) { + if (ent.inode_number && strcmp(ent.file_name, ".") && + strcmp(ent.file_name, "..")) { + unlink_inode(ent.inode_number); + } + } + } + } + // TODO: error handling + int res = fs->truncate(&inode, 0); + fs->inode_manager->free_inode(&inode); +} + +int FilesOperation::fischl_opendir(const char* path, struct fuse_file_info* fi) { + + u_int64_t fh = namei(path); + + if (fh == -1){ + return -ENOENT; + } + + INode_Data inode; + inode.inode_num = fh; + + fs->inode_manager->load_inode(&inode); + if(!permission_check(X_OK|R_OK, &inode)){ + return -EACCES; + } + fi->fh = fh; + return 0; +} + +int FilesOperation::fischl_rmdir(const char* path) { char *pathdup = strdup(path); char *lastSlash = strrchr(pathdup, '/'); *lastSlash = '\0'; - char *filename = lastSlash+1; + char *dirname = lastSlash+1; char *ParentPath = pathdup; - if (!strcmp(filename,".")||!strcmp(filename,"..")) { + if (!strcmp(dirname,".")||!strcmp(dirname,"..")) { printf("refusing to remove . or ..\n"); return -1; } - FileNode *parent_filenode = fischl_find_entry(root_node, ParentPath); + FileNode *parent_filenode = fischl_load_entry(root_node, ParentPath); if (parent_filenode == NULL) { - printf("parent %s not found by fischl_find_entry\n", ParentPath); + printf("parent %s not found by fischl_load_entry\n", ParentPath); free(pathdup); return -1; } @@ -330,6 +542,108 @@ int FilesOperation::fischl_unlink(const char* path) { INode_Data parent_INode; parent_INode.inode_num = parent_inode_number; fs->inode_manager->load_inode(&parent_INode); + if(!permission_check(W_OK, &parent_INode)){ + return -EACCES; + } + 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, '/'); + *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_load_entry(root_node, ParentPath); + if (parent_filenode == NULL) { + printf("parent %s not found by fischl_load_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); + if(!permission_check(W_OK, &parent_INode)){ + return -EACCES; + } 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); @@ -338,7 +652,11 @@ int FilesOperation::fischl_unlink(const char* path) { ent.deserialize(rw_buffer+i); if (strcmp(ent.file_name, filename)==0) { target_inode = ent.inode_number; + if(!permission_check_by_inode_num(W_OK, target_inode)){ + return -EACCES; + } ent.inode_number = 0; + memset(ent.file_name, 0, sizeof(ent.file_name)); ent.serialize(rw_buffer+i); break; } @@ -368,8 +686,30 @@ int FilesOperation::fischl_open(const char *path, struct fuse_file_info *fi){ if no files will use create function */ FileNode *get_file; - if((get_file = fischl_find_entry(root_node, path)) == NULL) + if((get_file = fischl_load_entry(root_node, path)) == NULL) return -ENOENT; + + INode_Data inode; + inode.inode_num = get_file->inode_number; + + fs->inode_manager->load_inode(&inode); + + if (fi->flags & O_WRONLY){ + if (!permission_check(W_OK, &inode)) { + return -EACCES; // Permission denied + } + } + if (fi->flags & O_RDONLY){ + if (!permission_check(R_OK, &inode)) { + return -EACCES; // Permission denied + } + } + if (fi->flags & O_RDWR){ + if (!permission_check(R_OK|W_OK, &inode)) { + return -EACCES; // Permission denied + } + } + //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; @@ -381,7 +721,7 @@ int FilesOperation::fischl_release(const char *path, struct fuse_file_info *fi){ if no files will use create function */ FileNode *get_file; - if((get_file = fischl_find_entry(root_node, path)) == NULL) + if((get_file = fischl_load_entry(root_node, path)) == NULL) return -ENOENT; //do with file descriptor that cannot be used fi->fh = -1; @@ -400,18 +740,22 @@ int FilesOperation::fischl_write(const char *path, const char *buf, size_t size, */ // use path for debug, filedescriptor is enough // FileNode *get_file; - // if((get_file = fischl_find_entry(root_node, path)) == NULL) + // if((get_file = fischl_load_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_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 - - size_t bytes_write = 0; - size_t block_index = offset / IO_BLOCK_SIZE; // Starting block index + //size_t len = (inode.metadata.size/IO_BLOCK_SIZE) * IO_BLOCK_SIZE; // Assuming each block is 4096 bytes + // Determine the length of the buffer + // Allocate memory for the new buffer + char* buffer = (char*)malloc(size); + memcpy(buffer, buf, size); + ssize_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 @@ -422,47 +766,457 @@ 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); + free(buffer); 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){ - /** 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 +int FilesOperation::fischl_readlink(const char* path, char* buf, size_t size){ + FileNode *get_file; + if((get_file = fischl_load_entry(root_node, path)) == NULL) + return -ENOENT; + INode_Data symlink_inode; + symlink_inode.inode_num = get_file->inode_number; + fs->inode_manager->load_inode(&symlink_inode); + if(!permission_check(R_OK, &symlink_inode)){ + return -EACCES; + } + //char buffer[symlink_inode.metadata.size]; + //memset(buffer, 0, sizeof(buffer)); + fs->read(&symlink_inode, buf, symlink_inode.metadata.size, 0); + buf[symlink_inode.metadata.size] = 0; + //printf("READLINK %d %s\n", symlink_inode.metadata.size, buf); + /*u_int64_t fh = namei(buffer); + if (fh == -1){ + return -ENOENT; + } INode_Data inode; // Assuming inode is correctly initialized here based on 'path' - inode.inode_num = fi->fh; + inode.inode_num = 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, 0); + printf("READLINK %d %s\n", bytes_read, buf);*/ + return 0; +} - 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 +int FilesOperation::fischl_symlink(const char* to, const char* from){ + //check path + //printf("SYMLINK %s %s\n", from, to); + char *pathdup = strdup(from); + 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_load_entry(root_node, ParentPath): root_node->self_info; + if (parent_filenode == NULL) { + fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); + free(pathdup); + return -ENOENT; + } + u_int64_t parent_inode_number = parent_filenode->inode_number; + if(!permission_check_by_inode_num(W_OK, parent_inode_number)){ + return -EACCES; + } + //make new inode + INode_Data* ret = create_new_inode(parent_inode_number, newFilename, S_IFLNK|0777); + 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->inode_num, newFilename, ret); + size_t size = strlen(to); + char* buffer = (char*)malloc(size); + memcpy(buffer, to, size); + //printf("%d %s\n", size, buffer); + size_t bytes_write = fs->write(ret, buffer, size, 0); + free(buffer); + free(pathdup); + fs->inode_manager->save_inode(ret); + //printf("%d %d %llu\n", bytes_write, ret->metadata.size, ret->inode_num); + return 0;//SUCESS +} - 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.metadata.size %d\n",__func__,__LINE__, 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 - 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); - // 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 +int FilesOperation::insert_inode_to(u_int64_t parent_inode_number, const char* name, INode_Data *new_inode, bool check_replace) { + // 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; } - return bytes_read; // Return the actual number of bytes read + // 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(check_replace){ + 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; + } + else{ + ent.inode_number = new_inode->inode_num; + ent.serialize(r_buffer+i); + fs->write(&inode, r_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + return 0; + } + } + } + } + + bool allocated = false; + + char rw_buffer[IO_BLOCK_SIZE] = {0}; + for (u_int64_t idx = 0; idx < inode.metadata.size / IO_BLOCK_SIZE; idx++) { + fs->read(&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_link(const char* from, const char* to){ + + FileNode *get_file; + if((get_file = fischl_load_entry(root_node, from)) == NULL) + return -ENOENT; + INode_Data ret; + ret.inode_num = get_file->inode_number; + fs->inode_manager->load_inode(&ret); + + //check path + char *pathdup = strdup(to); + 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_load_entry(root_node, ParentPath): root_node->self_info; + if (parent_filenode == NULL) { + fprintf(stderr,"[%s ,%d] ParentPath:{%s} not found\n",__func__,__LINE__, ParentPath); + free(pathdup); + return -1; + } + + u_int64_t parent_inode_number = parent_filenode->inode_number; + if(!permission_check_by_inode_num(W_OK, parent_inode_number)){ + return -EACCES; + } + if(insert_inode_to(parent_inode_number, newFilename, &ret, true)<0){ + return -1; + } + + ret.metadata.reference_count += 1; + fs->inode_manager->save_inode(&ret); + fischl_add_entry(parent_filenode->subdirectory, ret.inode_num, newFilename, &ret); + free(pathdup); + return 0; +} + + +// TODO: rename dir and rename fail +int FilesOperation::fischl_rename(const char *old_path, const char *new_path, unsigned int flags){ + //find old path + char *pathdup = strdup(old_path); + char *lastSlash = strrchr(pathdup, '/'); + *lastSlash = '\0'; + char *filename = lastSlash+1; + char *oldParentPath = pathdup; + if (!strcmp(filename,".")||!strcmp(filename,"..")) { + printf("refuse to remove . or ..\n"); + return -1; + } + //put old path info in rename struct + RenameInfo rename_info; + rename_info.exchangeExist = false; + rename_info.oldParentNode = fischl_load_entry(root_node, oldParentPath); + //if path end with / means to rename directory + rename_info.oldFileNode = strlen(filename)? fischl_load_entry(rename_info.oldParentNode->subdirectory, filename):rename_info.oldParentNode; + + if (rename_info.oldFileNode == NULL) { + fprintf(stderr,"[%s ,%d] path %s not found by fischl_load_entry\n",__func__,__LINE__, old_path); + free(pathdup); + return -ENOENT; + } + + //find new path + char *new_pathdup = strdup(new_path); + lastSlash = strrchr(new_pathdup, '/'); + *lastSlash = '\0'; // Split the string into parent path and new directory name; \0 + char *newParentPath = new_pathdup;//pathdup are separated by pathdup, so it take only + //put new path info in rename struct + rename_info.newName = lastSlash+1; //\0, get from + rename_info.newFileNode = fischl_load_entry(root_node, new_path); + rename_info.newParentNode = strlen(newParentPath)? fischl_load_entry(root_node, newParentPath): root_node->self_info; + + if(!permission_check_by_inode_num(W_OK, rename_info.oldParentNode->inode_number)){ + return -EACCES; + } + if(!permission_check_by_inode_num(W_OK, rename_info.newParentNode->inode_number)){ + return -EACCES; + } + if(!permission_check_by_inode_num(W_OK, rename_info.oldFileNode->inode_number)){ + return -EACCES; + } + if(rename_info.newFileNode != NULL && !permission_check_by_inode_num(W_OK, rename_info.newFileNode->inode_number)){ + return -EACCES; + } + + //configure with flag + if (flags & RENAME_NOREPLACE) { + // Check if newpath exists and return error if it does + if(rename_info.newFileNode != NULL){ + fprintf(stderr,"[%s ,%d] newpath has already existed\n",__func__,__LINE__); + free(new_pathdup);//new path + free(pathdup);//old path + return -1; + } + } + + if (flags & RENAME_EXCHANGE) { + // Ensure both oldpath and newpath exist and exchange them atomically + if(rename_info.newFileNode == NULL){ + fprintf(stderr,"[%s ,%d] newpath does not exist cannot exchange\n",__func__,__LINE__); + free(new_pathdup); + free(pathdup); + return -1; + } + rename_info.exchangeExist = true; + INode_Data parent_INode; + parent_INode.inode_num = rename_info.newParentNode->inode_number; + fs->inode_manager->load_inode(&parent_INode); + char rw_buffer[IO_BLOCK_SIZE] = {0}; + + bool change_flag = false; + //delete record on old path + 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 (ent.inode_number == rename_info.newFileNode->inode_number) { + change_flag = true;//should be change + strncpy(ent.file_name, filename, sizeof(ent.file_name) - 1); + ent.file_name[sizeof(ent.file_name) - 1] = '\0'; + ent.serialize(rw_buffer+i); + break; + } + } + if (change_flag) { + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + change_flag = false; + break; + } + } + parent_INode.inode_num = rename_info.oldParentNode->inode_number; + fs->inode_manager->load_inode(&parent_INode); + + change_flag = false; + //delete record on old path + 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 (ent.inode_number == rename_info.oldFileNode->inode_number) { + change_flag = true;//should be change + strncpy(ent.file_name, rename_info.newName, sizeof(ent.file_name) - 1); + ent.file_name[sizeof(ent.file_name) - 1] = '\0'; + ent.serialize(rw_buffer+i); + break; + } + } + if (change_flag) { + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + change_flag = false; + break; + } + } + fischl_rm_entry(rename_info.oldParentNode->subdirectory, filename); + fischl_rm_entry(rename_info.newParentNode->subdirectory, rename_info.newName); + return 0; + } + + // Normal rename logic if no flags are specified; can overwirte + // Hard Disk rename + if(rename_info.oldFileNode->subdirectory != NULL){//secure its directory + //remove its record from subdirectory; find .. from subdirectory + + } + // remove its record from parent + INode_Data parent_INode; + parent_INode.inode_num = rename_info.oldParentNode->inode_number; + fs->inode_manager->load_inode(&parent_INode); + char rw_buffer[IO_BLOCK_SIZE] = {0}; + + // relocate the old path file to new path + INode_Data ret; + ret.inode_num = rename_info.oldFileNode->inode_number; + fs->inode_manager->load_inode(&ret); + if(insert_inode_to(rename_info.newParentNode->inode_number, rename_info.newName, &ret, false)<0){ + return -1; + } + bool change_flag = false; + //delete record on old path + 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) { + change_flag = true;//should be change + ent.inode_number = 0; + memset(ent.file_name, 0, sizeof(ent.file_name)); + ent.serialize(rw_buffer+i); + break; + } + } + if (change_flag) { + fs->write(&parent_INode, rw_buffer, IO_BLOCK_SIZE, idx*IO_BLOCK_SIZE); + change_flag = false; + break; + } + } + fischl_rm_entry(rename_info.oldParentNode->subdirectory, filename); + + //free path + free(pathdup); + free(new_pathdup); + return 0; +} + +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); + if(!permission_check(W_OK, &inode)){ + return -EACCES; + } + res = fs->truncate(&inode, offset); + fs->inode_manager->save_inode(&inode); + return res; +} + +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_Data inode; + // Assuming inode is correctly initialized here based on 'path' + inode.inode_num = fi->fh; + fs->inode_manager->load_inode(&inode); + //printf("OUT READ %llu %llu %llu\n", inode.inode_num, inode.single_indirect_block, inode.double_indirect_block); + ssize_t bytes_read = fs->read(&inode, buf, size, offset); + //printf("BYTES_READ %d\n",int(bytes_read)); + //for (int i = 0; i < bytes_read; i++)printf("%x", buf[i]&0xff); + //printf("\n"); + /*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 + + 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.metadata.size %d\n",__func__,__LINE__, + 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 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); + // 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 +} + +int FilesOperation::fischl_utimens(const char *path, const struct timespec tv[2], 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.access_time = (u_int64_t)tv[0].tv_sec * 1000000000ULL + tv[0].tv_nsec; + inode.metadata.modification_time = (u_int64_t)tv[1].tv_sec * 1000000000ULL + tv[1].tv_nsec; + fs->inode_manager->save_inode(&inode); + return 0; +} + +int FilesOperation::fischl_statfs(const char* path, struct statvfs* stbuf) { + stbuf->f_bsize = 4096; + stbuf->f_blocks = 0; + stbuf->f_bfree = 0; + stbuf->f_files = 0; + stbuf->f_ffree = 0; + stbuf->f_namemax = 256; + return 0; } \ No newline at end of file diff --git a/lib/fischl.cpp b/lib/fischl.cpp index 2246652..b240e73 100644 --- a/lib/fischl.cpp +++ b/lib/fischl.cpp @@ -1,8 +1,313 @@ -#include "fischl.h" - -#include - -int fischl::init(){ - printf("Hello Fischl!"); - return 3; +#define FUSE_USE_VERSION 31 + +#include +#include +#include +#include +#include +#include +#include +#include "fs.hpp" +#include "files.h" + +/* + * 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; + bool load; +} 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) { + cfg->use_ino = 1; + options.fsop->initialize(options.load); +} + +int fischl_create(const char *path, mode_t mode, struct fuse_file_info *fi) { + return options.fsop->fischl_create(path, mode, fi); +} + + +void fischl_destroy(void* private_data) { + +} + +static int fischl_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { + return options.fsop->fischl_getattr(path, stbuf, fi); +} + +static int fischl_access(const char* path, int mask) { + return options.fsop->fischl_access(path, mask); +} + +static int fischl_readlink(const char* path, char* buf, size_t size) { + return options.fsop->fischl_readlink(path, buf, size); +} + +static int fischl_opendir(const char* path, struct fuse_file_info* fi) { + return options.fsop->fischl_opendir(path, 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 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) { + return options.fsop->fischl_mknod(path, mode, rdev); +} + +static int fischl_mkdir(const char *path, mode_t mode) { + return options.fsop->fischl_mkdir(path, mode); +} + +static int fischl_unlink(const char* path) { + return options.fsop->fischl_unlink(path); +} + +static int fischl_rmdir(const char* path) { + return options.fsop->fischl_rmdir(path); +} + +static int fischl_symlink(const char* from, const char* to) { + return options.fsop->fischl_symlink(from, to); +} + +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) { + return options.fsop->fischl_link(from, to); +} + +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 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 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) { + return options.fsop->fischl_utimens(path, tv, fi); +} + +static int fischl_open(const char *path, struct fuse_file_info *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 options.fsop->fischl_read(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 options.fsop->fischl_statfs(path, stbuf); +} + +static int fischl_release(const char* path, struct fuse_file_info *fi) { + return options.fsop->fischl_release(path, fi); +} + +static int fischl_releasedir(const char* path, struct fuse_file_info *fi) { + return options.fsop->fischl_releasedir(path, fi); +} + + +static const struct fuse_operations fischl_oper = { + + + .getattr = fischl_getattr, + .readlink = fischl_readlink, + .mknod = fischl_mknod, + .mkdir = fischl_mkdir, + .unlink = fischl_unlink, + .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, + .release = fischl_release, + /* +#ifdef HAVE_SETXATTR + .setxattr = fischl_setxattr, + .getxattr = fischl_getxattr, + .listxattr = fischl_listxattr, + .removexattr = fischl_removexattr, +#endif +*/ + .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 show_help(const char *progname) +{ + printf("usage: %s [options] \n\n", progname); + printf("File-system specific options:\n" + " --name= Name of the \"fischl\" file\n" + " (default: \"fischl\")\n" + " --contents= Contents \"fischl\" file\n" + " (default \"fischl, World!\\n\")\n" + "\n"); +} + + +int fischl(int argc, char *argv[]) +{ + int ret; + if(argc < 3){ + printf("WRONG ARGUMENTS\n"); + return 0; + } + std::swap(argv[0], argv[1]); + std::swap(argv[1], argv[2]); + + struct fuse_args args = FUSE_ARGS_INIT(argc-2, argv+2); + srand(time(NULL)); // Seed the random number generator + //const char* d = (argc < 2) ? "/dev/vdc" : argv[1]; + + //setupTestDirectory(&options.root); + if(strcmp(argv[0], "fake")==0){ + options.H = new FakeRawDisk(27648); + } + else{ + options.H = new RealRawDisk(argv[0]); + char zero_es[IO_BLOCK_SIZE] = {0}; + /*printf("zeroed\n"); + for (int i = 0; i < 200000; i++){ + options.H->write_block(i, zero_es); + }*/ + } + if(strcmp(argv[1], "l")==0){ + options.load = true; + } + else if(strcmp(argv[1], "n")==0){ + options.load = false; + } + else{ + printf("WRONG l/n ARGUMENTS\n"); + return 0; + } + options.fs = new Fs(options.H); + if(!options.load){ + printf("FORMAT %d\n", options.fs->format()); + } + options.fsop = new FilesOperation(*options.H, options.fs); + + /*INode_Data inode_data; + options.fs->inode_manager->new_inode(1, 2, 3, &inode_data); + + int buf_size = 100000; + int seg_size = 10; + char buf[buf_size]; + + int res; + int num = 1; + + for (u_int64_t i = 0; i < 30 * 1024 * 1024;) { + for (int j = 0; j < buf_size;) { + j += sprintf(&buf[j], "%010d\n", ++num); + } + res = options.fs->write(&inode_data, buf, buf_size, i); + if (res < buf_size) + printf("ERR: %d %d\n", res, i); + i += res; + } + + num = 1; + + printf("done write\n"); + char buf2[buf_size]; + + for (u_int64_t i = 0; i < 30 * 1024 * 1024;) { + for (int j = 0; j < buf_size;) { + j += sprintf(&buf[j], "%010d\n", ++num); + } + res = options.fs->read(&inode_data, buf2, buf_size, i); + if (res < buf_size) + printf("ERR2: %d %d\n", res, i); + i += res; + for (int j = 0; j < res; ++j) { + if (buf[j] != buf2[j]) + printf("err err err: %d %d", buf[j], i); + } + } + + printf("done read\n"); + + num = 1; + + for (u_int64_t i = 0; i < 30 * 1024 * 1024;) { + for (int j = 0; j < buf_size;) { + j += sprintf(&buf[j], "%010d\n", ++num); + } + res = options.fs->read(&inode_data, buf2, buf_size, i); + if (res < buf_size) + printf("ERR2: %d %d\n", res, i); + i += res; + for (int j = 0; j < res; ++j) { + if (buf[j] != buf2[j]) + printf("err err err: %d %d", buf[j], i); + } + } + + printf("done read2\n");*/ + + + + /* 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, &fischl_oper, NULL); + fuse_opt_free_args(&args); + return ret; } \ No newline at end of file diff --git a/lib/fs/datablock_manager.cpp b/lib/fs/datablock_manager.cpp index e6737d7..192f463 100644 --- a/lib/fs/datablock_manager.cpp +++ b/lib/fs/datablock_manager.cpp @@ -1,7 +1,7 @@ #include "fs.hpp" DataBlock_Manager::DataBlock_Manager(Fs *fs, u_int64_t block_segment_start, - u_int64_t block_segment_end) + u_int64_t block_segment_end) : fs(fs), block_segment_start(block_segment_start), block_segment_end(block_segment_end) {} @@ -58,6 +58,10 @@ int DataBlock_Manager_Bitmap::new_datablock(u_int64_t *block_num) { if ((err = fs->disk->read_block(bitmap_block_num, bitmap.buf)) < 0) return err; + // if (bitmap.get_next_node() == fs->superblock.free_list_head) + // printf("WARNING: ON LAST BITMAP " + // "BLOCK!\n"); + u_int64_t relative_block_num = bitmap.claim_relative_block(); if (relative_block_num == 0) @@ -122,6 +126,7 @@ int DataBlock_Manager_Bitmap::format() { char buf[IO_BLOCK_SIZE] = {0}; int err; u_int64_t i = block_segment_start; + write_u64(i, buf); for (; i <= block_segment_end - (2 * bitmap_region_size); i += bitmap_region_size) { write_u64(i + bitmap_region_size, buf); diff --git a/lib/fs/fs.cpp b/lib/fs/fs.cpp index d0caf08..053d777 100644 --- a/lib/fs/fs.cpp +++ b/lib/fs/fs.cpp @@ -1,10 +1,13 @@ #include "fs.hpp" +#include Fs::Fs(RawDisk *disk) : disk(disk) { + assert((disk->diskSize / IO_BLOCK_SIZE) > + 2 + NUM_INODE_BLOCKS + DATABLOCKS_PER_BITMAP_BLOCK); 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, disk->diskSize/IO_BLOCK_SIZE); + datablock_manager = new DataBlock_Manager_Bitmap( + this, 1 + NUM_INODE_BLOCKS, disk->diskSize / IO_BLOCK_SIZE); }; Fs::~Fs() { diff --git a/lib/fs/fs_data_types.cpp b/lib/fs/fs_data_types.cpp index c253b02..7680f35 100644 --- a/lib/fs/fs_data_types.cpp +++ b/lib/fs/fs_data_types.cpp @@ -1,4 +1,5 @@ #include "fs.hpp" +#include template T write_int(T num, char buf[]) { size_t i = 0; @@ -50,11 +51,15 @@ void SuperBlock_Data::deserialize(char buf[]) { } INode_Data::INode_Data(u_int64_t inode_num) : inode_num(inode_num) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); metadata.uid = -1; metadata.gid = -1; metadata.permissions = -1; metadata.size = 0; - metadata.reference_count = 0; + metadata.access_time = (u_int64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; + metadata.modification_time = (u_int64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; + metadata.reference_count = 1; single_indirect_block = double_indirect_block = triple_indirect_block = 0; @@ -68,6 +73,8 @@ size_t INode_Data::serialize_metadata(char buf[]) { i += write_u64(metadata.gid, &buf[i]); i += write_u64(metadata.permissions, &buf[i]); i += write_u64(metadata.size, &buf[i]); + i += write_u64(metadata.access_time, &buf[i]); + i += write_u64(metadata.modification_time, &buf[i]); i += write_u32(metadata.reference_count, &buf[i]); i += write_u32(metadata.flags, &buf[i]); return i; @@ -79,6 +86,8 @@ size_t INode_Data::deserialize_metadata(char buf[]) { i += read_u64(&metadata.gid, &buf[i]); i += read_u64(&metadata.permissions, &buf[i]); i += read_u64(&metadata.size, &buf[i]); + i += read_u64(&metadata.access_time, &buf[i]); + i += read_u64(&metadata.modification_time, &buf[i]); i += read_u32(&metadata.reference_count, &buf[i]); i += read_u32(&metadata.flags, &buf[i]); return i; diff --git a/lib/fs/fs_file_io.cpp b/lib/fs/fs_file_io.cpp new file mode 100644 index 0000000..4182b52 --- /dev/null +++ b/lib/fs/fs_file_io.cpp @@ -0,0 +1,391 @@ +#include "fs.hpp" + +class DatablockOperation { +public: + DatablockOperation(int (*_skip)(DatablockOperation *, u_int64_t) = nullptr) + : skip(_skip) {} + size_t count; + size_t offset; + size_t bytes_completed; + Fs *fs; + virtual int operation(u_int64_t block_num, bool *delete_block) = 0; + int (*skip)(DatablockOperation *, u_int64_t); +}; + +int default_skip_func(DatablockOperation *this_op, u_int64_t num_blocks) { + this_op->bytes_completed += (num_blocks * IO_BLOCK_SIZE) - this_op->offset; + this_op->offset = 0; + + if (this_op->bytes_completed >= this_op->count) + return 0; + return 1; +} + +int truncate_skip_func(DatablockOperation *this_op, u_int64_t num_blocks) { + this_op->offset = 0; + return 1; +} + +int Fs::sweep_inode_datablocks(INode_Data *inode_data, + u_int64_t start_block_index, bool allocate, + DatablockOperation *op) { + int result; + + //printf("SWEEP %llu %llu %llu\n", inode_data->inode_num, inode_data->single_indirect_block, inode_data->double_indirect_block); + + 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, + allocate, op)) <= 0) + return result; + start_index = NUMBER_OF_DIRECT_BLOCKS; + } + + start_index -= NUMBER_OF_DIRECT_BLOCKS; + + if (start_index < INDIRECT_BLOCKS) { + if ((result = sweep_datablocks(&(inode_data->single_indirect_block), 1, + start_index, allocate, op)) <= 0) + return result; + start_index = INDIRECT_BLOCKS; + } + + start_index -= INDIRECT_BLOCKS; + + 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 = INDIRECT_BLOCKS * INDIRECT_BLOCKS; + } + + start_index -= INDIRECT_BLOCKS * INDIRECT_BLOCKS; + + 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; + } + + return 1; +} + +// This can simply be made non recursive by copy pasting - it is just +// written this way as a proof of concept +int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, + u_int64_t start_block_index, bool allocate, + DatablockOperation *op) { + char buf[IO_BLOCK_SIZE]; + int err; + int result = -1; + + u_int64_t num_blocks_indirect; + u_int64_t num_blocks = 1; + for (int i = 0; i < indirect_num; ++i) { + num_blocks_indirect = num_blocks; + num_blocks *= INDIRECT_BLOCKS; + } + + if ((*block_num) == 0) { + if (allocate) { + if ((err = datablock_manager->new_datablock(block_num)) < 0) + return err; + } else if (op->skip != nullptr) { + return (*(op->skip))(op, num_blocks); + } + } + + //if((*block_num)>30000000000000LL)printf("DIES 1 %llu %d %llu\n", *block_num, indirect_num, start_block_index); + + if (indirect_num == 0) { + bool delete_block = false; + if ((result = op->operation(*block_num, &delete_block)) < 0) + return result; + if (delete_block) { + if ((err = datablock_manager->free_datablock(*block_num)) < 0) + return err; + (*block_num) = 0; + } + return result; + } + + if ((*block_num) == 0) { + memset(buf, 0, sizeof(buf)); + } else { + + if ((err = disk->read_block(*block_num, buf)) < 0) + return err; + } + + u_int64_t this_layer_start_index = start_block_index / num_blocks_indirect; + u_int64_t next_layer_start_index = + start_block_index - (num_blocks_indirect * this_layer_start_index); + + u_int64_t temp; + u_int64_t next_block_num; + bool modified = false; + + for (size_t i = this_layer_start_index * sizeof(u_int64_t); i < IO_BLOCK_SIZE; + i += sizeof(u_int64_t)) { + read_u64(&temp, &buf[i]); + next_block_num = temp; + + if ((result = sweep_datablocks(&next_block_num, indirect_num - 1, + next_layer_start_index, allocate, op)) < 0) + return result; + if (next_block_num != temp) { + write_u64(next_block_num, &buf[i]); + modified = true; + } + if (result == 0) + break; + next_layer_start_index = 0; + } + + if (modified) { + bool delete_block = true; + for (size_t i = 0; i < IO_BLOCK_SIZE; ++i) + if (buf[i] != 0) { + delete_block = false; + break; + } + if (delete_block) { + if ((err = datablock_manager->free_datablock(*block_num)) < 0) + return err; + (*block_num) = 0; + } else { + if ((err = disk->write_block(*block_num, buf)) < 0) + return err; + } + } + + return result; +} + +class ReadDatablockOperation : public DatablockOperation { +public: + char *buf; + ReadDatablockOperation() : DatablockOperation() {} + int operation(u_int64_t block_num, bool *delete_block) override { + char datablock_buf[IO_BLOCK_SIZE]; + int err; + + size_t read_size = + std::min(IO_BLOCK_SIZE - offset, count - bytes_completed); + + if (block_num != 0) { + if((block_num)>3000000000000LL)printf("DIES 2\n"); + if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0) + return err; + + memcpy(&buf[bytes_completed], &datablock_buf[offset], read_size); + } else { + memset(&buf[bytes_completed], 0, read_size); + } + + offset = 0; + bytes_completed += read_size; + + if (bytes_completed >= count) + return 0; + return 1; + } +}; + +class WriteDatablockOperation : public DatablockOperation { +public: + const char *buf; + WriteDatablockOperation() : DatablockOperation() {} + int operation(u_int64_t block_num, bool *delete_block) override { + char datablock_buf[IO_BLOCK_SIZE]; + int err; + + size_t write_size = + std::min(IO_BLOCK_SIZE - offset, count - bytes_completed); + + if (write_size < IO_BLOCK_SIZE){ + if((block_num)>3000000000000LL)printf("DIES 3\n"); + if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0) + return err; + } + + memcpy(&datablock_buf[offset], &buf[bytes_completed], write_size); + + if ((err = fs->disk->write_block(block_num, datablock_buf)) < 0) + return err; + + offset = 0; + bytes_completed += write_size; + + if (bytes_completed >= count) + return 0; + return 1; + } +}; + +class TruncateDatablockOperation : public DatablockOperation { +public: + TruncateDatablockOperation() : DatablockOperation(truncate_skip_func) {} + int operation(u_int64_t block_num, bool *delete_block) override { + char datablock_buf[IO_BLOCK_SIZE]; + int err; + + if (offset == 0) { + (*delete_block) = true; + return 1; + } + if((block_num)>3000000000000LL)printf("DIES 4\n"); + if ((err = fs->disk->read_block(block_num, datablock_buf)) < 0) + return err; + + memset(&datablock_buf[offset], 0, IO_BLOCK_SIZE - offset); + + if ((err = fs->disk->write_block(block_num, datablock_buf)) < 0) + return err; + + offset = 0; + + return 1; + } +}; + +class LseekNextDataDatablockOperation : public DatablockOperation { +public: + LseekNextDataDatablockOperation() : DatablockOperation(default_skip_func) {} + int operation(u_int64_t block_num, bool *delete_block) override { return 0; } +}; + +class LseekNextHoleDatablockOperation : public DatablockOperation { +public: + LseekNextHoleDatablockOperation() : DatablockOperation() {} + int operation(u_int64_t block_num, bool *delete_block) override { + if (block_num == 0) + return 0; + + bytes_completed += (IO_BLOCK_SIZE)-offset; + offset = 0; + + if (bytes_completed >= count) + return 0; + return 1; + } +}; + +ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count, + size_t offset) { + int err; + + if (offset >= inode_data->metadata.size) + return 0; + + u_int64_t start_block_index = offset / IO_BLOCK_SIZE; + size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); + + ReadDatablockOperation op = ReadDatablockOperation(); + op.offset = internal_offset; + op.buf = buf; + op.count = std::min(count, inode_data->metadata.size - offset); + op.bytes_completed = 0; + op.fs = this; + + //printf("IN READ %llu %llu %llu\n", inode_data->inode_num, inode_data->single_indirect_block, inode_data->double_indirect_block); + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) != 0) + return err; + + return op.bytes_completed; +} + +ssize_t Fs::write(INode_Data *inode_data, const char buf[], size_t count, + size_t offset) { + int err; + + u_int64_t start_block_index = offset / IO_BLOCK_SIZE; + size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); + + WriteDatablockOperation op = WriteDatablockOperation(); + op.offset = internal_offset; + op.buf = buf; + op.count = count; + op.bytes_completed = 0; + op.fs = this; + + 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); + + return op.bytes_completed; +} + +int Fs::truncate(INode_Data *inode_data, size_t length) { + int err; + + u_int64_t start_block_index = length / IO_BLOCK_SIZE; + size_t internal_offset = length - (start_block_index * IO_BLOCK_SIZE); + + TruncateDatablockOperation op = TruncateDatablockOperation(); + op.offset = internal_offset; + op.fs = this; + + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) < 0) + return err; + + inode_data->metadata.size = length; + + return 0; +} + +ssize_t Fs::lseek_next_data(INode_Data *inode_data, size_t offset) { + int err; + + if (offset >= inode_data->metadata.size) + return -1; + + u_int64_t start_block_index = offset / IO_BLOCK_SIZE; + size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); + + LseekNextDataDatablockOperation op = LseekNextDataDatablockOperation(); + op.offset = internal_offset; + op.count = inode_data->metadata.size; + op.bytes_completed = offset; + op.fs = this; + + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) < 0) + return err; + + if (op.bytes_completed >= inode_data->metadata.size) + return -1; + + return op.bytes_completed; +} + +ssize_t Fs::lseek_next_hole(INode_Data *inode_data, size_t offset) { + int err; + + if (offset >= inode_data->metadata.size) + return -1; + + u_int64_t start_block_index = offset / IO_BLOCK_SIZE; + size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); + + LseekNextHoleDatablockOperation op = LseekNextHoleDatablockOperation(); + op.offset = internal_offset; + op.count = inode_data->metadata.size; + op.bytes_completed = offset; + op.fs = this; + + if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, + &op)) < 0) + return err; + + if (op.bytes_completed >= inode_data->metadata.size) + return inode_data->metadata.size; + + return op.bytes_completed; +} \ No newline at end of file diff --git a/lib/fs/fs_read_write.cpp b/lib/fs/fs_read_write.cpp deleted file mode 100644 index 1aabf8a..0000000 --- a/lib/fs/fs_read_write.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#include "fs.hpp" - -class DatablockOperation { -public: - char *buf; - size_t count; - size_t offset; - size_t bytes_completed; - RawDisk *disk; - virtual int operation(u_int64_t block_num) = 0; -}; - -int Fs::sweep_inode_datablocks(INode_Data *inode_data, - u_int64_t start_block_index, bool allocate, - DatablockOperation *op) { - int result; - - 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, - allocate, op)) <= 0) - return result; - start_index = NUMBER_OF_DIRECT_BLOCKS; - } - - start_index -= NUMBER_OF_DIRECT_BLOCKS; - - if (start_index < IO_BLOCK_SIZE) { - if ((result = sweep_datablocks(&(inode_data->single_indirect_block), 1, - start_index, allocate, op)) <= 0) - return result; - start_index = IO_BLOCK_SIZE; - } - - start_index -= IO_BLOCK_SIZE; - - if (start_index < IO_BLOCK_SIZE * IO_BLOCK_SIZE) { - 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 -= IO_BLOCK_SIZE * IO_BLOCK_SIZE; - - if (start_index < (u_int64_t)IO_BLOCK_SIZE * IO_BLOCK_SIZE * IO_BLOCK_SIZE) { - if ((result = sweep_datablocks(&(inode_data->triple_indirect_block), 3, - start_index, allocate, op)) <= 0) - return result; - } - - return -1; -} - -// This can simply be made non recursive by copy pasting - it is just -// written this way as a proof of concept -int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num, - u_int64_t start_block_index, bool allocate, - DatablockOperation *op) { - char buf[IO_BLOCK_SIZE]; - int err; - int result = -1; - - if (allocate && (*block_num) == 0) - if ((err = datablock_manager->new_datablock(block_num)) < 0) - return err; - - if (indirect_num == 0) - return op->operation(*block_num); - - if ((*block_num) == 0) { - memset(buf, 0, sizeof(buf)); - } else { - 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; - - u_int64_t this_layer_start_index = start_block_index / indirect_block_size; - u_int64_t next_layer_start_index = - start_block_index - (indirect_block_size * this_layer_start_index); - - u_int64_t temp; - u_int64_t next_block_num; - bool modified = false; - - for (size_t i = this_layer_start_index * sizeof(u_int64_t); i < IO_BLOCK_SIZE; - i += sizeof(u_int64_t)) { - read_u64(&temp, &buf[i]); - next_block_num = temp; - if ((result = sweep_datablocks(&next_block_num, indirect_num - 1, - next_layer_start_index, allocate, op)) < 0) - return result; - if (next_block_num != temp) { - write_u64(next_block_num, &buf[i]); - modified = true; - } - if (result == 0) - break; - } - - if (modified) - if ((err = disk->write_block(*block_num, buf)) < 0) - return err; - - return result; -} - -class ReadDatablockOperation : public DatablockOperation { -public: - int operation(u_int64_t block_num) override { - char datablock_buf[IO_BLOCK_SIZE]; - int err; - - // printf("PRINT: (%d) %d %d %d\n", block_num, count, offset, - // bytes_completed); - - size_t read_size = - std::min(IO_BLOCK_SIZE - offset, count - bytes_completed); - - if (block_num != 0) { - if ((err = disk->read_block(block_num, datablock_buf)) < 0) - return err; - - memcpy(&buf[bytes_completed], &datablock_buf[offset], read_size); - } else { - memset(&buf[bytes_completed], 0, read_size); - } - - offset = 0; - bytes_completed += read_size; - - if (bytes_completed >= count) - return 0; - return 1; - } -}; - -class WriteDatablockOperation : public DatablockOperation { -public: - int operation(u_int64_t block_num) override { - char datablock_buf[IO_BLOCK_SIZE]; - int err; - - size_t write_size = - std::min(IO_BLOCK_SIZE - offset, count - bytes_completed); - - if (write_size < IO_BLOCK_SIZE) - if ((err = disk->read_block(block_num, datablock_buf)) < 0) - return err; - - memcpy(&datablock_buf[offset], &buf[bytes_completed], write_size); - - if ((err = disk->write_block(block_num, datablock_buf)) < 0) - return err; - - offset = 0; - bytes_completed += write_size; - - if (bytes_completed >= count) - return 0; - return 1; - } -}; - -ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count, - size_t offset) { - int err; - - u_int64_t start_block_index = offset / IO_BLOCK_SIZE; - size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); - - ReadDatablockOperation op = ReadDatablockOperation(); - op.offset = internal_offset; - op.buf = buf; - op.count = std::min(count, inode_data->metadata.size - offset); - op.bytes_completed = 0; - op.disk = disk; - - if ((err = sweep_inode_datablocks(inode_data, start_block_index, false, - &op)) < 0) - return err; - - return op.bytes_completed; -} - -ssize_t Fs::write(INode_Data *inode_data, char buf[], size_t count, - size_t offset) { - int err; - - u_int64_t start_block_index = offset / IO_BLOCK_SIZE; - size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE); - - WriteDatablockOperation op = WriteDatablockOperation(); - op.offset = internal_offset; - op.buf = buf; - op.count = count; - op.bytes_completed = 0; - op.disk = disk; - - 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); - - return op.bytes_completed; -} \ No newline at end of file diff --git a/lib/fs/fs_resize.cpp b/lib/fs/fs_resize.cpp deleted file mode 100644 index 194c064..0000000 --- a/lib/fs/fs_resize.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "fs.hpp" - -int Fs::allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) { - int result; - - for (size_t i = 0; i < NUMBER_OF_DIRECT_BLOCKS; ++i) { - result = - allocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num); - if (result <= 0) - return result; - } - - result = - allocate_indirect(&(inode_data->single_indirect_block), 1, datablock_num); - if (result <= 0) - return result; - - result = - allocate_indirect(&(inode_data->double_indirect_block), 2, datablock_num); - if (result <= 0) - return result; - - result = - allocate_indirect(&(inode_data->triple_indirect_block), 3, datablock_num); - if (result <= 0) - return result; - - return -1; -} - -// This can simply be made non recursive by copy pasting - it is just written -// this way as a proof of concept -int Fs::allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num) { - char buf[IO_BLOCK_SIZE]; - int result; - - if ((*storage) == 0) { - if ((result = datablock_manager->new_datablock(storage)) < 0) - return result; - if (n == 0) { - (*datablock_num) = (*storage); - return 0; - } - } - - if (n == 0) - return 1; - - u_int64_t temp; - - if ((result = disk->read_block(*storage, buf)) < 0) - return result; - - for (size_t i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) { - read_u64(&temp, &buf[i]); - result = allocate_indirect(&temp, n - 1, datablock_num); - if (result < 0) - return result; - if (result == 0) { - write_u64(temp, &buf[i]); - if ((result = disk->write_block(*storage, buf)) < 0) - return result; - return 0; - } - } - - return 1; -} - -int Fs::deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) { - int result; - - result = deallocate_indirect(&(inode_data->triple_indirect_block), 3, - datablock_num); - if (result <= 0) - return result; - - result = deallocate_indirect(&(inode_data->double_indirect_block), 2, - datablock_num); - if (result <= 0) - return result; - - result = deallocate_indirect(&(inode_data->single_indirect_block), 1, - datablock_num); - if (result <= 0) - return result; - - for (size_t i = NUMBER_OF_DIRECT_BLOCKS - 1; i >= 0; --i) { - result = - deallocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num); - if (result <= 0) - return result; - } - - return -1; -} - -int Fs::deallocate_indirect(u_int64_t *storage, int n, - u_int64_t *datablock_num) { - char buf[IO_BLOCK_SIZE]; - int result; - - if (*storage == 0) - return 1; - - if (n == 0) { - u_int64_t temp_datablock_num = (*storage); - if ((result = datablock_manager->free_datablock(*storage)) < 0) - return result; - (*datablock_num) = temp_datablock_num; - (*storage) = 0; - return 0; - } - - u_int64_t temp; - - if ((result = disk->read_block(*storage, buf)) < 0) - return result; - - for (size_t i = IO_BLOCK_SIZE - sizeof(u_int64_t); i >= 0; - i -= sizeof(u_int64_t)) { - read_u64(&temp, &buf[i]); - result = deallocate_indirect(&temp, n - 1, datablock_num); - if (result < 0) - return result; - if (result == 0) { - if (i == 0 && temp == 0) { - if ((result = datablock_manager->free_datablock(*storage)) < 0) - return result; - (*storage) = 0; - } else { - write_u64(temp, &buf[i]); - if ((result = disk->write_block(*storage, buf)) < 0) - return result; - } - return 0; - } - } - - return 1; -} \ No newline at end of file diff --git a/lib/main.cpp b/lib/main.cpp index 049c062..5474334 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,11 @@ 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/lib/rawdisk.cpp b/lib/rawdisk.cpp index c0ed0ab..f6203d0 100644 --- a/lib/rawdisk.cpp +++ b/lib/rawdisk.cpp @@ -10,12 +10,12 @@ void RawDisk::print_block(u_int64_t block_number) { return; } - printf("\nBlock %llu:\n", block_number); + printf("\nBlock %lu:\n", block_number); for (int i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) { num = 0; for (int j = 0; j < 8; j++) num |= ((u_int64_t)(unsigned char)buf[i + j]) << (8 * j); - printf("%llu ", num); + printf("%lu ", num); if ((i / sizeof(u_int64_t)) % nums_per_line == nums_per_line - 1) printf("\n"); } @@ -43,12 +43,14 @@ RealRawDisk::RealRawDisk(const char *directory) exit(1); } + //diskSize = 27648 * IO_BLOCK_SIZE; + // 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); + printf("Number of sectors: %lu\n", numSectors); + printf("Disk size (in bytes): %lu\n", diskSize); } RealRawDisk::~RealRawDisk() { @@ -61,12 +63,16 @@ int RealRawDisk::read_block(u_int64_t block_number, char *buffer) { u_int64_t offset = block_number * IO_BLOCK_SIZE; if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) { + printf("LSEEK ERROR %llu %llu\n", block_number, offset); perror("Error seeking to offset"); return -1; } // TODO: this is incorrect ssize_t bytesRead = read(fd, buffer, IO_BLOCK_SIZE); + //printf("READ BLOCK: %llu\n", block_number); + //for (int i = 0; i < IO_BLOCK_SIZE; i++)printf("%x", buffer[i]&0xff); + //printf("\n"); if (bytesRead < IO_BLOCK_SIZE) { perror("Error reading from device"); return -1; @@ -101,7 +107,7 @@ FakeRawDisk::FakeRawDisk(u_int64_t num_blocks) { exit(1); } printf("====Initializing FAKE RawDisk====\n"); - printf("FAKE Disk size (in bytes): %llu\n", diskSize); + printf("FAKE Disk size (in bytes): %lu\n", diskSize); perror("!!! USING FAKE RawDisk - THIS IS FOR TESTING ONLY !!!"); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 71919cf..21dcccd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,63 +1,69 @@ -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) -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address") +# 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) +# # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address") -# add test sources here ... -add_executable(${TARGET_LAYER0} - # add need lib and source code here - layer0.cpp +# # add test sources here ... +# add_executable(${TARGET_LAYER0} +# # add need lib and source code here +# layer0.cpp - ../lib/rawdisk.cpp +# ../lib/rawdisk.cpp -) -add_executable(${TARGET_LAYER1_API} - # add need lib and source code here - layer1_API.cpp +# ) +# add_executable(${TARGET_LAYER1_API} +# # add need lib and source code here +# layer1_API.cpp +# ../lib/rawdisk.cpp +# ../lib/fs/datablock_manager.cpp +# ../lib/fs/fs_data_types.cpp +# ../lib/fs/fs_file_io.cpp +# ../lib/fs/fs.cpp +# ../lib/fs/inode_manager.cpp +# ) +# 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_file_io.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_file_io.cpp +# ../lib/fs/fs.cpp +# ../lib/fs/inode_manager.cpp +# dir_API.cpp +# ) - ../lib/fischl.cpp - ../lib/rawdisk.cpp - ../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 -) -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_read_write.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_read_write.cpp - ../lib/fs/fs.cpp - ../lib/fs/inode_manager.cpp - dir_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) +# target_link_libraries(${TARGET_DIR_API} gtest gtest_main) -# 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 +# 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 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}) -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/dir_API.cpp b/test/dir_API.cpp index 265d608..272cfcd 100644 --- a/test/dir_API.cpp +++ b/test/dir_API.cpp @@ -12,7 +12,7 @@ #include #include "fs.hpp" #include "direntry.h" - +/* typedef struct file_test{ const char* name; file_test* next;//use linked-list to know the file at the same level directory @@ -217,7 +217,7 @@ TEST(DirTest, Add_FindFile_test) { file_permissions = 0; inode_dir.metadata.permissions = file_permissions | S_IFDIR; - /*add with subdirectory*/ + // 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 target_filepath = std::string("/") + mock_root->subdir->name + "/"; @@ -240,7 +240,7 @@ TEST(DirTest, Add_FindFile_test) { get_file = fischl_find_entry(get_dir->subdirectory,target_filepath.c_str()); EXPECT_TRUE(get_file != NULL); EXPECT_STREQ(get_file->name, mock_root->subdir->inFile->name); - /**********************************************************/ + //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 @@ -326,10 +326,11 @@ TEST(DirTest, Add_FindFile_test) { // temp = temp->next; // Move to next subdir // } -// } +// }*/ + int main(int argc, char **argv) { - srand(time(NULL)); // Seed the random number generator + /*srand(time(NULL)); // Seed the random number generator d = (argc < 2) ? "/dev/vdc" : argv[1]; setupTestDirectory(&mock_root); @@ -346,5 +347,6 @@ int main(int argc, char **argv) { freeDirHierarchy(mock_root);//mock_root printf("Free Total: Dir %d, File %d\n",total_free_dir, total_free_file); freeTree(root); - return result; + return result;*/ + return 0; } \ No newline at end of file diff --git a/test/layer1_API.cpp b/test/layer1_API.cpp index a1a3a87..29996ff 100644 --- a/test/layer1_API.cpp +++ b/test/layer1_API.cpp @@ -65,13 +65,16 @@ 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); + + 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 == fs->disk->diskSize/IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1); + assert(t == + fs->disk->diskSize / IO_BLOCK_SIZE - DATABLOCKS_PER_BITMAP_BLOCK - 1); /***************************test inode * de/allocation**********************************/ @@ -109,34 +112,35 @@ int main(int argc, char *argv[]) { // after free the datablock, the program will find the first smallest address // of datablock to give to the inode should test random resize each node, but // should use datablock_free data structure to record - 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); - for (int j = 0; j < 6; j++) { - fs->allocate_datablock(&inode_list[i], &temp_block_num); - printf("%llu," ,temp_block_num); - } - printf("\n"); - } - for (int i = 0; i < 10; 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("%llu,", rec_datablock_free[i][j]); - } - printf("\n"); - } + // 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); + // 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("\n"); + // } + // for (int i = 0; i < 10; 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("\n"); + // } - for (int i = 0; i < 10; 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("%llu," ,temp_block_num); - } - printf("\n"); - } + // for (int i = 0; i < 10; 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)); + // } + // // printf("\n"); + // } // printf("}\n"); delete H; // Delete the RawDisk object diff --git a/test/layer2_API_dir.cpp b/test/layer2_API_dir.cpp index 6d465d3..bf73734 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 @@ -37,6 +39,10 @@ int total_file_num = 0; int total_free_dir = 0; int total_free_file = 0; +FileNode* fischl_load_entry(TreeNode *root, const char *path){ + return fischl_find_entry(fs, root, path); +} + TEST(FileOperationTest, MkdirnodTest) { fsop->initialize_rootinode(); @@ -93,19 +99,19 @@ TEST(FileOperationTest, RamDiskTest) { FileNode* get_dir; u_int64_t get_disk_inum; - get_dir = fischl_find_entry(fsop->root_node, "/test");//this is file + get_dir = fischl_load_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 + get_dir = fischl_load_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/.."); + get_dir = fischl_load_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 @@ -113,7 +119,7 @@ TEST(FileOperationTest, RamDiskTest) { EXPECT_EQ(get_disk_inum, get_dir->inode_number); fsop->printDirectory(get_disk_inum); - get_dir = fischl_find_entry(fsop->root_node, "/foo/bar/."); + get_dir = fischl_load_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