summaryrefslogtreecommitdiff
path: root/src/tail.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1995-07-27 03:56:35 +0000
committerJim Meyering <jim@meyering.net>1995-07-27 03:56:35 +0000
commit8c17f50aea64f125655602fe2c2efb8855e88d9d (patch)
tree4576f346cc5db8790f320fdfca64cf7b0de7a465 /src/tail.c
parent28e28e6d749747b1b77878d31308c665195283ca (diff)
downloadcoreutils-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.c47
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))