mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
cp: manages the 'seen' file list before copying
Should help with tests/mv/childproof.sh
This commit is contained in:
parent
6b1f51385f
commit
837640bc02
2 changed files with 54 additions and 11 deletions
|
@ -1171,6 +1171,9 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
|
||||||
//
|
//
|
||||||
// key is the source file's information and the value is the destination filepath.
|
// key is the source file's information and the value is the destination filepath.
|
||||||
let mut copied_files: HashMap<FileInformation, PathBuf> = HashMap::with_capacity(sources.len());
|
let mut copied_files: HashMap<FileInformation, PathBuf> = HashMap::with_capacity(sources.len());
|
||||||
|
// remember the copied destinations for further usage.
|
||||||
|
// we can't use copied_files as it is because the key is the source file's information.
|
||||||
|
let mut copied_destinations: HashSet<PathBuf> = HashSet::with_capacity(sources.len());
|
||||||
|
|
||||||
let progress_bar = if options.progress_bar {
|
let progress_bar = if options.progress_bar {
|
||||||
let pb = ProgressBar::new(disk_usage(sources, options.recursive)?)
|
let pb = ProgressBar::new(disk_usage(sources, options.recursive)?)
|
||||||
|
@ -1191,17 +1194,38 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
|
||||||
if seen_sources.contains(source) {
|
if seen_sources.contains(source) {
|
||||||
// FIXME: compare sources by the actual file they point to, not their path. (e.g. dir/file == dir/../dir/file in most cases)
|
// FIXME: compare sources by the actual file they point to, not their path. (e.g. dir/file == dir/../dir/file in most cases)
|
||||||
show_warning!("source {} specified more than once", source.quote());
|
show_warning!("source {} specified more than once", source.quote());
|
||||||
} else if let Err(error) = copy_source(
|
} else {
|
||||||
&progress_bar,
|
// We need to compute the destination path
|
||||||
source,
|
|
||||||
target,
|
let dest = construct_dest_path(source, target, target_type, options)
|
||||||
target_type,
|
.unwrap_or_else(|_| target.to_path_buf());
|
||||||
options,
|
|
||||||
&mut symlinked_files,
|
if fs::metadata(&dest).is_ok() && !fs::symlink_metadata(&dest)?.file_type().is_symlink()
|
||||||
&mut copied_files,
|
{
|
||||||
) {
|
// There is already a file and it isn't a symlink (managed in a different place)
|
||||||
show_error_if_needed(&error);
|
if copied_destinations.contains(&dest) {
|
||||||
non_fatal_errors = true;
|
// If the target file was already created in this cp call, do not overwrite
|
||||||
|
return Err(Error::Error(format!(
|
||||||
|
"will not overwrite just-created '{}' with '{}'",
|
||||||
|
dest.display(),
|
||||||
|
source.display()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(error) = copy_source(
|
||||||
|
&progress_bar,
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
target_type,
|
||||||
|
options,
|
||||||
|
&mut symlinked_files,
|
||||||
|
&mut copied_files,
|
||||||
|
) {
|
||||||
|
show_error_if_needed(&error);
|
||||||
|
non_fatal_errors = true;
|
||||||
|
}
|
||||||
|
copied_destinations.insert(dest.clone());
|
||||||
}
|
}
|
||||||
seen_sources.insert(source);
|
seen_sources.insert(source);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3559,3 +3559,22 @@ fn test_cp_attributes_only() {
|
||||||
assert_eq!(mode_a, at.metadata(a).mode());
|
assert_eq!(mode_a, at.metadata(a).mode());
|
||||||
assert_eq!(mode_b, at.metadata(b).mode());
|
assert_eq!(mode_b, at.metadata(b).mode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cp_seen_file() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
|
||||||
|
at.mkdir("a");
|
||||||
|
at.mkdir("b");
|
||||||
|
at.mkdir("c");
|
||||||
|
at.write("a/f", "a");
|
||||||
|
at.write("b/f", "b");
|
||||||
|
|
||||||
|
ucmd.arg("a/f")
|
||||||
|
.arg("b/f")
|
||||||
|
.arg("c")
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("will not overwrite just-created 'c/f' with 'b/f'");
|
||||||
|
|
||||||
|
assert!(at.plus("c").join("f").exists());
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue