diff options
Diffstat (limited to 'gl/lib/renameatu.c')
-rw-r--r-- | gl/lib/renameatu.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/gl/lib/renameatu.c b/gl/lib/renameatu.c index 0eb33ab6..7ba186ca 100644 --- a/gl/lib/renameatu.c +++ b/gl/lib/renameatu.c @@ -133,12 +133,13 @@ renameatu (int fd1, char const *src, int fd2, char const *dst, break; case RENAME_NOREPLACE: - /* This has a race between the call to lstatat and the calls to - renameat below. This lstatat is needed even if RENAME_EXCL + /* This has a race between the call to fstatat and the calls to + renameat below. This fstatat is needed even if RENAME_EXCL is defined, because RENAME_EXCL is buggy on macOS 11.2: renameatx_np (fd, "X", fd, "X", RENAME_EXCL) incorrectly succeeds when X exists. */ - if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW) + if (fstatat (fd2, dst, &dst_st, AT_SYMLINK_NOFOLLOW) == 0 + || errno == EOVERFLOW) return errno_fail (EEXIST); if (errno != ENOENT) return -1; @@ -164,14 +165,14 @@ renameatu (int fd1, char const *src, int fd2, char const *dst, the source does not exist, or if the destination cannot be turned into a directory, give up now. Otherwise, strip trailing slashes before calling rename. */ - if (lstatat (fd1, src, &src_st)) + if (fstatat (fd1, src, &src_st, AT_SYMLINK_NOFOLLOW)) return -1; if (dst_found_nonexistent) { if (!S_ISDIR (src_st.st_mode)) return errno_fail (ENOENT); } - else if (lstatat (fd2, dst, &dst_st)) + else if (fstatat (fd2, dst, &dst_st, AT_SYMLINK_NOFOLLOW)) { if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) return -1; @@ -196,7 +197,7 @@ renameatu (int fd1, char const *src, int fd2, char const *dst, goto out; } strip_trailing_slashes (src_temp); - if (lstatat (fd1, src_temp, &src_st)) + if (fstatat (fd1, src_temp, &src_st, AT_SYMLINK_NOFOLLOW)) { rename_errno = errno; goto out; @@ -213,15 +214,16 @@ renameatu (int fd1, char const *src, int fd2, char const *dst, goto out; } strip_trailing_slashes (dst_temp); - if (lstatat (fd2, dst_temp, &dst_st)) + char readlink_buf[1]; + if (readlinkat (fd2, dst_temp, readlink_buf, sizeof readlink_buf) < 0) { - if (errno != ENOENT) + if (errno != ENOENT && errno != EINVAL) { rename_errno = errno; goto out; } } - else if (S_ISLNK (dst_st.st_mode)) + else goto out; } # endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */ |