Hi,

This patch works around 2 more issues with GNU/Hurd's renameat/renameat2
functions. When renaming directories, they misbehave if the source or
target have a trailing slash.

I wrote small test programs in the glibc bug reports [1] [2].

This patch fixes tests/test-renameat and tests/test-renameat2 in
Gnulib. And fixes tests/mv/backup-dir and tests/mv/trailing-slash in
Coreutils.

Collin

[1] https://sourceware.org/PR33607
[2] https://sourceware.org/PR33608

>From fc86d6efdf00ba60106a4c67d36dd0bfc447cf13 Mon Sep 17 00:00:00 2001
Message-ID: <fc86d6efdf00ba60106a4c67d36dd0bfc447cf13.1762494876.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Thu, 6 Nov 2025 21:18:12 -0800
Subject: [PATCH] renameat, renameatu: Work around GNU/Hurd bugs.

* lib/renameatu.c (renameatu): Handle RENAME_TRAILING_SLASH_SOURCE_BUG
and RENAME_TRAILING_SLASH_DEST_BUG when renameat2 is called.
* doc/glibc-functions/renameat2.texi: Mention the bugs.
* doc/posix-functions/renameat.texi: Likewise.
---
 ChangeLog                          |  8 ++++++++
 doc/glibc-functions/renameat2.texi | 10 ++++++++++
 doc/posix-functions/renameat.texi  | 15 +++++++++++++++
 lib/renameatu.c                    | 14 +++++++++++++-
 4 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index f3a5d317fd..2aa4a2b31d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-11-06  Collin Funk  <[email protected]>
+
+	renameat, renameatu: Work around GNU/Hurd bugs.
+	* lib/renameatu.c (renameatu): Handle RENAME_TRAILING_SLASH_SOURCE_BUG
+	and RENAME_TRAILING_SLASH_DEST_BUG when renameat2 is called.
+	* doc/glibc-functions/renameat2.texi: Mention the bugs.
+	* doc/posix-functions/renameat.texi: Likewise.
+
 2025-11-06  Paul Eggert  <[email protected]>
 
 	stdio-windows: fix <stdarg.h> include position
diff --git a/doc/glibc-functions/renameat2.texi b/doc/glibc-functions/renameat2.texi
index 7d3240bcc6..b4fa607eeb 100644
--- a/doc/glibc-functions/renameat2.texi
+++ b/doc/glibc-functions/renameat2.texi
@@ -25,6 +25,16 @@ @node renameat2
 platforms:
 @c https://sourceware.org/PR32570
 GNU/Hurd with glibc 2.41.
+@item
+@code{renameat2 (ATFDCWD, "dir", AT_FDCWD, "new/" ...)} fails with
+@code{errno} set to @code{ENOENT}, on some platforms:
+@c https://sourceware.org/PR33607
+GNU/Hurd with glibc 2.42.
+@item
+@code{renameat2 (ATFDCWD, "dir/", AT_FDCWD, "new" ...)} fails with
+@code{errno} set to @code{ENOTDIR}, on some platforms:
+@c https://sourceware.org/PR33608
+GNU/Hurd with glibc 2.42.
 @end itemize
 
 @mindex renameatu
diff --git a/doc/posix-functions/renameat.texi b/doc/posix-functions/renameat.texi
index 70caa69d32..ad06184c56 100644
--- a/doc/posix-functions/renameat.texi
+++ b/doc/posix-functions/renameat.texi
@@ -30,6 +30,21 @@ @node renameat
 This function ignores trailing slashes on symlinks on some platforms,
 such that @code{renameat(fd,"link/",fd,"new")} corrupts @file{link}:
 Solaris 9.
+@item
+@code{renameat (AT_FDCWD, "file", AT_FDCWD, "new/")} succeeds instead of
+failing and setting @code{errno} to @code{ENOTDIR}, on some platforms:
+@c https://sourceware.org/PR32570
+GNU/Hurd with glibc 2.41.
+@item
+@code{renameat (ATFDCWD, "dir", AT_FDCWD, "new/")} fails with
+@code{errno} set to @code{ENOENT}, on some platforms:
+@c https://sourceware.org/PR33607
+GNU/Hurd with glibc 2.42.
+@item
+@code{renameat (ATFDCWD, "dir/", AT_FDCWD, "new")} fails with
+@code{errno} set to @code{ENOTDIR}, on some platforms:
+@c https://sourceware.org/PR33608
+GNU/Hurd with glibc 2.42.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/lib/renameatu.c b/lib/renameatu.c
index 89653cb3e8..29c4839269 100644
--- a/lib/renameatu.c
+++ b/lib/renameatu.c
@@ -117,7 +117,19 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
   err = errno;
 #endif
 
-  if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP)))
+
+  if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP
+#if RENAME_TRAILING_SLASH_SOURCE_BUG
+                         || ! (err == ENOTDIR
+                               && ! (0 < strlen (src)
+                                     && src[strlen (src) - 1] == '/'))
+#endif
+#if RENAME_TRAILING_SLASH_DEST_BUG
+                         || ! (err == ENOENT
+                               && ! (0 < strlen (dst)
+                                     && dst[strlen (dst) - 1] == '/'))
+#endif
+                        )))
     return ret_val;
 
 #if HAVE_RENAMEAT
-- 
2.51.1

Reply via email to