-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Labels
Description
Component
rm -rf
Description
An issue with rm -rf: when deleting with rm -rf ., consistent with GNU rm, it refuses to delete the current directory, reports an error directly, and does not delete any contents.
❯ rm -rf .
rm: refusing to remove '.' or '..' directory: skipping '.'
However, when using rm -rf ./ or rm -rf .///, it reports an error as if the deletion failed (it should be consistent with rm -rf ., refusing directly without deleting anything), but in reality the contents of the current directory have already been deleted:
rm: cannot remove './': Invalid input
This is because the clean_trailing_slashes function collapses ./// into "./":
fn clean_trailing_slashes(path: &Path) -> &Path {
...
// Checks if element at the end is a '/'
if path_bytes[idx] == dir_separator {
for i in (1..path_bytes.len()).rev() {
if path_bytes[i - 1] != dir_separator {
idx = i;
break;
}
}
#[cfg(unix)]
return Path::new(OsStr::from_bytes(&path_bytes[0..=idx]));
...
}
}
path
}However, the path_is_current_or_parent_directory function only matches ".", "..", etc. It does not match equivalent paths like "./" or "../".
/// 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 {
let path_str = os_str_as_bytes(path.as_os_str());
let dir_separator = MAIN_SEPARATOR as u8;
if let Ok(path_bytes) = path_str {
return path_bytes == ([b'.'])
|| path_bytes == ([b'.', b'.'])
|| path_bytes.ends_with(&[dir_separator, b'.'])
|| path_bytes.ends_with(&[dir_separator, b'.', b'.'])
|| path_bytes.ends_with(&[dir_separator, b'.', dir_separator])
|| path_bytes.ends_with(&[dir_separator, b'.', b'.', dir_separator]);
}
false
}Test / Reproduction Steps
# Provide commands and setup to reproduceImpact
This results in the contents of the current directory being recursively deleted.