* lib/renameatu.c (renameat2ish, renameatu) [RENAME_SWAP]:
Use macOS RENAME_SWAP to implement GNU/Linux RENAME_EXCHANGE.
* tests/test-renameatu.c (main): Add a test for RENAME_EXCHANGE.
---
 ChangeLog                          | 7 +++++++
 doc/glibc-functions/renameat2.texi | 2 ++
 lib/renameatu.c                    | 8 ++++++++
 tests/test-renameatu.c             | 7 +++++++
 4 files changed, 24 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 258691d551..9deed7d1d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2024-03-16  Paul Eggert  <[email protected]>
+
+       renameatu: support RENAME_EXCHANGE on macOS
+       * lib/renameatu.c (renameat2ish, renameatu) [RENAME_SWAP]:
+       Use macOS RENAME_SWAP to implement GNU/Linux RENAME_EXCHANGE.
+       * tests/test-renameatu.c (main): Add a test for RENAME_EXCHANGE.
+
 2024-03-16  Collin Funk  <[email protected]>
 
        gnulib-tool.py: Follow gnulib-tool changes, part 59.
diff --git a/doc/glibc-functions/renameat2.texi 
b/doc/glibc-functions/renameat2.texi
index a59b797260..15cf9d1d7f 100644
--- a/doc/glibc-functions/renameat2.texi
+++ b/doc/glibc-functions/renameat2.texi
@@ -17,3 +17,5 @@ This function exists only on Linux and is therefore
 missing on many platforms:
 glibc 2.27, macOS 11.1, FreeBSD 14.0, NetBSD 9.0, OpenBSD 6.7, Minix 3.1.8, 
AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.4, Cygwin 1.7.x, mingw, MSVC 14, 
Android API level 29.
 @end itemize
+
+The @code{renameatu} module addresses some of these portability issues.
diff --git a/lib/renameatu.c b/lib/renameatu.c
index 174081c16b..6893232516 100644
--- a/lib/renameatu.c
+++ b/lib/renameatu.c
@@ -70,6 +70,10 @@ static int
 renameat2ish (int fd1, char const *src, int fd2, char const *dst,
               unsigned int flags)
 {
+# ifdef RENAME_SWAP
+  if (flags & RENAME_EXCHANGE)
+    return renameatx_np (fd1, src, fd2, dst, RENAME_SWAP);
+# endif
 # ifdef RENAME_EXCL
   if (flags)
     {
@@ -145,6 +149,10 @@ renameatu (int fd1, char const *src, int fd2, char const 
*dst,
       dst_found_nonexistent = true;
       break;
 
+    case RENAME_EXCHANGE:
+#ifdef RENAME_SWAP
+      break;
+#endif
     default:
       return errno_fail (ENOTSUP);
     }
diff --git a/tests/test-renameatu.c b/tests/test-renameatu.c
index 68faeb83e7..9f3a71f0d9 100644
--- a/tests/test-renameatu.c
+++ b/tests/test-renameatu.c
@@ -205,6 +205,13 @@ main (void)
            == -1)
           && errno == EEXIST);
 
+  errno = 0;
+  ASSERT (renameatu (dfd, BASE "sub2", dfd, BASE "sub1", RENAME_EXCHANGE) < 0
+          ? errno == EINVAL || errno == ENOSYS || errno == ENOTSUP
+          : (renameatu (dfd, BASE "sub1/file", dfd, BASE "sub2/file",
+                        RENAME_NOREPLACE)
+             == 0));
+
   /* Cleanup.  */
   ASSERT (close (dfd) == 0);
   ASSERT (unlink (BASE "sub2/file") == 0);
-- 
2.40.1


Reply via email to