rmdir: Remove all trailing slashes when checking for symlinks (#9983)

* rmdir: Remove all trailing slashes when checking for symlinks

rmdir: cargo fmt

l

* rmdir: Extract removal of trailing slashes to helper func

* rmdir: Add regression test for removal of trailing slashes when checking for symlink

* rmdir: add cfg flag to helper func which is only used on unix
This commit is contained in:
cerdelen
2026-01-02 16:38:14 +01:00
committed by GitHub
parent 9086f43b8e
commit 0566dfc6ef
2 changed files with 27 additions and 2 deletions
+12 -2
View File
@@ -66,10 +66,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Ok(path.metadata()?.file_type().is_dir())
}
let bytes = path.as_os_str().as_bytes();
let mut bytes = path.as_os_str().as_bytes();
if error.raw_os_error() == Some(libc::ENOTDIR) && bytes.ends_with(b"/") {
// Strip the trailing slash or .symlink_metadata() will follow the symlink
let no_slash: &Path = OsStr::from_bytes(&bytes[..bytes.len() - 1]).as_ref();
bytes = strip_trailing_slashes_from_path(bytes);
let no_slash: &Path = OsStr::from_bytes(bytes).as_ref();
if no_slash.is_symlink() && points_to_directory(no_slash).unwrap_or(true) {
show_error!(
"{}",
@@ -119,6 +120,15 @@ fn remove_single(path: &Path, opts: Opts) -> Result<(), Error<'_>> {
remove_dir(path).map_err(|error| Error { error, path })
}
#[cfg(unix)]
fn strip_trailing_slashes_from_path(path: &[u8]) -> &[u8] {
let mut end = path.len();
while end > 0 && path[end - 1] == b'/' {
end -= 1;
}
&path[..end]
}
// POSIX: https://pubs.opengroup.org/onlinepubs/009696799/functions/rmdir.html
#[cfg(not(windows))]
const NOT_EMPTY_CODES: &[i32] = &[libc::ENOTEMPTY, libc::EEXIST];
+15
View File
@@ -243,3 +243,18 @@ fn test_rmdir_remove_symlink_dangling() {
.fails()
.stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed\n");
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[test]
fn test_rmdir_remove_symlink_dir_with_trailing_slashes() {
// a symlink with trailing slashes should still be printing the 'Symbolic link not followed'
// message
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("dir");
at.symlink_dir("dir", "dl");
ucmd.arg("dl////")
.fails()
.stderr_is("rmdir: failed to remove 'dl////': Symbolic link not followed\n");
}