summaryrefslogtreecommitdiff
path: root/lib/lchmod.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2022-06-12 13:46:52 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2022-06-12 13:47:12 -0700
commitd682f8de7f9d384f4cfc482a3ba2960329a8db21 (patch)
tree65d04a8b5e462b2b4939b3addf0982de988a1bac /lib/lchmod.c
parent2cd86e5891af0cdb7d88d076e9613e5c8475e1ee (diff)
downloadgnulib-d682f8de7f9d384f4cfc482a3ba2960329a8db21.tar.gz
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.
Diffstat (limited to 'lib/lchmod.c')
-rw-r--r--lib/lchmod.c17
1 files changed, 7 insertions, 10 deletions
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;