1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

head: improve error mgmt.

And provide more details than GNU

Should fix tests/head/head-write-error
This commit is contained in:
Sylvestre Ledru 2025-03-05 11:06:07 +01:00
parent 0936cee9d5
commit dedd644016
2 changed files with 19 additions and 9 deletions

View file

@ -243,6 +243,14 @@ impl HeadOptions {
} }
} }
#[inline]
fn wrap_in_stdout_error(err: io::Error) -> io::Error {
io::Error::new(
err.kind(),
format!("error writing 'standard output': {}", err),
)
}
fn read_n_bytes(input: impl Read, n: u64) -> std::io::Result<u64> { fn read_n_bytes(input: impl Read, n: u64) -> std::io::Result<u64> {
// Read the first `n` bytes from the `input` reader. // Read the first `n` bytes from the `input` reader.
let mut reader = input.take(n); let mut reader = input.take(n);
@ -251,12 +259,12 @@ fn read_n_bytes(input: impl Read, n: u64) -> std::io::Result<u64> {
let stdout = std::io::stdout(); let stdout = std::io::stdout();
let mut stdout = stdout.lock(); let mut stdout = stdout.lock();
let bytes_written = io::copy(&mut reader, &mut stdout)?; let bytes_written = io::copy(&mut reader, &mut stdout).map_err(wrap_in_stdout_error)?;
// Make sure we finish writing everything to the target before // Make sure we finish writing everything to the target before
// exiting. Otherwise, when Rust is implicitly flushing, any // exiting. Otherwise, when Rust is implicitly flushing, any
// error will be silently ignored. // error will be silently ignored.
stdout.flush()?; stdout.flush().map_err(wrap_in_stdout_error)?;
Ok(bytes_written) Ok(bytes_written)
} }
@ -268,12 +276,12 @@ fn read_n_lines(input: &mut impl std::io::BufRead, n: u64, separator: u8) -> std
// Write those bytes to `stdout`. // Write those bytes to `stdout`.
let mut stdout = std::io::stdout(); let mut stdout = std::io::stdout();
let bytes_written = io::copy(&mut reader, &mut stdout)?; let bytes_written = io::copy(&mut reader, &mut stdout).map_err(wrap_in_stdout_error)?;
// Make sure we finish writing everything to the target before // Make sure we finish writing everything to the target before
// exiting. Otherwise, when Rust is implicitly flushing, any // exiting. Otherwise, when Rust is implicitly flushing, any
// error will be silently ignored. // error will be silently ignored.
stdout.flush()?; stdout.flush().map_err(wrap_in_stdout_error)?;
Ok(bytes_written) Ok(bytes_written)
} }
@ -298,13 +306,13 @@ fn read_but_last_n_bytes(input: impl std::io::BufRead, n: u64) -> std::io::Resul
// over the top. This gives a significant speedup (approx 4x). // over the top. This gives a significant speedup (approx 4x).
let mut writer = BufWriter::with_capacity(BUF_SIZE, stdout); let mut writer = BufWriter::with_capacity(BUF_SIZE, stdout);
for byte in take_all_but(input.bytes(), n) { for byte in take_all_but(input.bytes(), n) {
writer.write_all(&[byte?])?; writer.write_all(&[byte?]).map_err(wrap_in_stdout_error)?;
bytes_written += 1; bytes_written += 1;
} }
// Make sure we finish writing everything to the target before // Make sure we finish writing everything to the target before
// exiting. Otherwise, when Rust is implicitly flushing, any // exiting. Otherwise, when Rust is implicitly flushing, any
// error will be silently ignored. // error will be silently ignored.
writer.flush()?; writer.flush().map_err(wrap_in_stdout_error)?;
} }
Ok(bytes_written) Ok(bytes_written)
} }
@ -318,15 +326,17 @@ fn read_but_last_n_lines(
if let Some(n) = catch_too_large_numbers_in_backwards_bytes_or_lines(n) { if let Some(n) = catch_too_large_numbers_in_backwards_bytes_or_lines(n) {
let stdout = std::io::stdout(); let stdout = std::io::stdout();
let mut stdout = stdout.lock(); let mut stdout = stdout.lock();
for bytes in take_all_but(lines(input, separator), n) { for bytes in take_all_but(lines(input, separator), n) {
let bytes = bytes?; let bytes = bytes?;
bytes_written += u64::try_from(bytes.len()).unwrap(); bytes_written += u64::try_from(bytes.len()).unwrap();
stdout.write_all(&bytes)?;
stdout.write_all(&bytes).map_err(wrap_in_stdout_error)?;
} }
// Make sure we finish writing everything to the target before // Make sure we finish writing everything to the target before
// exiting. Otherwise, when Rust is implicitly flushing, any // exiting. Otherwise, when Rust is implicitly flushing, any
// error will be silently ignored. // error will be silently ignored.
stdout.flush()?; stdout.flush().map_err(wrap_in_stdout_error)?;
} }
Ok(bytes_written) Ok(bytes_written)
} }

View file

@ -806,7 +806,7 @@ fn test_write_to_dev_full() {
.pipe_in_fixture(INPUT) .pipe_in_fixture(INPUT)
.set_stdout(dev_full) .set_stdout(dev_full)
.run() .run()
.stderr_contains("No space left on device"); .stderr_contains("error writing 'standard output': No space left on device");
} }
} }
} }