From 077aca67ee4a9b5d356f53abe3b8b65b282718ca Mon Sep 17 00:00:00 2001 From: tirdesh Date: Sun, 25 Oct 2026 17:02:35 -0400 Subject: [PATCH] uucore: report unreadable files under --ignore-missing --ignore-missing dropped every file whose open failed, not only the ones that were absent, so a file that exists but cannot be read was skipped without a word and the run exited 0. Classify the error in get_file_to_check: only NotFound stays on the missing path, anything else is printed, counted through failed_open and returned as CantOpenFile. Drop the matching !ignore_missing guard on the final failed_open_file check, which ignored missing files never reach. --- .../src/lib/features/checksum/validate.rs | 14 +++++++-- tests/by-util/test_cksum.rs | 30 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/uucore/src/lib/features/checksum/validate.rs b/src/uucore/src/lib/features/checksum/validate.rs index 5b6be1e73d7..dee9fd386f1 100644 --- a/src/uucore/src/lib/features/checksum/validate.rs +++ b/src/uucore/src/lib/features/checksum/validate.rs @@ -613,7 +613,7 @@ fn get_file_to_check( Ok(Box::new(f)) } } - Err(err) => { + Err(err) if err.kind() == io::ErrorKind::NotFound => { if !opts.ignore_missing { // yes, we have both stderr and stdout here print_error(err); @@ -622,6 +622,13 @@ fn get_file_to_check( // we could not open the file but we want to continue Err(LineCheckError::FileNotFound) } + Err(err) => { + // The file exists but cannot be opened. `--ignore-missing` does + // not cover this, so report it whether or not it is set. + print_error(err); + failed_open(); + Err(LineCheckError::CantOpenFile) + } } } } @@ -1001,8 +1008,9 @@ fn process_checksum_file( return Err(FileCheckError::Failed); } - // If a file was missing, return an error unless we explicitly ignore it. - if res.failed_open_file > 0 && !opts.ignore_missing { + // Files we could not read are a failure. Missing files are only counted + // when they are not ignored, so this needs no further guard. + if res.failed_open_file > 0 { return Err(FileCheckError::Failed); } diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index a6b478cff29..0328b57b3c5 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -2155,6 +2155,36 @@ fn test_check_failed_to_read() { .stderr_contains("cksum: WARNING: 1 listed file could not be read"); } +#[test] +#[cfg(not(windows))] +fn test_check_ignore_missing_unopenable_file() { + // `--ignore-missing` excuses a file that is absent, not one that is + // present but cannot be opened. The latter is still a failed read. + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.write("f", "data\n"); + at.write( + "CHECKSUM", + "SHA1 (f) = c5d84736ba451747dd5f0eb9d17e104f3697ef47\n\ + SHA1 (f/sub) = ffffffffffffffffffffffffffffffffffffffff\n\ + SHA1 (not-file) = ffffffffffffffffffffffffffffffffffffffff\n", + ); + + scene + .ucmd() + .arg("--check") + .arg("--ignore-missing") + .arg("CHECKSUM") + .fails() + .stdout_is( + "f: OK\n\ + f/sub: FAILED open or read\n", + ) + .stderr_contains("cksum: WARNING: 1 listed file could not be read"); +} + #[test] fn test_zero_multiple_file() { new_ucmd!()