summaryrefslogtreecommitdiff
path: root/src/user/app/tmpfs
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/app/tmpfs')
-rw-r--r--src/user/app/tmpfs/tmpfs.c48
1 files changed, 44 insertions, 4 deletions
diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c
index 2594813..9bc3d6c 100644
--- a/src/user/app/tmpfs/tmpfs.c
+++ b/src/user/app/tmpfs/tmpfs.c
@@ -1,5 +1,6 @@
#include <camellia/fsutil.h>
#include <camellia/syscalls.h>
+#include <errno.h>
#include <shared/mem.h>
#include <stdbool.h>
#include <stddef.h>
@@ -11,12 +12,16 @@ struct node {
const char *name;
bool directory;
size_t namelen;
- struct node *sibling, *child;
char *buf;
size_t size, capacity;
+ size_t open; /* amount of open handles */
+
+ struct node *sibling, *child;
+ /* each node except special_root has exacly one sibling or child reference to it
+ * on remove(), it gets replaced with *sibling. */
+ struct node **ref;
};
-struct node *root = NULL;
static struct node special_root = {
.directory = true,
.size = 0,
@@ -57,17 +62,41 @@ static struct node *tmpfs_open(const char *path, struct fs_wait_response *res) {
node->name = namebuf;
node->directory = slash;
node->namelen = seglen;
- node->sibling = parent->child;
- parent->child = node;
+
+ if (parent->child) {
+ parent->child->ref = &node->sibling;
+ *parent->child->ref = parent->child;
+ }
+ node->ref = &parent->child;
+ *node->ref = node;
} else {
return NULL;
}
}
segpos += seglen;
}
+ node->open++;
return node;
}
+static void handle_down(struct node *node) {
+ node->open--;
+ if (!node->ref && node != &special_root && node->open == 0) {
+ free(node->buf);
+ free(node);
+ }
+}
+
+static long remove_node(struct node *node) {
+ if (node == &special_root) return -1;
+ if (!node->ref) return -1;
+ if (node->child) return -ENOTEMPTY;
+ *node->ref = node->sibling;
+ node->ref = NULL;
+ handle_down(node);
+ return 0;
+}
+
int main(void) {
const size_t buflen = 4096;
char *buf = malloc(buflen);
@@ -144,6 +173,17 @@ int main(void) {
}
break;
+ case VFSOP_REMOVE:
+ ptr = (void*)res.id;
+ _syscall_fs_respond(NULL, remove_node(ptr), 0);
+ break;
+
+ case VFSOP_CLOSE:
+ ptr = (void*)res.id;
+ handle_down(ptr);
+ _syscall_fs_respond(NULL, -1, 0);
+ break;
+
default:
_syscall_fs_respond(NULL, -1, 0);
break;