diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 1d6cfbffa8f..b078063ea50 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 fc547223bfa..7a3b28d234b 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"); +}