diff options
author | dzwdz | 2022-08-08 01:00:48 +0200 |
---|---|---|
committer | dzwdz | 2022-08-08 01:00:48 +0200 |
commit | 1252bdeaf795629ac34161bc59a263e998483247 (patch) | |
tree | 05d2fcba83fe0eb1f3d18044decca10dcea184c6 /src/user/app/tmpfs/tmpfs.c | |
parent | b99d66ce12b4a1a0dd452d8a38006eede0c05cf2 (diff) |
user: separate tmpfs into its own executable, add `mount`
Diffstat (limited to 'src/user/app/tmpfs/tmpfs.c')
-rw-r--r-- | src/user/app/tmpfs/tmpfs.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c new file mode 100644 index 0000000..88a9fac --- /dev/null +++ b/src/user/app/tmpfs/tmpfs.c @@ -0,0 +1,131 @@ +#include <camellia/fsutil.h> +#include <camellia/syscalls.h> +#include <shared/mem.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <user/lib/fs/dir.h> + +struct node { + const char *name; + size_t namelen; + struct node *next; + char *buf; + size_t size, capacity; +}; + +struct node *root = NULL; +static struct node special_root = { + .size = 0, +}; + +static struct node *lookup(const char *path, size_t len) { + for (struct node *iter = root; iter; iter = iter->next) { + if (iter->namelen == len && !memcmp(path, iter->name, len)) + return iter; + } + return NULL; +} + +static struct node *tmpfs_open(const char *path, struct fs_wait_response *res) { + struct node *node; + if (res->len == 0) return NULL; + path++; + res->len--; + + if (res->len == 0) return &special_root; + + // no directory support (yet) + if (memchr(path, '/', res->len)) return NULL; + + 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; + } + return node; +} + +int main(void) { + const size_t buflen = 4096; + char *buf = malloc(buflen); + struct fs_wait_response res; + struct node *ptr; + while (!_syscall_fs_wait(buf, buflen, &res)) { + switch (res.op) { + case VFSOP_OPEN: + ptr = tmpfs_open(buf, &res); + _syscall_fs_respond(ptr, ptr ? 0 : -1, 0); + break; + + case VFSOP_READ: + ptr = (void*)res.id; + if (ptr == &special_root) { + struct dirbuild db; + dir_start(&db, res.offset, buf, buflen); + for (struct node *iter = root; iter; iter = iter->next) + dir_append(&db, iter->name); + _syscall_fs_respond(buf, dir_finish(&db), 0); + } else { + fs_normslice(&res.offset, &res.len, ptr->size, false); + _syscall_fs_respond(ptr->buf + res.offset, res.len, 0); + break; + } + break; + + case VFSOP_WRITE: + ptr = (void*)res.id; + if (ptr == &special_root) { + _syscall_fs_respond(NULL, -1, 0); + break; + } + if (res.len > 0 && !ptr->buf) { + ptr->buf = malloc(256); + if (!ptr->buf) { + _syscall_fs_respond(NULL, -1, 0); + break; + } + memset(ptr->buf, 0, 256); + ptr->capacity = 256; + } + + fs_normslice(&res.offset, &res.len, ptr->size, true); + if (ptr->capacity <= res.offset + res.len) { + size_t newcap = 1; + while (newcap && newcap <= res.offset + res.len) + newcap *= 2; + if (!newcap) { /* overflow */ + _syscall_fs_respond(NULL, -1, 0); + break; + } + ptr->capacity = newcap; + ptr->buf = realloc(ptr->buf, ptr->capacity); + } + + memcpy(ptr->buf + res.offset, buf, res.len); + if ((res.flags & WRITE_TRUNCATE) || ptr->size < res.offset + res.len) { + ptr->size = res.offset + res.len; + } + _syscall_fs_respond(NULL, res.len, 0); + break; + + case VFSOP_GETSIZE: + ptr = (void*)res.id; + _syscall_fs_respond(NULL, ptr->size, 0); + break; + + default: + _syscall_fs_respond(NULL, -1, 0); + break; + } + } + return 1; +} |