From 2d386993e28c8cca6be7f28271268192c3cbd094 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 2 Aug 2025 12:58:06 -0700 Subject: [PATCH] tail: prefer readlink to lstat+S_ISLNK When not already calling lstat for some other reason, prefer readlink to lstat+S_ISLNK, as readlink does not suffer from EOVERFLOW issues. * src/rmdir.c (main): * src/tail.c (recheck, any_symlinks): * src/test.c (unary_operator): --- src/rmdir.c | 4 ++-- src/tail.c | 8 ++++---- src/test.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rmdir.c b/src/rmdir.c index 88fcb2521d..fead0bb198 100644 --- a/src/rmdir.c +++ b/src/rmdir.c @@ -269,8 +269,8 @@ main (int argc, char **argv) /* Ensure the last component was a symlink. */ char *dir_arg = xstrdup (dir); strip_trailing_slashes (dir); - ret = lstat (dir, &st); - if (ret == 0 && S_ISLNK (st.st_mode)) + char linkbuf[1]; + if (0 <= readlink (dir, linkbuf, 1)) { error (0, 0, _("failed to remove %s:" diff --git a/src/tail.c b/src/tail.c index 2579f4e13b..5543cc24cd 100644 --- a/src/tail.c +++ b/src/tail.c @@ -975,8 +975,8 @@ recheck (struct File_spec *f, bool blocking) then mark the file as not tailable. */ f->tailable = !(reopen_inaccessible_files && fd < 0); - if (! disable_inotify && ! lstat (f->name, &new_stats) - && S_ISLNK (new_stats.st_mode)) + char linkbuf[1]; + if (! disable_inotify && 0 <= readlink (f->name, linkbuf, 1)) { /* Diagnose the edge case where a regular file is changed to a symlink. We avoid inotify with symlinks since @@ -1352,9 +1352,9 @@ any_non_remote_file (const struct File_spec *f, int n_files) static bool any_symlinks (const struct File_spec *f, int n_files) { - struct stat st; + char linkbuf[1]; for (int i = 0; i < n_files; i++) - if (lstat (f[i].name, &st) == 0 && S_ISLNK (st.st_mode)) + if (0 <= readlink (f[i].name, linkbuf, 1)) return true; return false; } diff --git a/src/test.c b/src/test.c index fd9aa0d294..583cf74c9c 100644 --- a/src/test.c +++ b/src/test.c @@ -464,8 +464,8 @@ unary_operator (void) case 'h': /* File is a symbolic link? */ unary_advance (); - return (lstat (argv[pos - 1], &stat_buf) == 0 - && S_ISLNK (stat_buf.st_mode)); + char linkbuf[1]; + return 0 <= readlink (argv[pos - 1], linkbuf, 1); case 'u': /* File is setuid? */ unary_advance (); -- 2.47.2