2023-03-11 16:45:20 +00:00
|
|
|
#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>
|
2023-03-12 13:43:58 +00:00
|
|
|
#include <bits/open-flags.h>
|
|
|
|
|
|
|
|
// These flags are needed after open(), the rest only affect open().
|
2023-03-19 10:25:14 +00:00
|
|
|
constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND | O_NONBLOCK;
|
2023-03-11 16:45:20 +00:00
|
|
|
|
|
|
|
Result<u64> sys_open(Registers*, SyscallArgs args)
|
|
|
|
{
|
2023-03-12 15:30:36 +00:00
|
|
|
auto path = TRY(MemoryManager::strdup_from_user(args[0]));
|
2023-03-11 16:45:20 +00:00
|
|
|
int flags = (int)args[1];
|
2023-03-12 15:55:46 +00:00
|
|
|
mode_t mode = (mode_t)args[2];
|
2023-03-11 16:45:20 +00:00
|
|
|
|
|
|
|
Thread* current = Scheduler::current();
|
|
|
|
|
2023-03-12 15:30:36 +00:00
|
|
|
kinfoln("open: trying to open file %s, flags %d", path.chars(), flags);
|
2023-03-11 16:45:20 +00:00
|
|
|
|
2023-03-12 13:43:58 +00:00
|
|
|
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());
|
2023-03-12 13:43:58 +00:00
|
|
|
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);
|
|
|
|
}
|
2023-03-12 13:43:58 +00:00
|
|
|
else
|
|
|
|
return maybe_inode.release_error();
|
|
|
|
}
|
|
|
|
else if (flags & O_EXCL)
|
|
|
|
return err(EEXIST);
|
|
|
|
else
|
2023-03-12 15:55:46 +00:00
|
|
|
{
|
2023-03-12 13:43:58 +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);
|
|
|
|
}
|
2023-03-12 13:43:58 +00:00
|
|
|
|
|
|
|
if ((flags & O_WRONLY) && (flags & O_TRUNC)) inode->truncate(0);
|
2023-03-11 16:45:20 +00:00
|
|
|
|
|
|
|
int fd = TRY(current->allocate_fd(0));
|
|
|
|
|
2023-03-12 13:43:58 +00:00
|
|
|
current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP };
|
2023-03-11 16:45:20 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2023-03-12 12:57:38 +00:00
|
|
|
Option<FileDescriptor>& descriptor = current->fd_table[fd];
|
2023-03-11 16:45:20 +00:00
|
|
|
|
2023-03-11 17:02:50 +00:00
|
|
|
if (!descriptor.has_value()) return err(EBADF);
|
2023-03-11 16:45:20 +00:00
|
|
|
|
2023-03-11 17:02:50 +00:00
|
|
|
kinfoln("close: closing file descriptor %d (was referencing inode %zu)", fd, descriptor->inode->inode_number());
|
|
|
|
|
|
|
|
descriptor = {};
|
2023-03-11 16:45:20 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|