mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-24 10:23:31 +08:00
tail: seek to the end of block devices
* src/tail.c (tail_bytes): Try lseek(..., SEEK_END) when we can't determine the file size. * tests/tail-2/end-of-device.sh: Add a new root only test. * tests/local.mk: Reference the new test. * NEWS: Mention the improvement. Paul Eggert suggested using lseek() (rather than ioctl(BLKGETSIZE64)). Fixes https://bugs.gnu.org/29259
This commit is contained in:
parent
25030d942d
commit
31dd7a0de2
5
NEWS
5
NEWS
@ -31,6 +31,11 @@ GNU coreutils NEWS -*- outline -*-
|
||||
timeout would have then waited for the time limit to expire.
|
||||
[bug introduced in coreutils-8.27]
|
||||
|
||||
** Improvements
|
||||
|
||||
tail --bytes=NUM will efficiently seek to the end of block devices,
|
||||
rather than reading from the start.
|
||||
|
||||
** Build-related
|
||||
|
||||
Default man pages are now distributed which are used if perl is
|
||||
|
27
src/tail.c
27
src/tail.c
@ -1830,12 +1830,11 @@ tail_bytes (const char *pretty_filename, int fd, uintmax_t n_bytes,
|
||||
|
||||
if (from_start)
|
||||
{
|
||||
if ( ! presume_input_pipe
|
||||
&& S_ISREG (stats.st_mode) && n_bytes <= OFF_T_MAX)
|
||||
{
|
||||
xlseek (fd, n_bytes, SEEK_CUR, pretty_filename);
|
||||
*read_pos += n_bytes;
|
||||
}
|
||||
if (! presume_input_pipe && n_bytes <= OFF_T_MAX
|
||||
&& ((S_ISREG (stats.st_mode)
|
||||
&& xlseek (fd, n_bytes, SEEK_CUR, pretty_filename) >= 0)
|
||||
|| lseek (fd, n_bytes, SEEK_CUR) != -1))
|
||||
*read_pos += n_bytes;
|
||||
else
|
||||
{
|
||||
int t = start_bytes (pretty_filename, fd, n_bytes, read_pos);
|
||||
@ -1846,12 +1845,20 @@ tail_bytes (const char *pretty_filename, int fd, uintmax_t n_bytes,
|
||||
}
|
||||
else
|
||||
{
|
||||
off_t end_pos = ((! presume_input_pipe && usable_st_size (&stats)
|
||||
&& n_bytes <= OFF_T_MAX)
|
||||
? stats.st_size : -1);
|
||||
off_t end_pos = -1;
|
||||
off_t current_pos = -1;
|
||||
|
||||
if (! presume_input_pipe && n_bytes <= OFF_T_MAX)
|
||||
{
|
||||
if (usable_st_size (&stats))
|
||||
end_pos = stats.st_size;
|
||||
else if ((current_pos = lseek (fd, -n_bytes, SEEK_END)) != -1)
|
||||
end_pos = current_pos + n_bytes;
|
||||
}
|
||||
if (end_pos <= ST_BLKSIZE (stats))
|
||||
return pipe_bytes (pretty_filename, fd, n_bytes, read_pos);
|
||||
off_t current_pos = xlseek (fd, 0, SEEK_CUR, pretty_filename);
|
||||
if (current_pos == -1)
|
||||
current_pos = xlseek (fd, 0, SEEK_CUR, pretty_filename);
|
||||
if (current_pos < end_pos)
|
||||
{
|
||||
off_t bytes_remaining = end_pos - current_pos;
|
||||
|
@ -135,6 +135,7 @@ all_root_tests = \
|
||||
tests/rm/one-file-system.sh \
|
||||
tests/rm/read-only.sh \
|
||||
tests/tail-2/append-only.sh \
|
||||
tests/tail-2/end-of-device.sh \
|
||||
tests/touch/now-owned-by-other.sh
|
||||
|
||||
ALL_RECURSIVE_TARGETS += check-root
|
||||
|
48
tests/tail-2/end-of-device.sh
Executable file
48
tests/tail-2/end-of-device.sh
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
# Ensure that tail seeks to the end of a device
|
||||
|
||||
# Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
||||
print_ver_ tail
|
||||
|
||||
# need write access to local device
|
||||
# (even though we don't actually write anything)
|
||||
require_root_
|
||||
require_local_dir_
|
||||
|
||||
get_device_size() {
|
||||
BLOCKDEV=blockdev
|
||||
$BLOCKDEV -V >/dev/null 2>&1 || BLOCKDEV=/sbin/blockdev
|
||||
$BLOCKDEV --getsize64 "$1"
|
||||
}
|
||||
|
||||
# Get path to device the current dir is on.
|
||||
# Note df can only get fs size, not device size.
|
||||
device=$(df --output=source . | tail -n1) || framework_failure_
|
||||
|
||||
dev_size=$(get_device_size "$device") ||
|
||||
skip_ "failed to determine size of $device"
|
||||
|
||||
tail_offset=$(expr $dev_size - 1023) ||
|
||||
skip_ "failed to determine tail offset"
|
||||
|
||||
timeout 10 tail -c 1024 "$device" > end1 || fail=1
|
||||
timeout 10 tail -c +"$tail_offset" "$device" > end2 || fail=1
|
||||
test $(wc -c < end1) = 1024 || fail=1
|
||||
cmp end1 end2 || fail=1
|
||||
|
||||
Exit $fail
|
Loading…
Reference in New Issue
Block a user