summaryrefslogtreecommitdiff
path: root/src/user/app/tmpfs/tmpfs.c
diff options
context:
space:
mode:
authordzwdz2022-08-08 01:00:48 +0200
committerdzwdz2022-08-08 01:00:48 +0200
commit1252bdeaf795629ac34161bc59a263e998483247 (patch)
tree05d2fcba83fe0eb1f3d18044decca10dcea184c6 /src/user/app/tmpfs/tmpfs.c
parentb99d66ce12b4a1a0dd452d8a38006eede0c05cf2 (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.c131
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;
+}