diff --git a/Makefile b/Makefile index ca9ab4d..c579ff4 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ obj-y += source/main.o obj-y += source/core/flash.o obj-y += source/fs/mufs/block.o +obj-y += source/fs/mufs/dir.o obj-y += source/fs/mufs/super.o obj-y += source/fs/mufs/tree.o diff --git a/include/fs/mufs.h b/include/fs/mufs.h index 4da29f4..0f6edc1 100644 --- a/include/fs/mufs.h +++ b/include/fs/mufs.h @@ -6,6 +6,7 @@ struct mufs_dir; struct mufs_tree { struct mufs *fs; + uint32_t va; uint32_t file_size; uint32_t root; uint8_t depth; diff --git a/source/fs/mufs/dir.c b/source/fs/mufs/dir.c new file mode 100644 index 0000000..17248dc --- /dev/null +++ b/source/fs/mufs/dir.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include + +#include +#include + +#include + +#include "dir.h" +#include "tree.h" + +struct mufs_dir { + struct mufs *fs; + struct mufs_tree *tree; + uint32_t va; +}; + +static int resolve(struct mufs *fs, struct mufs_tree *tree, const char *path) +{ + if (!path || *path == '\0') { + memcpy(tree, &fs->root, sizeof *tree); + return 0; + } + + /* TODO: resolve directories. */ + return -1; +} + +struct mufs_dir *mufs_opendir(struct mufs *fs, const char *path) +{ + struct mufs_dir *dir; + + if (!(dir = malloc(sizeof *dir))) + return NULL; + + dir->fs = fs; + + /* TODO: resolve path */ + (void)path; + memcpy(&dir->tree, &fs->root, sizeof dir->tree); + dir->va = 0; + + return dir; +} + +void mufs_closedir(struct mufs_dir *dir) +{ + if (!dir) + return; + + free(dir); +} + +static size_t read_dirent(struct mufs *fs, struct mufs_tree *tree, + struct mufs_dirent *dirent, uint32_t va) +{ + struct mufs_dentry entry; + size_t ret = 0; + size_t len; + uint32_t base = va; + + if (va + sizeof(entry) > tree->file_size) + return 0; + + if (mufs_read(tree, &entry, va, sizeof entry) == 0) + return 0; + + if (!entry.type) + return 0; + + ret += sizeof entry; + va += sizeof entry; + len = min(entry.path_len, sizeof(dirent->path - 1)); + + if (va + len > tree->file_size) + return 0; + + if (mufs_read(tree, dirent->path, va, len) == 0) + return 0; + + dirent->path[len] = '\0'; + ret += len; + + dirent->type = entry.type; + + struct flash_dev *dev = fs->dev; + + if (mufs_lookup_page(tree, &dirent->tree.va, base & ~((UINT32_C(1) << dev->log2_block_size) - 1)) < 0) + return 0; + + dirent->tree.fs = fs; + dirent->tree.va |= base & ((UINT32_C(1) << dev->log2_block_size) - 1); + dirent->tree.file_size = entry.file_size; + dirent->tree.root = entry.root; + dirent->tree.depth = entry.depth; + + return ret; +} + +struct mufs_dtree { + uint32_t file_size; + uint32_t root; + uint8_t depth; +} __attribute__((packed)); + +static size_t write_dirent(struct mufs_tree *tree, + uint32_t va, struct mufs_dirent *dirent) +{ + struct mufs_dtree dtree; + struct mufs_dentry entry; + + entry.type = dirent->type; + entry.file_size = dirent->tree.file_size; + entry.root = dirent->tree.root; + entry.depth = dirent->tree.depth; + entry.path_len = strlen(dirent->path); + + if (mufs_write(tree, dirent->path, va + sizeof entry, + entry.path_len) == 0) + return 0; + + if (mufs_write(tree, &entry, va, sizeof entry) == 0) + return 0; + + tree->file_size = max(tree->file_size, va + sizeof entry + entry.path_len); + + dtree.file_size = tree->file_size; + dtree.root = tree->root; + dtree.depth = tree->depth; + + printf("tree->va=%u\n", tree->va); + + if (flash_write(tree->fs->dev, tree->va, &dtree, sizeof dtree) == 0) + return 0; + + return entry.path_len + sizeof entry; +} + +int mufs_readdir(struct mufs_dir *dir, struct mufs_dirent *dirent) +{ + size_t ret; + + if (!dir || !dirent || dir->va >= dir->tree->file_size) + return -1; + + if ((ret = read_dirent(dir->fs, dir->tree, dirent, dir->va)) > 0) { + dir->va += ret; + return 0; + } + + dir->va = align_up(dir->va + 1, dir->fs->dev->log2_block_size); + + if ((ret = read_dirent(dir->fs, dir->tree, dirent, dir->va)) > 0) { + dir->va += ret; + return 0; + } + + printf("return?\n"); + return -1; +} + +int mufs_mkdir(struct mufs *fs, const char *path) +{ + struct mufs_dirent dirent; + struct mufs_tree tree; + size_t len; + char *s; + char *name; + + if (!path) + return -1; + + if (!(s = strdup(path))) + return -1; + + if (!(name = strrchr(s, '/'))) { + name = s; + s = NULL; + } else { + *name++ = '\0'; + } + + if (*name == '\0') + return -1; + + if (resolve(fs, &tree, s) < 0) + return -1; + + len = min(strlen(name), sizeof(dirent.path) - 1); + memcpy(dirent.path, name, len); + dirent.path[len] = '\0'; + dirent.type = MUFS_DIR; + + dirent.tree.fs = fs; + dirent.tree.file_size = 0; + dirent.tree.root = 0; + dirent.tree.depth = 0; + + if (!is_aligned(tree.file_size, fs->dev->log2_block_size) && + write_dirent(&tree, tree.file_size, &dirent) > 0) + return 0; + + if (write_dirent(&tree, align_up(tree.file_size, + fs->dev->log2_block_size), &dirent) > 0) + return 0; + + return -1; +} diff --git a/source/fs/mufs/dir.h b/source/fs/mufs/dir.h new file mode 100644 index 0000000..95404f6 --- /dev/null +++ b/source/fs/mufs/dir.h @@ -0,0 +1,12 @@ +#pragma once + +struct mufs_dentry { + uint8_t type; + uint32_t file_size; + uint32_t root; + uint8_t depth; + uint16_t path_len; +} __attribute__((packed)); + +#define MUFS_FILE BIT(0) +#define MUFS_DIR BIT(1) diff --git a/source/fs/mufs/super.c b/source/fs/mufs/super.c index c473195..fcd0814 100644 --- a/source/fs/mufs/super.c +++ b/source/fs/mufs/super.c @@ -1,18 +1,20 @@ +#include #include #include #include #include #include +#include #include +#include "dir.h" + struct mufs_super { char magic[4]; uint32_t nblocks; - uint32_t file_size; - uint32_t root; - uint8_t depth; + struct mufs_dentry root; } __attribute__((packed)); int mufs_mount(struct mufs *fs, struct flash_dev *dev) @@ -32,9 +34,11 @@ int mufs_mount(struct mufs *fs, struct flash_dev *dev) fs->nblocks = super.nblocks; fs->log2_nentries = fs->dev->log2_block_size - ilog2(sizeof(uint32_t)); - fs->root.file_size = super.file_size; - fs->root.root = super.root; - fs->root.depth = super.depth; + fs->root.fs = fs; + fs->root.va = offsetof(struct mufs_super, root) + 1; + fs->root.file_size = super.root.file_size; + fs->root.root = super.root.root; + fs->root.depth = super.root.depth; return 0; } @@ -44,11 +48,14 @@ int mufs_format(struct flash_dev *dev) struct mufs_super super; memcpy(super.magic, "mufs", 4); + super.nblocks = flash_get_capacity(dev) >> dev->log2_block_size; - super.file_size = 0; - super.root = 0; - super.depth = 0; + super.root.type = MUFS_DIR; + super.root.file_size = 0; + super.root.root = 0; + super.root.depth = 0; + super.root.path_len = 0; if (flash_write(dev, 0, &super, sizeof super) == 0) return -1; diff --git a/source/shell/mufs.c b/source/shell/mufs.c index 5dac496..c0e75c4 100644 --- a/source/shell/mufs.c +++ b/source/shell/mufs.c @@ -16,10 +16,14 @@ static void do_mufs_mount(const char *s); static void do_mufs_format(const char *s); +static void do_mufs_mkdir(const char *s); +static void do_mufs_ls(const char *s); static struct cmd mufs_cmds[] = { { "mount", do_mufs_mount }, { "format", do_mufs_format }, + { "mkdir", do_mufs_mkdir }, + { "ls", do_mufs_ls }, { NULL, NULL }, }; @@ -39,6 +43,9 @@ static void do_mufs_mount(const char *s) fprintf(stderr, "error: unable to mount the filesystem.\n"); return; } + + printf("log2_nentries=%u\n", mufs.log2_nentries); + printf("nentries=%u\n", UINT32_C(1) << mufs.log2_nentries); } static void do_mufs_format(const char *s) @@ -56,6 +63,31 @@ static void do_mufs_format(const char *s) } } +static void do_mufs_mkdir(const char *s) +{ + if (mufs_mkdir(&mufs, s) < 0) { + fprintf(stderr, "error: unable to create the directory\n"); + return; + } +} + +static void do_mufs_ls(const char *s) +{ + struct mufs_dirent ent; + struct mufs_dir *dir; + + if (!(dir = mufs_opendir(&mufs, s))) { + fprintf(stderr, "error: unable to open the directory\n"); + return; + } + + while (mufs_readdir(dir, &ent) == 0) { + printf("%s\n", ent.path); + } + + mufs_closedir(dir); +} + void do_mufs_cmd(const char *line) { cmd_exec(mufs_cmds, line);