#include "Log.h" #include "fs/VFS.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include #include #include #include #include Result sys_read(Registers*, SyscallArgs args) { int fd = (int)args[0]; u8* buf = (u8*)args[1]; usize size = (usize)args[2]; if (!MemoryManager::validate_user_write(buf, size)) return err(EFAULT); Thread* current = Scheduler::current(); auto& descriptor = *TRY(current->resolve_fd(fd)); if (!descriptor.is_readable()) return err(EBADF); while (descriptor.inode->blocking()) { if (descriptor.should_block()) kernel_sleep(10); else return err(EAGAIN); } usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size)); descriptor.offset += nread; return nread; } Result sys_write(Registers*, SyscallArgs args) { int fd = (int)args[0]; const u8* buf = (const u8*)args[1]; usize size = (usize)args[2]; if (!MemoryManager::validate_user_read(buf, size)) return err(EFAULT); Thread* current = Scheduler::current(); auto& descriptor = *TRY(current->resolve_fd(fd)); if (!descriptor.is_writable()) return err(EBADF); if (descriptor.should_append()) descriptor.offset = descriptor.inode->size(); usize nwritten = TRY(descriptor.inode->write(buf, descriptor.offset, size)); descriptor.offset += nwritten; return nwritten; } Result sys_lseek(Registers*, SyscallArgs args) { int fd = (int)args[0]; off_t offset = (long)args[1]; int whence = (int)args[2]; Thread* current = Scheduler::current(); auto& descriptor = *TRY(current->resolve_fd(fd)); off_t new_offset; switch (whence) { case SEEK_SET: new_offset = offset; break; case SEEK_CUR: new_offset = TRY(safe_add((long)descriptor.offset, offset)); break; case SEEK_END: new_offset = TRY(safe_add((long)descriptor.inode->size(), offset)); break; default: return err(EINVAL); } if (new_offset < 0) return err(EINVAL); descriptor.offset = (usize)new_offset; return (u64)new_offset; } Result sys_fcntl(Registers*, SyscallArgs args) { int fd = (int)args[0]; int cmd = (int)args[1]; Thread* current = Scheduler::current(); auto& descriptor = *TRY(current->resolve_fd(fd)); bool is_cloexec = true; switch (cmd) { case F_DUPFD: is_cloexec = false; [[fallthrough]]; case F_DUPFD_CLOEXEC: { int arg = (int)args[2]; int new_fd = TRY(current->allocate_fd(arg)); current->fd_table[new_fd] = descriptor; if (is_cloexec) current->fd_table[new_fd]->flags |= O_CLOEXEC; else current->fd_table[new_fd]->flags &= ~O_CLOEXEC; return (u64)new_fd; } default: return err(EINVAL); } }