From b585e98dacf9496ed25782051152d515e60d12cc Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 11 Jul 2025 07:52:22 +0200 Subject: [PATCH] cp: Fix --no-dereference --parents with symlink source If the source is a symbolic link pointing at a directory, --parents was ignored, as we entered the "copy as directory" code path. Fixes: #8330 --- src/uu/cp/src/cp.rs | 2 +- tests/by-util/test_cp.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 1d6cfbffa..b078063ea 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1502,7 +1502,7 @@ fn copy_source( copied_files: &mut HashMap, ) -> CopyResult<()> { let source_path = Path::new(&source); - if source_path.is_dir() { + if source_path.is_dir() && (options.dereference || !source_path.is_symlink()) { // Copy as directory copy_directory( progress_bar, diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index fc547223b..7a3b28d23 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -6706,3 +6706,23 @@ fn test_cp_preserve_context_root() { print!("Test skipped; requires root user"); } } + +#[test] +#[cfg(not(windows))] +fn test_cp_no_dereference_symlink_with_parents() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + at.mkdir("directory"); + at.symlink_file("directory", "symlink-to-directory"); + + ts.ucmd() + .args(&["--parents", "--no-dereference", "symlink-to-directory", "x"]) + .fails() + .stderr_contains("with --parents, the destination must be a directory"); + + at.mkdir("x"); + ts.ucmd() + .args(&["--parents", "--no-dereference", "symlink-to-directory", "x"]) + .succeeds(); + assert_eq!(at.resolve_link("x/symlink-to-directory"), "directory"); +}