Bruno added the issymlink and issymlinkat inline functions to Gnulib to
make code like this easier to understand:

   char dummy[1];
   if (0 <= readlink (dir, dummy, 1))
     {
        /* Handle symbolic links here.  */
     }

This patch converts the few cases used in coreutils.

Will push tomorrow, unless there is any objections.

Collin

>From 5fdb6e1b9b3096a6a5708d435af2bb82049cdd0b Mon Sep 17 00:00:00 2001
Message-ID: <5fdb6e1b9b3096a6a5708d435af2bb82049cdd0b.1756877797.git.collin.fu...@gmail.com>
From: Collin Funk <collin.fu...@gmail.com>
Date: Tue, 2 Sep 2025 22:25:46 -0700
Subject: [PATCH] maint: prefer issymlink to readlink with a small buffer

* bootstrap.conf (gnulib_modules): Add issymlink and issymlinkat.
* src/copy.c: Include issymlink.h.
(copy_reg): Use issymlink instead of readlinkat.
* src/rmdir.c: Include issymlink.h.
(main): Use issymlink instead of readlink.
* src/tail.c: Include issymlink.h.
(recheck, any_symlinks): Use issymlink instead of readlink.
* src/test.c: Include issymlink.h.
(unary_operator): Use issymlink instead of readlink.
---
 bootstrap.conf | 2 ++
 src/copy.c     | 6 +++---
 src/rmdir.c    | 4 ++--
 src/tail.c     | 7 +++----
 src/test.c     | 4 ++--
 5 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/bootstrap.conf b/bootstrap.conf
index 49fcf30f3..7d09752bc 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -152,6 +152,8 @@ gnulib_modules="
   isapipe
   isatty
   isblank
+  issymlink
+  issymlinkat
   largefile
   lchmod
   ldtoastr
diff --git a/src/copy.c b/src/copy.c
index 73ded6857..e89f376f2 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -49,6 +49,7 @@
 #include "hashcode-file.h"
 #include "ignore-value.h"
 #include "ioblksize.h"
+#include "issymlink.h"
 #include "quote.h"
 #include "renameatu.h"
 #include "root-uid.h"
@@ -1444,7 +1445,7 @@ copy_reg (char const *src_name, char const *dst_name,
 
       /* When trying to copy through a dangling destination symlink,
          the above open fails with EEXIST.  If that happens, and
-         readlinkat shows that it is a symlink, then we
+         issymlinkat shows that it is a symlink, then we
          have a problem: trying to resolve this dangling symlink to
          a directory/destination-entry pair is fundamentally racy,
          so punt.  If x->open_dangling_dest_symlink is set (cp sets
@@ -1454,8 +1455,7 @@ copy_reg (char const *src_name, char const *dst_name,
          only when copying, i.e., not in move_mode.  */
       if (dest_desc < 0 && dest_errno == EEXIST && ! x->move_mode)
         {
-          char dummy[1];
-          if (0 <= readlinkat (dst_dirfd, dst_relname, dummy, sizeof dummy))
+          if (issymlinkat (dst_dirfd, dst_relname) == 1)
             {
               if (x->open_dangling_dest_symlink)
                 {
diff --git a/src/rmdir.c b/src/rmdir.c
index fead0bb19..9ca3f7ed1 100644
--- a/src/rmdir.c
+++ b/src/rmdir.c
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 
 #include "system.h"
+#include "issymlink.h"
 #include "prog-fprintf.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
@@ -269,8 +270,7 @@ main (int argc, char **argv)
                       /* Ensure the last component was a symlink.  */
                       char *dir_arg = xstrdup (dir);
                       strip_trailing_slashes (dir);
-                      char linkbuf[1];
-                      if (0 <= readlink (dir, linkbuf, 1))
+                      if (issymlink (dir) == 1)
                         {
                           error (0, 0,
                                  _("failed to remove %s:"
diff --git a/src/tail.c b/src/tail.c
index ce3a3285b..753963937 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -39,6 +39,7 @@
 #include "fcntl--.h"
 #include "iopoll.h"
 #include "isapipe.h"
+#include "issymlink.h"
 #include "posixver.h"
 #include "quote.h"
 #include "stat-size.h"
@@ -976,8 +977,7 @@ recheck (struct File_spec *f, bool blocking)
 
   affirm (valid_file_spec (f));
 
-  char linkbuf[1];
-  if (! disable_inotify && 0 <= readlink (f->name, linkbuf, 1))
+  if (! disable_inotify && issymlink (f->name) == 1)
     {
       /* Diagnose the edge case where a regular file is changed
          to a symlink.  We avoid inotify with symlinks since
@@ -1350,9 +1350,8 @@ any_non_remote_file (const struct File_spec *f, int n_files)
 static bool
 any_symlinks (const struct File_spec *f, int n_files)
 {
-  char linkbuf[1];
   for (int i = 0; i < n_files; i++)
-    if (0 <= readlink (f[i].name, linkbuf, 1))
+    if (issymlink (f[i].name) == 1)
       return true;
   return false;
 }
diff --git a/src/test.c b/src/test.c
index 0c0785b9c..61bf8b741 100644
--- a/src/test.c
+++ b/src/test.c
@@ -41,6 +41,7 @@
 #include "system.h"
 #include "assure.h"
 #include "c-ctype.h"
+#include "issymlink.h"
 #include "quote.h"
 #include "stat-time.h"
 #include "strnumcmp.h"
@@ -467,8 +468,7 @@ unary_operator (void)
 
     case 'h':			/* File is a symbolic link? */
       unary_advance ();
-      char linkbuf[1];
-      return 0 <= readlink (argv[pos - 1], linkbuf, 1);
+      return issymlink (argv[pos - 1]) == 1;
 
     case 'u':			/* File is setuid? */
       unary_advance ();
-- 
2.51.0

Reply via email to