diff --git a/src/uu/cp/src/copydir.rs b/src/uu/cp/src/copydir.rs index a8b941364..763d66c0b 100644 --- a/src/uu/cp/src/copydir.rs +++ b/src/uu/cp/src/copydir.rs @@ -87,6 +87,9 @@ struct Context<'a> { /// The target path to which the directory will be copied. target: &'a Path, + + /// The source path from which the directory will be copied. + root: &'a Path, } impl<'a> Context<'a> { @@ -102,6 +105,7 @@ impl<'a> Context<'a> { current_dir, root_parent, target, + root, }) } } @@ -156,11 +160,19 @@ struct Entry { } impl Entry { - fn new(context: &Context, direntry: &DirEntry) -> Result { + fn new( + context: &Context, + direntry: &DirEntry, + no_target_dir: bool, + ) -> Result { let source_relative = direntry.path().to_path_buf(); let source_absolute = context.current_dir.join(&source_relative); - let descendant = + let mut descendant = get_local_to_root_parent(&source_absolute, context.root_parent.as_deref())?; + if no_target_dir { + descendant = descendant.strip_prefix(context.root)?.to_path_buf(); + } + let local_to_target = context.target.join(descendant); let target_is_file = context.target.is_file(); Ok(Self { @@ -389,7 +401,7 @@ pub(crate) fn copy_directory( { match direntry_result { Ok(direntry) => { - let entry = Entry::new(&context, &direntry)?; + let entry = Entry::new(&context, &direntry, options.no_target_dir)?; copy_direntry( progress_bar, entry, diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index c79367afb..565279a62 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -230,6 +230,22 @@ fn test_cp_arg_no_target_directory() { .stderr_contains("cannot overwrite directory"); } +#[test] +fn test_cp_arg_no_target_directory_with_recursive() { + let (at, mut ucmd) = at_and_ucmd!(); + + at.mkdir("dir"); + at.mkdir("dir2"); + at.touch("dir/a"); + at.touch("dir/b"); + + ucmd.arg("-rT").arg("dir").arg("dir2").succeeds(); + + assert!(at.plus("dir2").join("a").exists()); + assert!(at.plus("dir2").join("b").exists()); + assert!(!at.plus("dir2").join("dir").exists()); +} + #[test] fn test_cp_target_directory_is_file() { new_ucmd!()