diff --git a/src/io/FileAt.hxx b/src/io/FileAt.hxx new file mode 100644 index 0000000000..53cd9686c1 --- /dev/null +++ b/src/io/FileAt.hxx @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright CM4all GmbH +// author: Max Kellermann + +#pragma once + +#include "FileDescriptor.hxx" + +/** + * Reference to a file by an anchor directory (which can be an + * `O_PATH` descriptor) and a path name relative to it. + */ +struct FileAt { + FileDescriptor directory; + const char *name; +}; diff --git a/src/io/Open.cxx b/src/io/Open.cxx index 8514e95cbf..f962c273da 100644 --- a/src/io/Open.cxx +++ b/src/io/Open.cxx @@ -5,6 +5,11 @@ #include "UniqueFileDescriptor.hxx" #include "lib/fmt/SystemError.hxx" +#ifdef __linux__ +#include "FileAt.hxx" +#include "system/linux/openat2.h" +#endif + #include UniqueFileDescriptor @@ -93,4 +98,21 @@ OpenDirectory(FileDescriptor directory, const char *name, int flags) return fd; } -#endif +UniqueFileDescriptor +TryOpen(FileAt file, const struct open_how &how) noexcept +{ + int fd = openat2(file.directory.Get(), file.name, &how, sizeof(how)); + return UniqueFileDescriptor{AdoptTag{}, fd}; +} + +UniqueFileDescriptor +Open(FileAt file, const struct open_how &how) +{ + auto fd = TryOpen(file, how); + if (!fd.IsDefined()) + throw FmtErrno("Failed to open {:?}", file.name); + + return fd; +} + +#endif // __linux__ diff --git a/src/io/Open.hxx b/src/io/Open.hxx index 2ff0501f8e..08c9bbdc58 100644 --- a/src/io/Open.hxx +++ b/src/io/Open.hxx @@ -36,4 +36,25 @@ OpenWriteOnly(FileDescriptor directory, const char *name, int flags=0); UniqueFileDescriptor OpenDirectory(FileDescriptor directory, const char *name, int flags=0); +struct opwn_how; +struct FileAt; + +/** + * Wrapper for openat2() which converts the returned file descriptor + * to a #UniqueFileDescriptor. + * + * Returns an "undefined" instance on error and sets errno. + */ +UniqueFileDescriptor +TryOpen(FileAt file, const struct open_how &how) noexcept; + +/** + * Wrapper for openat2() which converts the returned file descriptor + * to a #UniqueFileDescriptor. + * + * Throws on error. + */ +UniqueFileDescriptor +Open(FileAt file, const struct open_how &how); + #endif diff --git a/src/system/linux/openat2.h b/src/system/linux/openat2.h new file mode 100644 index 0000000000..362ffad2e5 --- /dev/null +++ b/src/system/linux/openat2.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright CM4all GmbH +// author: Max Kellermann + +#pragma once + +#include // for O_* +#include // for RESOLVE_* +#include +#include + +static inline int +openat2(int dirfd, const char *pathname, + const struct open_how *how, size_t size) +{ + return syscall(__NR_openat2, dirfd, pathname, how, size); +}