From 938035b9b4b5913ec4919290117f14d99438be8c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 14 Jul 2025 16:41:05 -0700 Subject: [PATCH] =?utf8?q?maint:=20don=E2=80=99t=20lseek=20memory=20object?= =?utf8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This affects behavior only on memory objects, which are not in Linux. Formerly the code would use lseek on these objects, but POSIX says the result of lseek is unspecified on them, and in QNX lseek has undefined behavior on typed memory objects. * src/head.c (elide_tail_bytes_file, elide_tail_lines_file): Omit unnecessary uses of presume_input_pipe. Improve some out-of-date comments. (head): Do not assume a file is seekable merely because its st_size is usable. Instead, seek only on regular files. * src/od.c (skip): Do not seek on memory objects. --- src/head.c | 16 ++++++++-------- src/od.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/head.c b/src/head.c index 21ff87df62..1d83d2f1fc 100644 --- a/src/head.c +++ b/src/head.c @@ -452,8 +452,8 @@ elide_tail_bytes_pipe (char const *filename, int fd, uintmax_t n_elide, } /* For the file FILENAME with descriptor FD, output all but the last N_ELIDE - bytes. If SIZE is nonnegative, this is a regular file positioned - at CURRENT_POS with SIZE bytes. Return true on success. + bytes. If CURRENT_POS is nonnegative, this is a regular file positioned + at CURRENT_POS. The file's status is ST. Return true on success. Give a diagnostic and return false upon error. */ /* NOTE: if the input file shrinks by more than N_ELIDE bytes between @@ -464,7 +464,7 @@ elide_tail_bytes_file (char const *filename, int fd, uintmax_t n_elide, struct stat const *st, off_t current_pos) { off_t size = st->st_size; - if (presume_input_pipe || current_pos < 0 || size <= STP_BLKSIZE (st)) + if (current_pos < 0 || size <= STP_BLKSIZE (st)) return elide_tail_bytes_pipe (filename, fd, n_elide, current_pos); else { @@ -745,16 +745,16 @@ elide_tail_lines_seekable (char const *pretty_filename, int fd, } /* For the file FILENAME with descriptor FD, output all but the last N_ELIDE - lines. If SIZE is nonnegative, this is a regular file positioned - at START_POS with SIZE bytes. Return true on success. - Give a diagnostic and return nonzero upon error. */ + lines. If CURRENT_POS is nonnegative, this is a regular file positioned + at CURRENT_POS. The file's status is ST. Return true on success. + Give a diagnostic and return false upon error. */ static bool elide_tail_lines_file (char const *filename, int fd, uintmax_t n_elide, struct stat const *st, off_t current_pos) { off_t size = st->st_size; - if (presume_input_pipe || current_pos < 0 || size <= STP_BLKSIZE (st)) + if (current_pos < 0 || size <= STP_BLKSIZE (st)) return elide_tail_lines_pipe (filename, fd, n_elide, current_pos); else { @@ -838,7 +838,7 @@ head (char const *filename, int fd, uintmax_t n_units, bool count_lines, quoteaf (filename)); return false; } - if (! presume_input_pipe && usable_st_size (&st)) + if (! presume_input_pipe && S_ISREG (st.st_mode)) { current_pos = elseek (fd, 0, SEEK_CUR, filename); if (current_pos < 0) diff --git a/src/od.c b/src/od.c index be7d067519..d38a4c3803 100644 --- a/src/od.c +++ b/src/od.c @@ -1109,8 +1109,6 @@ skip (intmax_t n_skip) if (fstat (fileno (in_stream), &file_stats) == 0) { - bool usable_size = usable_st_size (&file_stats); - /* The st_size field is valid for regular files. If the number of bytes left to skip is larger than the size of the current file, we can decrement n_skip @@ -1118,7 +1116,8 @@ skip (intmax_t n_skip) when st_size is no greater than the block size, because some kernels report nonsense small file sizes for proc-like file systems. */ - if (usable_size && STP_BLKSIZE (&file_stats) < file_stats.st_size) + if (S_ISREG (file_stats.st_mode) + && STP_BLKSIZE (&file_stats) < file_stats.st_size) { if (file_stats.st_size < n_skip) n_skip -= file_stats.st_size; @@ -1133,11 +1132,14 @@ skip (intmax_t n_skip) } } - else if (!usable_size && fseeko (in_stream, n_skip, SEEK_CUR) == 0) + else if (! (S_ISREG (file_stats.st_mode) + || S_TYPEISSHM (&file_stats) + || S_TYPEISTMO (&file_stats)) + && fseeko (in_stream, n_skip, SEEK_CUR) == 0) n_skip = 0; - /* If it's not a regular file with nonnegative size, - or if it's so small that it might be in a proc-like file system, + /* If it's neither a seekable file with unusable size, nor a + regular file so large it can't be in a proc-like file system, position the file pointer by reading. */ else -- 2.47.2