From e0c7bad47a54d865ef6194643e2cd20f6094e507 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Fri, 6 Jan 2023 20:45:30 +0100
Subject: kernel: turn the NULLFS into an always present special handle

preparing for HANDLE_PROCFS
---
 src/kernel/proc.c                   | 14 ++++++++++++--
 src/kernel/syscalls.c               | 12 +++++-------
 src/shared/include/camellia/flags.h |  4 ++++
 src/user/app/shell/shell.c          |  7 +++++++
 4 files changed, 28 insertions(+), 9 deletions(-)

(limited to 'src')

diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 85992d5..6bc7754 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -287,6 +287,14 @@ handle_t process_find_free_handle(struct process *proc, handle_t start_at) {
 }
 
 struct handle *process_handle_get(struct process *p, handle_t id) {
+	if (id == HANDLE_NULLFS) {
+		static struct handle h = (struct handle){
+			.type = HANDLE_FS_FRONT,
+			.backend = NULL,
+			.refcount = 2,
+		};
+		return &h;
+	}
 	if (id < 0 || id >= HANDLE_MAX) return NULL;
 	return p->_handles[id];
 }
@@ -311,7 +319,7 @@ handle_t process_handle_dup(struct process *p, handle_t from, handle_t to) {
 
 	if (to == from) return to;
 	toh = &p->_handles[to];
-	fromh = (from >= 0 && from < HANDLE_MAX) ? p->_handles[from] : NULL;
+	fromh = process_handle_get(p, from);
 
 	if (*toh) handle_close(*toh);
 	*toh = fromh;
@@ -321,7 +329,9 @@ handle_t process_handle_dup(struct process *p, handle_t from, handle_t to) {
 }
 
 struct handle *process_handle_take(struct process *p, handle_t hid) {
-	if (hid < 0 || hid >= HANDLE_MAX) return NULL;
+	if (hid < 0 || hid >= HANDLE_MAX) {
+		return process_handle_get(p, hid);
+	}
 	struct handle *h = p->_handles[hid];
 	p->_handles[hid] = NULL;
 	return h;
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 88e98c6..2ace0f4 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -145,13 +145,11 @@ long _syscall_mount(handle_t hid, const char __user *path, long len) {
 		len--;
 	}
 
-	if (hid >= 0) { // mounting a real backend?
-		struct handle *handle = process_handle_get(process_current, hid);
-		if (!handle || handle->type != HANDLE_FS_FRONT)
-			goto fail;
-		backend = handle->backend;
-		backend->refcount++;
-	} // otherwise backend == NULL
+	struct handle *handle = process_handle_get(process_current, hid);
+	if (!handle || handle->type != HANDLE_FS_FRONT)
+		goto fail;
+	backend = handle->backend;
+	if (backend) backend->refcount++;
 
 	// append to mount list
 	// TODO move to kernel/vfs/mount.c
diff --git a/src/shared/include/camellia/flags.h b/src/shared/include/camellia/flags.h
index b7cc42d..632ac3e 100644
--- a/src/shared/include/camellia/flags.h
+++ b/src/shared/include/camellia/flags.h
@@ -27,3 +27,7 @@
  * The idea is that if all flags which allow modifying the filesystem state require
  * OPEN_WRITE to be set, filesystem handlers could just check for the OPEN_WRITE flag. */
 #define OPEN_CREATE 4
+
+
+/* special handles */
+#define HANDLE_NULLFS -2
diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c
index 909d625..8aa640b 100644
--- a/src/user/app/shell/shell.c
+++ b/src/user/app/shell/shell.c
@@ -46,6 +46,13 @@ void run_args(int argc, char **argv, struct redir *redir) {
 			exit(1);
 		}
 		return;
+	} else if (!strcmp(argv[0], "shadow")) {
+		if (argc < 2) {
+			fprintf(stderr, "shadow: missing path\n");
+		} else {
+			_syscall_mount(HANDLE_NULLFS, argv[1], strlen(argv[1]));
+		}
+		return;
 	} else if (!strcmp(argv[0], "cd")) {
 		if (chdir(argc > 1 ? argv[1] : "/") < 0)
 			perror("cd");
-- 
cgit v1.2.3