Luna/kernel/src/sys/open.cpp
apio d66506256d
All checks were successful
continuous-integration/drone/push Build is passing
kernel/VFS+libc: Introduce modes
2023-03-12 16:55:46 +01:00

75 lines
2.1 KiB
C++

#include "Log.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/modes.h>
#include <bits/open-flags.h>
// These flags are needed after open(), the rest only affect open().
constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND;
Result<u64> 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<VFS::Inode> 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<u64> sys_close(Registers*, SyscallArgs args)
{
int fd = (int)args[0];
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
Thread* current = Scheduler::current();
Option<FileDescriptor>& 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;
}