kernel: Introduce *at() syscall framework, add openat() and fstatat()
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
df95126ccd
commit
82e7b0e860
@ -15,6 +15,8 @@ namespace VFS
|
||||
|
||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, SharedPtr<Inode> working_directory)
|
||||
{
|
||||
if (*path == '\0') return err(ENOENT);
|
||||
|
||||
auto parser = TRY(PathParser::create(path));
|
||||
|
||||
SharedPtr<Inode> current_inode;
|
||||
|
@ -9,11 +9,12 @@
|
||||
// These flags are needed after open(), the rest only affect open().
|
||||
constexpr int FLAGS_TO_KEEP = O_RDWR | O_APPEND | O_NONBLOCK | O_CLOEXEC;
|
||||
|
||||
Result<u64> sys_open(Registers*, SyscallArgs args)
|
||||
Result<u64> sys_openat(Registers*, SyscallArgs args)
|
||||
{
|
||||
auto path = TRY(MemoryManager::strdup_from_user(args[0]));
|
||||
int flags = (int)args[1];
|
||||
mode_t mode = (mode_t)args[2];
|
||||
int dirfd = (int)args[0];
|
||||
auto path = TRY(MemoryManager::strdup_from_user(args[1]));
|
||||
int flags = (int)args[2];
|
||||
mode_t mode = (mode_t)args[3];
|
||||
|
||||
Thread* current = Scheduler::current();
|
||||
|
||||
@ -22,14 +23,16 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
|
||||
// Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR
|
||||
if ((flags & O_RDWR) == 0) { return err(EINVAL); }
|
||||
|
||||
if ((flags & O_DIRECTORY) & (flags & O_CREAT)) return err(EINVAL);
|
||||
|
||||
int error;
|
||||
bool ok =
|
||||
VFS::resolve_path(path.chars(), current->auth, current->current_directory).try_set_value_or_error(inode, error);
|
||||
SharedPtr<VFS::Inode> parent_inode;
|
||||
bool ok = current->resolve_atfile(dirfd, path, false, &parent_inode).try_set_value_or_error(inode, error);
|
||||
if (!ok)
|
||||
{
|
||||
if (error == ENOENT && (flags & O_CREAT))
|
||||
if (error == ENOENT && (flags & O_CREAT) && !path.is_empty())
|
||||
{
|
||||
inode = TRY(VFS::create_file(path.chars(), current->auth, current->current_directory));
|
||||
inode = TRY(VFS::create_file(path.chars(), current->auth, parent_inode));
|
||||
inode->chmod(mode);
|
||||
inode->chown(current->auth.euid, current->auth.egid);
|
||||
}
|
||||
@ -50,9 +53,9 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
|
||||
|
||||
int fd = TRY(current->allocate_fd(0));
|
||||
|
||||
current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP };
|
||||
kinfoln("openat: opening file %s from dirfd %d, flags %d, mode %#o = fd %d", path.chars(), dirfd, flags, mode, fd);
|
||||
|
||||
kinfoln("open: opening file %s, flags %d, mode %#o = fd %d", path.chars(), flags, mode, fd);
|
||||
current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP };
|
||||
|
||||
return (u64)fd;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "sys/Syscall.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include <bits/atfile.h>
|
||||
#include <bits/modes.h>
|
||||
#include <bits/struct_stat.h>
|
||||
|
||||
@ -19,8 +20,17 @@ static mode_t make_mode(mode_t mode, VFS::InodeType type)
|
||||
return result;
|
||||
}
|
||||
|
||||
static Result<u64> do_stat(SharedPtr<VFS::Inode> inode, stat* st)
|
||||
Result<u64> sys_fstatat(Registers*, SyscallArgs args)
|
||||
{
|
||||
int dirfd = (int)args[0];
|
||||
auto path = TRY(MemoryManager::strdup_from_user(args[1]));
|
||||
stat* st = (stat*)args[2];
|
||||
int flags = (int)args[3];
|
||||
|
||||
Thread* current = Scheduler::current();
|
||||
|
||||
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH));
|
||||
|
||||
stat kstat;
|
||||
|
||||
kstat.st_ino = inode->inode_number();
|
||||
@ -34,27 +44,3 @@ static Result<u64> do_stat(SharedPtr<VFS::Inode> inode, stat* st)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result<u64> sys_stat(Registers*, SyscallArgs args)
|
||||
{
|
||||
auto path = TRY(MemoryManager::strdup_from_user(args[0]));
|
||||
stat* st = (stat*)args[1];
|
||||
|
||||
Thread* current = Scheduler::current();
|
||||
|
||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||
|
||||
return do_stat(inode, st);
|
||||
}
|
||||
|
||||
Result<u64> sys_fstat(Registers*, SyscallArgs args)
|
||||
{
|
||||
int fd = (int)args[0];
|
||||
stat* st = (stat*)args[1];
|
||||
|
||||
Thread* current = Scheduler::current();
|
||||
|
||||
auto descriptor = *TRY(current->resolve_fd(fd));
|
||||
|
||||
return do_stat(descriptor.inode, st);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
#include "thread/Thread.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include <bits/atfile.h>
|
||||
#include <bits/open-flags.h>
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/Atomic.h>
|
||||
#include <luna/PathParser.h>
|
||||
|
||||
static Atomic<u64> g_next_id;
|
||||
|
||||
@ -45,6 +48,24 @@ Result<FileDescriptor*> Thread::resolve_fd(int fd)
|
||||
return maybe_descriptor.value_ptr();
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> Thread::resolve_atfile(int dirfd, const String& path, bool allow_empty_path,
|
||||
SharedPtr<VFS::Inode>* parent_inode)
|
||||
{
|
||||
if (parent_inode) *parent_inode = this->current_directory;
|
||||
|
||||
if (PathParser::is_absolute(path.view())) return VFS::resolve_path(path.chars(), this->auth);
|
||||
|
||||
if (dirfd == AT_FDCWD) return VFS::resolve_path(path.chars(), this->auth, this->current_directory);
|
||||
|
||||
auto descriptor = TRY(resolve_fd(dirfd));
|
||||
|
||||
if (parent_inode) *parent_inode = descriptor->inode;
|
||||
|
||||
if (path.is_empty() && allow_empty_path) return descriptor->inode;
|
||||
|
||||
return VFS::resolve_path(path.chars(), this->auth, descriptor->inode);
|
||||
}
|
||||
|
||||
bool FileDescriptor::should_append()
|
||||
{
|
||||
return flags & O_APPEND;
|
||||
|
@ -73,6 +73,8 @@ struct Thread : public LinkedListNode<Thread>
|
||||
|
||||
Result<int> allocate_fd(int min);
|
||||
Result<FileDescriptor*> resolve_fd(int fd);
|
||||
Result<SharedPtr<VFS::Inode>> resolve_atfile(int dirfd, const String& path, bool allow_empty_path,
|
||||
SharedPtr<VFS::Inode>* parent_inode = nullptr);
|
||||
|
||||
FPData fp_data;
|
||||
|
||||
|
10
libc/include/bits/atfile.h
Normal file
10
libc/include/bits/atfile.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* bits/atfile.h: Definitions for *at() functions. */
|
||||
|
||||
#ifndef _BITS_ATFILE_H
|
||||
#define _BITS_ATFILE_H
|
||||
|
||||
#define AT_FDCWD -100
|
||||
|
||||
#define AT_EMPTY_PATH 1
|
||||
|
||||
#endif
|
@ -3,6 +3,7 @@
|
||||
#ifndef _FCNTL_H
|
||||
#define _FCNTL_H
|
||||
|
||||
#include <bits/atfile.h>
|
||||
#include <bits/fcntl.h>
|
||||
#include <bits/open-flags.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -13,7 +13,7 @@ extern "C"
|
||||
|
||||
mode_t mode = (mode_t)va_arg(ap, int);
|
||||
|
||||
long rc = syscall(SYS_open, path, flags, mode);
|
||||
long rc = syscall(SYS_openat, AT_FDCWD, path, flags, mode);
|
||||
|
||||
va_end(ap);
|
||||
__errno_return(rc, int);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <bits/errno-return.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
@ -19,13 +20,13 @@ extern "C"
|
||||
|
||||
int stat(const char* path, struct stat* st)
|
||||
{
|
||||
long rc = syscall(SYS_stat, path, st);
|
||||
long rc = syscall(SYS_fstatat, AT_FDCWD, path, st, 0);
|
||||
__errno_return(rc, int);
|
||||
}
|
||||
|
||||
int fstat(int fd, struct stat* st)
|
||||
{
|
||||
long rc = syscall(SYS_fstat, fd, st);
|
||||
long rc = syscall(SYS_fstatat, fd, "", st, AT_EMPTY_PATH);
|
||||
__errno_return(rc, int);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#define enumerate_syscalls(_e) \
|
||||
_e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) _e(write) \
|
||||
_e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(openat) _e(close) _e(read) _e(getpid) _e(write) \
|
||||
_e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \
|
||||
_e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(chmod) _e(chown) \
|
||||
_e(ioctl) _e(stat) _e(fstat) _e(chdir) _e(getcwd) _e(unlink)
|
||||
_e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlink)
|
||||
|
||||
enum Syscalls
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ namespace os
|
||||
{
|
||||
auto file = TRY(adopt_shared_if_nonnull(new (std::nothrow) File({})));
|
||||
|
||||
long rc = syscall(SYS_open, path.chars(), flags, mode);
|
||||
long rc = syscall(SYS_openat, AT_FDCWD, path.chars(), flags, mode);
|
||||
int fd = TRY(Result<int>::from_syscall(rc));
|
||||
|
||||
file->m_fd = fd;
|
||||
|
Loading…
Reference in New Issue
Block a user