+2022-06-12 Paul Eggert <eggert@cs.ucla.edu>
+
+ fchmodat: port better to MS-Windows etc.
+ MS-Windows problem reported by Bruno Haible in:
+ https://lists.gnu.org/r/bug-gnulib/2022-06/msg00041.html
+ Although I don’t use MS-Windows I see some related fstatat etc.
+ problems and am trying to fix them with this further patch.
+ * lib/fchmodat.c (fchmodat):
+ * lib/lchmod.c (lchmod):
+ * lib/lchown.c (lchown)
+ [!HAVE_LCHOWN && HAVE_CHOWN && !CHOWN_MODIFIES_SYMLINK]:
+ * lib/renameatu.c (renameatu)
+ [HAVE_RENAME && RENAME_TRAILING_SLASH_SOURCE_BUG]:
+ Use readlinkat/readlink instead of fstatat/lstat to test merely
+ whether a string names a symlink, as this avoids problems
+ with EOVERFLOW. Also, I hope it works around the MS-Windows
+ issues that Bruno noted.
+ * m4/fchmodat.m4 (gl_PREREQ_FCHMODAT):
+ Check for readlinkat, not lchmod.
+ * m4/lchmod.m4 (gl_FUNC_LCHMOD): Do not require AC_CANONICAL_HOST
+ or check for lstat.
+ (gl_PREREQ_LCHMOD): Check for readlink.
+ * modules/lchown (Depends-on): Add readlink. Do not depend on
+ lstat merely because !HAVE_LCHOWN.
+ * modules/renameatu (Depends-on): Add fstatat, readlinkat.
+
2022-06-11 Paul Eggert <eggert@cs.ucla.edu>
fchmodat: port to old Linux kernel + newer headers
# if NEED_FCHMODAT_NONSYMLINK_FIX
if (flags == AT_SYMLINK_NOFOLLOW)
{
- struct stat st;
+# if HAVE_READLINKAT
+ char readlink_buf[1];
-# ifdef O_PATH
+# ifdef O_PATH
/* Open a file descriptor with O_NOFOLLOW, to make sure we don't
follow symbolic links, if /proc is mounted. O_PATH is used to
avoid a failure if the file is not readable.
int err;
char buf[1];
- if (0 <= readlinkat (fd, "", buf, sizeof buf))
+ if (0 <= readlinkat (fd, "", readlink_buf, sizeof readlink_buf))
err = EOPNOTSUPP;
else if (errno == EINVAL)
{
errno = err;
if (0 <= err)
return err == 0 ? 0 : -1;
-# endif
+# endif
/* O_PATH + /proc is not supported. */
- int fstatat_result = fstatat (dir, file, &st, AT_SYMLINK_NOFOLLOW);
- if (fstatat_result != 0)
- return fstatat_result;
- if (S_ISLNK (st.st_mode))
+
+ if (0 <= readlinkat (dir, file, readlink_buf, sizeof readlink_buf))
{
errno = EOPNOTSUPP;
return -1;
}
+# endif
/* Fall back on orig_fchmodat with no flags, despite a possible race. */
flags = 0;
int
lchmod (char const *file, mode_t mode)
{
-#ifdef O_PATH
+#if HAVE_READLINK
+ char readlink_buf[1];
+
+# ifdef O_PATH
/* Open a file descriptor with O_NOFOLLOW, to make sure we don't
follow symbolic links, if /proc is mounted. O_PATH is used to
avoid a failure if the file is not readable.
return fd;
int err;
- char buf[1];
- if (0 <= readlinkat (fd, "", buf, sizeof buf))
+ if (0 <= readlinkat (fd, "", readlink_buf, sizeof readlink_buf))
err = EOPNOTSUPP;
else if (errno == EINVAL)
{
errno = err;
if (0 <= err)
return err == 0 ? 0 : -1;
-#endif
+# endif
/* O_PATH + /proc is not supported. */
-#if HAVE_LSTAT
- struct stat st;
- int lstat_result = lstat (file, &st);
- if (lstat_result != 0)
- return lstat_result;
- if (S_ISLNK (st.st_mode))
+ if (0 <= readlink (file, readlink_buf, sizeof readlink_buf))
{
errno = EOPNOTSUPP;
return -1;
{
# if HAVE_CHOWN
# if ! CHOWN_MODIFIES_SYMLINK
- struct stat stats;
+ char readlink_buf[1];
- if (lstat (file, &stats) == 0 && S_ISLNK (stats.st_mode))
+ if (0 <= readlink (file, readlink_buf, sizeof readlink_buf))
{
errno = EOPNOTSUPP;
return -1;
goto out;
}
strip_trailing_slashes (dst_temp);
- if (lstatat (fd2, dst_temp, &dst_st))
+ char readlink_buf[1];
+ if (readlinkat (fd2, dst_temp, readlink_buf, sizeof readlink_buf) < 0)
{
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != EINVAL)
{
rename_errno = errno;
goto out;
}
}
- else if (S_ISLNK (dst_st.st_mode))
+ else
goto out;
}
# endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */
-# fchmodat.m4 serial 6
+# fchmodat.m4 serial 7
dnl Copyright (C) 2004-2022 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
# Prerequisites of lib/fchmodat.c.
AC_DEFUN([gl_PREREQ_FCHMODAT],
[
- AC_CHECK_FUNCS_ONCE([lchmod])
+ AC_CHECK_FUNCS_ONCE([readlinkat])
:
])
-#serial 8
+#serial 9
dnl Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl Persuade glibc <sys/stat.h> to declare lchmod().
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
- AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
-
- AC_CHECK_FUNCS_ONCE([lchmod lstat])
+ AC_CHECK_FUNCS_ONCE([lchmod])
if test "$ac_cv_func_lchmod" = no; then
HAVE_LCHMOD=0
fi
# Prerequisites of lib/lchmod.c.
AC_DEFUN([gl_PREREQ_LCHMOD],
[
+ AC_CHECK_FUNCS_ONCE([readlink])
:
])
Depends-on:
unistd
+readlink [test $HAVE_LCHOWN = 0]
chown [test $HAVE_LCHOWN = 0 || test $REPLACE_LCHOWN = 1]
errno [test $HAVE_LCHOWN = 0 || test $REPLACE_LCHOWN = 1]
-lstat [test $HAVE_LCHOWN = 0 || test $REPLACE_LCHOWN = 1]
stdbool [test $HAVE_LCHOWN = 0 || test $REPLACE_LCHOWN = 1]
sys_stat [test $HAVE_LCHOWN = 0 || test $REPLACE_LCHOWN = 1]
+lstat [test $REPLACE_LCHOWN = 1]
configure.ac:
gl_FUNC_LCHOWN
fcntl-h
filenamecat-lgpl [test $HAVE_RENAMEAT = 0 || test $REPLACE_RENAMEAT = 1]
openat-h [test $HAVE_RENAMEAT = 0 || test $REPLACE_RENAMEAT = 1]
+fstatat [test $REPLACE_RENAMEAT = 1]
+readlinkat [test $REPLACE_RENAMEAT = 1]
statat [test $REPLACE_RENAMEAT = 1]
stdbool [test $REPLACE_RENAMEAT = 1]
at-internal [test $HAVE_RENAMEAT = 0]