From 9f3fdb830f61cd8c8c1f1db9d03cba1c546c1a7e Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sun, 24 Jul 2022 15:07:57 +0200
Subject: user: change the directory structure to prepare for multiple binaries

---
 src/user/lib/fs/misc.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/user/lib/fs/misc.h |  16 +++++
 2 files changed, 179 insertions(+)
 create mode 100644 src/user/lib/fs/misc.c
 create mode 100644 src/user/lib/fs/misc.h

(limited to 'src/user/lib/fs')

diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
new file mode 100644
index 0000000..9522cfa
--- /dev/null
+++ b/src/user/lib/fs/misc.c
@@ -0,0 +1,163 @@
+#include <user/lib/fs/misc.h>
+#include <user/lib/stdlib.h>
+#include <shared/flags.h>
+#include <shared/mem.h>
+#include <shared/syscalls.h>
+#include <stdbool.h>
+
+bool fork2_n_mount(const char *path) {
+	handle_t h;
+	if (_syscall_fork(FORK_NEWFS, &h) > 0) { /* parent */
+		_syscall_mount(h, path, strlen(path));
+		close(h);
+		return true;
+	}
+	return false;
+}
+
+void fs_passthru(const char *prefix) {
+	struct fs_wait_response res;
+	const size_t buf_len = 1024;
+	char *buf = malloc(buf_len);
+	int prefix_len = prefix ? strlen(prefix) : 0;
+	if (!buf) _syscall_exit(1);
+
+	while (!_syscall_fs_wait(buf, buf_len, &res)) {
+		switch (res.op) {
+			case VFSOP_OPEN:
+				if (prefix) {
+					if (prefix_len + res.len > buf_len) {
+						_syscall_fs_respond(NULL, -1, 0);
+						break;
+					}
+
+					// TODO memmove
+					char tmp[64];
+					memcpy(tmp, buf, res.len);
+					memcpy(buf + prefix_len, tmp, res.len);
+					memcpy(buf, prefix, prefix_len);
+					res.len += prefix_len;
+				}
+				_syscall_fs_respond(NULL, _syscall_open(buf, res.len, res.flags), FSR_DELEGATE);
+				break;
+
+			default:
+				_syscall_fs_respond(NULL, -1, 0);
+				break;
+		}
+	}
+	_syscall_exit(0);
+}
+
+void fs_whitelist(const char **list) {
+	struct fs_wait_response res;
+	const size_t buf_len = 1024;
+	char *buf = malloc(buf_len);
+	bool allow;
+	if (!buf) _syscall_exit(1);
+
+	while (!_syscall_fs_wait(buf, buf_len, &res)) {
+		switch (res.op) {
+			case VFSOP_OPEN:
+				allow = false;
+				// TODO reverse dir_inject
+				for (const char **iter = list; *iter; iter++) {
+					size_t len = strlen(*iter); // inefficient, whatever
+					if (len <= res.len && !memcmp(buf, *iter, len)) {
+						allow = true;
+						break;
+					}
+				}
+				_syscall_fs_respond(NULL, allow ? _syscall_open(buf, res.len, res.flags) : -1, FSR_DELEGATE);
+				break;
+
+			default:
+				_syscall_fs_respond(NULL, -1, 0);
+				break;
+		}
+	}
+	_syscall_exit(0);
+}
+
+
+void fs_dir_inject(const char *path) {
+	struct fs_dir_handle {
+		const char *inject;
+		int delegate, inject_len;
+	};
+
+	const size_t path_len = strlen(path);
+	struct fs_wait_response res;
+	struct fs_dir_handle *data;
+	const size_t buf_len = 1024;
+	char *buf = malloc(buf_len);
+	int ret, inject_len;
+
+	if (!buf) _syscall_exit(1);
+
+	while (!_syscall_fs_wait(buf, buf_len, &res)) {
+		data = res.id;
+		switch (res.op) {
+			case VFSOP_OPEN:
+				if (buf[res.len - 1] == '/' &&
+						res.len < path_len && !memcmp(path, buf, res.len))
+				{
+					/* opening a directory that we're injecting into */
+
+					data = malloc(sizeof *data);
+					data->delegate = _syscall_open(buf, res.len, res.flags);
+					data->inject = path + res.len;
+
+					/* inject up to the next slash */
+					inject_len = 0;
+					while (data->inject[inject_len] && data->inject[inject_len] != '/')
+						inject_len++;
+					if (data->inject[inject_len] == '/')
+						inject_len++;
+					data->inject_len = inject_len;
+
+					_syscall_fs_respond(data, 0, 0);
+				} else {
+					_syscall_fs_respond(NULL, _syscall_open(buf, res.len, res.flags), FSR_DELEGATE);
+				}
+				break;
+
+			case VFSOP_CLOSE:
+				if (data->delegate >= 0)
+					close(data->delegate);
+				_syscall_fs_respond(NULL, 0, 0);
+				break;
+
+			case VFSOP_READ:
+				if (res.offset > 0) _syscall_fs_respond(NULL, 0, 0); // TODO working offsets
+
+				int out_len = data->inject_len;
+				memcpy(buf, data->inject, out_len);
+				buf[out_len++] = '\0';
+
+				if (data->delegate >= 0) {
+					int to_read = res.capacity < buf_len ? res.capacity : buf_len;
+					to_read -= out_len;
+					ret = _syscall_read(data->delegate, buf + out_len, to_read, 0);
+					if (ret > 0) out_len += ret;
+					// TODO deduplicate entries
+				}
+
+				_syscall_fs_respond(buf, out_len, 0);
+				break;
+
+			case VFSOP_WRITE:
+				if (data->delegate >= 0)
+					ret = _syscall_write(data->delegate, buf, res.len, res.offset);
+				else
+					ret = -1;
+				_syscall_fs_respond(NULL, ret, 0);
+				break;
+
+			default:
+				_syscall_fs_respond(NULL, -1, 0);
+				break;
+		}
+	}
+	_syscall_exit(0);
+}
diff --git a/src/user/lib/fs/misc.h b/src/user/lib/fs/misc.h
new file mode 100644
index 0000000..3a8b071
--- /dev/null
+++ b/src/user/lib/fs/misc.h
@@ -0,0 +1,16 @@
+#pragma once
+#include <user/lib/stdlib.h>
+#include <stdbool.h>
+
+bool fork2_n_mount(const char *path);
+
+void fs_passthru(const char *prefix);
+void fs_whitelist(const char **list);
+
+void fs_dir_inject(const char *path);
+
+/** Mounts something and injects its path into the fs */
+// TODO path needs to have a trailing slash
+#define MOUNT(path, impl) \
+	if (!fork2_n_mount(path)) {_klogf("impl %s", path); impl;} \
+	if (!fork2_n_mount("/"))  {_klogf("dir for %s", path); fs_dir_inject(path);}
-- 
cgit v1.2.3