Skip to content

Commit 31afe1d

Browse files
committed
head: continue after per-file read error
1 parent f28d828 commit 31afe1d

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/uu/head/src/head.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,19 @@ fn print_n_lines(input: &mut impl io::BufRead, n: u64, separator: u8) -> io::Res
202202
let stdout = stdout.lock();
203203
let mut writer = BufWriter::with_capacity(BUF_SIZE, stdout);
204204

205-
let bytes_written = io::copy(&mut reader, &mut writer).map_err(wrap_in_stdout_error)?;
205+
let mut bytes_written = 0;
206+
let mut buf = [0; BUF_SIZE];
207+
loop {
208+
let n = match reader.read(&mut buf) {
209+
Ok(0) => break,
210+
Ok(n) => n,
211+
Err(e) => return Err(e),
212+
};
213+
214+
writer.write_all(&buf[..n]).map_err(wrap_in_stdout_error)?;
215+
216+
bytes_written += n as u64;
217+
}
206218

207219
// Make sure we finish writing everything to the target before
208220
// exiting. Otherwise, when Rust is implicitly flushing, any
@@ -493,7 +505,16 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
493505
continue;
494506
}
495507
};
496-
head_file(&mut file_handle, options)?;
508+
match head_file(&mut file_handle, options) {
509+
Ok(_) => {}
510+
Err(err) => {
511+
show!(HeadError::Io {
512+
name: file.into(),
513+
err
514+
});
515+
continue;
516+
}
517+
}
497518
Ok(())
498519
};
499520
if let Err(err) = res {

tests/by-util/test_head.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,22 @@ fn test_multiple_nonexistent_files() {
251251
.stderr_contains("cannot open 'bogusfile2' for reading: No such file or directory");
252252
}
253253

254+
#[test]
255+
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
256+
#[cfg_attr(wasi_runner, ignore = "WASI sandbox: host paths not visible")]
257+
fn test_multiple_files_read_error_continues_to_next_file() {
258+
let ts = TestScenario::new(util_name!());
259+
let at = &ts.fixtures;
260+
261+
at.write("a", "hello\n");
262+
263+
ts.ucmd()
264+
.args(&["/proc/self/mem", "a"])
265+
.fails()
266+
.stdout_is("==> /proc/self/mem <==\n\n==> a <==\nhello\n")
267+
.stderr_contains("head: error reading '/proc/self/mem': Input/output error");
268+
}
269+
254270
// there was a bug not caught by previous tests
255271
// where for negative n > 3, the total amount of lines
256272
// was correct, but it would eat from the second line

0 commit comments

Comments
 (0)