Skip to content

Commit a1c260e

Browse files
committed
cp: keep handling the rest of the paths if one does not exists
Signed-off-by: Guillaume Ranquet <[email protected]>
1 parent 92c3de5 commit a1c260e

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

src/uu/cp/src/cp.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::cmp::Ordering;
99
use std::collections::{HashMap, HashSet};
1010
#[cfg(not(windows))]
1111
use std::ffi::CString;
12+
use std::ffi::OsString;
1213
use std::fs::{self, File, Metadata, OpenOptions, Permissions};
1314
use std::io;
1415
#[cfg(unix)]
@@ -677,7 +678,7 @@ pub fn uu_app() -> Command {
677678
Arg::new(options::PATHS)
678679
.action(ArgAction::Append)
679680
.value_hint(clap::ValueHint::AnyPath)
680-
.value_parser(ValueParser::path_buf()),
681+
.value_parser(clap::value_parser!(OsString)),
681682
)
682683
}
683684

@@ -707,8 +708,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
707708
}
708709

709710
let paths: Vec<PathBuf> = matches
710-
.remove_many::<PathBuf>(options::PATHS)
711-
.map(|v| v.collect())
711+
.remove_many::<OsString>(options::PATHS)
712+
.map(|v| v.map(PathBuf::from).collect())
712713
.unwrap_or_default();
713714

714715
let (sources, target) = parse_path_args(paths, &options)?;
@@ -1389,7 +1390,13 @@ fn copy_source(
13891390
}
13901391
}
13911392
}
1392-
res
1393+
// this is just for gnu tests compatibility
1394+
Ok(res.map_err(|err| {
1395+
if err.to_string().contains("No such file or directory") {
1396+
return format!("cannot stat {}: No such file or directory", source.quote());
1397+
}
1398+
err.to_string()
1399+
})?)
13931400
}
13941401
}
13951402

@@ -2129,19 +2136,10 @@ fn copy_file(
21292136
let context = context_for(source, dest);
21302137
let context = context.as_str();
21312138

2132-
let source_metadata = {
2133-
let result = if options.dereference(source_in_command_line) {
2134-
fs::metadata(source)
2135-
} else {
2136-
fs::symlink_metadata(source)
2137-
};
2138-
// this is just for gnu tests compatibility
2139-
result.map_err(|err| {
2140-
if err.to_string().contains("No such file or directory") {
2141-
return format!("cannot stat {}: No such file or directory", source.quote());
2142-
}
2143-
err.to_string()
2144-
})?
2139+
let source_metadata = if options.dereference(source_in_command_line) {
2140+
fs::metadata(source)?
2141+
} else {
2142+
fs::symlink_metadata(source)?
21452143
};
21462144

21472145
let dest_permissions = calculate_dest_permissions(dest, &source_metadata, options, context)?;

tests/by-util/test_cp.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5659,3 +5659,25 @@ fn test_cp_parents_absolute_path() {
56595659
let res = format!("dest{}/a/b/f", at.root_dir_resolved());
56605660
at.file_exists(res);
56615661
}
5662+
5663+
/// Test the behavior of copying a non existent file to a folder
5664+
#[test]
5665+
#[cfg(unix)]
5666+
fn test_cp_existant_and_nonexistent_file() {
5667+
let scene = TestScenario::new(util_name!());
5668+
let at = &scene.fixtures;
5669+
5670+
at.mkdir(TEST_COPY_TO_FOLDER_NEW);
5671+
5672+
scene
5673+
.ucmd()
5674+
.arg("-a")
5675+
.arg(TEST_NONEXISTENT_FILE)
5676+
.arg(TEST_HELLO_WORLD_SOURCE)
5677+
.arg(TEST_COPY_TO_FOLDER_NEW)
5678+
.fails()
5679+
.stderr_only("cp: cannot stat 'nonexistent_file.txt': No such file or directory\n");
5680+
5681+
// Check existing file has been copied
5682+
assert!(at.file_exists(TEST_COPY_TO_FOLDER_NEW_FILE));
5683+
}

0 commit comments

Comments
 (0)