From 854f585e1acdc0f52b09bd6c8da1ff18d533d1b3 Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 12 Oct 2022 15:28:52 +0200 Subject: [PATCH] Kernel: Add a seek() system call Now, time for libc support!! --- kernel/include/fs/FileDescriptor.h | 11 +++++++ kernel/include/sys/Syscall.h | 4 ++- kernel/src/fs/FileDescriptor.cpp | 8 +++++ kernel/src/sys/Syscall.cpp | 1 + kernel/src/sys/stdio.cpp | 52 ++++++++++++++++++++++++++++-- 5 files changed, 72 insertions(+), 4 deletions(-) diff --git a/kernel/include/fs/FileDescriptor.h b/kernel/include/fs/FileDescriptor.h index 43a715aa..d9ff1480 100644 --- a/kernel/include/fs/FileDescriptor.h +++ b/kernel/include/fs/FileDescriptor.h @@ -29,6 +29,17 @@ struct Descriptor void open(VFS::Node* node, bool can_read, bool can_write); + int seek(long offset); + long offset() + { + return (long)m_offset; + } + + unsigned long length() + { + return m_node->length; + } + Descriptor(const Descriptor& other); Descriptor(); diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index 9b480eed..91f265f7 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -14,6 +14,7 @@ #define SYS_open 9 #define SYS_read 10 #define SYS_close 11 +#define SYS_seek 12 namespace Syscall { @@ -31,4 +32,5 @@ void sys_mmap(Context* context, void* address, size_t size, int flags); void sys_munmap(Context* context, void* address, size_t size); void sys_open(Context* context, const char* filename, int flags); void sys_read(Context* context, int fd, size_t size, char* buffer); -void sys_close(Context* context, int fd); \ No newline at end of file +void sys_close(Context* context, int fd); +void sys_seek(Context* context, int fd, long offset, int whence); \ No newline at end of file diff --git a/kernel/src/fs/FileDescriptor.cpp b/kernel/src/fs/FileDescriptor.cpp index 7a491403..2cf2b27d 100644 --- a/kernel/src/fs/FileDescriptor.cpp +++ b/kernel/src/fs/FileDescriptor.cpp @@ -1,4 +1,5 @@ #include "fs/FileDescriptor.h" +#include "errno.h" Descriptor::Descriptor() : m_is_open(false) { @@ -31,4 +32,11 @@ ssize_t Descriptor::write(size_t size, const char* buffer) ssize_t result = VFS::write(m_node, m_offset, size, buffer); m_offset += result; return result; +} + +int Descriptor::seek(long offset) +{ + if (m_node->type != VFS_DEVICE && offset > m_node->length) + return -EINVAL; // FIXME: Support seeking beyond the current file's length. + m_offset = (uint64_t)offset; } \ No newline at end of file diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index a1ed7f31..62469182 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -20,6 +20,7 @@ void Syscall::entry(Context* context) case SYS_open: sys_open(context, (const char*)context->rdi, (int)context->rsi); break; case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break; case SYS_close: sys_close(context, (int)context->rdi); break; + case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); default: context->rax = -ENOSYS; break; } } \ No newline at end of file diff --git a/kernel/src/sys/stdio.cpp b/kernel/src/sys/stdio.cpp index 6968747a..bf716d5f 100644 --- a/kernel/src/sys/stdio.cpp +++ b/kernel/src/sys/stdio.cpp @@ -11,8 +11,57 @@ #define OPEN_READ 1 #define OPEN_WRITE 2 +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + #define STDIO_FAIL(function, error) kwarnln("%s failed with %s", #function, #error) +void sys_seek(Context* context, int fd, long offset, int whence) +{ + if (whence < SEEK_SET || whence > SEEK_END) + { + STDIO_FAIL(seek, EINVAL); + context->rax = -EINVAL; + return; + } + if (fd >= TASK_MAX_FDS || fd < 0) + { + STDIO_FAIL(seek, EBADF); + context->rax = -EBADF; + return; + } + Task* current_task = Scheduler::current_task(); + if (!current_task->files[fd].is_open()) + { + STDIO_FAIL(seek, EBADF); + context->rax = -EBADF; + return; + } + long new_offset; + if (whence == SEEK_SET) new_offset = offset; + else if (whence == SEEK_CUR) + new_offset = offset + current_task->files[fd].offset(); + else if (whence == SEEK_END) + new_offset = current_task->files[fd].length() + offset; + else + __builtin_unreachable(); + if (new_offset < 0) + { + STDIO_FAIL(seek, EINVAL); + context->rax = -EINVAL; // FIXME: Is this the right error? + return; + } + int result = current_task->files[fd].seek(new_offset); + if (result < 0) + { + context->rax = result; + return; + } + context->rax = new_offset; + return; +} + void sys_write(Context* context, int fd, size_t size, const char* addr) { if (!addr) @@ -23,7 +72,6 @@ void sys_write(Context* context, int fd, size_t size, const char* addr) } if (fd >= TASK_MAX_FDS || fd < 0) { - kwarnln("file descriptor %d is outside the valid range", fd); STDIO_FAIL(write, EBADF); context->rax = -EBADF; return; @@ -31,14 +79,12 @@ void sys_write(Context* context, int fd, size_t size, const char* addr) Task* current_task = Scheduler::current_task(); if (!current_task->files[fd].is_open()) { - kwarnln("file descriptor %d is not open", fd); STDIO_FAIL(write, EBADF); context->rax = -EBADF; return; } if (!current_task->files[fd].can_write()) { - kwarnln("file descriptor %d is not open for writing", fd); STDIO_FAIL(write, EBADF); context->rax = -EBADF; return;