From 42bb42a2e1718469133fe3a71ac76c40389bbb30 Mon Sep 17 00:00:00 2001 From: tomoda <40169443+yukitomoda@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:27:03 +0900 Subject: [PATCH] Fix rm for symlinks pointing to directory on windows (issue #11461) (#11463) - this PR closes #11461 # Description Using `std::fs::remove_dir` instead of `std::fs::remove_file` when try remove symlinks pointing to a directory on Windows. # User-Facing Changes none # Tests + Formatting - [x] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - [x] `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - I got 2 test fails on my Windows devenv; these fails in main branch too - `commands::complete::basic` : passed on Ubuntu, failed on Windows (a bug?) - `commands::cp::copy_file_with_read_permission`: failed on Windows with Japanese environment (This test refers error message, so that fails on environments using a language except for english.) - [x] `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library # After Submitting This fix has no changes to user-facing interface. --- crates/nu-command/src/filesystem/rm.rs | 22 +++++++++++++++++----- crates/nu-command/tests/commands/rm.rs | 13 +++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/crates/nu-command/src/filesystem/rm.rs b/crates/nu-command/src/filesystem/rm.rs index a05668a43..17ecb6578 100644 --- a/crates/nu-command/src/filesystem/rm.rs +++ b/crates/nu-command/src/filesystem/rm.rs @@ -381,11 +381,23 @@ fn rm( { unreachable!() } - } else if metadata.is_file() - || is_socket - || is_fifo - || metadata.file_type().is_symlink() - { + } else if metadata.is_symlink() { + // In Windows, symlink pointing to a directory can be removed using + // std::fs::remove_dir instead of std::fs::remove_file. + #[cfg(windows)] + { + f.metadata().and_then(|metadata| { + if metadata.is_dir() { + std::fs::remove_dir(&f) + } else { + std::fs::remove_file(&f) + } + }) + } + + #[cfg(not(windows))] + std::fs::remove_file(&f) + } else if metadata.is_file() || is_socket || is_fifo { std::fs::remove_file(&f) } else { std::fs::remove_dir_all(&f) diff --git a/crates/nu-command/tests/commands/rm.rs b/crates/nu-command/tests/commands/rm.rs index 90e697c31..2b9345e2f 100644 --- a/crates/nu-command/tests/commands/rm.rs +++ b/crates/nu-command/tests/commands/rm.rs @@ -375,6 +375,19 @@ fn removes_symlink() { }); } +#[test] +fn removes_symlink_pointing_to_directory() { + Playground::setup("rm_symlink_to_directory", |dirs, sandbox| { + sandbox.mkdir("test").symlink("test", "test_link"); + + nu!(cwd: sandbox.cwd(), "rm test_link"); + + assert!(!dirs.test().join("test_link").exists()); + // The pointed directory should not be deleted. + assert!(dirs.test().join("test").exists()); + }); +} + #[test] fn removes_file_after_cd() { Playground::setup("rm_after_cd", |dirs, sandbox| {