]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tail: refactor SEEK_END and lines
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 29 Jul 2025 16:14:37 +0000 (09:14 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 4 Aug 2025 02:48:05 +0000 (19:48 -0700)
* src/tail.c (tail_lines): Refactor to simplify the confusing
code for using SEEK_END when counting lines.  The old code
had a ‘end_pos != 0’ expression that was always true.

src/tail.c

index 6ba3e8379bb2c9292b0ca34e34c1c0c4f01f326c..4715bd1d8567d17b879628d43d98bc1ad794fe24 100644 (file)
@@ -1964,38 +1964,30 @@ tail_lines (char const *pretty_filename, int fd, struct stat const *st,
             return t < 0;
           *read_pos += dump_remainder (false, pretty_filename, fd, COPY_TO_EOF);
         }
+      return true;
     }
   else
     {
-      off_t start_pos = -1;
-      off_t end_pos;
-
-      /* Use file_lines only if FD refers to a regular file for
-         which lseek (... SEEK_END) works.  */
-      if ( ! presume_input_pipe
-           && S_ISREG (st->st_mode)
-           && (start_pos = lseek (fd, 0, SEEK_CUR)) != -1
-           && start_pos < (end_pos = lseek (fd, 0, SEEK_END)))
-        {
-          *read_pos = end_pos;
-          if (end_pos != 0
-              && ! file_lines (pretty_filename, fd, st, n_lines,
-                               start_pos, end_pos, read_pos))
-            return false;
-        }
-      else
+      /* Use file_lines only if FD is a regular file and SEEK_END
+         reports more data.  */
+      off_t start_pos = (!presume_input_pipe && S_ISREG (st->st_mode)
+                         ? lseek (fd, 0, SEEK_CUR)
+                         : -1);
+      off_t end_pos = start_pos < 0 ? -1 : lseek (fd, 0, SEEK_END);
+      if (0 <= end_pos)
         {
-          /* Under very unlikely circumstances, it is possible to reach
-             this point after positioning the file pointer to end of file
-             via the 'lseek (...SEEK_END)' above.  In that case, reposition
-             the file pointer back to start_pos before calling pipe_lines.  */
-          if (start_pos != -1)
-            xlseek (fd, start_pos, SEEK_SET, pretty_filename);
+          if (start_pos < end_pos)
+            return file_lines (pretty_filename, fd, st, n_lines,
+                               start_pos, end_pos, read_pos);
 
-          return pipe_lines (pretty_filename, fd, n_lines, read_pos);
+          /* Do not read from before the start offset, even if the
+             input file shrank.  */
+          if (end_pos < start_pos)
+            xlseek (fd, start_pos, SEEK_SET, pretty_filename);
         }
+
+      return pipe_lines (pretty_filename, fd, n_lines, read_pos);
     }
-  return true;
 }
 
 /* Display the last N_UNITS units of file FILENAME,