diff options
author | Marvin Borner | 2022-01-02 18:37:51 +0100 |
---|---|---|
committer | Marvin Borner | 2022-01-02 18:37:51 +0100 |
commit | e4b01ac99b3d13c5d1057eacc04757cea957cbd7 (patch) | |
tree | 5bc2a7af3a788047aab8482959eddc306831adfe | |
parent | 6a1f4e4d394b3c5ff7a7d1c58a8775a645275e4a (diff) |
Read/write maybe more
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | inc/spec.h | 21 | ||||
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | src/fuse.c | 200 | ||||
-rw-r--r-- | src/mkfs.c | 28 |
5 files changed, 208 insertions, 47 deletions
@@ -1,8 +1,8 @@ # MarFS -> This is a sub-project of Melvix and shouldn't be used otherwise. +> This is a sub-project of Melvix and shouldn't be used otherwise. It's not fast and 32-bit only. -As of right now, there are two utility programs in this project: +As of right now, there are two utility programs for GNU/Linux in this project: * `mkfs` creates an empty MarFS filesystem on a specified image * `fuse` mounts a specified MarFS-formatted image onto a specified directory @@ -16,6 +16,7 @@ #define MARFS_NAME_LENGTH 32 #define MARFS_ENTRY_SIZE 1024 +#define MARFS_EMPTY_ENTRY 0 #define MARFS_DIR_ENTRY 1 #define MARFS_FILE_ENTRY 2 @@ -29,8 +30,9 @@ struct marfs_header { char magic[6]; u32 version; u32 entry_size; + u32 entry_count; struct marfs_pointer main; - u8 padding[MARFS_ENTRY_SIZE - 22]; + u8 padding[MARFS_ENTRY_SIZE - 26]; } PACKED; struct marfs_entry_header { @@ -45,18 +47,27 @@ struct marfs_dir_entry_data { struct marfs_pointer pointer; } PACKED; -struct marfs_dir_entry { +struct marfs_dir_entry_info { struct marfs_entry_header header; u32 count; +} PACKED; + +struct marfs_dir_entry { + struct marfs_dir_entry_info info; struct marfs_dir_entry_data entries[MARFS_DIR_ENTRY_COUNT]; - u8 padding[MARFS_ENTRY_SIZE - sizeof(struct marfs_entry_header) - sizeof(u32) - + u8 padding[MARFS_ENTRY_SIZE - sizeof(struct marfs_dir_entry_info) - (MARFS_DIR_ENTRY_COUNT * sizeof(struct marfs_dir_entry_data))]; } PACKED; -struct marfs_file_entry { +struct marfs_file_entry_info { struct marfs_entry_header header; + u32 parent; u32 size; - u8 data[MARFS_ENTRY_SIZE - sizeof(struct marfs_entry_header) - sizeof(u32)]; +} PACKED; + +struct marfs_file_entry { + struct marfs_file_entry_info info; + u8 data[MARFS_ENTRY_SIZE - sizeof(struct marfs_file_entry_info)]; } PACKED; #endif @@ -47,7 +47,7 @@ $(MNT): mount: disk $(MNT) @DEV=$$(losetup -a | grep $(BUILD)/disk.img | grep -m 1 -o '/dev/loop[[:digit:]]*') && \ PART="p1" && \ - ($(SU) $(BUILD)/marfs_fuse "$$DEV$$PART" -f $(MNT) &) && \ + ($(SU) $(BUILD)/marfs_fuse "$$DEV$$PART" -f $(MNT) -o allow_other &) && \ echo "Mounted $$DEV$$PART" umount: @@ -31,26 +31,57 @@ static void debug(const char *fmt, ...) printf("\n"); } -static void sector(u32 index, u32 size, void *buf) +static void read_sector(u32 index, u32 size, void *buf) { - fseek(image, index * header.entry_size, SEEK_SET); + assert(index < header.entry_count); + assert(fseek(image, index * header.entry_size, SEEK_SET) == 0); assert(fread(buf, 1, size, image) == size); } +static void write_sector(u32 index, u32 size, void *buf) +{ + assert(index < header.entry_count); + assert(fseek(image, index * header.entry_size, SEEK_SET) == 0); + assert(fwrite(buf, 1, size, image) == size); +} + +static u32 find_free_sector(void) +{ + static u32 start = 1; + + struct marfs_entry_header h; + for (u32 i = start; i < header.entry_count - start; i++) { + read_sector(i, sizeof(h), &h); + if (h.type == MARFS_EMPTY_ENTRY) { + start = i; + return i; + } + } + + fprintf(stderr, "error: no free sector left\n"); + exit(1); +} + // first -> start = header.main.head +// TODO: Improve static u8 read_entry_header(const char *path, u32 start, struct marfs_entry_header *entry_header) { + struct marfs_entry_header h; + read_sector(start, sizeof(h), &h); + + if (*path == '/' && *(path + 1) == 0) { + *entry_header = h; + return 1; + } + while (*path && *path == '/') path++; - struct marfs_entry_header h; - sector(start, sizeof(h), &h); - if (h.type == MARFS_DIR_ENTRY) { struct marfs_dir_entry entry; - sector(start, sizeof(entry), &entry); - assert(entry.count <= MARFS_DIR_ENTRY_COUNT); - for (u32 i = 0; i < entry.count; i++) { + read_sector(start, sizeof(entry), &entry); + assert(entry.info.count <= MARFS_DIR_ENTRY_COUNT); + for (u32 i = 0; i < entry.info.count; i++) { struct marfs_dir_entry_data *data = &entry.entries[i]; if (!strncmp(path, data->name, data->length)) { if (path[data->length] == '/') { @@ -58,14 +89,17 @@ static u8 read_entry_header(const char *path, u32 start, struct marfs_entry_head entry_header); } if (!path[data->length]) { - *entry_header = h; + struct marfs_entry_header sub; + read_sector(data->pointer.head, sizeof(sub), &sub); + *entry_header = sub; return 1; } } } - if (entry.header.next != MARFS_END) - return read_entry_header(path, entry.header.next, entry_header); + if (entry.info.header.next != MARFS_END) + return read_entry_header(path, entry.info.header.next, entry_header); + *entry_header = h; } else if (h.type == MARFS_FILE_ENTRY) { *entry_header = h; return 1; @@ -91,8 +125,10 @@ static void marfs_destroy(void *data) debug("destroy()"); UNUSED(data); - if (image) + if (image) { + write_sector(0, sizeof(header), &header); fclose(image); + } } static int marfs_open(const char *file_path, struct fuse_file_info *file_info) @@ -113,13 +149,21 @@ static int marfs_getattr(const char *path, struct stat *stat, struct fuse_file_i UNUSED(info); memset(stat, 0, sizeof(*stat)); - if (strcmp(path, "/") == 0) { - stat->st_mode = S_IFDIR | 0000; - } else if (strcmp(path + 1, "aah") == 0) { - stat->st_mode = S_IFREG | 0000; - stat->st_size = 0; - } else { + + struct marfs_entry_header h; + u8 aah = read_entry_header(path, header.main.head, &h); + if (!aah) return -ENOENT; + + if (h.type == MARFS_DIR_ENTRY) { + stat->st_mode = S_IFDIR; + } else if (h.type == MARFS_FILE_ENTRY) { + struct marfs_file_entry_info i; + read_sector(h.id, sizeof(i), &i); + stat->st_mode = S_IFREG; + stat->st_size = i.size; + } else { + return -EINVAL; } return 0; @@ -129,29 +173,29 @@ static int marfs_readdir(const char *path, void *buf, fuse_fill_dir_t fill, off_ struct fuse_file_info *file_info, enum fuse_readdir_flags flags) { debug("readdir() on %s and offset %lu", path, offset); - UNUSED(offset); UNUSED(file_info); UNUSED(flags); - if (strcmp(path, "/") != 0) + + struct marfs_entry_header h; + u8 aah = read_entry_header(path, header.main.head, &h); + if (!aah) return -ENOENT; + if (h.type != MARFS_DIR_ENTRY) + return -EINVAL; + fill(buf, ".", NULL, 0, 0); fill(buf, "..", NULL, 0, 0); - fill(buf, "aah", NULL, 0, 0); - return 0; -} + struct marfs_dir_entry d; + u32 sector = h.id; + do { + read_sector(sector, sizeof(d), &d); + for (u32 i = 0; i < d.info.count; i++) + fill(buf, d.entries[i].name, NULL, 0, 0); + } while ((sector = h.next) != MARFS_END); -static int marfs_release(const char *path, struct fuse_file_info *file_info) -{ - debug("release() on %s", path); - return 0; -} - -static int marfs_releasedir(const char *path, struct fuse_file_info *file_info) -{ - debug("releasedir() on %s", path); return 0; } @@ -159,6 +203,24 @@ static int marfs_read(const char *path, char *buf, size_t to_read, off_t offset, struct fuse_file_info *file_info) { debug("read() on %s, %lu", path, to_read); + UNUSED(offset); + UNUSED(file_info); + + struct marfs_entry_header h; + u8 aah = read_entry_header(path, header.main.head, &h); + if (!aah) + return -ENOENT; + + if (h.type != MARFS_FILE_ENTRY) + return -EISDIR; + + struct marfs_file_entry f; + + // TODO: Multiple sector read + read_sector(h.id, sizeof(f), &f); + to_read = MIN(to_read, f.info.size); + memcpy(buf, f.data, MIN(sizeof(f.data), to_read)); + return to_read; } @@ -166,12 +228,82 @@ static int marfs_write(const char *path, const char *buf, size_t to_write, off_t struct fuse_file_info *file_info) { debug("write() on %s", path); + UNUSED(offset); + UNUSED(file_info); + + struct marfs_entry_header h; + u8 aah = read_entry_header(path, header.main.head, &h); + if (!aah) + return -ENOENT; + + if (h.type != MARFS_FILE_ENTRY) + return -EISDIR; + + struct marfs_file_entry f; + + // TODO: Multiple sector write + read_sector(h.id, sizeof(f), &f); + memcpy(f.data, buf, MIN(sizeof(f.data), to_write)); + f.info.size = to_write; // TODO: Append?? + write_sector(h.id, sizeof(f), &f); + return to_write; } static int marfs_create(const char *path, mode_t mode, struct fuse_file_info *file_info) { debug("create() on %s", path); + UNUSED(mode); + UNUSED(file_info); + + struct marfs_entry_header parent = { .type = 0 }; + u8 aah = read_entry_header(path, header.main.head, &parent); + if (aah) { + debug("%s already exists\n", path); + errno = EEXIST; + return -1; + } + if (parent.type != MARFS_DIR_ENTRY) { + debug("%s could not get created\n", path); + return -1; + } + + u32 sector = find_free_sector(); + struct marfs_file_entry_info info = { + .header.type = MARFS_FILE_ENTRY, + .header.id = sector, + .header.prev = MARFS_END, + .header.next = MARFS_END, + .size = 0, + }; + write_sector(sector, sizeof(info), &info); + + char *base = strrchr(path, '/'); + if (!(base++)) + return -EINVAL; + + u32 last = parent.id; + while (parent.next != MARFS_END) + last = parent.next; + + struct marfs_dir_entry dir; + read_sector(last, sizeof(dir), &dir); + + assert(dir.info.count + 1 < MARFS_DIR_ENTRY_COUNT); // TODO: Create new dir entry at end + + struct marfs_dir_entry_data data = (struct marfs_dir_entry_data){ + .length = strlen(base), + .pointer = MARFS_POINT(sector, sector), + }; + + if (data.length > MARFS_NAME_LENGTH) + return -EINVAL; + + strcpy(data.name, base); + dir.entries[dir.info.count++] = data; + + write_sector(last, sizeof(dir), &dir); + return 0; } @@ -219,8 +351,6 @@ static struct fuse_operations operations = { .opendir = marfs_opendir, .getattr = marfs_getattr, .readdir = marfs_readdir, - .release = marfs_release, - .releasedir = marfs_releasedir, .read = marfs_read, .write = marfs_write, .create = marfs_create, @@ -244,7 +374,7 @@ int main(int argc, char **argv) argv++; argc--; - image = fopen(path, "r"); + image = fopen(path, "r+"); if (!image) { fprintf(stderr, "error: invalid image path '%s' specified: %s\n", path, strerror(errno)); @@ -20,16 +20,35 @@ int main(int argc, char *argv[]) return 1; } + printf("Formatting %s...\n", argv[1]); + FILE *image = fopen(argv[1], "r+"); if (!image) { fprintf(stderr, "%s: error: no valid image specified\n", argv[0]); return 1; } + fseek(image, 0, SEEK_END); + size_t size = ftell(image); + + if (size < 2 * MARFS_ENTRY_SIZE) { + fprintf(stderr, "%s: error: too small image size: %luB but at least %dB needed\n", + argv[0], size, 2 * MARFS_ENTRY_SIZE); + return 1; + } + + struct marfs_entry_header entry_header = { 0 }; + for (u32 i = 0; i < size / MARFS_ENTRY_SIZE; i++) { + fseek(image, i * MARFS_ENTRY_SIZE, SEEK_SET); + assert(fwrite(&entry_header, 1, sizeof(entry_header), image) == + sizeof(entry_header)); + } + struct marfs_header header = { .magic = MARFS_MAGIC, .version = MARFS_SPEC_VERSION, .entry_size = MARFS_ENTRY_SIZE, + .entry_count = size / MARFS_ENTRY_SIZE, .main = MARFS_POINT(1, 1), .padding = { 0 }, }; @@ -40,15 +59,16 @@ int main(int argc, char *argv[]) fprintf(stderr, "%s: error: header write failed: %lu bytes written\n", argv[0], write); - struct marfs_dir_entry main = { + struct marfs_dir_entry_info info = { .header.type = MARFS_DIR_ENTRY, + .header.id = 1, .header.prev = MARFS_END, .header.next = MARFS_END, + .count = 0, }; - main.entries[0].name[0] = 0; - write = fwrite(&main, 1, sizeof(main), image); - if (write != sizeof(main)) + write = fwrite(&info, 1, sizeof(info), image); + if (write != sizeof(info)) fprintf(stderr, "%s: error: main directory write failed: %lu bytes written\n", argv[0], write); |