diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index 264ae29aa..d547f2b47 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -23,7 +23,7 @@ clap = { workspace = true } libc = { workspace = true } memchr = { workspace = true } notify = { workspace = true } -uucore = { workspace = true, features = ["parser"] } +uucore = { workspace = true, features = ["fs", "parser"] } same-file = { workspace = true } [target.'cfg(windows)'.dependencies] diff --git a/src/uu/tail/src/paths.rs b/src/uu/tail/src/paths.rs index c2fc4f170..72579df93 100644 --- a/src/uu/tail/src/paths.rs +++ b/src/uu/tail/src/paths.rs @@ -158,7 +158,6 @@ impl FileExtTail for File { pub trait MetadataExtTail { fn is_tailable(&self) -> bool; fn got_truncated(&self, other: &Metadata) -> UResult; - fn get_block_size(&self) -> u64; fn file_id_eq(&self, other: &Metadata) -> bool; } @@ -180,17 +179,6 @@ impl MetadataExtTail for Metadata { Ok(other.len() < self.len() && other.modified()? != self.modified()?) } - fn get_block_size(&self) -> u64 { - #[cfg(unix)] - { - self.blocks() - } - #[cfg(not(unix))] - { - self.len() - } - } - fn file_id_eq(&self, _other: &Metadata) -> bool { #[cfg(unix)] { diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index aa74f08c6..1d13e3168 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -26,7 +26,7 @@ use args::{FilterMode, Settings, Signum, parse_args}; use chunks::ReverseChunks; use follow::Observer; use memchr::{memchr_iter, memrchr_iter}; -use paths::{FileExtTail, HeaderPrinter, Input, InputKind, MetadataExtTail}; +use paths::{FileExtTail, HeaderPrinter, Input, InputKind}; use same_file::Handle; use std::cmp::Ordering; use std::collections::HashMap; @@ -169,14 +169,15 @@ fn tail_file( } observer.add_bad_path(path, input.display_name.as_str(), false)?; } else if input.is_tailable() { - let metadata = path.metadata().ok(); match File::open(path) { Ok(mut file) => { + let st = file.metadata()?; + let blksize_limit = uucore::fs::sane_blksize::sane_blksize_from_metadata(&st); header_printer.print_input(input); let mut reader; if !settings.presume_input_pipe && file.is_seekable(if input.is_stdin() { offset } else { 0 }) - && metadata.as_ref().unwrap().get_block_size() > 0 + && (!st.is_file() || st.len() > blksize_limit) { bounded_tail(&mut file, settings); reader = BufReader::new(file); @@ -448,6 +449,7 @@ fn backwards_thru_file(file: &mut File, num_delimiters: u64, delimiter: u8) { /// being a nice performance win for very large files. fn bounded_tail(file: &mut File, settings: &Settings) { debug_assert!(!settings.presume_input_pipe); + let mut limit = None; // Find the position in the file to start printing from. match &settings.mode { @@ -462,9 +464,8 @@ fn bounded_tail(file: &mut File, settings: &Settings) { return; } FilterMode::Bytes(Signum::Negative(count)) => { - let len = file.seek(SeekFrom::End(0)).unwrap(); - file.seek(SeekFrom::End(-((*count).min(len) as i64))) - .unwrap(); + file.seek(SeekFrom::End(-(*count as i64))).unwrap(); + limit = Some(*count); } FilterMode::Bytes(Signum::Positive(count)) if count > &1 => { // GNU `tail` seems to index bytes and lines starting at 1, not @@ -477,10 +478,7 @@ fn bounded_tail(file: &mut File, settings: &Settings) { _ => {} } - // Print the target section of the file. - let stdout = stdout(); - let mut stdout = stdout.lock(); - io::copy(file, &mut stdout).unwrap(); + print_target_section(file, limit); } fn unbounded_tail(reader: &mut BufReader, settings: &Settings) -> UResult<()> { @@ -547,6 +545,21 @@ fn unbounded_tail(reader: &mut BufReader, settings: &Settings) -> UR Ok(()) } +fn print_target_section(file: &mut R, limit: Option) +where + R: Read + ?Sized, +{ + // Print the target section of the file. + let stdout = stdout(); + let mut stdout = stdout.lock(); + if let Some(limit) = limit { + let mut reader = file.take(limit); + io::copy(&mut reader, &mut stdout).unwrap(); + } else { + io::copy(file, &mut stdout).unwrap(); + } +} + #[cfg(test)] mod tests { diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index 9ddaba370..11f20ec1e 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -4923,3 +4923,12 @@ fn test_failed_write_is_reported() { .fails() .stderr_is("tail: No space left on device\n"); } + +#[test] +#[cfg(target_os = "linux")] +fn test_dev_zero() { + new_ucmd!() + .args(&["-c", "1", "/dev/zero"]) + .succeeds() + .stdout_only("\0"); +}