tail: fix panic on write error in bounded_tail (#11886)

* tail: fix panic on write error in bounded_tail

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* tail: increase test file size to ensure bounded_tail path

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Lorenzo Rossi
2026-04-19 13:39:40 +02:00
committed by GitHub
co-authored by pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
parent 09587d3706
commit fbefc2bd99
2 changed files with 23 additions and 6 deletions
+8 -6
View File
@@ -174,7 +174,7 @@ fn tail_file(
&& file.is_seekable(if input.is_stdin() { offset } else { 0 })
&& (!st.is_file() || st.len() > blksize_limit)
{
bounded_tail(&mut file, settings);
bounded_tail(&mut file, settings)?;
reader = BufReader::new(file);
} else {
reader = BufReader::new(file);
@@ -460,7 +460,7 @@ fn backwards_thru_file(file: &mut File, num_delimiters: u64, delimiter: u8) {
/// end of the file, and then read the file "backwards" in blocks of size
/// `BLOCK_SIZE` until we find the location of the first line/byte. This ends up
/// being a nice performance win for very large files.
fn bounded_tail(file: &mut File, settings: &Settings) {
fn bounded_tail(file: &mut File, settings: &Settings) -> UResult<()> {
debug_assert!(!settings.presume_input_pipe);
let mut limit = None;
@@ -493,7 +493,8 @@ fn bounded_tail(file: &mut File, settings: &Settings) {
_ => {}
}
print_target_section(file, limit);
print_target_section(file, limit)?;
Ok(())
}
fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
@@ -574,7 +575,7 @@ fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UR
Ok(())
}
fn print_target_section<R>(file: &mut R, limit: Option<u64>)
fn print_target_section<R>(file: &mut R, limit: Option<u64>) -> UResult<()>
where
R: Read + ?Sized,
{
@@ -583,10 +584,11 @@ where
let mut stdout = stdout.lock();
if let Some(limit) = limit {
let mut reader = file.take(limit);
io::copy(&mut reader, &mut stdout).unwrap();
io::copy(&mut reader, &mut stdout)?;
} else {
io::copy(file, &mut stdout).unwrap();
io::copy(file, &mut stdout)?;
}
Ok(())
}
#[cfg(test)]
+15
View File
@@ -5086,6 +5086,21 @@ fn test_failed_write_is_reported() {
.stderr_is("tail: No space left on device\n");
}
#[cfg(target_os = "linux")]
#[test]
fn test_failed_write_is_reported_on_seekable_input() {
let ts = TestScenario::new("tail");
let at = &ts.fixtures;
at.write("bigfile", &"x\n".repeat(1_100_000));
ts.ucmd()
.arg("bigfile")
.set_stdout(File::create("/dev/full").unwrap())
.fails()
.stderr_is("tail: No space left on device\n");
}
#[test]
#[cfg(target_os = "linux")]
fn test_dev_zero() {