]> Savannah Git Hosting - gnulib.git/commitdiff
fchmodat: port better to MS-Windows etc.
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 12 Jun 2022 20:46:52 +0000 (13:46 -0700)
committerBruno Haible <bruno@clisp.org>
Wed, 31 Aug 2022 23:13:19 +0000 (01:13 +0200)
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
lib/fchmodat.c
lib/lchmod.c
lib/lchown.c
lib/renameatu.c
m4/fchmodat.m4
m4/lchmod.m4
modules/lchown
modules/renameatu

index 13cd60378f73a3c8a5be51b20be7878dd0bb68df..3209c58e2100ed1edcce26f805fcac477c73530c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+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
index 3531b9030fd1bf7d2dbab1dab5127a5efd1a4b6f..e886ec4befa624713574bdef627a7fe38d3ff4b7 100644 (file)
@@ -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, &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;
index b6ff81c7134967ab11dda3ee232d66b19df24d2a..0e227592ae657739245c1b00b841fa00f8d5dfd1 100644 (file)
 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;
index 105c2d9990b404de54fbd579a15d83b252947f93..8b0d871a27ed8576c4bef40c96a318ed87acdc2a 100644 (file)
@@ -45,9 +45,9 @@ lchown (const char *file, uid_t uid, gid_t gid)
 {
 # 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;
index 764ac742f7ae3963110bc7bc8429af75ebf00bf0..f323af5698d00c0c9dd29e022a6fc386ae5ab77b 100644 (file)
@@ -213,15 +213,16 @@ renameatu (int fd1, char const *src, int fd2, char const *dst,
           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 */
index a5cf95a88be193413b83cb5cb5a66f4ff2a01007..f743ce1b02544cd7b3db58b49d2791a8cda6237c 100644 (file)
@@ -1,4 +1,4 @@
-# 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,
@@ -97,6 +97,6 @@ AC_DEFUN([gl_FUNC_FCHMODAT],
 # Prerequisites of lib/fchmodat.c.
 AC_DEFUN([gl_PREREQ_FCHMODAT],
 [
-  AC_CHECK_FUNCS_ONCE([lchmod])
+  AC_CHECK_FUNCS_ONCE([readlinkat])
   :
 ])
index 5baee738efdc6cb50671d8a24a7f2df3ae01e128..bfc925fbe482054c4d9873fc8f75e7653edaa73e 100644 (file)
@@ -1,4 +1,4 @@
-#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
@@ -15,9 +15,7 @@ AC_DEFUN([gl_FUNC_LCHMOD],
   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
@@ -26,5 +24,6 @@ AC_DEFUN([gl_FUNC_LCHMOD],
 # Prerequisites of lib/lchmod.c.
 AC_DEFUN([gl_PREREQ_LCHMOD],
 [
+  AC_CHECK_FUNCS_ONCE([readlink])
   :
 ])
index 1ddecca4c79e279fc3c47197188fa7524535b4be..c366e9ef03d1e0f3f64f8a4720c39f1c7ff70b84 100644 (file)
@@ -7,11 +7,12 @@ m4/lchown.m4
 
 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
index 5ce8e47587da08a7d7fc3257e3eac66616d9d351..72d74faeca3e00e31a217379c071a2e516465d88 100644 (file)
@@ -13,6 +13,8 @@ extensions
 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]