From: Paul Eggert Date: Tue, 29 Jul 2025 16:14:37 +0000 (-0700) Subject: tail: refactor SEEK_END and lines X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3918655d4b4bc0e52349aebd7c9816b401ac0d9d;p=thirdparty%2Fcoreutils.git tail: refactor SEEK_END and lines * 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. --- diff --git a/src/tail.c b/src/tail.c index 6ba3e8379b..4715bd1d85 100644 --- a/src/tail.c +++ b/src/tail.c @@ -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,