cp: fix cp -rT dir dir2 leads to different result than with GNU cp (#5467)

* add a test case test_cp_treat_dest_as_a_normal_file

* fix 5457

* cp: fix comment

---------

Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
This commit is contained in:
tommady 2023-10-31 00:55:03 +08:00 committed by GitHub
parent 72193f8adc
commit a4775d288b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 3 deletions

View file

@ -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<Self, StripPrefixError> {
fn new(
context: &Context,
direntry: &DirEntry,
no_target_dir: bool,
) -> Result<Self, StripPrefixError> {
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,

View file

@ -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!()