1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

rm: correct prompt for removing inaccessible dir

Change the prompt when attempting to remove an inaccessible
directory. Before this commit, the prompt was

    rm: remove write-protected directory 'dir'?

After this commit, the prompt is

    rm: attempt removal of inaccessible directory 'dir'?

This required slightly adjusting the logic for which prompt messages to
display under which circumstances.

Fixes #7309.
This commit is contained in:
Jeffrey Finkelstein 2025-02-18 18:39:45 -05:00
parent bc995283c4
commit 2b531b78ef
2 changed files with 44 additions and 20 deletions

View file

@ -339,15 +339,18 @@ fn is_dir_empty(path: &Path) -> bool {
} }
} }
#[cfg(unix)]
fn is_readable_metadata(metadata: &Metadata) -> bool {
let mode = metadata.permissions().mode();
(mode & 0o400) > 0
}
/// Whether the given file or directory is readable. /// Whether the given file or directory is readable.
#[cfg(unix)] #[cfg(unix)]
fn is_readable(path: &Path) -> bool { fn is_readable(path: &Path) -> bool {
match std::fs::metadata(path) { match std::fs::metadata(path) {
Err(_) => false, Err(_) => false,
Ok(metadata) => { Ok(metadata) => is_readable_metadata(&metadata),
let mode = metadata.permissions().mode();
(mode & 0o400) > 0
}
} }
} }
@ -357,15 +360,18 @@ fn is_readable(_path: &Path) -> bool {
true true
} }
#[cfg(unix)]
fn is_writable_metadata(metadata: &Metadata) -> bool {
let mode = metadata.permissions().mode();
(mode & 0o200) > 0
}
/// Whether the given file or directory is writable. /// Whether the given file or directory is writable.
#[cfg(unix)] #[cfg(unix)]
fn is_writable(path: &Path) -> bool { fn is_writable(path: &Path) -> bool {
match std::fs::metadata(path) { match std::fs::metadata(path) {
Err(_) => false, Err(_) => false,
Ok(metadata) => { Ok(metadata) => is_writable_metadata(&metadata),
let mode = metadata.permissions().mode();
(mode & 0o200) > 0
}
} }
} }
@ -623,20 +629,25 @@ fn prompt_file_permission_readonly(path: &Path) -> bool {
// Most cases are covered by keep eye out for edge cases // Most cases are covered by keep eye out for edge cases
#[cfg(unix)] #[cfg(unix)]
fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool {
use std::os::unix::fs::PermissionsExt; match (
let mode = metadata.permissions().mode(); is_readable_metadata(metadata),
// Check if directory has user write permissions is_writable_metadata(metadata),
// Why is S_IWUSR showing up as a u16 on macos? options.interactive,
#[allow(clippy::unnecessary_cast)] ) {
let user_writable = (mode & (libc::S_IWUSR as u32)) != 0; (false, false, _) => prompt_yes!(
if !user_writable { "attempt removal of inaccessible directory {}?",
prompt_yes!("remove write-protected directory {}?", path.quote()) path.quote()
} else if options.interactive == InteractiveMode::Always { ),
prompt_yes!("remove directory {}?", path.quote()) (false, true, InteractiveMode::Always) => prompt_yes!(
} else { "attempt removal of inaccessible directory {}?",
true path.quote()
),
(true, false, _) => prompt_yes!("remove write-protected directory {}?", path.quote()),
(_, _, InteractiveMode::Always) => prompt_yes!("remove directory {}?", path.quote()),
(_, _, _) => true,
} }
} }
/// Checks if the path is referring to current or parent directory , if it is referring to current or any parent directory in the file tree e.g '/../..' , '../..' /// Checks if the path is referring to current or parent directory , if it is referring to current or any parent directory in the file tree e.g '/../..' , '../..'
fn path_is_current_or_parent_directory(path: &Path) -> bool { fn path_is_current_or_parent_directory(path: &Path) -> bool {
let path_str = os_str_as_bytes(path.as_os_str()); let path_str = os_str_as_bytes(path.as_os_str());

View file

@ -874,6 +874,19 @@ fn test_inaccessible_dir_nonempty() {
assert!(at.dir_exists("dir")); assert!(at.dir_exists("dir"));
} }
#[cfg(not(windows))]
#[test]
fn test_inaccessible_dir_interactive() {
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("dir");
at.set_mode("dir", 0);
ucmd.args(&["-i", "-d", "dir"])
.pipe_in("y\n")
.succeeds()
.stderr_only("rm: attempt removal of inaccessible directory 'dir'? ");
assert!(!at.dir_exists("dir"));
}
#[cfg(not(windows))] #[cfg(not(windows))]
#[test] #[test]
fn test_inaccessible_dir_recursive() { fn test_inaccessible_dir_recursive() {