summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel/arch/amd64/driver/fsroot.c2
-rw-r--r--src/kernel/syscalls.c27
-rw-r--r--src/shared/include/camellia/errno.h1
-rw-r--r--src/shared/include/camellia/syscalls.h2
-rw-r--r--src/shared/include/camellia/types.h1
-rw-r--r--src/user/app/shell/builtins.c36
-rw-r--r--src/user/app/tmpfs/tmpfs.c48
-rw-r--r--src/user/lib/syscall.c4
8 files changed, 115 insertions, 6 deletions
diff --git a/src/kernel/arch/amd64/driver/fsroot.c b/src/kernel/arch/amd64/driver/fsroot.c
index 7856fba..3bbf2d1 100644
--- a/src/kernel/arch/amd64/driver/fsroot.c
+++ b/src/kernel/arch/amd64/driver/fsroot.c
@@ -25,7 +25,7 @@ static int handle(struct vfs_request *req) {
// TODO getsize for the other kernel provided directories
case VFSOP_GETSIZE: return sizeof dir;
- default: return 0;
+ default: return -ENOSYS;
}
}
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 5dca49f..288aa1e 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -266,7 +266,7 @@ long _syscall_write(handle_t handle_num, const void __user *buf, size_t len, lon
long _syscall_getsize(handle_t hid) {
struct handle *h = process_handle_get(process_current, hid);
if (!h) SYSCALL_RETURN(-1);
- if (h->type != HANDLE_FILE) SYSCALL_RETURN(-2);
+ if (h->type != HANDLE_FILE) SYSCALL_RETURN(-ENOSYS);
vfsreq_create((struct vfs_request) {
.type = VFSOP_GETSIZE,
.id = h->file_id,
@@ -276,6 +276,28 @@ long _syscall_getsize(handle_t hid) {
return -1; // dummy
}
+long _syscall_remove(handle_t hid) {
+ if (hid < 0 || hid >= HANDLE_MAX) return -1;
+ struct handle **hslot = &process_current->handles[hid];
+ struct handle *h = *hslot;
+ if (!h) SYSCALL_RETURN(-1);
+ if (h->type == HANDLE_FILE) {
+ vfsreq_create((struct vfs_request) {
+ .type = VFSOP_REMOVE,
+ .id = h->file_id,
+ .caller = process_current,
+ .backend = h->backend,
+ });
+ handle_close(*hslot);
+ *hslot = NULL;
+ return -1; // dummy
+ } else {
+ handle_close(*hslot);
+ *hslot = NULL;
+ SYSCALL_RETURN(-ENOSYS);
+ }
+}
+
long _syscall_close(handle_t hid) {
if (hid < 0 || hid >= HANDLE_MAX) return -1;
struct handle **h = &process_current->handles[hid];
@@ -441,6 +463,9 @@ long _syscall(long num, long a, long b, long c, long d, long e) {
case _SYSCALL_GETSIZE:
_syscall_getsize(a);
break;
+ case _SYSCALL_REMOVE:
+ _syscall_remove(a);
+ break;
case _SYSCALL_CLOSE:
_syscall_close(a);
break;
diff --git a/src/shared/include/camellia/errno.h b/src/shared/include/camellia/errno.h
index 5a9e743..e352015 100644
--- a/src/shared/include/camellia/errno.h
+++ b/src/shared/include/camellia/errno.h
@@ -7,3 +7,4 @@
#define ERANGE 6
#define ENOMEM 7
#define ENOENT 8
+#define ENOTEMPTY 9
diff --git a/src/shared/include/camellia/syscalls.h b/src/shared/include/camellia/syscalls.h
index ade75a5..b6c93fe 100644
--- a/src/shared/include/camellia/syscalls.h
+++ b/src/shared/include/camellia/syscalls.h
@@ -21,6 +21,7 @@ enum {
_SYSCALL_READ,
_SYSCALL_WRITE,
_SYSCALL_GETSIZE,
+ _SYSCALL_REMOVE,
_SYSCALL_CLOSE,
_SYSCALL_FS_FORK2,
@@ -65,6 +66,7 @@ handle_t _syscall_dup(handle_t from, handle_t to, int flags);
long _syscall_read(handle_t h, void __user *buf, size_t len, long offset);
long _syscall_write(handle_t h, const void __user *buf, size_t len, long offset, int flags);
long _syscall_getsize(handle_t h);
+long _syscall_remove(handle_t h);
long _syscall_close(handle_t h);
struct fs_wait_response {
diff --git a/src/shared/include/camellia/types.h b/src/shared/include/camellia/types.h
index cb17b3a..622d705 100644
--- a/src/shared/include/camellia/types.h
+++ b/src/shared/include/camellia/types.h
@@ -17,5 +17,6 @@ enum vfs_operation {
VFSOP_READ,
VFSOP_WRITE,
VFSOP_GETSIZE,
+ VFSOP_REMOVE,
VFSOP_CLOSE,
};
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;
diff --git a/src/user/lib/syscall.c b/src/user/lib/syscall.c
index e22f718..1635636 100644
--- a/src/user/lib/syscall.c
+++ b/src/user/lib/syscall.c
@@ -42,6 +42,10 @@ long _syscall_getsize(handle_t h) {
return _syscall(_SYSCALL_GETSIZE, (long)h, 0, 0, 0, 0);
}
+long _syscall_remove(handle_t h) {
+ return _syscall(_SYSCALL_REMOVE, (long)h, 0, 0, 0, 0);
+}
+
long _syscall_close(handle_t h) {
return _syscall(_SYSCALL_CLOSE, (long)h, 0, 0, 0, 0);
}