diff options
author | Jim Meyering <jim@meyering.net> | 1995-07-27 03:56:35 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1995-07-27 03:56:35 +0000 |
commit | 8c17f50aea64f125655602fe2c2efb8855e88d9d (patch) | |
tree | 4576f346cc5db8790f320fdfca64cf7b0de7a465 /src/tail.c | |
parent | 28e28e6d749747b1b77878d31308c665195283ca (diff) | |
download | coreutils-8c17f50aea64f125655602fe2c2efb8855e88d9d.tar.xz |
(tail_bytes) [from_start]: For regular files, seek
relative to the initial input file pointer position, not
necessarily from the beginning of the file.
[!from_start]: Don't back up past the initial position of the
input file pointer.
(tail_lines): Call file_lines only if FD refers to a regular file
with its file pointer positioned at beginning of file. Otherwise,
call pipe_lines. This is a kludge. Once there's a decent test
suite, fix this properly.
Before, (echo 1; echo 2) > k; sh -c 'read x; tail' < k
would output both lines of the input file even though the first had
already been read. Reported by John Roll (john@panic.harvard.edu).
Diffstat (limited to 'src/tail.c')
-rw-r--r-- | src/tail.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/src/tail.c b/src/tail.c index 448c35571..9046938a2 100644 --- a/src/tail.c +++ b/src/tail.c @@ -476,7 +476,7 @@ tail_bytes (filename, fd, n_bytes) if (from_start) { if (S_ISREG (stats.st_mode)) - lseek (fd, n_bytes, SEEK_SET); + lseek (fd, n_bytes, SEEK_CUR); else if (start_bytes (filename, fd, n_bytes)) return 1; dump_remainder (filename, fd); @@ -485,13 +485,37 @@ tail_bytes (filename, fd, n_bytes) { if (S_ISREG (stats.st_mode)) { - if (lseek (fd, (off_t) 0, SEEK_END) <= n_bytes) - /* The file is shorter than we want, or just the right size, so - print the whole file. */ - lseek (fd, (off_t) 0, SEEK_SET); + off_t current_pos, end_pos; + size_t bytes_remaining; + + if ((current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1 + && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1) + { + off_t diff; + /* Be careful here. The current position may actually be + beyond the end of the file. */ + bytes_remaining = (diff = end_pos - current_pos) < 0 ? 0 : diff; + } + else + { + error (0, errno, "%s", filename); + return 1; + } + + if (bytes_remaining <= n_bytes) + { + /* From the current position to end of file, there are no + more bytes than have been requested. So reposition the + file pointer to the incoming current position and print + everything after that. */ + lseek (fd, current_pos, SEEK_SET); + } else - /* The file is longer than we want, so go back. */ - lseek (fd, -n_bytes, SEEK_END); + { + /* There are more bytes remaining than were requested. + Back up. */ + lseek (fd, -n_bytes, SEEK_END); + } dump_remainder (filename, fd); } else @@ -526,7 +550,14 @@ tail_lines (filename, fd, n_lines) } else { - if (S_ISREG (stats.st_mode)) + /* Use file_lines only if FD refers to a regular file with + its file pointer positioned at beginning of file. */ + /* FIXME: adding the lseek conjunct is a kludge. + Once there's a reasonable test suite, fix the true culprit: + file_lines. file_lines shouldn't presume that the input + file pointer is initially positioned to beginning of file. */ + if (S_ISREG (stats.st_mode) + && lseek (fd, (off_t) 0, SEEK_CUR) == (off_t) 0) { length = lseek (fd, (off_t) 0, SEEK_END); if (length != 0 && file_lines (filename, fd, n_lines, length)) |