On Cygwin 3.4.6, but not on Cygwin 3.5.3, I see a test failure:

FAIL: test-renameatu.exe

The cause is that the renameat2 function, which was added in Cygwin 2.9.0,
does not fail as expected when the RENAME_NOREPLACE flag is specified and
source and destination are the same.

The workaround is simply to not use renameat2 in this case. Done through
this patch. It fixes the test failure.


2024-05-23  Bruno Haible  <br...@clisp.org>

        renameatu: Work around Cygwin 3.4.6 bug.
        * m4/renameat.m4 (gl_FUNC_RENAMEAT): Test whether renameat2 works, and
        define HAVE_WORKING_RENAMEAT2 if so.
        * lib/renameatu.c (renameatu): Test HAVE_WORKING_RENAMEAT2 instead of
        HAVE_RENAMEAT2.
        * doc/glibc-functions/renameat2.texi: Mention the Cygwin bug.

diff --git a/doc/glibc-functions/renameat2.texi 
b/doc/glibc-functions/renameat2.texi
index ba577f4e2a..9588225f39 100644
--- a/doc/glibc-functions/renameat2.texi
+++ b/doc/glibc-functions/renameat2.texi
@@ -13,9 +13,12 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function exists only on Linux and is therefore
-missing on many platforms:
-glibc 2.27, macOS 11.1, FreeBSD 14.0, NetBSD 10.0, OpenBSD 6.7, Minix 3.1.8, 
AIX 7.1, HP-UX 11.31, Solaris 11.4, Cygwin 1.7.x, mingw, MSVC 14, Android API 
level 29.
+This function is missing on many platforms:
+glibc 2.27, macOS 11.1, FreeBSD 14.0, NetBSD 10.0, OpenBSD 6.7, Minix 3.1.8, 
AIX 7.1, HP-UX 11.31, Solaris 11.4, Cygwin 2.8.x, mingw, MSVC 14, Android API 
level 29.
+@item
+This function succeeds when the @code{RENAME_NOREPLACE} flag is specified
+and the source and destination are the same file, on some platforms:
+Cygwin 3.4.6.
 @end itemize
 
 The @code{renameatu} module addresses some of these portability issues.
diff --git a/lib/renameatu.c b/lib/renameatu.c
index 815e3e0da9..437fc8f71a 100644
--- a/lib/renameatu.c
+++ b/lib/renameatu.c
@@ -106,7 +106,7 @@ renameatu (int fd1, char const *src, int fd2, char const 
*dst,
   int ret_val = -1;
   int err = EINVAL;
 
-#ifdef HAVE_RENAMEAT2
+#if HAVE_WORKING_RENAMEAT2
   ret_val = renameat2 (fd1, src, fd2, dst, flags);
   err = errno;
 #elif defined SYS_renameat2
diff --git a/m4/renameat.m4 b/m4/renameat.m4
index 565400f5db..adf1f6bdd0 100644
--- a/m4/renameat.m4
+++ b/m4/renameat.m4
@@ -1,5 +1,5 @@
 # renameat.m4
-# serial 4
+# serial 5
 dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -14,6 +14,7 @@ AC_DEFUN([gl_FUNC_RENAMEAT]
   AC_REQUIRE([gl_FUNC_OPENAT])
   AC_REQUIRE([gl_FUNC_RENAME])
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_HEADERS([linux/fs.h])
   AC_CHECK_FUNCS_ONCE([renameat])
@@ -24,4 +25,39 @@ AC_DEFUN([gl_FUNC_RENAMEAT]
     REPLACE_RENAMEAT=1
   fi
   gl_CHECK_FUNCS_ANDROID([renameat2], [[#include <stdio.h>]])
+  if test $ac_cv_func_renameat2 = yes; then
+    AC_CACHE_CHECK([whether renameat2 works],
+      [gl_cv_func_renameat2_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+            #include <fcntl.h>
+            #include <stdio.h>
+            int main ()
+            {
+              /* This test fails on Cygwin 3.4.6.  */
+              if (renameat2 (AT_FDCWD, "conftest.c", AT_FDCWD, "conftest.c",
+                             RENAME_NOREPLACE) == 0)
+                return 1;
+              return 0;
+            }
+         ]])],
+         [gl_cv_func_renameat2_works=yes],
+         [gl_cv_func_renameat2_works=no],
+         [case "$host_os" in
+                     # Guess yes on Linux.
+            linux*)  gl_cv_func_renameat2_works="guessing yes" ;;
+                     # Guess no on Cygwin.
+            cygwin*) gl_cv_func_renameat2_works="guessing no" ;;
+                     # If we don't know, obey --enable-cross-guesses.
+            *)       gl_cv_func_renameat2_works="$gl_cross_guess_normal" ;;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_renameat2_works" in
+      *yes)
+        AC_DEFINE([HAVE_WORKING_RENAMEAT2], [1],
+          [Define if the renameat2 function exists and it works.])
+        ;;
+    esac
+  fi
 ])




Reply via email to