summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/user/app/tmpfs/tmpfs.c61
1 files changed, 38 insertions, 23 deletions
diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c
index ed3c2e3..2594813 100644
--- a/src/user/app/tmpfs/tmpfs.c
+++ b/src/user/app/tmpfs/tmpfs.c
@@ -1,6 +1,7 @@
#include <camellia/fsutil.h>
#include <camellia/syscalls.h>
#include <shared/mem.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
@@ -8,19 +9,21 @@
struct node {
const char *name;
+ bool directory;
size_t namelen;
- struct node *next;
+ struct node *sibling, *child;
char *buf;
size_t size, capacity;
};
struct node *root = NULL;
static struct node special_root = {
+ .directory = true,
.size = 0,
};
-static struct node *lookup(const char *path, size_t len) {
- for (struct node *iter = root; iter; iter = iter->next) {
+static struct node *lookup(struct node *parent, const char *path, size_t len) {
+ for (struct node *iter = parent->child; iter; iter = iter->sibling) {
if (iter->namelen == len && !memcmp(path, iter->name, len))
return iter;
}
@@ -28,28 +31,39 @@ static struct node *lookup(const char *path, size_t len) {
}
static struct node *tmpfs_open(const char *path, struct fs_wait_response *res) {
- struct node *node;
+ struct node *node = &special_root;
if (res->len == 0) return NULL;
+ if (res->len == 1) return node;
path++;
res->len--;
- if (res->len == 0) return &special_root;
+ bool more = true;
+ size_t segpos = 0, seglen; /* segments end with a slash, inclusive */
+ while (more) {
+ struct node *const parent = node;
+ char *slash = memchr(path + segpos, '/', res->len);
+ seglen = (slash ? (size_t)(slash - path + 1) : res->len) - segpos;
+ more = segpos + seglen < res->len;
- // no directory support (yet)
- if (memchr(path, '/', res->len)) return NULL;
+ node = lookup(parent, path + segpos, seglen);
+ if (!node) {
+ if (!more && (res->flags & OPEN_CREATE)) {
+ node = malloc(sizeof *node);
+ memset(node, 0, sizeof *node);
- node = lookup(path, res->len);
- if (!node && (res->flags & OPEN_CREATE)) {
- node = malloc(sizeof *node);
- memset(node, 0, sizeof *node);
-
- char *namebuf = malloc(res->len + 1);
- memcpy(namebuf, path, res->len);
- namebuf[res->len] = '\0';
- node->name = namebuf;
- node->namelen = res->len;
- node->next = root;
- root = node;
+ char *namebuf = malloc(seglen + 1);
+ memcpy(namebuf, path + segpos, seglen);
+ namebuf[seglen] = '\0';
+ node->name = namebuf;
+ node->directory = slash;
+ node->namelen = seglen;
+ node->sibling = parent->child;
+ parent->child = node;
+ } else {
+ return NULL;
+ }
+ }
+ segpos += seglen;
}
return node;
}
@@ -68,10 +82,10 @@ int main(void) {
case VFSOP_READ:
ptr = (void*)res.id;
- if (ptr == &special_root) {
+ if (ptr->directory) {
struct dirbuild db;
dir_start(&db, res.offset, buf, buflen);
- for (struct node *iter = root; iter; iter = iter->next)
+ for (struct node *iter = ptr->child; iter; iter = iter->sibling)
dir_append(&db, iter->name);
_syscall_fs_respond(buf, dir_finish(&db), 0);
} else {
@@ -118,10 +132,11 @@ int main(void) {
case VFSOP_GETSIZE:
ptr = (void*)res.id;
- if (ptr == &special_root) {
+ if (ptr->directory) {
+ // TODO could be cached in ptr->size
struct dirbuild db;
dir_start(&db, res.offset, NULL, buflen);
- for (struct node *iter = root; iter; iter = iter->next)
+ for (struct node *iter = ptr->child; iter; iter = iter->sibling)
dir_append(&db, iter->name);
_syscall_fs_respond(NULL, dir_finish(&db), 0);
} else {