diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 87767b904b..cb88b6a2b9 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (path) eacces +// spell-checker:ignore (path) eacces inacc use clap::{builder::ValueParser, crate_version, parser::ValueSource, Arg, ArgAction, Command}; use std::collections::VecDeque; @@ -330,14 +330,20 @@ fn handle_dir(path: &Path, options: &Options) -> bool { if options.recursive && (!is_root || !options.preserve_root) { if options.interactive != InteractiveMode::Always && !options.verbose { if let Err(e) = fs::remove_dir_all(path) { - had_err = true; - if e.kind() == std::io::ErrorKind::PermissionDenied { - // GNU compatibility (rm/fail-eacces.sh) - // here, GNU doesn't use some kind of remove_dir_all - // It will show directory+file - show_error!("cannot remove {}: {}", path.quote(), "Permission denied"); - } else { - show_error!("cannot remove {}: {}", path.quote(), e); + // GNU compatibility (rm/empty-inacc.sh) + // remove_dir_all failed. maybe it is because of the permissions + // but if the directory is empty, remove_dir might work. + // So, let's try that before failing for real + if let Err(_e) = fs::remove_dir(path) { + had_err = true; + if e.kind() == std::io::ErrorKind::PermissionDenied { + // GNU compatibility (rm/fail-eacces.sh) + // here, GNU doesn't use some kind of remove_dir_all + // It will show directory+file + show_error!("cannot remove {}: {}", path.quote(), "Permission denied"); + } else { + show_error!("cannot remove {}: {}", path.quote(), e); + } } } } else { diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 73f99566c4..5125c746da 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -647,6 +647,21 @@ fn test_prompt_write_protected_no() { assert!(at.file_exists(file_2)); } +#[cfg(feature = "chmod")] +#[test] +fn test_remove_inaccessible_dir() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let dir_1 = "test_rm_protected"; + + at.mkdir(dir_1); + + scene.ccmd("chmod").arg("0").arg(dir_1).succeeds(); + + scene.ucmd().arg("-rf").arg(dir_1).succeeds(); + assert!(!at.dir_exists(dir_1)); +} + #[test] #[cfg(not(windows))] fn test_fifo_removal() {