From d682f8de7f9d384f4cfc482a3ba2960329a8db21 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 12 Jun 2022 13:46:52 -0700 Subject: 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. --- lib/lchmod.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'lib/lchmod.c') diff --git a/lib/lchmod.c b/lib/lchmod.c index b4cc0a8176..f21bf7f652 100644 --- a/lib/lchmod.c +++ b/lib/lchmod.c @@ -45,7 +45,10 @@ 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. @@ -55,8 +58,7 @@ lchmod (char const *file, mode_t mode) 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) { @@ -73,16 +75,11 @@ lchmod (char const *file, mode_t mode) 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; -- cgit v1.2.1