mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Merge pull request #4071 from jfinkels/cp-parents-dir-2
cp: correctly copy ancestor dirs in --parents mode
This commit is contained in:
commit
e031e5f416
3 changed files with 53 additions and 7 deletions
|
@ -303,6 +303,27 @@ pub(crate) fn copy_directory(
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If in `--parents` mode, create all the necessary ancestor directories.
|
||||||
|
//
|
||||||
|
// For example, if the command is `cp --parents a/b/c d`, that
|
||||||
|
// means we need to copy the two ancestor directories first:
|
||||||
|
//
|
||||||
|
// a -> d/a
|
||||||
|
// a/b -> d/a/b
|
||||||
|
//
|
||||||
|
let tmp = if options.parents {
|
||||||
|
if let Some(parent) = root.parent() {
|
||||||
|
let new_target = target.join(parent);
|
||||||
|
std::fs::create_dir_all(&new_target)?;
|
||||||
|
new_target
|
||||||
|
} else {
|
||||||
|
target.to_path_buf()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target.to_path_buf()
|
||||||
|
};
|
||||||
|
let target = tmp.as_path();
|
||||||
|
|
||||||
let mut hard_links: Vec<(String, u64)> = vec![];
|
let mut hard_links: Vec<(String, u64)> = vec![];
|
||||||
let preserve_hard_links = options.preserve_hard_links();
|
let preserve_hard_links = options.preserve_hard_links();
|
||||||
|
|
||||||
|
|
|
@ -1146,7 +1146,16 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
|
||||||
}
|
}
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
return Err("XAttrs are only supported on unix.".to_string().into());
|
// The documentation for GNU cp states:
|
||||||
|
//
|
||||||
|
// > Try to preserve SELinux security context and
|
||||||
|
// > extended attributes (xattr), but ignore any failure
|
||||||
|
// > to do that and print no corresponding diagnostic.
|
||||||
|
//
|
||||||
|
// so we simply do nothing here.
|
||||||
|
//
|
||||||
|
// TODO Silently ignore failures in the `#[cfg(unix)]`
|
||||||
|
// block instead of terminating immediately on errors.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -217,15 +217,18 @@ fn test_cp_target_directory_is_file() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cp_arg_interactive() {
|
fn test_cp_arg_interactive() {
|
||||||
new_ucmd!()
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
at.touch("a");
|
||||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
at.touch("b");
|
||||||
.arg("-i")
|
// TODO The prompt in GNU cp is different, and it doesn't have the
|
||||||
|
// response either.
|
||||||
|
//
|
||||||
|
// See <https://github.com/uutils/coreutils/issues/4023>.
|
||||||
|
ucmd.args(&["-i", "a", "b"])
|
||||||
.pipe_in("N\n")
|
.pipe_in("N\n")
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.no_stdout()
|
.no_stdout()
|
||||||
.stderr_contains(format!("overwrite '{}'?", TEST_HOW_ARE_YOU_SOURCE))
|
.stderr_is("cp: overwrite 'b'? [y/N]: cp: Not overwriting 'b' at user request\n");
|
||||||
.stderr_contains("Not overwriting");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1996,6 +1999,19 @@ fn test_copy_same_symlink_no_dereference_dangling() {
|
||||||
ucmd.args(&["-d", "a", "b"]).succeeds();
|
ucmd.args(&["-d", "a", "b"]).succeeds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
#[test]
|
||||||
|
fn test_cp_parents_2_dirs() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
at.mkdir_all("a/b/c");
|
||||||
|
at.mkdir("d");
|
||||||
|
ucmd.args(&["-a", "--parents", "a/b/c", "d"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.no_stdout();
|
||||||
|
assert!(at.dir_exists("d/a/b/c"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "issue #3332"]
|
#[ignore = "issue #3332"]
|
||||||
fn test_cp_parents_2() {
|
fn test_cp_parents_2() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue