summaryrefslogtreecommitdiff
path: root/src/user/lib
diff options
context:
space:
mode:
authordzwdz2022-08-08 13:12:41 +0200
committerdzwdz2022-08-08 13:12:41 +0200
commitc7af8418c9a2222cde5ab3a6953b31803d0a8ef1 (patch)
treece9b5f19cfd292eb4e70086cb061527f29a68bba /src/user/lib
parent1252bdeaf795629ac34161bc59a263e998483247 (diff)
user: union filesystems
Diffstat (limited to 'src/user/lib')
-rw-r--r--src/user/lib/fs/misc.c65
-rw-r--r--src/user/lib/fs/misc.h1
2 files changed, 66 insertions, 0 deletions
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
index 1fb5c3b..54f54fd 100644
--- a/src/user/lib/fs/misc.c
+++ b/src/user/lib/fs/misc.c
@@ -135,6 +135,71 @@ void fs_whitelist(const char **list) {
exit(0);
}
+void fs_union(const char **list) {
+ struct fs_wait_response res;
+
+ /* the buffer is split into two halves:
+ * the second one is filled out with the path by fs_wait
+ * the first one is used for the prepended paths */
+ const size_t buflen = 1024;
+ const size_t prelen = 512;
+ const size_t postlen = buflen - prelen;
+ char *pre = malloc(buflen);
+ char *post = pre + prelen;
+ long ret;
+ struct dirbuild db;
+ if (!pre) exit(1);
+
+ while (!_syscall_fs_wait(post, postlen, &res)) {
+ switch (res.op) {
+ case VFSOP_OPEN:
+ if (res.len == 1) { /* root directory */
+ _syscall_fs_respond(NULL, 0, 0);
+ break;
+ }
+
+ ret = -1;
+ for (size_t i = 0; ret < 0 && list[i]; i++) {
+ const char *prefix = list[i];
+ size_t prefixlen = strlen(prefix); // TODO cache
+ if (prefixlen > prelen) continue;
+ char *path = post - prefixlen;
+ memcpy(path, prefix, prefixlen);
+
+ ret = _syscall_open(path, prefixlen + res.len, res.flags);
+
+ post[res.len] = '\0';
+ }
+ if (ret < 0) ret = -1;
+ _syscall_fs_respond(NULL, ret, FSR_DELEGATE);
+ break;
+
+ case VFSOP_READ:
+ if (res.capacity > buflen)
+ res.capacity = buflen;
+ bool end = false;
+ dir_start(&db, res.offset, pre, res.capacity);
+ for (size_t i = 0; !end && list[i]; i++) {
+ const char *prefix = list[i];
+ size_t prefixlen = strlen(prefix);
+ // TODO only open the directories once
+ // TODO ensure trailing slash
+ handle_t h = _syscall_open(prefix, prefixlen, 0);
+ if (h < 0) continue;
+ end = end || dir_append_from(&db, h);
+ _syscall_close(h);
+ }
+ _syscall_fs_respond(pre, dir_finish(&db), 0);
+ break;
+
+ default:
+ _syscall_fs_respond(NULL, -1, 0);
+ break;
+ }
+ }
+ exit(0);
+}
+
void fs_dir_inject(const char *path) {
struct fs_dir_handle {
diff --git a/src/user/lib/fs/misc.h b/src/user/lib/fs/misc.h
index 1a9c555..8fe6834 100644
--- a/src/user/lib/fs/misc.h
+++ b/src/user/lib/fs/misc.h
@@ -8,6 +8,7 @@ bool fork2_n_mount(const char *path);
void fs_passthru(const char *prefix);
void fs_whitelist(const char **list);
+void fs_union(const char **list);
void fs_dir_inject(const char *path);