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
