]> Savannah Git Hosting - gnulib.git/commitdiff
renameatu: port to macOS tmpfs
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 14 Dec 2021 20:32:30 +0000 (12:32 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 14 Dec 2021 20:33:01 +0000 (12:33 -0800)
Problem reported by Sudhip Nashi (Bug#52193).
* lib/renameatu.c (renameat2ish) [HAVE_RENAMEAT]: New function.
(renameatu): Use the new function, to avoid a bug when
renameatx_np fails with errno == ENOTSUP.  Don’t try to support
RENAME_EXCHANGE; the old code didn’t work and nobody using using
RENAME_EXCHANGE anyway.

ChangeLog
lib/renameatu.c

index 0e20dcb58596d4c3e6a37ef62b5510732d906d08..370cd9839891526e9e346d8da9a7577dbe44872e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2021-12-14  Paul Eggert  <eggert@cs.ucla.edu>
+
+       renameatu: port to macOS tmpfs
+       Problem reported by Sudhip Nashi (Bug#52193).
+       * lib/renameatu.c (renameat2ish) [HAVE_RENAMEAT]: New function.
+       (renameatu): Use the new function, to avoid a bug when
+       renameatx_np fails with errno == ENOTSUP.  Don’t try to support
+       RENAME_EXCHANGE; the old code didn’t work and nobody using using
+       RENAME_EXCHANGE anyway.
+
 2021-12-12  Bruno Haible  <bruno@clisp.org>
 
        gnulib-tool: Support non-recursive-gnulib-prefix-hack with tests.
index 38438a4ef11cca8fab3b18c3385e3d632c4ac058..b75f95269fa701247b713f020914ce3c12c47ec2 100644 (file)
@@ -61,6 +61,29 @@ rename_noreplace (char const *src, char const *dst)
 
 #undef renameat
 
+#if HAVE_RENAMEAT
+
+/* Act like renameat (FD1, SRC, FD2, DST), except fail with EEXIST if
+   FLAGS is nonzero and it is easy to fail atomically if DST already exists.
+   This lets renameatu be atomic when it can be implemented in terms
+   of renameatx_np.  */
+static int
+renameat2ish (int fd1, char const *src, int fd2, char const *dst,
+              unsigned int flags)
+{
+# ifdef RENAME_EXCL
+  if (flags)
+    {
+      int r = renameatx_np (fd1, src, fd2, dst, RENAME_EXCL);
+      if (r == 0 || errno != ENOTSUP)
+        return r;
+    }
+# endif
+
+  return renameat (fd1, src, fd2, dst);
+}
+#endif
+
 /* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in
    the directory open on descriptor FD2.  If possible, do it without
    changing the working directory.  Otherwise, resort to using
@@ -93,9 +116,6 @@ 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;
@@ -107,23 +127,12 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
   struct stat dst_st;
   bool dst_found_nonexistent = false;
 
-  /* 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 ((flags & RENAME_NOREPLACE) != 0)
+  switch (flags)
     {
+    case 0:
+      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
          is defined, because RENAME_EXCL is buggy on macOS 11.2:
@@ -134,26 +143,22 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
       if (errno != ENOENT)
         return -1;
       dst_found_nonexistent = true;
+      break;
+
+    default:
+      return errno_fail (ENOTSUP);
     }
 
   /* 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
+    return renameat2ish (fd1, src, fd2, dst, flags);
 
   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
+    return renameat2ish (fd1, src, fd2, dst, flags);
 
   /* Presence of a trailing slash requires directory semantics.  If
      the source does not exist, or if the destination cannot be turned
@@ -226,11 +231,7 @@ 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
+  ret_val = renameat2ish (fd1, src_temp, fd2, dst_temp, flags);
   rename_errno = errno;
   goto out;
  out: