mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
rm: report permission denied for unreadable subdirectories
When rm -rf encounters a subdirectory without read permission, handle_permission_denied attempts unlink_at on it. If that fails with ENOTEMPTY, force mode was silently swallowing the error, causing the parent removal to fail with a misleading "Directory not empty" message instead. Now always reports permission denied when we cannot open a subdirectory and cannot remove it directly. Fixes #10966
This commit is contained in:
committed by
Daniel Hofstetter
parent
e93361bab6
commit
cf3b6d45ae
@@ -197,21 +197,13 @@ fn handle_permission_denied(
|
||||
// When we can't open a subdirectory due to permission denied,
|
||||
// try to remove it directly (it might be empty).
|
||||
// This matches GNU rm behavior with -f flag.
|
||||
if let Err(remove_err) = dir_fd.unlink_at(entry_name, true) {
|
||||
// Failed to remove - show appropriate error
|
||||
if remove_err.kind() == std::io::ErrorKind::PermissionDenied {
|
||||
// Permission denied errors are always shown, even with force
|
||||
show_permission_denied_error(entry_path);
|
||||
return true;
|
||||
} else if !options.force {
|
||||
let remove_err = remove_err.map_err_context(
|
||||
|| translate!("rm-error-cannot-remove", "file" => entry_path.quote()),
|
||||
);
|
||||
show_error!("{remove_err}");
|
||||
return true;
|
||||
}
|
||||
// With force mode, suppress non-permission errors
|
||||
return !options.force;
|
||||
if let Err(_remove_err) = dir_fd.unlink_at(entry_name, true) {
|
||||
// The directory is not empty (or another error) and we can't read it
|
||||
// to remove its contents. Report the original permission denied error.
|
||||
// This matches GNU rm behavior — the real problem is we lack
|
||||
// permission to traverse the directory.
|
||||
show_permission_denied_error(entry_path);
|
||||
return true;
|
||||
}
|
||||
// Successfully removed empty directory
|
||||
verbose_removed_directory(entry_path, options);
|
||||
|
||||
@@ -1006,6 +1006,22 @@ fn test_unreadable_and_nonempty_dir() {
|
||||
assert!(at.dir_exists("a"));
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_recursive_remove_unreadable_subdir() {
|
||||
// Regression test for https://github.com/uutils/coreutils/issues/10966
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir_all("foo/bar");
|
||||
at.touch("foo/bar/baz");
|
||||
at.set_mode("foo/bar", 0o0000);
|
||||
|
||||
let result = ucmd.args(&["-r", "-f", "foo"]).fails();
|
||||
result.stderr_contains("Permission denied");
|
||||
result.stderr_contains("foo/bar");
|
||||
|
||||
at.set_mode("foo/bar", 0o0755);
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_inaccessible_dir() {
|
||||
|
||||
Reference in New Issue
Block a user