Luna/kernel/src/sys/open.cpp
apio b54a7f3a80
All checks were successful
continuous-integration/drone/push Build is passing
kernel+libc: Add O_* flags and parse them in open()
O_RDONLY, O_WRONLY, O_RDWR, O_TRUNC, O_CREAT and O_EXCL are fully implemented.

O_APPEND is partially implemented.

Other flags are not here yet.
2023-03-12 14:43:58 +01:00

68 lines
1.9 KiB
C++

#include "Log.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.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)
{
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<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);
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<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;
}