├── EXT文件系统机制原理详解-51CTO.COM.html ├── Project 06_ Simple File System.html ├── README.md └── project ├── Makefile ├── README.md ├── bin └── .empty ├── data ├── image.20 ├── image.200 └── image.5 ├── include ├── .DS_Store └── sfs │ ├── disk.h │ └── fs.h ├── lib └── .empty ├── src ├── .DS_Store ├── library │ ├── disk.cpp │ └── fs.cpp └── shell │ └── sfssh.cpp └── tests ├── test_cat.sh ├── test_copyin.sh ├── test_copyout.sh ├── test_create.sh ├── test_debug.sh ├── test_format.sh ├── test_mount.sh ├── test_remove.sh ├── test_stat.sh └── test_valgrind.sh /README.md: -------------------------------------------------------------------------------- 1 | #### 实现一个简单的文件系统 2 | 3 | 4 | 参考文档: 5 | 6 | EXT文件系统解释:https://www.51cto.com/article/603104.html 7 | 8 | 实验课和代码来源:https://www3.nd.edu/~pbui/teaching/cse.30341.fa19/project06.html 9 | -------------------------------------------------------------------------------- /project/Makefile: -------------------------------------------------------------------------------- 1 | CXX= g++ 2 | CXXFLAGS= -g -gdwarf-2 -std=gnu++11 -Wall -Iinclude -fPIC 3 | LDFLAGS= -Llib 4 | AR= ar 5 | ARFLAGS= rcs 6 | 7 | LIB_HEADERS= $(wildcard include/sfs/*.h) 8 | LIB_SOURCE= $(wildcard src/library/*.cpp) 9 | LIB_OBJECTS= $(LIB_SOURCE:.cpp=.o) 10 | LIB_STATIC= lib/libsfs.a 11 | 12 | SHELL_SOURCE= $(wildcard src/shell/*.cpp) 13 | SHELL_OBJECTS= $(SHELL_SOURCE:.cpp=.o) 14 | SHELL_PROGRAM= bin/sfssh 15 | 16 | all: $(LIB_STATIC) $(SHELL_PROGRAM) 17 | 18 | %.o: %.cpp $(LIB_HEADERS) 19 | $(CXX) $(CXXFLAGS) -c -o $@ $< 20 | 21 | $(LIB_STATIC): $(LIB_OBJECTS) $(LIB_HEADERS) 22 | $(AR) $(ARFLAGS) $@ $(LIB_OBJECTS) 23 | 24 | $(SHELL_PROGRAM): $(SHELL_OBJECTS) $(LIB_STATIC) 25 | $(CXX) $(LDFLAGS) -o $@ $(SHELL_OBJECTS) -lsfs 26 | 27 | test: $(SHELL_PROGRAM) 28 | @for test_script in tests/test_*.sh; do $${test_script}; done 29 | 30 | clean: 31 | rm -f $(LIB_OBJECTS) $(LIB_STATIC) $(SHELL_OBJECTS) $(SHELL_PROGRAM) 32 | 33 | .PHONY: all clean 34 | -------------------------------------------------------------------------------- /project/README.md: -------------------------------------------------------------------------------- 1 | CSE.30341.FA17: Project 06 2 | ========================== 3 | 4 | This is the documentation for [Project 06] of [CSE.30341.FA17]. 5 | 6 | Members 7 | ------- 8 | 9 | 1. Domer McDomerson (dmcdomer@nd.edu) 10 | 2. Belle Fleur (bfleur@nd.edu) 11 | 12 | Design 13 | ------ 14 | 15 | > 1. To implement `Filesystem::debug`, you will need to load the file system 16 | > data structures and report the **superblock** and **inodes**. 17 | > 18 | > - How will you read the superblock? 19 | > - How will you traverse all the inodes? 20 | > - How will you determine all the information related to an inode? 21 | > - How will you determine all the blocks related to an inode? 22 | 23 | Response. 24 | 25 | > 2. To implement `FileSystem::format`, you will need to write the superblock 26 | > and clear the remaining blocks in the file system. 27 | > 28 | > - What pre-condition must be true before this operation can succeed? 29 | > - What information must be written into the superblock? 30 | > - How would you clear all the remaining blocks? 31 | 32 | Response. 33 | 34 | > 3. To implement `FileSystem::mount`, you will need to prepare a filesystem 35 | > for use by reading the superblock and allocating the free block bitmap. 36 | > 37 | > - What pre-condition must be true before this operation can succeed? 38 | > - What sanity checks must you perform? 39 | > - How will you record that you mounted a disk? 40 | > - How will you determine which blocks are free? 41 | 42 | Response. 43 | 44 | > 4. To implement `FileSystem::create`, you will need to locate a free inode 45 | > and save a new inode into the inode table. 46 | > 47 | > - How will you locate a free inode? 48 | > - What information would you see in a new inode? 49 | > - How will you record this new inode? 50 | 51 | Response. 52 | 53 | > 5. To implement `FileSystem::remove`, you will need to locate the inode and 54 | > then free its associated blocks. 55 | > 56 | > - How will you determine if the specified inode is valid? 57 | > - How will you free the direct blocks? 58 | > - How will you free the indirect blocks? 59 | > - How will you update the inode table? 60 | 61 | Response. 62 | 63 | > 6. To implement `FileSystem::stat`, you will need to locate the inode and 64 | > return its size. 65 | > 66 | > - How will you determine if the specified inode is valid? 67 | > - How will you determine the inode's size? 68 | 69 | Response. 70 | 71 | > 7. To implement `FileSystem::read`, you will need to locate the inode and 72 | > copy data from appropriate blocks to the user-specified data buffer. 73 | > 74 | > - How will you determine if the specified inode is valid? 75 | > - How will you determine which block to read from? 76 | > - How will you handle the offset? 77 | > - How will you copy from a block to the data buffer? 78 | 79 | Response. 80 | 81 | > 8. To implement `FileSystem::write`, you will need to locate the inode and 82 | > copy data the user-specified data buffer to data blocks in the file 83 | > system. 84 | > 85 | > - How will you determine if the specified inode is valid? 86 | > - How will you determine which block to write to? 87 | > - How will you handle the offset? 88 | > - How will you know if you need a new block? 89 | > - How will you manage allocating a new block if you need another one? 90 | > - How will you copy from a block to the data buffer? 91 | > - How will you update the inode? 92 | 93 | Errata 94 | ------ 95 | 96 | > Describe any known errors, bugs, or deviations from the requirements. 97 | 98 | Extra Credit 99 | ------------ 100 | 101 | > Describe what extra credit (if any) that you implemented. 102 | 103 | [Project 06]: https://www3.nd.edu/~pbui/teaching/cse.30341.fa17/project06.html 104 | [CSE.30341.FA17]: https://www3.nd.edu/~pbui/teaching/cse.30341.fa17/ 105 | [Google Drive]: https://drive.google.com 106 | -------------------------------------------------------------------------------- /project/bin/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/bin/.empty -------------------------------------------------------------------------------- /project/data/image.20: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/data/image.20 -------------------------------------------------------------------------------- /project/data/image.200: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/data/image.200 -------------------------------------------------------------------------------- /project/data/image.5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/data/image.5 -------------------------------------------------------------------------------- /project/include/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/include/.DS_Store -------------------------------------------------------------------------------- /project/include/sfs/disk.h: -------------------------------------------------------------------------------- 1 | // disk.h: Disk emulator 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | class Disk { 8 | private: 9 | int FileDescriptor; // File descriptor of disk image 10 | size_t Blocks; // Number of blocks in disk image 11 | size_t Reads; // Number of reads performed 12 | size_t Writes; // Number of writes performed 13 | size_t Mounts; // Number of mounts 14 | 15 | // Check parameters 16 | // @param blocknum Block to operate on 17 | // @param data Buffer to operate on 18 | // Throws invalid_argument exception on error. 19 | void sanity_check(int blocknum, char *data); 20 | 21 | public: 22 | // Number of bytes per block 23 | const static size_t BLOCK_SIZE = 4096; 24 | 25 | // Default constructor 26 | Disk() : FileDescriptor(0), Blocks(0), Reads(0), Writes(0), Mounts(0) {} 27 | 28 | // Destructor 29 | ~Disk(); 30 | 31 | // Open disk image 32 | // @param path Path to disk image 33 | // @param nblocks Number of blocks in disk image 34 | // Throws runtime_error exception on error. 35 | void open(const char *path, size_t nblocks); 36 | 37 | // Return size of disk (in terms of blocks) 38 | size_t size() const { return Blocks; } 39 | 40 | // Return whether or not disk is mounted 41 | bool mounted() const { return Mounts > 0; } 42 | 43 | // Increment mounts 44 | void mount() { Mounts++; } 45 | 46 | // Decrement mounts 47 | void unmount() { if (Mounts > 0) Mounts--; } 48 | 49 | // Read block from disk 50 | // @param blocknum Block to read from 51 | // @param data Buffer to read into 52 | void read(int blocknum, char *data); 53 | 54 | // Write block to disk 55 | // @param blocknum Block to write to 56 | // @param data Buffer to write from 57 | void write(int blocknum, char *data); 58 | }; 59 | -------------------------------------------------------------------------------- /project/include/sfs/fs.h: -------------------------------------------------------------------------------- 1 | // fs.h: File System 2 | 3 | #pragma once 4 | 5 | #include "sfs/disk.h" 6 | 7 | #include 8 | 9 | class FileSystem { 10 | public: 11 | const static uint32_t MAGIC_NUMBER = 0xf0f03410; 12 | const static uint32_t INODES_PER_BLOCK = 128; 13 | const static uint32_t POINTERS_PER_INODE = 5; 14 | const static uint32_t POINTERS_PER_BLOCK = 1024; 15 | 16 | private: 17 | struct SuperBlock { // Superblock structure 18 | uint32_t MagicNumber; // File system magic number 19 | uint32_t Blocks; // Number of blocks in file system 20 | uint32_t InodeBlocks; // Number of blocks reserved for inodes 21 | uint32_t Inodes; // Number of inodes in file system 22 | }; 23 | 24 | struct Inode { 25 | uint32_t Valid; // Whether or not inode is valid 26 | uint32_t Size; // Size of file 27 | uint32_t Direct[POINTERS_PER_INODE]; // Direct pointers 28 | uint32_t Indirect; // Indirect pointer 29 | }; 30 | 31 | union Block { 32 | SuperBlock Super; // Superblock 33 | Inode Inodes[INODES_PER_BLOCK]; // Inode block 34 | uint32_t Pointers[POINTERS_PER_BLOCK]; // Pointer block 35 | char Data[Disk::BLOCK_SIZE]; // Data block 36 | }; 37 | 38 | // TODO: Internal helper functions 39 | 40 | // TODO: Internal member variables 41 | 42 | public: 43 | static void debug(Disk *disk); 44 | static bool format(Disk *disk); 45 | 46 | bool mount(Disk *disk); 47 | 48 | ssize_t create(); 49 | bool remove(size_t inumber); 50 | ssize_t stat(size_t inumber); 51 | 52 | ssize_t read(size_t inumber, char *data, size_t length, size_t offset); 53 | ssize_t write(size_t inumber, char *data, size_t length, size_t offset); 54 | }; 55 | -------------------------------------------------------------------------------- /project/lib/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/lib/.empty -------------------------------------------------------------------------------- /project/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InferBear/FileSystem/d7e38f7e842dc7754db689451e76020e59913fe4/project/src/.DS_Store -------------------------------------------------------------------------------- /project/src/library/disk.cpp: -------------------------------------------------------------------------------- 1 | // disk.cpp: disk emulator 2 | 3 | #include "sfs/disk.h" 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void Disk::open(const char *path, size_t nblocks) { 13 | FileDescriptor = ::open(path, O_RDWR|O_CREAT, 0600); 14 | if (FileDescriptor < 0) { 15 | char what[BUFSIZ]; 16 | snprintf(what, BUFSIZ, "Unable to open %s: %s", path, strerror(errno)); 17 | throw std::runtime_error(what); 18 | } 19 | 20 | if (ftruncate(FileDescriptor, nblocks*BLOCK_SIZE) < 0) { 21 | char what[BUFSIZ]; 22 | snprintf(what, BUFSIZ, "Unable to open %s: %s", path, strerror(errno)); 23 | throw std::runtime_error(what); 24 | } 25 | 26 | Blocks = nblocks; 27 | Reads = 0; 28 | Writes = 0; 29 | } 30 | 31 | Disk::~Disk() { 32 | if (FileDescriptor > 0) { 33 | printf("%lu disk block reads\n", Reads); 34 | printf("%lu disk block writes\n", Writes); 35 | close(FileDescriptor); 36 | FileDescriptor = 0; 37 | } 38 | } 39 | 40 | void Disk::sanity_check(int blocknum, char *data) { 41 | char what[BUFSIZ]; 42 | 43 | if (blocknum < 0) { 44 | snprintf(what, BUFSIZ, "blocknum (%d) is negative!", blocknum); 45 | throw std::invalid_argument(what); 46 | } 47 | 48 | if (blocknum >= (int)Blocks) { 49 | snprintf(what, BUFSIZ, "blocknum (%d) is too big!", blocknum); 50 | throw std::invalid_argument(what); 51 | } 52 | 53 | if (data == NULL) { 54 | snprintf(what, BUFSIZ, "null data pointer!"); 55 | throw std::invalid_argument(what); 56 | } 57 | } 58 | 59 | void Disk::read(int blocknum, char *data) { 60 | sanity_check(blocknum, data); 61 | 62 | if (lseek(FileDescriptor, blocknum*BLOCK_SIZE, SEEK_SET) < 0) { 63 | char what[BUFSIZ]; 64 | snprintf(what, BUFSIZ, "Unable to lseek %d: %s", blocknum, strerror(errno)); 65 | throw std::runtime_error(what); 66 | } 67 | 68 | if (::read(FileDescriptor, data, BLOCK_SIZE) != BLOCK_SIZE) { 69 | char what[BUFSIZ]; 70 | snprintf(what, BUFSIZ, "Unable to read %d: %s", blocknum, strerror(errno)); 71 | throw std::runtime_error(what); 72 | } 73 | 74 | Reads++; 75 | } 76 | 77 | void Disk::write(int blocknum, char *data) { 78 | sanity_check(blocknum, data); 79 | 80 | if (lseek(FileDescriptor, blocknum*BLOCK_SIZE, SEEK_SET) < 0) { 81 | char what[BUFSIZ]; 82 | snprintf(what, BUFSIZ, "Unable to lseek %d: %s", blocknum, strerror(errno)); 83 | throw std::runtime_error(what); 84 | } 85 | 86 | if (::write(FileDescriptor, data, BLOCK_SIZE) != BLOCK_SIZE) { 87 | char what[BUFSIZ]; 88 | snprintf(what, BUFSIZ, "Unable to write %d: %s", blocknum, strerror(errno)); 89 | throw std::runtime_error(what); 90 | } 91 | 92 | Writes++; 93 | } 94 | -------------------------------------------------------------------------------- /project/src/library/fs.cpp: -------------------------------------------------------------------------------- 1 | // fs.cpp: File System 2 | 3 | #include "sfs/fs.h" 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // Debug file system ----------------------------------------------------------- 12 | 13 | void FileSystem::debug(Disk *disk) { 14 | Block block; 15 | 16 | // Read Superblock 17 | disk->read(0, block.Data); 18 | 19 | printf("SuperBlock:\n"); 20 | printf(" %u blocks\n" , block.Super.Blocks); 21 | printf(" %u inode blocks\n" , block.Super.InodeBlocks); 22 | printf(" %u inodes\n" , block.Super.Inodes); 23 | 24 | // Read Inode blocks 25 | } 26 | 27 | // Format file system ---------------------------------------------------------- 28 | 29 | bool FileSystem::format(Disk *disk) { 30 | // Write superblock 31 | 32 | // Clear all other blocks 33 | return true; 34 | } 35 | 36 | // Mount file system ----------------------------------------------------------- 37 | 38 | bool FileSystem::mount(Disk *disk) { 39 | // Read superblock 40 | 41 | // Set device and mount 42 | 43 | // Copy metadata 44 | 45 | // Allocate free block bitmap 46 | 47 | return true; 48 | } 49 | 50 | // Create inode ---------------------------------------------------------------- 51 | 52 | ssize_t FileSystem::create() { 53 | // Locate free inode in inode table 54 | 55 | // Record inode if found 56 | return 0; 57 | } 58 | 59 | // Remove inode ---------------------------------------------------------------- 60 | 61 | bool FileSystem::remove(size_t inumber) { 62 | // Load inode information 63 | 64 | // Free direct blocks 65 | 66 | // Free indirect blocks 67 | 68 | // Clear inode in inode table 69 | return true; 70 | } 71 | 72 | // Inode stat ------------------------------------------------------------------ 73 | 74 | ssize_t FileSystem::stat(size_t inumber) { 75 | // Load inode information 76 | return 0; 77 | } 78 | 79 | // Read from inode ------------------------------------------------------------- 80 | 81 | ssize_t FileSystem::read(size_t inumber, char *data, size_t length, size_t offset) { 82 | // Load inode information 83 | 84 | // Adjust length 85 | 86 | // Read block and copy to data 87 | return 0; 88 | } 89 | 90 | // Write to inode -------------------------------------------------------------- 91 | 92 | ssize_t FileSystem::write(size_t inumber, char *data, size_t length, size_t offset) { 93 | // Load inode 94 | 95 | // Write block and copy to data 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /project/src/shell/sfssh.cpp: -------------------------------------------------------------------------------- 1 | // sfssh.cpp: Simple file system shell 2 | 3 | #include "sfs/disk.h" 4 | #include "sfs/fs.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // Macros 15 | 16 | #define streq(a, b) (strcmp((a), (b)) == 0) 17 | 18 | // Command prototypes 19 | 20 | void do_debug(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 21 | void do_format(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 22 | void do_mount(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 23 | void do_cat(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 24 | void do_copyout(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 25 | void do_create(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 26 | void do_remove(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 27 | void do_stat(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 28 | void do_copyin(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 29 | void do_help(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2); 30 | 31 | bool copyout(FileSystem &fs, size_t inumber, const char *path); 32 | bool copyin(FileSystem &fs, const char *path, size_t inumber); 33 | 34 | // Main execution 35 | 36 | int main(int argc, char *argv[]) { 37 | Disk disk; 38 | FileSystem fs; 39 | 40 | if (argc != 3) { 41 | fprintf(stderr, "Usage: %s \n", argv[0]); 42 | return EXIT_FAILURE; 43 | } 44 | 45 | try { 46 | disk.open(argv[1], atoi(argv[2])); 47 | } catch (std::runtime_error &e) { 48 | fprintf(stderr, "Unable to open disk %s: %s\n", argv[1], e.what()); 49 | return EXIT_FAILURE; 50 | } 51 | 52 | while (true) { 53 | char line[BUFSIZ], cmd[BUFSIZ], arg1[BUFSIZ], arg2[BUFSIZ]; 54 | 55 | fprintf(stderr, "sfs> "); 56 | fflush(stderr); 57 | 58 | if (fgets(line, BUFSIZ, stdin) == NULL) { 59 | break; 60 | } 61 | 62 | int args = sscanf(line, "%s %s %s", cmd, arg1, arg2); 63 | if (args == 0) { 64 | continue; 65 | } 66 | 67 | if (streq(cmd, "debug")) { 68 | do_debug(disk, fs, args, arg1, arg2); 69 | } else if (streq(cmd, "format")) { 70 | do_format(disk, fs, args, arg1, arg2); 71 | } else if (streq(cmd, "mount")) { 72 | do_mount(disk, fs, args, arg1, arg2); 73 | } else if (streq(cmd, "cat")) { 74 | do_cat(disk, fs, args, arg1, arg2); 75 | } else if (streq(cmd, "copyout")) { 76 | do_copyout(disk, fs, args, arg1, arg2); 77 | } else if (streq(cmd, "create")) { 78 | do_create(disk, fs, args, arg1, arg2); 79 | } else if (streq(cmd, "remove")) { 80 | do_remove(disk, fs, args, arg1, arg2); 81 | } else if (streq(cmd, "stat")) { 82 | do_stat(disk, fs, args, arg1, arg2); 83 | } else if (streq(cmd, "copyin")) { 84 | do_copyin(disk, fs, args, arg1, arg2); 85 | } else if (streq(cmd, "help")) { 86 | do_help(disk, fs, args, arg1, arg2); 87 | } else if (streq(cmd, "exit") || streq(cmd, "quit")) { 88 | break; 89 | } else { 90 | printf("Unknown command: %s", line); 91 | printf("Type 'help' for a list of commands.\n"); 92 | } 93 | } 94 | 95 | return EXIT_SUCCESS; 96 | } 97 | 98 | // Command functions 99 | 100 | void do_debug(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 101 | if (args != 1) { 102 | printf("Usage: debug\n"); 103 | return; 104 | } 105 | 106 | fs.debug(&disk); 107 | } 108 | 109 | void do_format(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 110 | if (args != 1) { 111 | printf("Usage: format\n"); 112 | return; 113 | } 114 | 115 | if (fs.format(&disk)) { 116 | printf("disk formatted.\n"); 117 | } else { 118 | printf("format failed!\n"); 119 | } 120 | } 121 | 122 | void do_mount(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 123 | if (args != 1) { 124 | printf("Usage: mount\n"); 125 | return; 126 | } 127 | 128 | if (fs.mount(&disk)) { 129 | printf("disk mounted.\n"); 130 | } else { 131 | printf("mount failed!\n"); 132 | } 133 | } 134 | 135 | void do_cat(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 136 | if (args != 2) { 137 | printf("Usage: cat \n"); 138 | return; 139 | } 140 | 141 | if (!copyout(fs, atoi(arg1), "/dev/stdout")) { 142 | printf("cat failed!\n"); 143 | } 144 | } 145 | 146 | void do_copyout(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 147 | if (args != 3) { 148 | printf("Usage: copyout \n"); 149 | return; 150 | } 151 | 152 | if (!copyout(fs, atoi(arg1), arg2)) { 153 | printf("copyout failed!\n"); 154 | } 155 | } 156 | 157 | void do_create(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 158 | if (args != 1) { 159 | printf("Usage: create\n"); 160 | return; 161 | } 162 | 163 | ssize_t inumber = fs.create(); 164 | if (inumber >= 0) { 165 | printf("created inode %ld.\n", inumber); 166 | } else { 167 | printf("create failed!\n"); 168 | } 169 | } 170 | 171 | void do_remove(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 172 | if (args != 2) { 173 | printf("Usage: remove \n"); 174 | return; 175 | } 176 | 177 | ssize_t inumber = atoi(arg1); 178 | if (fs.remove(inumber)) { 179 | printf("removed inode %ld.\n", inumber); 180 | } else { 181 | printf("remove failed!\n"); 182 | } 183 | } 184 | 185 | void do_stat(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 186 | if (args != 2) { 187 | printf("Usage: stat \n"); 188 | return; 189 | } 190 | 191 | ssize_t inumber = atoi(arg1); 192 | ssize_t bytes = fs.stat(inumber); 193 | if (bytes >= 0) { 194 | printf("inode %ld has size %ld bytes.\n", inumber, bytes); 195 | } else { 196 | printf("stat failed!\n"); 197 | } 198 | } 199 | 200 | void do_copyin(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 201 | if (args != 3) { 202 | printf("Usage: copyin \n"); 203 | return; 204 | } 205 | 206 | if (!copyin(fs, arg1, atoi(arg2))) { 207 | printf("copyin failed!\n"); 208 | } 209 | } 210 | 211 | void do_help(Disk &disk, FileSystem &fs, int args, char *arg1, char *arg2) { 212 | printf("Commands are:\n"); 213 | printf(" format\n"); 214 | printf(" mount\n"); 215 | printf(" debug\n"); 216 | printf(" create\n"); 217 | printf(" remove \n"); 218 | printf(" cat \n"); 219 | printf(" stat \n"); 220 | printf(" copyin \n"); 221 | printf(" copyout \n"); 222 | printf(" help\n"); 223 | printf(" quit\n"); 224 | printf(" exit\n"); 225 | } 226 | 227 | bool copyout(FileSystem &fs, size_t inumber, const char *path) { 228 | FILE *stream = fopen(path, "w"); 229 | if (stream == nullptr) { 230 | fprintf(stderr, "Unable to open %s: %s\n", path, strerror(errno)); 231 | return false; 232 | } 233 | 234 | char buffer[4*BUFSIZ] = {0}; 235 | size_t offset = 0; 236 | while (true) { 237 | ssize_t result = fs.read(inumber, buffer, sizeof(buffer), offset); 238 | if (result <= 0) { 239 | break; 240 | } 241 | fwrite(buffer, 1, result, stream); 242 | offset += result; 243 | } 244 | 245 | printf("%lu bytes copied\n", offset); 246 | fclose(stream); 247 | return true; 248 | } 249 | 250 | bool copyin(FileSystem &fs, const char *path, size_t inumber) { 251 | FILE *stream = fopen(path, "r"); 252 | if (stream == nullptr) { 253 | fprintf(stderr, "Unable to open %s: %s\n", path, strerror(errno)); 254 | return false; 255 | } 256 | 257 | char buffer[4*BUFSIZ] = {0}; 258 | size_t offset = 0; 259 | while (true) { 260 | ssize_t result = fread(buffer, 1, sizeof(buffer), stream); 261 | if (result <= 0) { 262 | break; 263 | } 264 | 265 | ssize_t actual = fs.write(inumber, buffer, result, offset); 266 | if (actual < 0) { 267 | fprintf(stderr, "fs.write returned invalid result %ld\n", actual); 268 | break; 269 | } 270 | offset += actual; 271 | if (actual != result) { 272 | fprintf(stderr, "fs.write only wrote %ld bytes, not %ld bytes\n", actual, result); 273 | break; 274 | } 275 | } 276 | 277 | printf("%lu bytes copied\n", offset); 278 | fclose(stream); 279 | return true; 280 | } 281 | -------------------------------------------------------------------------------- /project/tests/test_cat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test data/image.5 4 | 5 | image-5-output() { 6 | cat < /dev/null | sort) <(image-5-output) > test.log; then 57 | echo "Success" 58 | else 59 | echo "Failure" 60 | cat test.log 61 | fi 62 | rm -f test.log 63 | 64 | # Test data/image.20 65 | 66 | image-20-input() { 67 | cat < /dev/null | sort) <(image-20-output) > test.log; then 511 | echo "Success" 512 | else 513 | echo "Failure" 514 | cat test.log 515 | fi 516 | rm -f test.log 517 | -------------------------------------------------------------------------------- /project/tests/test_copyin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRATCH=$(mktemp -d) 4 | trap "rm -fr $SCRATCH" INT QUIT TERM EXIT 5 | 6 | # Test: data/image.5 7 | 8 | cp data/image.5 $SCRATCH/image.5 9 | cat < /dev/null 2>&1 10 | debug 11 | mount 12 | copyout 1 $SCRATCH/1.txt 13 | create 14 | debug 15 | copyin $SCRATCH/1.txt 0 16 | debug 17 | copyout 0 $SCRATCH/1.copy 18 | EOF 19 | echo -n "Testing copyin in $SCRATCH/image.5 ... " 20 | if [ $(md5sum $SCRATCH/1.copy | awk '{print $1}') = '1edec6bc701059c45053cf79e7e16588' ]; then 21 | echo "Success" 22 | else 23 | echo "Failure" 24 | fi 25 | 26 | # Test: data/image.20 27 | 28 | cp data/image.20 $SCRATCH/image.20 29 | cat < /dev/null 2>&1 30 | debug 31 | mount 32 | copyout 2 $SCRATCH/2.txt 33 | copyout 3 $SCRATCH/3.txt 34 | create 35 | copyin $SCRATCH/3.txt 0 36 | create 37 | copyin $SCRATCH/2.txt 1 38 | copyout 0 $SCRATCH/3.copy 39 | copyout 1 $SCRATCH/2.copy 40 | debug 41 | EOF 42 | echo -n "Testing copyin in $SCRATCH/image.20 ... " 43 | if [ $(md5sum $SCRATCH/2.copy | awk '{print $1}') = '1adf08d52e0f1a162a3a887a19fcf1f8' ] && 44 | [ $(md5sum $SCRATCH/3.copy | awk '{print $1}') = 'd083a4be9fde347b98a8dbdfcc196819' ]; then 45 | echo "Success" 46 | else 47 | echo "Failure" 48 | fi 49 | 50 | # Test: data/image.200 51 | 52 | cp data/image.200 $SCRATCH/image.200 53 | cat < /dev/null 2>&1 54 | debug 55 | mount 56 | copyout 1 $SCRATCH/1.txt 57 | copyout 2 $SCRATCH/2.txt 58 | copyout 9 $SCRATCH/9.txt 59 | create 60 | copyin $SCRATCH/1.txt 0 61 | create 62 | copyin $SCRATCH/2.txt 3 63 | create 64 | copyin $SCRATCH/9.txt 4 65 | debug 66 | copyout 0 $SCRATCH/1.copy 67 | copyout 3 $SCRATCH/2.copy 68 | copyout 4 $SCRATCH/9.copy 69 | EOF 70 | echo -n "Testing copyin in $SCRATCH/image.200 ... " 71 | if [ $(md5sum $SCRATCH/1.copy | awk '{print $1}') = '0af623d6d8cb0a514816e17c7386a298' ] && 72 | [ $(md5sum $SCRATCH/2.copy | awk '{print $1}') = '307fe5cee7ac87c3b06ea5bda80301ee' ] && 73 | [ $(md5sum $SCRATCH/9.copy | awk '{print $1}') = 'fa4280d88da260281e509296fd2f3ea2' ]; then 74 | echo "Success" 75 | else 76 | echo "Failure" 77 | fi 78 | -------------------------------------------------------------------------------- /project/tests/test_copyout.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRATCH=$(mktemp -d) 4 | trap "rm -fr $SCRATCH" INT QUIT TERM EXIT 5 | 6 | # Test: data/image.5 7 | 8 | echo -n "Testing copyout in data/image.5 ... " 9 | cat < /dev/null 2>&1 10 | mount 11 | copyout 1 $SCRATCH/1.txt 12 | EOF 13 | if [ $(md5sum $SCRATCH/1.txt | awk '{print $1}') = '1edec6bc701059c45053cf79e7e16588' ]; then 14 | echo "Success" 15 | else 16 | echo "Failure" 17 | fi 18 | 19 | # Test: data/image.20 20 | 21 | cat < /dev/null 2>&1 22 | mount 23 | copyout 2 $SCRATCH/2.txt 24 | copyout 3 $SCRATCH/3.txt 25 | EOF 26 | 27 | echo -n "Testing copyout in data/image.20 ... " 28 | if [ $(md5sum $SCRATCH/2.txt | awk '{print $1}') = 'bfd6a31563edfd2a943edc29c37366b1' ] && 29 | [ $(md5sum $SCRATCH/3.txt | awk '{print $1}') = 'd083a4be9fde347b98a8dbdfcc196819' ]; then 30 | echo "Success" 31 | else 32 | echo "Failure" 33 | fi 34 | 35 | # Test: data/image.200 36 | 37 | cat < /dev/null 2>&1 38 | mount 39 | copyout 1 $SCRATCH/1.txt 40 | copyout 2 $SCRATCH/2.txt 41 | copyout 9 $SCRATCH/9.txt 42 | EOF 43 | 44 | echo -n "Testing copyout in data/image.200 ... " 45 | if [ $(md5sum $SCRATCH/1.txt | awk '{print $1}') = '0af623d6d8cb0a514816e17c7386a298' ] && 46 | [ $(md5sum $SCRATCH/2.txt | awk '{print $1}') = '307fe5cee7ac87c3b06ea5bda80301ee' ] && 47 | [ $(md5sum $SCRATCH/9.txt | awk '{print $1}') = 'cc4e48a5fe0ba15b13a98b3fd34b340e' ]; then 48 | echo "Success" 49 | else 50 | echo "Failure" 51 | fi 52 | -------------------------------------------------------------------------------- /project/tests/test_create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test-input() { 4 | echo debug 5 | echo mount 6 | for i in $(seq 128); do 7 | echo create 8 | done 9 | echo debug 10 | } 11 | 12 | test-output() { 13 | cat < /dev/null) <(test-output); then 550 | echo "Success" 551 | else 552 | echo "False" 553 | fi 554 | -------------------------------------------------------------------------------- /project/tests/test_debug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | image-5-output() { 4 | cat < /dev/null) <($OUTPUT) > test.log; then 70 | echo "Success" 71 | else 72 | echo "Failure" 73 | cat test.log 74 | fi 75 | rm -f test.log 76 | } 77 | 78 | test-debug data/image.5 5 image-5-output 79 | test-debug data/image.20 20 image-20-output 80 | test-debug data/image.200 200 image-200-output 81 | -------------------------------------------------------------------------------- /project/tests/test_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | image-5-output() { 4 | cat < /dev/null) <($OUTPUT) > test.log; then 57 | echo "Success" 58 | else 59 | echo "Failure" 60 | cat test.log 61 | fi 62 | rm -f $DISK.formatted test.log 63 | } 64 | 65 | test-format data/image.5 5 image-5-output 66 | test-format data/image.20 20 image-20-output 67 | test-format data/image.200 200 image-200-output 68 | -------------------------------------------------------------------------------- /project/tests/test_mount.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #!/bin/bash 4 | 5 | mount-input() { 6 | cat < /dev/null) <($TEST-output) > test.log; then 56 | echo "Success" 57 | else 58 | echo "Failure" 59 | cat test.log 60 | fi 61 | rm -f test.log 62 | } 63 | 64 | test-mount mount 65 | test-mount mount-mount 66 | test-mount mount-format 67 | 68 | SCRATCH=$(mktemp -d) 69 | trap "rm -fr $SCRATCH" INT QUIT TERM EXIT 70 | 71 | bad-mount-input() { 72 | cat < $SCRATCH/image.5 86 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 87 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 88 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 89 | echo -n "Testing bad-mount on $SCRATCH/image.5 ... " 90 | if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then 91 | echo "Success" 92 | else 93 | echo "Failure" 94 | cat $SCRATCH/test.log 95 | fi 96 | 97 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf1 0xf0) > $SCRATCH/image.5 98 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 99 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 100 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 101 | echo -n "Testing bad-mount on $SCRATCH/image.5 ... " 102 | if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then 103 | echo "Success" 104 | else 105 | echo "Failure" 106 | cat $SCRATCH/test.log 107 | fi 108 | 109 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf0 0xf0) > $SCRATCH/image.5 110 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x00 0x00 0x00 0x00) >> $SCRATCH/image.5 111 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 112 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 113 | echo -n "Testing bad-mount on $SCRATCH/image.5 ... " 114 | if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then 115 | echo "Success" 116 | else 117 | echo "Failure" 118 | cat $SCRATCH/test.log 119 | fi 120 | 121 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf0 0xf0) > $SCRATCH/image.5 122 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 123 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x02 0x00 0x00 0x00) >> $SCRATCH/image.5 124 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 125 | echo -n "Testing bad-mount on $SCRATCH/image.5 ... " 126 | if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then 127 | echo "Success" 128 | else 129 | echo "Failure" 130 | cat $SCRATCH/test.log 131 | fi 132 | 133 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf0 0xf0) > $SCRATCH/image.5 134 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 135 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 136 | echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x70 0x00 0x00 0x00) >> $SCRATCH/image.5 137 | echo -n "Testing bad-mount on $SCRATCH/image.5 ... " 138 | if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then 139 | echo "Success" 140 | else 141 | echo "Failure" 142 | cat $SCRATCH/test.log 143 | fi 144 | -------------------------------------------------------------------------------- /project/tests/test_remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRATCH=$(mktemp -d) 4 | 5 | # Test 0 6 | 7 | test-0-input() { 8 | echo debug 9 | echo mount 10 | echo create 11 | echo create 12 | echo create 13 | echo remove 0 14 | echo debug 15 | echo create 16 | echo remove 0 17 | echo remove 0 18 | echo remove 1 19 | echo remove 3 20 | echo debug 21 | } 22 | 23 | test-0-output() { 24 | cat < /dev/null) <(test-0-output) > $SCRATCH/test.log; then 75 | echo "Success" 76 | else 77 | echo "False" 78 | cat $SCRATCH/test.log 79 | fi 80 | 81 | # Test 1 82 | 83 | test-1-input() { 84 | cat < /dev/null) <(test-1-output) > $SCRATCH/test.log; then 167 | echo "Success" 168 | else 169 | echo "False" 170 | cat $SCRATCH/test.log 171 | fi 172 | 173 | # Test 2 174 | 175 | test-2-input() { 176 | cat < /dev/null) <(test-2-output) > $SCRATCH/test.log; then 241 | echo "Success" 242 | else 243 | echo "False" 244 | cat $SCRATCH/test.log 245 | fi 246 | -------------------------------------------------------------------------------- /project/tests/test_stat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | image-5-input() { 4 | cat < /dev/null) <(image-$BLOCKS-output) > test.log; then 70 | echo "Success" 71 | else 72 | echo "Failure" 73 | cat test.log 74 | fi 75 | rm -f test.log 76 | } 77 | 78 | test-stat 5 79 | test-stat 20 80 | test-stat 200 81 | -------------------------------------------------------------------------------- /project/tests/test_valgrind.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRATCH=$(mktemp -d) 4 | trap "rm -fr $SCRATCH" INT QUIT TERM EXIT 5 | 6 | # Test: data/image.200 7 | 8 | test-input() { 9 | cat <