#include "Log.h" #include "fs/VFS.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include // These flags are needed after open(), the rest only affect open(). constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND; Result sys_open(Registers*, SyscallArgs args) { u64 path_address = args[0]; if (!MemoryManager::validate_userspace_string(path_address)) return err(EFAULT); const char* path = (const char*)path_address; int flags = (int)args[1]; Thread* current = Scheduler::current(); kinfoln("open: trying to open file %s, flags %d", path, flags); SharedPtr inode; // Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR if ((flags & O_RDWR) == 0) { return err(EINVAL); } auto maybe_inode = VFS::resolve_path(path); if (maybe_inode.has_error()) { if (maybe_inode.error() == ENOENT && (flags & O_CREAT)) inode = TRY(VFS::create_file(path)); else return maybe_inode.release_error(); } else if (flags & O_EXCL) return err(EEXIST); else inode = maybe_inode.release_value(); if ((flags & O_WRONLY) && (flags & O_TRUNC)) inode->truncate(0); int fd = TRY(current->allocate_fd(0)); current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP }; kinfoln("open: allocated file descriptor %d for inode %zu", fd, inode->inode_number()); return (u64)fd; } Result sys_close(Registers*, SyscallArgs args) { int fd = (int)args[0]; if (fd < 0 || fd >= FD_MAX) return err(EBADF); Thread* current = Scheduler::current(); Option& descriptor = current->fd_table[fd]; if (!descriptor.has_value()) return err(EBADF); kinfoln("close: closing file descriptor %d (was referencing inode %zu)", fd, descriptor->inode->inode_number()); descriptor = {}; return 0; }