summaryrefslogtreecommitdiff
path: root/src/user/lib/fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/lib/fs')
-rw-r--r--src/user/lib/fs/dir.c84
-rw-r--r--src/user/lib/fs/dirinject.c129
-rw-r--r--src/user/lib/fs/misc.c160
-rw-r--r--src/user/lib/fs/whitelist.c114
4 files changed, 0 insertions, 487 deletions
diff --git a/src/user/lib/fs/dir.c b/src/user/lib/fs/dir.c
deleted file mode 100644
index b7f840d..0000000
--- a/src/user/lib/fs/dir.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <camellia/fs/dir.h>
-
-void dir_start(struct dirbuild *db, long offset, char *buf, size_t buflen) {
- db->offset = offset;
- db->buf = buf;
- db->bpos = 0;
- db->blen = buflen;
- db->error = 0;
-
- // TODO decide how negative directory offsets should be handled
- if (offset < 0) db->error = -ENOSYS;
-}
-
-bool dir_append(struct dirbuild *db, const char *name) {
- return dir_appendl(db, name, strlen(name));
-}
-
-bool dir_appendl(struct dirbuild *db, const char *name, size_t len) {
- if (db->error) return true;
- if (len > (size_t)LONG_MAX) {
- db->error = -1;
- return true;
- }
-
- len++; // account for the null byte
-
- if (db->offset < (long)len) {
- name += db->offset;
- len -= db->offset;
- db->offset = 0;
-
- if (db->buf) {
- // TODO no buffer overrun check
- memcpy(db->buf + db->bpos, name, len - 1);
- db->buf[db->bpos + len - 1] = '\0';
- }
- db->bpos += len;
- } else {
- db->offset -= len;
- }
- return false;
-}
-
-bool dir_append_from(struct dirbuild *db, hid_t h) {
- if (db->error) return true;
- if (db->buf && db->bpos == db->blen) return false;
-
- int ret;
- if (db->buf) {
- ret = _sys_read(h, db->buf + db->bpos, db->blen - db->bpos, db->offset);
- if (ret < 0) {
- db->error = ret;
- return true;
- } else if (ret > 0) {
- /* not eof */
- db->offset = 0;
- db->bpos += ret;
- return false;
- } /* else ret == 0, EOF, need getsize */
- }
-
- ret = _sys_getsize(h);
- if (ret < 0) {
- db->error = ret;
- return true;
- }
- if (db->offset < ret) {
- /* should only occur when !buf, otherwise leaks previous data from buf.
- * TODO consider impact */
- db->bpos += ret - db->offset;
- db->offset = 0;
- } else {
- db->offset -= ret;
- }
- return false;
-}
-
-long dir_finish(struct dirbuild *db) {
- return db->error ? db->error : db->bpos;
-}
diff --git a/src/user/lib/fs/dirinject.c b/src/user/lib/fs/dirinject.c
deleted file mode 100644
index 9b08756..0000000
--- a/src/user/lib/fs/dirinject.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <assert.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/param.h>
-#include <unistd.h>
-
-typedef struct Handle {
- int delegate;
- int plen;
- char path[];
-} Handle;
-
-static int
-dir_seglen(const char *path)
-{
- /* if path contains /, return its position + 1
- * otherwise, return strlen */
- int len = 0;
- while (path[len]) {
- if (path[len] == '/') {
- len++;
- break;
- }
- len++;
- }
- return len;
-}
-
-static int
-find_injects(const char *injects[], const char *path, int plen, struct dirbuild *db)
-{
- // TODO deduplicate
- const char *inj;
- int matches = 0;
- assert(plen >= 1);
- assert(path[plen-1] == '/');
-
- while ((inj = *injects++)) {
- int ilen = strlen(inj);
- if (plen < ilen && memcmp(path, inj, plen) == 0) {
- if (db) {
- /* inj[plen-1] == '/' */
- const char *ent = inj + plen;
- dir_appendl(db, ent, dir_seglen(ent));
- }
- matches++;
- }
- }
- return matches;
-}
-
-void
-fs_dirinject2(const char *injects[])
-{
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
- if (!buf) exit(1);
-
- for (;;) {
- struct ufs_request req;
- hid_t reqh = _sys_fs_wait(buf, buflen, &req);
- if (reqh < 0) break;
- Handle *hndl = req.id;
- switch (req.op) {
- case VFSOP_OPEN: {
- if (buf[req.len - 1] == '/') {
- if (find_injects(injects, buf, req.len, NULL) > 0) {
- /* opening a directory that we're injecting into */
- hndl = malloc(sizeof(Handle) + req.len);
- if (hndl == NULL) {
- _sys_fs_respond(reqh, NULL, -EGENERIC, 0);
- break;
- }
- /* ignore errors from _sys_open */
- hndl->delegate = _sys_open(buf, req.len, req.flags);
- hndl->plen = req.len;
- memcpy(hndl->path, buf, hndl->plen);
- _sys_fs_respond(reqh, hndl, 0, 0);
- break;
- }
- }
- /* default behaviour */
- forward_open(reqh, buf, req.len, req.flags);
- break;
- }
-
- case VFSOP_CLOSE: {
- if (hndl->delegate >= 0) {
- close(hndl->delegate);
- }
- free(hndl);
- _sys_fs_respond(reqh, NULL, 0, 0);
- break;
- }
-
- case VFSOP_READ:
- case VFSOP_GETSIZE: {
- struct dirbuild db;
- char *target = NULL;
- if (req.op == VFSOP_READ) {
- target = buf;
- }
- req.capacity = MIN(req.capacity, buflen);
-
- dir_start(&db, req.offset, target, req.capacity);
- find_injects(injects, hndl->path, hndl->plen, &db);
- if (hndl->delegate >= 0) {
- dir_append_from(&db, hndl->delegate);
- }
- _sys_fs_respond(reqh, target, dir_finish(&db), 0);
- break;
- }
-
- default: {
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- }
- exit(0);
-}
-
-void
-fs_dirinject(const char *path) {
- fs_dirinject2((const char*[]){ path, NULL });
-}
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
deleted file mode 100644
index 30e5ab4..0000000
--- a/src/user/lib/fs/misc.c
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/compat.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-
-void forward_open(hid_t reqh, const char *path, long len, int flags) {
- // TODO use threads
- // TODO solve for more complex cases, e.g. fs_union
- /* done in a separate thread/process because open() can block,
- * but that should only hold the caller back, and not the fs driver.
- *
- * for example, running `httpd` in one term would prevent you from doing
- * basically anything on the second term, because fs_dirinject would be
- * stuck on open()ing the socket */
- if (!_sys_fork(FORK_NOREAP, NULL)) {
- _sys_fs_respond(reqh, NULL, _sys_open(path, len, flags), FSR_DELEGATE);
- exit(0);
- }
- close(reqh);
-}
-
-void fs_passthru(const char *prefix) {
- const size_t buflen = 1024;
- char *buf = malloc(buflen);
- int prefix_len = prefix ? strlen(prefix) : 0;
- if (!buf) exit(1);
-
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, buflen, &res);
- if (reqh < 0) break;
- switch (res.op) {
- case VFSOP_OPEN:
- if (prefix) {
- if (prefix_len + res.len > buflen) {
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
-
- memmove(buf + prefix_len, buf, res.len);
- memcpy(buf, prefix, prefix_len);
- res.len += prefix_len;
- }
- forward_open(reqh, buf, res.len, res.flags);
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- exit(0);
-}
-
-void fs_union(const char **list) {
- struct ufs_request 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 (!c0_fs_wait(post, postlen, &res)) {
- switch (res.op) {
- case VFSOP_OPEN:
- if (res.len == 1) { /* root directory */
- c0_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 = _sys_open(path, prefixlen + res.len, res.flags);
-
- post[res.len] = '\0';
- }
- if (ret < 0) ret = -1;
- c0_fs_respond(NULL, ret, FSR_DELEGATE);
- break;
-
- case VFSOP_READ:
- case VFSOP_GETSIZE:
- if (res.capacity > buflen)
- res.capacity = buflen;
- bool end = false;
- char *target = res.op == VFSOP_READ ? pre : NULL;
- dir_start(&db, res.offset, target, 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
- hid_t h = _sys_open(prefix, prefixlen, OPEN_READ);
- if (h < 0) continue;
- end = end || dir_append_from(&db, h);
- _sys_close(h);
- }
- c0_fs_respond(target, dir_finish(&db), 0);
- break;
-
- default:
- c0_fs_respond(NULL, -1, 0);
- break;
- }
- }
- exit(0);
-}
-
-hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req) {
- hid_t reqh;
- for (;;) {
- reqh = _sys_fs_wait(buf, len, req);
- if (reqh < 0) break;
- if (req->op == VFSOP_OPEN) {
- if (req->len == len) {
- _sys_fs_respond(reqh, NULL, -ENAMETOOLONG, 0);
- continue;
- }
- buf[req->len] = '\0';
- // TODO ensure passed paths don't have null bytes in them in the kernel
- }
- break;
- }
- return reqh;
-}
-
-int mount_at(const char *path) {
- hid_t h;
- int ret = _sys_fork(FORK_NEWFS, &h);
- if (ret == 0) {
- _klogf("%s: impl", path);
- setproctitle("%s", path);
- } else if (ret > 0) {
- _sys_mount(h, path, strlen(path));
- close(h);
- } else {
- _sys_mount(HANDLE_NULLFS, path, strlen(path));
- }
- return ret;
-}
diff --git a/src/user/lib/fs/whitelist.c b/src/user/lib/fs/whitelist.c
deleted file mode 100644
index 54a79c3..0000000
--- a/src/user/lib/fs/whitelist.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-
-static int dir_seglen2(const char *path, size_t len) {
- /* returns the length of the first segment of the path, including the trailing / (if any). */
- for (size_t i = 0; i < len; i++) {
- if (path[i] == '/')
- return i + 1;
- }
- return len;
-}
-
-/** @return the length of the path w/o suffixes */
-static size_t suffix_parse(const char *path, size_t len, bool *ro_ptr) {
- bool ro = false;
- if (len >= 3 && !memcmp(path + len - 3, ":ro", 3)) {
- ro = true;
- len -= 3;
- }
- if (ro_ptr) *ro_ptr = ro;
- return len;
-}
-
-/** Check if a path is a prefix of another path. */
-// TODO move to libc; tests
-static bool prefix_match(const char *prefix, size_t plen, const char *full, size_t flen) {
- if (flen < plen) return false;
- if (flen == plen)
- return memcmp(full, prefix, flen) == 0;
- return plen >= 1
- && prefix[plen - 1] == '/' /* prefixes must point to one of the parent directories */
- && memcmp(full, prefix, plen) == 0;
-}
-
-void fs_whitelist(const char **whitelist) {
- const size_t buflen = 1024;
- char *buf = malloc(buflen);
- if (!buf) exit(1);
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, buflen, &res);
- if (reqh < 0) break;
-
- char *ipath = res.id; /* the path of the open()ed directory */
-
- switch (res.op) {
- case VFSOP_OPEN: {
- bool error = false;
- bool passthru = false;
- bool inject = false;
-
- for (const char **entry = whitelist; *entry; entry++) {
- bool ro = false;
- size_t entry_len = suffix_parse(*entry, strlen(*entry), &ro);
- /* If *entry is a prefix of the opened path, pass the open() through. */
- if (prefix_match(*entry, entry_len, buf, res.len)) {
- passthru = true;
- if (ro && OPEN_WRITEABLE(res.flags))
- error = true;
- break;
- }
- /* If the path is a prefix of *entry, we might need to inject a directory. */
- if (prefix_match(buf, res.len, *entry, entry_len)) {
- inject = true;
- }
- }
- if (error) {
- _sys_fs_respond(reqh, NULL, -EACCES, 0);
- } else if (passthru) {
- forward_open(reqh, buf, res.len, res.flags);
- } else if (inject) {
- // TODO all the inject points could be precomputed
- ipath = malloc(res.len + 1);
- memcpy(ipath, buf, res.len);
- ipath[res.len] = '\0';
- _sys_fs_respond(reqh, ipath, 0, 0);
- } else {
- _sys_fs_respond(reqh, NULL, -1, 0);
- }
- break;
- }
- case VFSOP_READ:
- case VFSOP_GETSIZE: {
- struct dirbuild db;
- size_t ilen = strlen(ipath);
- char *target = res.op == VFSOP_READ ? buf : NULL;
- dir_start(&db, res.offset, target, buflen);
- for (const char **entry = whitelist; *entry; entry++) {
- // TODO could be precomputed too
- size_t elen = suffix_parse(*entry, strlen(*entry), NULL);
- if (ilen < elen && !memcmp(ipath, *entry, ilen))
- dir_appendl(&db, *entry + ilen, dir_seglen2(*entry + ilen, elen - ilen));
- }
- _sys_fs_respond(reqh, target, dir_finish(&db), 0);
- break;
- }
- case VFSOP_CLOSE: {
- free(ipath);
- _sys_fs_respond(reqh, NULL, 0, 0);
- break;
- }
- default: {
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- }
- exit(0);
-}