summaryrefslogtreecommitdiff
path: root/src/user/lib/fs
diff options
context:
space:
mode:
authordzwdz2022-07-24 15:07:57 +0200
committerdzwdz2022-07-24 15:07:57 +0200
commit9f3fdb830f61cd8c8c1f1db9d03cba1c546c1a7e (patch)
treef5ec030c736f5201332c51cb99169b288185b84b /src/user/lib/fs
parent0228be3fd404cdebecf6d21b8964f6063f12dfbe (diff)
user: change the directory structure to prepare for multiple binaries
Diffstat (limited to 'src/user/lib/fs')
-rw-r--r--src/user/lib/fs/misc.c163
-rw-r--r--src/user/lib/fs/misc.h16
2 files changed, 179 insertions, 0 deletions
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);}