diff options
author | dzwdz | 2022-08-08 13:12:41 +0200 |
---|---|---|
committer | dzwdz | 2022-08-08 13:12:41 +0200 |
commit | c7af8418c9a2222cde5ab3a6953b31803d0a8ef1 (patch) | |
tree | ce9b5f19cfd292eb4e70086cb061527f29a68bba /src | |
parent | 1252bdeaf795629ac34161bc59a263e998483247 (diff) |
user: union filesystems
Diffstat (limited to 'src')
-rw-r--r-- | src/user/app/init/init.c | 4 | ||||
-rw-r--r-- | src/user/app/shell/builtins.c | 2 | ||||
-rw-r--r-- | src/user/lib/fs/misc.c | 65 | ||||
-rw-r--r-- | src/user/lib/fs/misc.h | 1 |
4 files changed, 71 insertions, 1 deletions
diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c index f011ca5..c788cb6 100644 --- a/src/user/app/init/init.c +++ b/src/user/app/init/init.c @@ -39,6 +39,10 @@ int main(void) { const char *argv[] = {"/bin/vterm", NULL}; execv(argv[0], (void*)argv); } + MOUNT_AT("/union/") { + const char *list[] = {"/tmp/", "/init/", NULL}; + fs_union(list); + } if (fork()) { /* used to trigger a kernel bug diff --git a/src/user/app/shell/builtins.c b/src/user/app/shell/builtins.c index 2562c18..0f06482 100644 --- a/src/user/app/shell/builtins.c +++ b/src/user/app/shell/builtins.c @@ -125,7 +125,7 @@ static void cmd_ls(int argc, char **argv) { return; } for (;;) { - int len = fread(buf, 1, sizeof buf, file); + int len = fread(buf, 1, buflen, file); if (len <= 0) break; for (int i = 0; i < len; i++) if (buf[i] == '\0') buf[i] = '\n'; 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); |