On 6/12/22 08:03, Bruno Haible wrote:
Two tests now fail, that succeeded before yesterday's patch.
Thanks for reporting that. Although I don't have MS-Windows I stared at
the code a bit and I think I see what might be the problem. I found some
other potential issues too (basically, I didn't switch from
fstatat/lstat to readlinkat/readlink often enough so the code is still
prone to EOVERFLOW problems). I installed the attached further patch,
which I hope fixes things on MS-Windows and fixes the other issues too.
From d682f8de7f9d384f4cfc482a3ba2960329a8db21 Mon Sep 17 00:00:00 2001
From: Paul Eggert
Date: Sun, 12 Jun 2022 13:46:52 -0700
Subject: [PATCH] fchmodat: port better to MS-Windows etc.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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.
---
ChangeLog | 26 ++
lib/fchmodat.c| 16
lib/lchmod.c | 17 +++--
lib/lchown.c | 4 ++--
lib/renameatu.c | 7 ---
m4/fchmodat.m4| 4 ++--
m4/lchmod.m4 | 7 +++
modules/lchown| 3 ++-
modules/renameatu | 2 ++
9 files changed, 56 insertions(+), 30 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2d0340b933..2daa6d8c81 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2022-06-12 Paul Eggert
+
+ 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-12 Bruno Haible
doc: Update O_PATH platforms list.
diff --git a/lib/fchmodat.c b/lib/fchmodat.c
index b233c366de..8ed4cb7398 100644
--- a/lib/fchmodat.c
+++ b/lib/fchmodat.c
@@ -83,9 +83,10 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
# 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.
@@ -96,7 +97,7 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
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)
{
@@ -113,17 +114,16 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
errno = err;
if (0 <= err)
return err == 0 ? 0 : -1;
-# endif
+# endif
/* O_PATH + /proc is not supported. */
- int fstatat_result = fstatat (dir, file, , 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