#include "Log.h" #include "fs/VFS.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include #include // These flags are needed after open(), the rest only affect open(). constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND | O_NONBLOCK; Result sys_open(Registers*, SyscallArgs args) { auto path = TRY(MemoryManager::strdup_from_user(args[0])); int flags = (int)args[1]; mode_t mode = (mode_t)args[2]; Thread* current = Scheduler::current(); kinfoln("open: trying to open file %s, flags %d", path.chars(), 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.chars()); if (maybe_inode.has_error()) { if (maybe_inode.error() == ENOENT && (flags & O_CREAT)) { inode = TRY(VFS::create_file(path.chars())); inode->chmod(mode); } else return maybe_inode.release_error(); } else if (flags & O_EXCL) return err(EEXIST); else { inode = maybe_inode.release_value(); if ((flags & O_RDONLY) && (inode->mode() & S_IRUSR) == 0) return err(EACCES); if ((flags & O_WRONLY) && (inode->mode() & S_IWUSR) == 0) return err(EACCES); } 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; }