├── 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 <