[PATCH 7/8] fchownat: don’t mishandle AT _EMPTY_PATH

Paul Eggert <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs
Message-ID <[email protected]>
This has the same motivation as the recent fchmodat change.
* lib/fchownat.c (AT_EMPTY_PATH): Default to 0.
(FCHOWNAT_EMPTY_FILENAME_BUG): Remove; no longer needed.
(rpl_fchownat): Do not mishandle AT_EMPTY_PATH if specified
and if the underlying library+kernel supports it.
* m4/fchownat.m4 (gl_FUNC_FCHOWNAT):
Don’t define FCHOWNAT_EMPTY_FILENAME_BUG, as it is no longer needed.
---
 ChangeLog      |  9 +++++++++
 lib/fchownat.c | 26 +++++++++++++++-----------
 m4/fchownat.m4 |  8 ++------
 3 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d78d0d1102..5bf7f08c52 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2026-06-16  Paul Eggert  <[email protected]>
 
+	fchownat: don’t mishandle AT_EMPTY_PATH
+	This has the same motivation as the recent fchmodat change.
+	* lib/fchownat.c (AT_EMPTY_PATH): Default to 0.
+	(FCHOWNAT_EMPTY_FILENAME_BUG): Remove; no longer needed.
+	(rpl_fchownat): Do not mishandle AT_EMPTY_PATH if specified
+	and if the underlying library+kernel supports it.
+	* m4/fchownat.m4 (gl_FUNC_FCHOWNAT):
+	Don’t define FCHOWNAT_EMPTY_FILENAME_BUG, as it is no longer needed.
+
 	fchmodat: don’t mishandle AT_EMPTY_PATH
 	This does not add support for AT_EMPTY_PATH on platforms lacking it.
 	It merely fixes bugs in handling AT_EMPTY_PATH on platforms
diff --git a/lib/fchownat.c b/lib/fchownat.c
index 5c9901fbbd..1201e1b100 100644
--- a/lib/fchownat.c
+++ b/lib/fchownat.c
@@ -36,15 +36,16 @@
 #include "openat.h"
 #include "stat-time.h"
 
+#ifndef AT_EMPTY_PATH
+# define AT_EMPTY_PATH 0
+#endif
+
 #ifndef CHOWN_CHANGE_TIME_BUG
 # define CHOWN_CHANGE_TIME_BUG 0
 #endif
 #ifndef CHOWN_TRAILING_SLASH_BUG
 # define CHOWN_TRAILING_SLASH_BUG 0
 #endif
-#ifndef FCHOWNAT_EMPTY_FILENAME_BUG
-# define FCHOWNAT_EMPTY_FILENAME_BUG 0
-#endif
 
 /* Gnulib target platforms lacking utimensat do not need it,
    because in practice the bug it works around does not occur.  */
@@ -107,25 +108,28 @@ local_lchownat (int fd, char const *file, uid_t owner, gid_t group);
    chown and lchown.  */
 
 int
-rpl_fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag)
+rpl_fchownat (int fd, char const *file, uid_t owner, gid_t group, int flags)
 {
   /* No need to worry about CHOWN_FAILS_TO_HONOR_ID_OF_NEGATIVE_ONE
      or CHOWN_MODIFIES_SYMLINK, as no known fchownat implementations
      have these bugs.  */
 
-  if (FCHOWNAT_EMPTY_FILENAME_BUG && file[0] == '\0')
+  if (file && *file)
+    flags &= ~AT_EMPTY_PATH;
+  else if (! (flags & AT_EMPTY_PATH))
     {
       errno = ENOENT;
       return -1;
     }
 
   bool trailing_slash_check = (CHOWN_TRAILING_SLASH_BUG
-                               && file[0] && file[strlen (file) - 1] == '/');
+                               && file && *file
+                               && file[strlen (file) - 1] == '/');
   if (trailing_slash_check)
-    flag &= ~AT_SYMLINK_NOFOLLOW;
+    flags &= ~AT_SYMLINK_NOFOLLOW;
 
 # if FCHOWNAT_NOFOLLOW_BUG
-  if (flag == AT_SYMLINK_NOFOLLOW)
+  if (flags == AT_SYMLINK_NOFOLLOW)
     return local_lchownat (fd, file, owner, group);
 # endif
 
@@ -138,7 +142,7 @@ rpl_fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag)
 
   if (change_time_check | trailing_slash_check)
     {
-      int r = fstatat (fd, file, &st, flag);
+      int r = fstatat (fd, file, &st, flags);
 
       /* EOVERFLOW means the file exists, which is all that the
          trailing slash check needs.  */
@@ -146,7 +150,7 @@ rpl_fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag)
         return r;
     }
 
-  int result = fchownat (fd, file, owner, group, flag);
+  int result = fchownat (fd, file, owner, group, flags);
 
   /* If no change in ownership, but at least one argument was not -1,
      update ctime indirectly via a no-change update to atime and mtime.
@@ -160,7 +164,7 @@ rpl_fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag)
       struct timespec times[2];
       times[0] = get_stat_atime (&st);
       times[1] = get_stat_mtime (&st);
-      utimensat (fd, file, times, flag);
+      utimensat (fd, file, times, flags);
     }
 
   return result;
diff --git a/m4/fchownat.m4 b/m4/fchownat.m4
index f1ee41c70a..f0fb726035 100644
--- a/m4/fchownat.m4
+++ b/m4/fchownat.m4
@@ -1,5 +1,5 @@
 # fchownat.m4
-# serial 8
+# serial 9
 dnl Copyright (C) 2004-2026 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -27,11 +27,7 @@ AC_DEFUN([gl_FUNC_FCHOWNAT]
                    perform lchown tasks.])
        ])
      gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG(
-       [REPLACE_FCHOWNAT=1
-        AC_DEFINE([FCHOWNAT_EMPTY_FILENAME_BUG], [1],
-                  [Define to 1 if your platform has fchownat, but it does
-                   not reject an empty file name.])
-       ])
+       [REPLACE_FCHOWNAT=1])
      if test $REPLACE_CHOWN = 1; then
        REPLACE_FCHOWNAT=1
      fi],
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.