Luna/kernel/src/sys/open.cpp

75 lines
2.1 KiB
C++
Raw Normal View History

#include "Log.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
2023-03-12 15:55:46 +00:00
#include <bits/modes.h>
#include <bits/open-flags.h>
// These flags are needed after open(), the rest only affect open().
2023-03-24 20:19:24 +00:00
constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND | O_NONBLOCK | O_CLOEXEC;
Result<u64> sys_open(Registers*, SyscallArgs args)
{
2023-03-12 15:30:36 +00:00
auto path = TRY(MemoryManager::strdup_from_user(args[0]));
int flags = (int)args[1];
2023-03-12 15:55:46 +00:00
mode_t mode = (mode_t)args[2];
Thread* current = Scheduler::current();
2023-03-12 15:30:36 +00:00
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); }
2023-03-12 15:30:36 +00:00
auto maybe_inode = VFS::resolve_path(path.chars());
if (maybe_inode.has_error())
{
2023-03-12 15:55:46 +00:00
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
2023-03-12 15:55:46 +00:00
{
inode = maybe_inode.release_value();
2023-03-12 15:55:46 +00:00
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];
2023-03-11 17:02:50 +00:00
if (!descriptor.has_value()) return err(EBADF);
2023-03-11 17:02:50 +00:00
kinfoln("close: closing file descriptor %d (was referencing inode %zu)", fd, descriptor->inode->inode_number());
descriptor = {};
return 0;
}