From 9b945d2bc00e190916088243d41eb999b57a6a00 Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 6 Jul 2023 14:01:12 -0300 Subject: [PATCH] syscalls: linkat --- kernel-src/arch/x86-64/syscall.asm | 4 +- kernel-src/arch/x86-64/syscalllog.c | 8 ++-- kernel-src/include/kernel/syscalls.h | 31 +++++++++++++ kernel-src/sys/syscalls/linkat.c | 61 ++++++++++++++++++++++++++ patches/mlibc/jinx-working-patch.patch | 32 +++++++++++--- 5 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 kernel-src/sys/syscalls/linkat.c diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index 54219254..b512e718 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -28,6 +28,7 @@ extern syscall_unlinkat extern syscall_ioctl extern syscall_mkdirat extern syscall_clockget +extern syscall_linkat syscalltab: dq syscall_print dq syscall_mmap @@ -58,7 +59,8 @@ dq syscall_unlinkat dq syscall_ioctl dq syscall_mkdirat dq syscall_clockget -syscallcount equ 29 +dq syscall_linkat +syscallcount equ 30 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index 825d419f..215a0a6e 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -4,7 +4,7 @@ #ifdef SYSCALL_LOGGING -#define SYSCALL_COUNT 29 +#define SYSCALL_COUNT 30 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -36,7 +36,8 @@ static char *name[] = { "unlinkat", "ioctl", "mkdirat", - "clockget" + "clockget", + "linkat" }; static char *args[] = { @@ -68,7 +69,8 @@ static char *args[] = { "dirfd %d pathname %d flags %d", // unlinkat "fd %d request %lu argument %d", // ioctl "dirfd %d path %s mode %o", // mkdirat - "clockid %d timespec %p" // clockget + "clockid %d timespec %p", // clockget + "olddirfd %d oldpath %s newdirfd %d oldpath %s flags %d type %d" // linkat }; #endif diff --git a/kernel-src/include/kernel/syscalls.h b/kernel-src/include/kernel/syscalls.h index 9285b20f..5d695e5a 100644 --- a/kernel-src/include/kernel/syscalls.h +++ b/kernel-src/include/kernel/syscalls.h @@ -3,10 +3,41 @@ #include #include +#include +#include +#include typedef struct { uint64_t ret; uint64_t errno; } syscallret_t; +static inline int dirfd_enter(char *path, int dirfd, file_t **file, vnode_t **dirnode) { + if (*path == '/') { + *dirnode = sched_getroot(); + } else if (dirfd == AT_FDCWD) { + *dirnode = sched_getcwd(); + } else { + *file = fd_get(dirfd); + if (file == NULL) { + return EBADF; + } + + *dirnode = (*file)->vnode; + + if ((*dirnode)->type != V_TYPE_DIR) { + fd_release(*file); + return ENOTDIR; + } + } + return 0; +} + +static inline void dirfd_leave(vnode_t *dirnode, file_t *file) { + if (file) + fd_release(file); + else + VOP_RELEASE(dirnode); +} + #endif diff --git a/kernel-src/sys/syscalls/linkat.c b/kernel-src/sys/syscalls/linkat.c new file mode 100644 index 00000000..a117cea1 --- /dev/null +++ b/kernel-src/sys/syscalls/linkat.c @@ -0,0 +1,61 @@ +#include +#include + + +syscallret_t syscall_linkat(context_t *, int olddirfd, const char *uoldpath, int newdirfd, const char *unewpath, int flags, int type) { + syscallret_t ret = { + .ret = -1 + }; + + char *oldpath = alloc(strlen(uoldpath) + 1); + if (oldpath == NULL) { + ret.errno = ENOMEM; + return ret; + } + + char *newpath = alloc(strlen(unewpath) + 1); + if (newpath == NULL) { + free(oldpath); + ret.errno = ENOMEM; + return ret; + } + + // TODO safe strcopy + strcpy(oldpath, uoldpath); + strcpy(newpath, unewpath); + + vnode_t *olddirnode = NULL; + file_t *oldfile = NULL; + vnode_t *newdirnode = NULL; + file_t *newfile = NULL; + ret.errno = dirfd_enter(oldpath, olddirfd, &oldfile, &olddirnode); + + if (ret.errno) + goto cleanup; + + ret.errno = dirfd_enter(newpath, newdirfd, &newfile, &newdirnode); + + if (ret.errno) + goto cleanup; + + vattr_t attr = { + .gid = _cpu()->thread->proc->cred.gid, + .uid = _cpu()->thread->proc->cred.uid + }; + + ret.errno = vfs_link(olddirnode, oldpath, newdirnode, newpath, type == 0 ? V_TYPE_REGULAR : V_TYPE_LINK, &attr); + ret.ret = ret.errno ? -1 : 0; + + cleanup: + + if (olddirnode) + dirfd_leave(olddirnode, oldfile); + + if (newdirnode) + dirfd_leave(newdirnode, newfile); + + free(oldpath); + free(newpath); + + return ret; +} diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index 0d4ba146..3b097360 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -133,10 +133,10 @@ index 0000000..e5b087a + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 -index 0000000..97b963a +index 0000000..0b9a48b --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp -@@ -0,0 +1,301 @@ +@@ -0,0 +1,322 @@ +#include +#include +#include @@ -211,6 +211,27 @@ index 0000000..97b963a + return 0; + } + ++ static int dolink(int oldfd, const char *oldpath, int newfd, const char *newpath, int flags, int type) { ++ long ret; ++ return syscall(SYSCALL_LINKAT, &ret, oldfd, (uint64_t)oldpath, newfd, (uint64_t)newpath, flags, type); ++ } ++ ++ int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { ++ return dolink(olddirfd, old_path, newdirfd, new_path, flags, 0); ++ } ++ ++ int sys_link(const char *old_path, const char *new_path) { ++ return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); ++ } ++ ++ int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { ++ return dolink(AT_FDCWD, target_path, dirfd, link_path, 0, 1); ++ } ++ ++ int sys_symlink(const char *target_path, const char *link_path) { ++ return sys_symlinkat(target_path, AT_FDCWD, link_path); ++ } ++ + int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + long ret; + return syscall(SYSCALL_MKDIRAT, &ret, dirfd, (uint64_t)path, mode); @@ -309,7 +330,7 @@ index 0000000..97b963a + long ret; + switch (fsfdt) { + case fsfd_target::path: -+ return syscall(SYSCALL_FSTATAT, &ret, AT_FDCWD, (uint64_t)path, (uint64_t)statbuf, 0); ++ return syscall(SYSCALL_FSTATAT, &ret, AT_FDCWD, (uint64_t)path, (uint64_t)statbuf, flags); + case fsfd_target::fd: + return syscall(SYSCALL_FSTAT, &ret, fd, (uint64_t)statbuf); + case fsfd_target::fd_path: @@ -457,10 +478,10 @@ index 0000000..990eca0 +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 -index 0000000..96da753 +index 0000000..ee926b6 --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -0,0 +1,52 @@ +@@ -0,0 +1,53 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + @@ -493,6 +514,7 @@ index 0000000..96da753 +#define SYSCALL_IOCTL 26 +#define SYSCALL_MKDIRAT 27 +#define SYSCALL_CLOCKGET 28 ++#define SYSCALL_LINKAT 29 + +#include +#include