Also, tune when LSTAT_FOLLOWS_SLASHED_SYMLINK.
* doc/posix-functions/faccessat.texi: Mention the problem.
* lib/faccessat.c (FACCESSAT_NEVER_EOVERFLOWS)
(LSTAT_FOLLOWS_SLASHED_SYMLINK): Default to 0.
(rpl_faccessat): If !FACCESSAT_NEVER_EOVERFLOWS, check
for F_OK and EOVERFLOW, which means we can return 0.
If LSTAT_FOLLOWS_SLASHED_SYMLINK, don't worry about
file names ending in slashes, as faccessat should already
do the right thing for them.
* m4/faccessat.m4 (gl_FUNC_FACCESSAT_EOVERFLOW): New macro.
(gl_FUNC_FACCESSAT): Use it.
2020-12-24 Paul Eggert <eggert@cs.ucla.edu>
+ faccessat: work around F_OK EOVERFLOW bug
+ * doc/posix-functions/faccessat.texi: Mention the problem.
+ * lib/faccessat.c (FACCESSAT_NEVER_EOVERFLOWS): Default to 0.
+ (rpl_faccessat): If !FACCESSAT_NEVER_EOVERFLOWS, check
+ for F_OK and EOVERFLOW, which means we can return 0.
+ * m4/faccessat.m4 (gl_FUNC_FACCESSAT_EOVERFLOW): New macro.
+ (gl_FUNC_FACCESSAT): Use it.
+
stat failing with EOVERFLOW implies existence
* lib/euidaccess.c (euidaccess):
* lib/file-has-acl.c (file_has_acl):
On some platforms, @code{faccessat (dfd, "file/", amode, flag)}
succeeds instead of failing when @file{file} is not a directory.
macOS 10.13.
+@item
+On some platforms, @code{faccessat} can incorrectly fail with
+@code{EOVERFLOW} when the mode is @code{F_OK}:
+GNU/Linux with glibc 2.32, or with Linux kernel 5.7.
+@c This bug should be fixed in glibc 2.33 and kernel 5.8. See:
+@c https://sourceware.org/bugzilla/show_bug.cgi?id=18683
@end itemize
Portability problems not fixed by Gnulib:
which is supported by GNU @code{faccessat}.
@item
On some platforms, @code{faccessat} can mishandle @code{AT_EACCESS}
-after a process starts as root and then becomes non-root:
-GNU/Linux with glibc 2.32.
-@c This bug should be fixed in glibc 2.33. See:
+after a process starts as root and then becomes non-root,
+or can incorrectly fail with @code{EOVERFLOW} when the mode
+is not @code{F_OK}:
+GNU/Linux with glibc 2.32, or with Linux kernel 5.7.
+@c These bugs should be fixed in glibc 2.33 and kernel 5.8. See:
@c https://sourceware.org/bugzilla/show_bug.cgi?id=18683
@end itemize
#include <sys/stat.h>
#undef _GL_INCLUDING_UNISTD_H
+#ifndef FACCESSAT_NEVER_EOVERFLOWS
+# define FACCESSAT_NEVER_EOVERFLOWS 0
+#endif
+#ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK
+# define LSTAT_FOLLOWS_SLASHED_SYMLINK 0
+#endif
+
#if HAVE_FACCESSAT
static int
orig_faccessat (int fd, char const *name, int mode, int flag)
{
int result = orig_faccessat (fd, file, mode, flag);
- if (result == 0 && file[strlen (file) - 1] == '/')
+ if (result != 0)
+ {
+ if (!FACCESSAT_NEVER_EOVERFLOWS && mode == F_OK && errno == EOVERFLOW)
+ return 0;
+ }
+ else if (!LSTAT_FOLLOWS_SLASHED_SYMLINK && file[strlen (file) - 1] == '/')
{
struct stat st;
result = fstatat (fd, file, &st, 0);
-# serial 8
+# serial 9
# See if we need to provide faccessat replacement.
dnl Copyright (C) 2009-2020 Free Software Foundation, Inc.
# Written by Eric Blake.
+AC_DEFUN([gl_FUNC_FACCESSAT_EOVERFLOW],
+[
+ AC_CHECK_FUNCS_ONCE([faccessat])
+ if test "$ac_cv_func_faccessat" = yes; then
+ AC_CACHE_CHECK([whether faccessat works when stat would EOVERFLOW],
+ [gl_cv_func_faccessat_never_eoverflows],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([],
+ [[#ifdef __linux__
+ #include <linux/version.h>
+ #if (! (KERNEL_VERSION (5, 8, 0) <= LINUX_VERSION_CODE \
+ && 2 < (__GLIBC__ + (33 <= __GLIBC_MINOR__))))
+ #error "faccessat might fail with EOVERFLOW"
+ #endif
+ #endif
+ ]])],
+ [gl_cv_func_faccessat_never_eoverflows=yes],
+ [gl_cv_func_faccessat_never_eoverflows=no])])
+ if test "$gl_cv_func_faccessat_never_eoverflows" = yes; then
+ AC_DEFINE([FACCESSAT_NEVER_EOVERFLOWS], 1,
+ [Define to 1 if faccessat is EOVERFLOW-free.])
+ fi
+ fi
+])
+
AC_DEFUN([gl_FUNC_FACCESSAT],
[
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
dnl Persuade glibc <unistd.h> to declare faccessat().
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ AC_REQUIRE([gl_FUNC_FACCESSAT_EOVERFLOW])
+
AC_CHECK_FUNCS_ONCE([faccessat])
if test $ac_cv_func_faccessat = no; then
HAVE_FACCESSAT=0
else
- case "$gl_cv_func_lstat_dereferences_slashed_symlink" in
- *yes) ;;
+ case $gl_cv_func_lstat_dereferences_slashed_symlink,$gl_cv_func_faccessat_never_eoverflows in
+ *yes,*yes) ;;
*) REPLACE_FACCESSAT=1 ;;
esac
fi