]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
fchmodat: Use issymlinkat.
authorBruno Haible <bruno@clisp.org>
Thu, 14 Aug 2025 20:18:57 +0000 (22:18 +0200)
committerBruno Haible <bruno@clisp.org>
Thu, 14 Aug 2025 22:23:29 +0000 (00:23 +0200)
* lib/fchmodat.c (fchmodat): Use issymlinkat instead of readlinkat.
* modules/fchmodat (Depends-on): Add issymlinkat, openat.

ChangeLog
lib/fchmodat.c
modules/fchmodat

index 9df8c9b99b78c25c8d581c41269f64a4b4a9833f..386c8bd475e99257b5415d568a30c6aa482cadd8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2025-08-14  Bruno Haible  <bruno@clisp.org>
+
+       fchmodat: Use issymlinkat.
+       * lib/fchmodat.c (fchmodat): Use issymlinkat instead of readlinkat.
+       * modules/fchmodat (Depends-on): Add issymlinkat, openat.
+
 2025-08-14  Bruno Haible  <bruno@clisp.org>
 
        lchmod: Use issymlink, issymlinkat.
index eb82e1cafbfad473bcf89e619e80749ff53bdc1c..57222e58eb65e802e7f76f077adc196d8cb292ff 100644 (file)
@@ -84,8 +84,6 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
   if (flags == AT_SYMLINK_NOFOLLOW)
     {
 #  if HAVE_READLINKAT
-      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
@@ -96,17 +94,20 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
         return fd;
 
       int err;
-      if (0 <= readlinkat (fd, "", readlink_buf, sizeof readlink_buf))
-        err = EOPNOTSUPP;
-      else if (errno == EINVAL)
-        {
-          static char const fmt[] = "/proc/self/fd/%d";
-          char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
-          sprintf (buf, fmt, fd);
-          err = chmod (buf, mode) == 0 ? 0 : errno == ENOENT ? -1 : errno;
-        }
-      else
-        err = errno == ENOENT ? -1 : errno;
+      {
+        int ret = issymlinkat (fd, "");
+        if (ret > 0)
+          err = EOPNOTSUPP;
+        else if (ret == 0)
+          {
+            static char const fmt[] = "/proc/self/fd/%d";
+            char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
+            sprintf (buf, fmt, fd);
+            err = chmod (buf, mode) == 0 ? 0 : errno == ENOENT ? -1 : errno;
+          }
+        else
+          err = errno == ENOENT ? -1 : errno;
+      }
 
       close (fd);
 
@@ -117,7 +118,7 @@ fchmodat (int dir, char const *file, mode_t mode, int flags)
 
       /* O_PATH + /proc is not supported.  */
 
-      if (0 <= readlinkat (dir, file, readlink_buf, sizeof readlink_buf))
+      if (issymlinkat (dir, file) > 0)
         {
           errno = EOPNOTSUPP;
           return -1;
index 3afd0efd3035397d56dc159d4e31d346e4a0b383..914825c1a47ebbce22bf13639df901e28766d507 100644 (file)
@@ -14,6 +14,8 @@ fcntl-h         [test $HAVE_FCHMODAT = 0 || test $REPLACE_FCHMODAT = 1]
 unistd-h        [test $HAVE_FCHMODAT = 0 || test $REPLACE_FCHMODAT = 1]
 intprops        [test $HAVE_FCHMODAT = 0 || test $REPLACE_FCHMODAT = 1]
 c99             [test $REPLACE_FCHMODAT = 1]
+issymlinkat     [test $REPLACE_FCHMODAT = 1]
+openat          [test $REPLACE_FCHMODAT = 1]
 at-internal     [test $HAVE_FCHMODAT = 0]
 chmod           [test $HAVE_FCHMODAT = 0]
 extern-inline   [test $HAVE_FCHMODAT = 0]