diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index 896e0c923e1..de879f3115e 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -202,7 +202,19 @@ fn print_n_lines(input: &mut impl io::BufRead, n: u64, separator: u8) -> io::Res let stdout = stdout.lock(); let mut writer = BufWriter::with_capacity(BUF_SIZE, stdout); - let bytes_written = io::copy(&mut reader, &mut writer).map_err(wrap_in_stdout_error)?; + let mut bytes_written = 0; + let mut buf = [0; BUF_SIZE]; + loop { + let n = match reader.read(&mut buf) { + Ok(0) => break, + Ok(n) => n, + Err(e) => return Err(e), + }; + + writer.write_all(&buf[..n]).map_err(wrap_in_stdout_error)?; + + bytes_written += n as u64; + } // Make sure we finish writing everything to the target before // exiting. Otherwise, when Rust is implicitly flushing, any @@ -493,7 +505,16 @@ fn uu_head(options: &HeadOptions) -> UResult<()> { continue; } }; - head_file(&mut file_handle, options)?; + match head_file(&mut file_handle, options) { + Ok(_) => {} + Err(err) => { + show!(HeadError::Io { + name: file.into(), + err + }); + continue; + } + } Ok(()) }; if let Err(err) = res { diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index 8406c3d9082..9b8d8c33e17 100644 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -251,6 +251,22 @@ fn test_multiple_nonexistent_files() { .stderr_contains("cannot open 'bogusfile2' for reading: No such file or directory"); } +#[test] +#[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[cfg_attr(wasi_runner, ignore = "WASI sandbox: host paths not visible")] +fn test_multiple_files_read_error_continues_to_next_file() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + at.write("a", "hello\n"); + + ts.ucmd() + .args(&["/proc/self/mem", "a"]) + .fails() + .stdout_is("==> /proc/self/mem <==\n\n==> a <==\nhello\n") + .stderr_contains("head: error reading '/proc/self/mem': Input/output error"); +} + // there was a bug not caught by previous tests // where for negative n > 3, the total amount of lines // was correct, but it would eat from the second line