mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 10:37:45 +00:00
Kernel+LibC: Implement the openat() syscall
POSIX's openat() is very similar to open(), except you also provide a file descriptor referring to a directory from which relative paths should be resolved. Passing it the magical fd number AT_FDCWD means "resolve from current directory" (which is indeed also what open() normally does.) This fixes libarchive's bsdtar, since it was trying to do something extremely wrong in the absence of openat() support. The issue has recently been fixed upstream in libarchive: https://github.com/libarchive/libarchive/issues/1239 However, we should have openat() support anyway, so I went ahead and implemented it. :^) Fixes #748.
This commit is contained in:
parent
4f27745136
commit
18348cebf1
6 changed files with 80 additions and 7 deletions
|
@ -1351,15 +1351,12 @@ int Process::sys$open(const Syscall::SC_open_params* params)
|
|||
{
|
||||
if (!validate_read_typed(params))
|
||||
return -EFAULT;
|
||||
auto* path = params->path;
|
||||
auto path_length = params->path_length;
|
||||
auto options = params->options;
|
||||
auto mode = params->mode;
|
||||
auto [path, path_length, options, mode] = *params;
|
||||
if (!validate_read(path, path_length))
|
||||
return -EFAULT;
|
||||
#ifdef DEBUG_IO
|
||||
dbgprintf("%s(%u) sys$open(\"%s\")\n", name().characters(), pid(), path);
|
||||
#endif
|
||||
if (!validate_read(path, path_length))
|
||||
return -EFAULT;
|
||||
int fd = alloc_fd();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
@ -1375,6 +1372,46 @@ int Process::sys$open(const Syscall::SC_open_params* params)
|
|||
return fd;
|
||||
}
|
||||
|
||||
int Process::sys$openat(const Syscall::SC_openat_params* params)
|
||||
{
|
||||
if (!validate_read_typed(params))
|
||||
return -EFAULT;
|
||||
auto [dirfd, path, path_length, options, mode] = *params;
|
||||
if (!validate_read(path, path_length))
|
||||
return -EFAULT;
|
||||
#ifdef DEBUG_IO
|
||||
dbgprintf("%s(%u) sys$openat(%d, \"%s\")\n", dirfd, name().characters(), pid(), path);
|
||||
#endif
|
||||
int fd = alloc_fd();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
RefPtr<Custody> base;
|
||||
if (dirfd == AT_FDCWD) {
|
||||
base = current_directory();
|
||||
} else {
|
||||
auto* base_description = file_description(dirfd);
|
||||
if (!base_description)
|
||||
return -EBADF;
|
||||
if (!base_description->is_directory())
|
||||
return -ENOTDIR;
|
||||
if (!base_description->custody())
|
||||
return -EINVAL;
|
||||
base = base_description->custody();
|
||||
}
|
||||
|
||||
auto result = VFS::the().open(path, options, mode & ~umask(), *base);
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
auto description = result.value();
|
||||
if (options & O_DIRECTORY && !description->is_directory())
|
||||
return -ENOTDIR; // FIXME: This should be handled by VFS::open.
|
||||
description->set_file_flags(options);
|
||||
u32 fd_flags = (options & O_CLOEXEC) ? FD_CLOEXEC : 0;
|
||||
m_fds[fd].set(move(description), fd_flags);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int Process::alloc_fd(int first_candidate_fd)
|
||||
{
|
||||
int fd = -EMFILE;
|
||||
|
|
|
@ -124,6 +124,7 @@ public:
|
|||
pid_t sys$getppid();
|
||||
mode_t sys$umask(mode_t);
|
||||
int sys$open(const Syscall::SC_open_params*);
|
||||
int sys$openat(const Syscall::SC_openat_params*);
|
||||
int sys$close(int fd);
|
||||
ssize_t sys$read(int fd, u8*, ssize_t);
|
||||
ssize_t sys$write(int fd, const u8*, ssize_t);
|
||||
|
|
|
@ -134,7 +134,8 @@ struct timespec;
|
|||
__ENUMERATE_SYSCALL(fchdir) \
|
||||
__ENUMERATE_SYSCALL(getrandom) \
|
||||
__ENUMERATE_SYSCALL(clock_gettime) \
|
||||
__ENUMERATE_SYSCALL(clock_nanosleep)
|
||||
__ENUMERATE_SYSCALL(clock_nanosleep) \
|
||||
__ENUMERATE_SYSCALL(openat)
|
||||
|
||||
namespace Syscall {
|
||||
|
||||
|
@ -179,6 +180,14 @@ struct SC_open_params {
|
|||
u16 mode;
|
||||
};
|
||||
|
||||
struct SC_openat_params {
|
||||
int dirfd;
|
||||
const char* path;
|
||||
int path_length;
|
||||
int options;
|
||||
u16 mode;
|
||||
};
|
||||
|
||||
struct SC_select_params {
|
||||
int nfds;
|
||||
fd_set* readfds;
|
||||
|
|
|
@ -448,3 +448,6 @@ struct ifreq {
|
|||
#define ifr_llprio ifr_ifru.ifru_metric // link layer priority
|
||||
#define ifr_hwaddr ifr_ifru.ifru_hwaddr // MAC address
|
||||
};
|
||||
|
||||
#define AT_FDCWD -100
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue