summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel/fd.c8
-rw-r--r--src/kernel/fd.h4
-rw-r--r--src/kernel/syscalls.c11
-rw-r--r--src/kernel/vfs/mount.h2
4 files changed, 24 insertions, 1 deletions
diff --git a/src/kernel/fd.c b/src/kernel/fd.c
index 77fea05..810cdb7 100644
--- a/src/kernel/fd.c
+++ b/src/kernel/fd.c
@@ -7,8 +7,11 @@ static int fdop_special_tty(struct fdop_args *args);
int fdop_dispatch(struct fdop_args args) {
switch(args.fd->type) {
- case FD_EMPTY:
+ case FD_EMPTY: {
+ if (args.type == FDOP_MOUNT) // mounting an empty fd is allowed
+ return 0;
return -1;
+ }
case FD_SPECIAL_TTY:
return fdop_special_tty(&args);
default:
@@ -18,6 +21,9 @@ int fdop_dispatch(struct fdop_args args) {
static int fdop_special_tty(struct fdop_args *args) {
switch(args->type) {
+ case FDOP_MOUNT:
+ return 0; // no special action needed
+
case FDOP_READ:
return -1; // input not implemented yet
diff --git a/src/kernel/fd.h b/src/kernel/fd.h
index b35c979..bcc9902 100644
--- a/src/kernel/fd.h
+++ b/src/kernel/fd.h
@@ -17,6 +17,7 @@ struct fd {
enum fdop { // describes the operations which can be done on file descriptors
+ FDOP_MOUNT, // also closes the original fd
FDOP_READ,
FDOP_WRITE,
FDOP_CLOSE,
@@ -26,6 +27,9 @@ struct fdop_args {
enum fdop type;
struct fd *fd;
union {
+ struct { // FDOP_MOUNT
+ struct mount *target;
+ } mnt;
struct { // FDOP_READ, FDOP_WRITE
user_ptr ptr;
size_t len;
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index bf17fd3..737484d 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -104,8 +104,10 @@ int _syscall_fd_mount(fd_t fd, const user_ptr path, int len) {
struct virt_iter iter;
struct vfs_mount *mount;
char *path_buf;
+ int res;
if (len > PATH_MAX) return -1;
+ if (fd < 0 || fd >= FD_MAX) return -1;
// copy the path to the kernel
path_buf = kmalloc(len);
@@ -124,10 +126,19 @@ int _syscall_fd_mount(fd_t fd, const user_ptr path, int len) {
mount->prev = process_current->mount;
mount->prefix = path_buf;
mount->prefix_len = len;
+ memcpy(&mount->fd, &process_current->fds[fd], sizeof(struct fd));
+
+ res = fdop_dispatch((struct fdop_args){
+ .type = FDOP_MOUNT,
+ .fd = &process_current->fds[fd],
+ .mnt = {mount},
+ });
+ if (res < 0) goto fail;
process_current->mount = mount;
return 0;
fail:
kfree(path_buf);
+ kfree(mount);
return -1;
}
diff --git a/src/kernel/vfs/mount.h b/src/kernel/vfs/mount.h
index b99f97e..3e9d8ae 100644
--- a/src/kernel/vfs/mount.h
+++ b/src/kernel/vfs/mount.h
@@ -1,7 +1,9 @@
#pragma once
+#include <kernel/fd.h>
struct vfs_mount {
struct vfs_mount *prev;
char *prefix;
size_t prefix_len;
+ struct fd fd;
};