From 12aee8d9c127a85105b3e8f24cbcebc61c2db3e4 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Thu, 11 Aug 2022 21:16:15 +0200
Subject: vfs: support for removing files

---
 src/user/app/shell/builtins.c | 36 ++++++++++++++++++++++++++++++++
 src/user/app/tmpfs/tmpfs.c    | 48 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 80 insertions(+), 4 deletions(-)

(limited to 'src/user/app')

diff --git a/src/user/app/shell/builtins.c b/src/user/app/shell/builtins.c
index efc427d..6611002 100644
--- a/src/user/app/shell/builtins.c
+++ b/src/user/app/shell/builtins.c
@@ -1,5 +1,6 @@
 #include "builtins.h"
 #include "shell.h"
+#include <camellia/path.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -135,6 +136,40 @@ static void cmd_ls(int argc, char **argv) {
 	}
 }
 
+static void cmd_rm(int argc, char **argv) {
+	if (argc < 2) {
+		eprintf("no arguments");
+		return;
+	}
+	const size_t buflen = PATH_MAX;
+	char *buf = malloc(buflen);
+	for (int i = 1; i < argc; i++) {
+		handle_t h;
+		long ret;
+		size_t abslen;
+		char *path = argv[i];
+		if (*path == '\0') {
+			eprintf("ignoring empty argument");
+			continue;
+		}
+		abslen = absolutepath(buf, path, buflen);
+		if (!abslen) {
+			eprintf("invalid path %s", path);
+			continue;
+		}
+		h = _syscall_open(buf, abslen - 1, 0);
+		if (h < 0) {
+			eprintf("couldn't open %s (err %u)", path, -h);
+			continue;
+		}
+		ret = _syscall_remove(h);
+		if (ret < 0) {
+			eprintf("couldn't remove %s (err %u)", path, -ret);
+			continue;
+		}
+	}
+}
+
 static void cmd_sleep(int argc, char **argv) {
 	if (argc < 2) {
 		eprintf("no arguments");
@@ -177,6 +212,7 @@ struct builtin builtins[] = {
 	{"getsize", cmd_getsize},
 	{"hexdump", cmd_hexdump},
 	{"ls", cmd_ls},
+	{"rm", cmd_rm},
 	{"sleep", cmd_sleep},
 	{"touch", cmd_touch},
 	{"whitelist", cmd_whitelist},
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;
-- 
cgit v1.2.3