diff options
-rw-r--r-- | src/user/app/tmpfs/tmpfs.c | 61 |
1 files changed, 38 insertions, 23 deletions
diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c index ed3c2e3..2594813 100644 --- a/src/user/app/tmpfs/tmpfs.c +++ b/src/user/app/tmpfs/tmpfs.c @@ -1,6 +1,7 @@ #include <camellia/fsutil.h> #include <camellia/syscalls.h> #include <shared/mem.h> +#include <stdbool.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> @@ -8,19 +9,21 @@ struct node { const char *name; + bool directory; size_t namelen; - struct node *next; + struct node *sibling, *child; char *buf; size_t size, capacity; }; struct node *root = NULL; static struct node special_root = { + .directory = true, .size = 0, }; -static struct node *lookup(const char *path, size_t len) { - for (struct node *iter = root; iter; iter = iter->next) { +static struct node *lookup(struct node *parent, const char *path, size_t len) { + for (struct node *iter = parent->child; iter; iter = iter->sibling) { if (iter->namelen == len && !memcmp(path, iter->name, len)) return iter; } @@ -28,28 +31,39 @@ static struct node *lookup(const char *path, size_t len) { } static struct node *tmpfs_open(const char *path, struct fs_wait_response *res) { - struct node *node; + struct node *node = &special_root; if (res->len == 0) return NULL; + if (res->len == 1) return node; path++; res->len--; - if (res->len == 0) return &special_root; + bool more = true; + size_t segpos = 0, seglen; /* segments end with a slash, inclusive */ + while (more) { + struct node *const parent = node; + char *slash = memchr(path + segpos, '/', res->len); + seglen = (slash ? (size_t)(slash - path + 1) : res->len) - segpos; + more = segpos + seglen < res->len; - // no directory support (yet) - if (memchr(path, '/', res->len)) return NULL; + node = lookup(parent, path + segpos, seglen); + if (!node) { + if (!more && (res->flags & OPEN_CREATE)) { + node = malloc(sizeof *node); + memset(node, 0, sizeof *node); - node = lookup(path, res->len); - if (!node && (res->flags & OPEN_CREATE)) { - node = malloc(sizeof *node); - memset(node, 0, sizeof *node); - - char *namebuf = malloc(res->len + 1); - memcpy(namebuf, path, res->len); - namebuf[res->len] = '\0'; - node->name = namebuf; - node->namelen = res->len; - node->next = root; - root = node; + char *namebuf = malloc(seglen + 1); + memcpy(namebuf, path + segpos, seglen); + namebuf[seglen] = '\0'; + node->name = namebuf; + node->directory = slash; + node->namelen = seglen; + node->sibling = parent->child; + parent->child = node; + } else { + return NULL; + } + } + segpos += seglen; } return node; } @@ -68,10 +82,10 @@ int main(void) { case VFSOP_READ: ptr = (void*)res.id; - if (ptr == &special_root) { + if (ptr->directory) { struct dirbuild db; dir_start(&db, res.offset, buf, buflen); - for (struct node *iter = root; iter; iter = iter->next) + for (struct node *iter = ptr->child; iter; iter = iter->sibling) dir_append(&db, iter->name); _syscall_fs_respond(buf, dir_finish(&db), 0); } else { @@ -118,10 +132,11 @@ int main(void) { case VFSOP_GETSIZE: ptr = (void*)res.id; - if (ptr == &special_root) { + if (ptr->directory) { + // TODO could be cached in ptr->size struct dirbuild db; dir_start(&db, res.offset, NULL, buflen); - for (struct node *iter = root; iter; iter = iter->next) + for (struct node *iter = ptr->child; iter; iter = iter->sibling) dir_append(&db, iter->name); _syscall_fs_respond(NULL, dir_finish(&db), 0); } else { |