From 1252bdeaf795629ac34161bc59a263e998483247 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Mon, 8 Aug 2022 01:00:48 +0200
Subject: user: separate tmpfs into its own executable, add `mount`

---
 src/user/app/tmpfs/tmpfs.c | 131 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)
 create mode 100644 src/user/app/tmpfs/tmpfs.c

(limited to 'src/user/app/tmpfs')

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;
+}
-- 
cgit v1.2.3