]> Savannah Git Hosting - gnulib.git/commitdiff
renameatu: Fix test failures on macOS.
authorBruno Haible <bruno@clisp.org>
Sat, 2 Jan 2021 15:54:21 +0000 (16:54 +0100)
committerBruno Haible <bruno@clisp.org>
Sat, 2 Jan 2021 15:58:59 +0000 (16:58 +0100)
Reported by Martin Storsjö <martin@martin.st> in
<https://lists.gnu.org/archive/html/bug-gnulib/2020-12/msg00003.html>.

* lib/renameatu.c (renameatu): Don't call renameatx_np right away.
Instead, treat it as a variant of renameat, with all possible bugs that
renameat might have.

ChangeLog
lib/renameatu.c

index 4dd088d87107cd562243bc45aa706a03b581ccd8..6d95f4990019d9151d4017896a1e023331bd8b3a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2021-01-02  Bruno Haible  <bruno@clisp.org>
+
+       renameatu: Fix test failures on macOS.
+       Reported by Martin Storsjö <martin@martin.st> in
+       <https://lists.gnu.org/archive/html/bug-gnulib/2020-12/msg00003.html>.
+       * lib/renameatu.c (renameatu): Don't call renameatx_np right away.
+       Instead, treat it as a variant of renameat, with all possible bugs that
+       renameat might have.
+
 2021-01-02  Bruno Haible  <bruno@clisp.org>
 
        getgroups test: Avoid warning with glibc >= 2.32 and gcc >= 10.
index 974d23455cc7559dfd74e5fe217d2958041e1359..c493a38dc1f387cddb1440ed4a8cb26cc0d01d7f 100644 (file)
@@ -86,14 +86,6 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
 #elif defined SYS_renameat2
   ret_val = syscall (SYS_renameat2, fd1, src, fd2, dst, flags);
   err = errno;
-#elif defined RENAME_EXCL
-  if (! (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE)))
-    {
-      ret_val = renameatx_np (fd1, src, fd2, dst,
-                             ((flags & RENAME_EXCHANGE ? RENAME_SWAP : 0)
-                              | (flags & RENAME_NOREPLACE ? RENAME_EXCL : 0)));
-      err = errno;
-    }
 #endif
 
   if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP)))
@@ -101,6 +93,9 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
 
 #if HAVE_RENAMEAT
   {
+# if defined RENAME_EXCL                /* macOS */
+  unsigned int uflags;
+# endif
   size_t src_len;
   size_t dst_len;
   char *src_temp = (char *) src;
@@ -112,33 +107,52 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
   struct stat dst_st;
   bool dst_found_nonexistent = false;
 
-  if (flags != 0)
+  /* Check the flags.  */
+# if defined RENAME_EXCL
+  /* We can support RENAME_EXCHANGE and RENAME_NOREPLACE.  */
+  if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
+# else
+  /* RENAME_NOREPLACE is the only flag currently supported.  */
+  if (flags & ~RENAME_NOREPLACE)
+# endif
+    return errno_fail (ENOTSUP);
+
+# if defined RENAME_EXCL
+  uflags = ((flags & RENAME_EXCHANGE ? RENAME_SWAP : 0)
+            | (flags & RENAME_NOREPLACE ? RENAME_EXCL : 0));
+# endif
+
+# if !defined RENAME_EXCL
+  if ((flags & RENAME_NOREPLACE) != 0)
     {
-      /* RENAME_NOREPLACE is the only flag currently supported.  */
-      if (flags & ~RENAME_NOREPLACE)
-        return errno_fail (ENOTSUP);
-      else
-        {
-          /* This has a race between the call to lstatat and the calls to
-             renameat below.  */
-          if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW)
-            return errno_fail (EEXIST);
-          if (errno != ENOENT)
-            return -1;
-          dst_found_nonexistent = true;
-        }
+      /* This has a race between the call to lstatat and the calls to
+         renameat below.  */
+      if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW)
+        return errno_fail (EEXIST);
+      if (errno != ENOENT)
+        return -1;
+      dst_found_nonexistent = true;
     }
+# endif
 
   /* Let strace see any ENOENT failure.  */
   src_len = strlen (src);
   dst_len = strlen (dst);
   if (!src_len || !dst_len)
+# if defined RENAME_EXCL
+    return renameatx_np (fd1, src, fd2, dst, uflags);
+# else
     return renameat (fd1, src, fd2, dst);
+# endif
 
   src_slash = src[src_len - 1] == '/';
   dst_slash = dst[dst_len - 1] == '/';
   if (!src_slash && !dst_slash)
+# if defined RENAME_EXCL
+    return renameatx_np (fd1, src, fd2, dst, uflags);
+# else
     return renameat (fd1, src, fd2, dst);
+# endif
 
   /* Presence of a trailing slash requires directory semantics.  If
      the source does not exist, or if the destination cannot be turned
@@ -211,7 +225,11 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
      on Solaris, since all other systems either lack renameat or honor
      trailing slash correctly.  */
 
+# if defined RENAME_EXCL
+  ret_val = renameatx_np (fd1, src_temp, fd2, dst_temp, uflags);
+# else
   ret_val = renameat (fd1, src_temp, fd2, dst_temp);
+# endif
   rename_errno = errno;
   goto out;
  out: