*sum: Fix read_byte_lines discarding read errors (#10671)

* *sum: Fix read_byte_lines discarding read errors

* test(*sum): test IOerror handling in checkfile
This commit is contained in:
Dorian Péron
2026-02-03 21:15:54 +01:00
committed by GitHub
parent d41ed38422
commit 1ea01a31d3
3 changed files with 41 additions and 19 deletions
@@ -15,7 +15,7 @@ use std::io::{self, BufReader, Read, Write, stderr, stdin};
use os_display::Quotable;
use crate::checksum::{AlgoKind, ChecksumError, SizedAlgoKind, digest_reader, unescape_filename};
use crate::error::{FromIo, UError, UResult, USimpleError};
use crate::error::{FromIo, UError, UIoError, UResult, USimpleError};
use crate::quoting_style::{QuotingStyle, locale_aware_escape_name};
use crate::sum::DigestOutput;
use crate::{
@@ -851,7 +851,6 @@ fn process_checksum_file(
};
let reader = BufReader::new(file);
let lines = read_os_string_lines(reader).collect::<Vec<_>>();
// cached_line_format is used to ensure that several non algo-based checksum line
// will use the same parser.
@@ -861,9 +860,16 @@ fn process_checksum_file(
// Behavior tested in gnu_cksum_c::test_warn
let mut last_algo = None;
for (i, line) in lines.iter().enumerate() {
for (i, line_res) in read_os_string_lines(reader).enumerate() {
let line = line_res.map_err(|e| {
USimpleError::new(
UIoError::from(e).code(),
format!("{}: read error", filename_input.maybe_quote()),
)
})?;
let line_result = process_checksum_line(
line,
&line,
i,
cli_algo_kind,
cli_algo_length,
+16 -14
View File
@@ -513,24 +513,25 @@ pub fn os_string_to_vec(s: OsString) -> mods::error::UResult<Vec<u8>> {
/// which avoids panicking on non UTF-8 input.
pub fn read_byte_lines<R: std::io::Read>(
mut buf_reader: BufReader<R>,
) -> impl Iterator<Item = Vec<u8>> {
) -> impl Iterator<Item = std::io::Result<Vec<u8>>> {
iter::from_fn(move || {
let mut buf = Vec::with_capacity(256);
let size = buf_reader.read_until(b'\n', &mut buf).ok()?;
if size == 0 {
return None;
}
match buf_reader.read_until(b'\n', &mut buf) {
Ok(0) => None,
Err(e) => Some(Err(e)),
Ok(_) => {
// Trim (\r)\n
if buf.ends_with(b"\n") {
buf.pop();
if buf.ends_with(b"\r") {
buf.pop();
}
}
// Trim (\r)\n
if buf.ends_with(b"\n") {
buf.pop();
if buf.ends_with(b"\r") {
buf.pop();
Some(Ok(buf))
}
}
Some(buf)
})
}
@@ -539,8 +540,9 @@ pub fn read_byte_lines<R: std::io::Read>(
/// but it still will on Windows.
pub fn read_os_string_lines<R: std::io::Read>(
buf_reader: BufReader<R>,
) -> impl Iterator<Item = OsString> {
read_byte_lines(buf_reader).map(|byte_line| os_string_from_vec(byte_line).expect("UTF-8 error"))
) -> impl Iterator<Item = std::io::Result<OsString>> {
read_byte_lines(buf_reader)
.map(|byte_line_res| byte_line_res.map(|bl| os_string_from_vec(bl).expect("UTF-8 error")))
}
/// Prompt the user with a formatted string and returns `true` if they reply `'y'` or `'Y'`
+15 -1
View File
@@ -2,7 +2,7 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) asdf algo algos asha mgmt xffname hexa GFYEQ HYQK Yqxb dont
// spell-checker:ignore (words) asdf algo algos asha mgmt xffname hexa GFYEQ HYQK Yqxb dont checkfile
use uutests::at_and_ucmd;
use uutests::new_ucmd;
@@ -3060,3 +3060,17 @@ fn test_check_file_with_io_error() {
.stderr_contains("Input/output error")
.stdout_contains("FAILED open or read");
}
#[test]
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
fn test_check_checkfile_with_io_error() {
// /proc/self/mem causes EIO when read without proper seeking
new_ucmd!()
.arg("-a")
.arg("md5")
.arg("--check")
.arg("/proc/self/mem")
.fails()
.stderr_contains("/proc/self/mem: read error")
.no_stdout();
}