diff --git a/glnx-dirfd.c b/glnx-dirfd.c index af4cab825d8e562fa637e5bc5760548b79512e4f..4b7d5a04786d10cc8ee24b26ac72f0aa18b580e7 100644 --- a/glnx-dirfd.c +++ b/glnx-dirfd.c @@ -43,6 +43,9 @@ glnx_opendirat_with_errno (int dfd, int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY; if (!follow) flags |= O_NOFOLLOW; + + dfd = glnx_dirfd_canonicalize (dfd); + return openat (dfd, path, flags); } diff --git a/glnx-dirfd.h b/glnx-dirfd.h index 27cd03b87fad6bdca485730a51546e8088a3236d..585d16aff8bb566bb1ae080f0797b8d3b158652e 100644 --- a/glnx-dirfd.h +++ b/glnx-dirfd.h @@ -27,6 +27,23 @@ #include <fcntl.h> G_BEGIN_DECLS + +/** + * glnx_dirfd_canonicalize: + * @fd: A directory file descriptor + * + * It's often convenient in programs to use `-1` for "unassigned fd", + * and also because gobject-introspection doesn't support `AT_FDCWD`, + * libglnx honors `-1` to mean `AT_FDCWD`. This small inline function + * canonicalizes `-1 -> AT_FDCWD`. + */ +static inline int +glnx_dirfd_canonicalize (int fd) +{ + if (fd == -1) + return AT_FDCWD; + return fd; +} struct GLnxDirFdIterator { gboolean initialized; diff --git a/glnx-fdio.c b/glnx-fdio.c index 77be6e114e8aaca691b98a3a7d90cee5c10400a5..63dea2b9b96a32858ef45ab1359b6a3a2230e034 100644 --- a/glnx-fdio.c +++ b/glnx-fdio.c @@ -35,6 +35,7 @@ #define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int) #include <glnx-fdio.h> +#include <glnx-dirfd.h> #include <glnx-errors.h> #include <glnx-xattrs.h> #include <glnx-backport-autoptr.h> @@ -212,6 +213,8 @@ glnx_file_get_contents_utf8_at (int dfd, char *buf; gsize len; + dfd = glnx_dirfd_canonicalize (dfd); + do fd = openat (dfd, subpath, O_RDONLY | O_NOCTTY | O_CLOEXEC); while (G_UNLIKELY (fd == -1 && errno == EINTR)); @@ -255,6 +258,8 @@ glnx_readlinkat_malloc (int dfd, { size_t l = 100; + dfd = glnx_dirfd_canonicalize (dfd); + for (;;) { char *c; @@ -482,6 +487,9 @@ glnx_file_copy_at (int src_dfd, if (g_cancellable_set_error_if_cancelled (cancellable, error)) goto out; + src_dfd = glnx_dirfd_canonicalize (src_dfd); + dest_dfd = glnx_dirfd_canonicalize (dest_dfd); + if (S_ISLNK (src_stbuf->st_mode)) { return copy_symlink_at (src_dfd, src_subpath, src_stbuf, diff --git a/glnx-shutil.c b/glnx-shutil.c index 9fcb65a0617f2649cdec95492c30b3f93f6137f0..967e364973a624da7fb47b71c7a031bfc4319b0c 100644 --- a/glnx-shutil.c +++ b/glnx-shutil.c @@ -118,7 +118,7 @@ glnx_shutil_rm_rf_children (GLnxDirFdIterator *dfd_iter, /** * glnx_shutil_rm_rf_at: - * @dfd: A directory file descriptor, or -1 for current + * @dfd: A directory file descriptor, or `AT_FDCWD` or `-1` for current * @path: Path * @cancellable: Cancellable * @error: Error @@ -137,6 +137,8 @@ glnx_shutil_rm_rf_at (int dfd, glnx_fd_close int target_dfd = -1; g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + dfd = glnx_dirfd_canonicalize (dfd); + /* With O_NOFOLLOW first */ target_dfd = openat (dfd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);