From a1960f5da0cc5bc34dcb0d7f05f45a1e4e48d3a7 Mon Sep 17 00:00:00 2001 From: electricboogie <32370782+electricboogie@users.noreply.github.com> Date: Wed, 15 Dec 2021 15:18:02 -0600 Subject: [PATCH] Fix cp bug: pre-write permission change (#2769) --- src/uu/cp/src/cp.rs | 12 +++++++++--- tests/by-util/test_cp.rs | 6 ++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 518a2262c..e98ced717 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -63,7 +63,7 @@ quick_error! { #[derive(Debug)] pub enum Error { /// Simple io::Error wrapper - IoErr(err: io::Error) { from() cause(err) display("{}", err) } + IoErr(err: io::Error) { from() cause(err) display("{}", err)} /// Wrapper for io::Error with path context IoErrContext(err: io::Error, path: String) { @@ -1292,7 +1292,13 @@ fn copy_file(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> { .map(|meta| !meta.file_type().is_symlink()) .unwrap_or(false) { - fs::set_permissions(&dest, dest_permissions).unwrap(); + // Here, to match GNU semantics, we quietly ignore an error + // if a user does not have the correct ownership to modify + // the permissions of a file. + // + // FWIW, the OS will throw an error later, on the write op, if + // the user does not have permission to write to the file. + fs::set_permissions(&dest, dest_permissions).ok(); } for attribute in &options.preserve_attributes { copy_attribute(&source, &dest, attribute)?; @@ -1312,7 +1318,7 @@ fn copy_helper(source: &Path, dest: &Path, options: &Options, context: &str) -> /* workaround a limitation of fs::copy * https://github.com/rust-lang/rust/issues/79390 */ - File::create(dest)?; + File::create(dest).context(dest.display().to_string())?; } else if is_symlink { copy_link(source, dest)?; } else if options.reflink_mode != ReflinkMode::Never { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 50abfe967..fc9dd589c 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -725,6 +725,12 @@ fn test_cp_parents_dest_not_directory() { .stderr_contains("with --parents, the destination must be a directory"); } +#[test] +#[cfg(unix)] +fn test_cp_writable_special_file_permissions() { + new_ucmd!().arg("/dev/null").arg("/dev/zero").succeeds(); +} + #[test] fn test_cp_preserve_no_args() { new_ucmd!()