bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

renameatu: Fix test failures on macOS


From: Bruno Haible
Subject: renameatu: Fix test failures on macOS
Date: Sat, 02 Jan 2021 17:03:16 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-197-generic; KDE/5.18.0; x86_64; ; )

On macOS 10.13, I'm seeing these test failures (for a long time already).

FAIL: test-renameat
===================

../../gltests/test-rename.h:619: assertion 'func (BASE "link2/", BASE "link2") 
== -1' failed
FAIL test-renameat (exit status: 134)

FAIL: test-renameatu
====================

../../gltests/test-rename.h:619: assertion 'func (BASE "link2/", BASE "link2") 
== -1' failed
FAIL test-renameatu (exit status: 134)

This was also reported by Martin Storsjö.

The situation is that config.h contains:

#define HAVE_RENAMEAT 1
/* #undef HAVE_RENAMEAT2 */
/* #undef RENAME_DEST_EXISTS_BUG */
/* #undef RENAME_HARD_LINK_BUG */
#define RENAME_TRAILING_SLASH_DEST_BUG 1
#define RENAME_TRAILING_SLASH_SOURCE_BUG 1

But the invocation of 'renameatx_np' right at the beginning of renameatu()
assumes that it works without bugs. Which it doesn't.

This patch fixes both test failures.


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.

diff --git a/lib/renameatu.c b/lib/renameatu.c
index 974d234..c493a38 100644
--- a/lib/renameatu.c
+++ b/lib/renameatu.c
@@ -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:




reply via email to

[Prev in Thread] Current Thread [Next in Thread]