1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 07:25:07 +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:
Andreas Kling 2019-11-10 13:47:02 +01:00
parent 4f27745136
commit 18348cebf1
6 changed files with 80 additions and 7 deletions

View file

@ -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;