summaryrefslogtreecommitdiff
path: root/src/user/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/lib')
-rw-r--r--src/user/lib/fs/dirinject.c129
-rw-r--r--src/user/lib/fs/misc.c78
-rw-r--r--src/user/lib/include/camellia/fs/misc.h3
3 files changed, 133 insertions, 77 deletions
diff --git a/src/user/lib/fs/dirinject.c b/src/user/lib/fs/dirinject.c
new file mode 100644
index 0000000..9b08756
--- /dev/null
+++ b/src/user/lib/fs/dirinject.c
@@ -0,0 +1,129 @@
+#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
index c68d2be..2a39e9a 100644
--- a/src/user/lib/fs/misc.c
+++ b/src/user/lib/fs/misc.c
@@ -20,20 +20,6 @@ bool fork2_n_mount(const char *path) {
return false;
}
-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;
-}
-
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
@@ -41,7 +27,7 @@ void forward_open(hid_t reqh, const char *path, long len, int flags) {
* 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_dir_inject would be
+ * 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);
@@ -150,66 +136,6 @@ void fs_union(const char **list) {
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);
- 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;
- struct fs_dir_handle *data = res.id;
- switch (res.op) {
- struct dirbuild db;
- 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 = _sys_open(buf, res.len, res.flags);
- data->inject = path + res.len;
- data->inject_len = dir_seglen(data->inject);
- _sys_fs_respond(reqh, data, 0, 0);
- } else {
- forward_open(reqh, buf, res.len, res.flags);
- }
- break;
-
- case VFSOP_CLOSE:
- if (data->delegate >= 0)
- close(data->delegate);
- free(data);
- _sys_fs_respond(reqh, NULL, 0, 0);
- break;
-
- case VFSOP_READ:
- case VFSOP_GETSIZE:
- if (res.capacity > buflen)
- res.capacity = buflen;
- char *target = res.op == VFSOP_READ ? buf : NULL;
- dir_start(&db, res.offset, target, res.capacity);
- dir_appendl(&db, data->inject, data->inject_len);
- if (data->delegate >= 0)
- dir_append_from(&db, data->delegate);
- _sys_fs_respond(reqh, target, dir_finish(&db), 0);
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- exit(0);
-}
-
hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req) {
hid_t reqh;
for (;;) {
@@ -240,7 +166,7 @@ bool mount_at_pred(const char *path) {
if (strcmp("/", path) && !fork2_n_mount("/")) {
_klogf("%s: dir", path);
setproctitle("d'%s'", path);
- fs_dir_inject(path);
+ fs_dirinject(path);
exit(1);
}
return false; /* continue after the for loop */
diff --git a/src/user/lib/include/camellia/fs/misc.h b/src/user/lib/include/camellia/fs/misc.h
index c84c5b6..92679e9 100644
--- a/src/user/lib/include/camellia/fs/misc.h
+++ b/src/user/lib/include/camellia/fs/misc.h
@@ -10,7 +10,8 @@ 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);
+void fs_dirinject(const char *path);
+void fs_dirinject2(const char *injects[]);
bool mount_at_pred(const char *path);