diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 7265e89f12a..076daba838b 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -18,7 +18,7 @@ use std::io; use std::os::unix::ffi::OsStrExt; #[cfg(unix)] use std::os::unix::fs::{FileTypeExt, PermissionsExt}; -use std::path::{Path, PathBuf, StripPrefixError}; +use std::path::{Path, PathBuf, StripPrefixError, MAIN_SEPARATOR_STR}; use std::string::ToString; use clap::{builder::ValueParser, crate_version, Arg, ArgAction, ArgMatches, Command}; @@ -96,6 +96,9 @@ quick_error! { Backup(description: String) { display("{}\nTry '{} --help' for more information.", description, uucore::execution_phrase()) } NotADirectory(path: PathBuf) { display("'{}' is not a directory", path.display()) } + + /// Result of trying to copy file to non-existing directory, e.g. `cp a no-such/` + CannotCreateRegularFile(path: PathBuf) { display("cannot create regular file '{}': Not a directory", path.display()) } } } @@ -1674,6 +1677,8 @@ fn copy_file( if file_or_link_exists(dest) { handle_existing_dest(source, dest, options, source_in_command_line)?; + } else if dest.to_string_lossy().ends_with(MAIN_SEPARATOR_STR) { + return Err(Error::CannotCreateRegularFile(dest.to_path_buf())); } if options.preserve_hard_links() { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index c8761fab8fb..2cd92a08e15 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -104,6 +104,15 @@ fn test_cp_existing_target() { assert!(!at.file_exists(format!("{TEST_EXISTING_FILE}~"))); } +#[test] +fn test_cp_non_existing_target_dir() { + new_ucmd!() + .arg(TEST_HELLO_WORLD_SOURCE) + .arg("non-existing-dir/") + .fails() + .stderr_is("cp: cannot create regular file 'non-existing-dir/': Not a directory\n"); +} + #[test] fn test_cp_duplicate_files() { let (at, mut ucmd) = at_and_ucmd!();