diff --git a/src/uu/rmdir/src/rmdir.rs b/src/uu/rmdir/src/rmdir.rs index 4f13afcbf..e0c9f73bc 100644 --- a/src/uu/rmdir/src/rmdir.rs +++ b/src/uu/rmdir/src/rmdir.rs @@ -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]; diff --git a/tests/by-util/test_rmdir.rs b/tests/by-util/test_rmdir.rs index 0c52a2287..669884488 100644 --- a/tests/by-util/test_rmdir.rs +++ b/tests/by-util/test_rmdir.rs @@ -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"); +}