From a1c260eeefd7db64981edfd0f4c088d1528dc19b Mon Sep 17 00:00:00 2001 From: Guillaume Ranquet Date: Tue, 9 Apr 2024 17:06:43 +0200 Subject: [PATCH] cp: keep handling the rest of the paths if one does not exists Signed-off-by: Guillaume Ranquet --- src/uu/cp/src/cp.rs | 32 +++++++++++++++----------------- tests/by-util/test_cp.rs | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 7207673a5ff..c9620348c6f 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -9,6 +9,7 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; #[cfg(not(windows))] use std::ffi::CString; +use std::ffi::OsString; use std::fs::{self, File, Metadata, OpenOptions, Permissions}; use std::io; #[cfg(unix)] @@ -677,7 +678,7 @@ pub fn uu_app() -> Command { Arg::new(options::PATHS) .action(ArgAction::Append) .value_hint(clap::ValueHint::AnyPath) - .value_parser(ValueParser::path_buf()), + .value_parser(clap::value_parser!(OsString)), ) } @@ -707,8 +708,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } let paths: Vec = matches - .remove_many::(options::PATHS) - .map(|v| v.collect()) + .remove_many::(options::PATHS) + .map(|v| v.map(PathBuf::from).collect()) .unwrap_or_default(); let (sources, target) = parse_path_args(paths, &options)?; @@ -1389,7 +1390,13 @@ fn copy_source( } } } - res + // this is just for gnu tests compatibility + Ok(res.map_err(|err| { + if err.to_string().contains("No such file or directory") { + return format!("cannot stat {}: No such file or directory", source.quote()); + } + err.to_string() + })?) } } @@ -2129,19 +2136,10 @@ fn copy_file( let context = context_for(source, dest); let context = context.as_str(); - let source_metadata = { - let result = if options.dereference(source_in_command_line) { - fs::metadata(source) - } else { - fs::symlink_metadata(source) - }; - // this is just for gnu tests compatibility - result.map_err(|err| { - if err.to_string().contains("No such file or directory") { - return format!("cannot stat {}: No such file or directory", source.quote()); - } - err.to_string() - })? + let source_metadata = if options.dereference(source_in_command_line) { + fs::metadata(source)? + } else { + fs::symlink_metadata(source)? }; let dest_permissions = calculate_dest_permissions(dest, &source_metadata, options, context)?; diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 3b4ec74f775..08b873fbd6a 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -5659,3 +5659,25 @@ fn test_cp_parents_absolute_path() { let res = format!("dest{}/a/b/f", at.root_dir_resolved()); at.file_exists(res); } + +/// Test the behavior of copying a non existent file to a folder +#[test] +#[cfg(unix)] +fn test_cp_existant_and_nonexistent_file() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.mkdir(TEST_COPY_TO_FOLDER_NEW); + + scene + .ucmd() + .arg("-a") + .arg(TEST_NONEXISTENT_FILE) + .arg(TEST_HELLO_WORLD_SOURCE) + .arg(TEST_COPY_TO_FOLDER_NEW) + .fails() + .stderr_only("cp: cannot stat 'nonexistent_file.txt': No such file or directory\n"); + + // Check existing file has been copied + assert!(at.file_exists(TEST_COPY_TO_FOLDER_NEW_FILE)); +}