From abd581f62e97d0b147306ac40eac13af71c6fbba Mon Sep 17 00:00:00 2001 From: cerdelen <95369756+cerdelen@users.noreply.github.com> Date: Thu, 1 Jan 2026 11:41:05 +0100 Subject: [PATCH] chmod: fix error handling if multiple files are handled (#9793) * chmod: fix error handling if multiple files are handled * chmod: add regression test for correct exit codes * chmod: fix test expected error msg --------- Co-authored-by: Sylvestre Ledru --- src/uu/chmod/src/chmod.rs | 2 +- tests/by-util/test_chmod.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/uu/chmod/src/chmod.rs b/src/uu/chmod/src/chmod.rs index 24566272b..b7e0f3fd9 100644 --- a/src/uu/chmod/src/chmod.rs +++ b/src/uu/chmod/src/chmod.rs @@ -411,7 +411,7 @@ impl Chmoder { return Err(ChmodError::PreserveRoot("/".into()).into()); } if self.recursive { - r = self.walk_dir_with_context(file, true); + r = self.walk_dir_with_context(file, true).and(r); } else { r = self.chmod_file(file).and(r); } diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index 446cdd6d3..5e3407328 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -375,6 +375,38 @@ fn test_permission_denied() { .stderr_is("chmod: cannot access 'd/no-x/y': Permission denied\n"); } +#[test] +#[allow(clippy::unreadable_literal)] +fn test_chmod_recursive_correct_exit_code() { + let (at, mut ucmd) = at_and_ucmd!(); + + // create 3 folders to test on + at.mkdir("a"); + at.mkdir("a/b"); + at.mkdir("z"); + + // remove read permissions for folder a so the chmod command for a/b fails + let mut perms = at.metadata("a").permissions(); + perms.set_mode(0o000); + set_permissions(at.plus_as_string("a"), perms).unwrap(); + + #[cfg(not(target_os = "linux"))] + let err_msg = "chmod: Permission denied\n"; + #[cfg(target_os = "linux")] + let err_msg = "chmod: cannot access 'a': Permission denied\n"; + + // order of command is a, a/b then c + // command is expected to fail and not just take the last exit code + ucmd.arg("-R") + .arg("--verbose") + .arg("a+w") + .arg("a") + .arg("z") + .umask(0) + .fails() + .stderr_is(err_msg); +} + #[test] #[allow(clippy::unreadable_literal)] fn test_chmod_recursive() {