diff --git a/src/uu/wc/src/count_fast.rs b/src/uu/wc/src/count_fast.rs index 5fa1a978f38..1eb1d912724 100644 --- a/src/uu/wc/src/count_fast.rs +++ b/src/uu/wc/src/count_fast.rs @@ -10,7 +10,7 @@ use super::WordCountable; #[cfg(any(target_os = "linux", target_os = "android"))] use std::fs::OpenOptions; -use std::io::{self, ErrorKind, Read}; +use std::io::{self, ErrorKind, Read, Seek, SeekFrom}; #[cfg(unix)] use libc::{sysconf, S_IFREG, _SC_PAGESIZE}; @@ -100,7 +100,7 @@ pub(crate) fn count_bytes_fast(handle: &mut T) -> (usize, Opti // would count up only to a couple of bytes. // This condition usually occurs for files in pseudo-filesystems like /proc, /sys // that report `st_size` in the multiples of system page size. - // In such cases - fall back on full read + // In such cases - attempt `seek()` for the end of file // // And finally a special case of input redirection in *nix shell: // `( wc -c ; wc -c ) < file` should return @@ -126,6 +126,10 @@ pub(crate) fn count_bytes_fast(handle: &mut T) -> (usize, Opti // regular file or file from /proc, /sys and similar pseudo-filesystems // with size that is NOT a multiple of system page size return (stat.st_size as usize, None); + } else if let Some(file) = handle.inner_file() { + if let Ok(n) = file.seek(SeekFrom::End(0)) { + return (n as usize, None); + } } } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/src/uu/wc/src/countable.rs b/src/uu/wc/src/countable.rs index 64397446491..d27c7fb5968 100644 --- a/src/uu/wc/src/countable.rs +++ b/src/uu/wc/src/countable.rs @@ -17,12 +17,14 @@ use std::os::unix::io::AsRawFd; pub trait WordCountable: AsRawFd + Read { type Buffered: BufRead; fn buffered(self) -> Self::Buffered; + fn inner_file(&mut self) -> Option<&mut File>; } #[cfg(not(unix))] pub trait WordCountable: Read { type Buffered: BufRead; fn buffered(self) -> Self::Buffered; + fn inner_file(&mut self) -> Option<&mut File>; } impl WordCountable for StdinLock<'_> { @@ -31,6 +33,9 @@ impl WordCountable for StdinLock<'_> { fn buffered(self) -> Self::Buffered { self } + fn inner_file(&mut self) -> Option<&mut File> { + None + } } impl WordCountable for File { @@ -39,4 +44,8 @@ impl WordCountable for File { fn buffered(self) -> Self::Buffered { BufReader::new(self) } + + fn inner_file(&mut self) -> Option<&mut File> { + Some(self) + } }