diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index b7c64928f..40266689c 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1261,13 +1261,15 @@ fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> fn copy_on_write_linux(source: &Path, dest: &Path, mode: ReflinkMode) -> CopyResult<()> { debug_assert!(mode != ReflinkMode::Never); - let src_file = File::open(source).unwrap().into_raw_fd(); + let src_file = File::open(source) + .context(&*context_for(source, dest))? + .into_raw_fd(); let dst_file = OpenOptions::new() .write(true) .truncate(false) .create(true) .open(dest) - .unwrap() + .context(&*context_for(source, dest))? .into_raw_fd(); match mode { ReflinkMode::Always => unsafe { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index e995cc56c..c56e1ca57 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -7,6 +7,8 @@ use std::fs::set_permissions; #[cfg(not(windows))] use std::os::unix::fs; +#[cfg(target_os = "linux")] +use std::os::unix::fs::PermissionsExt; #[cfg(windows)] use std::os::windows::fs::symlink_file; @@ -1257,3 +1259,20 @@ fn test_cp_reflink_bad() { .fails() .stderr_contains("invalid argument"); } + +#[test] +#[cfg(target_os = "linux")] +fn test_cp_reflink_insufficient_permission() { + let (at, mut ucmd) = at_and_ucmd!(); + + at.make_file("unreadable") + .set_permissions(PermissionsExt::from_mode(0o000)) + .unwrap(); + + ucmd.arg("-r") + .arg("--reflink=auto") + .arg("unreadable") + .arg(TEST_EXISTING_FILE) + .fails() + .stderr_only("cp: 'unreadable' -> 'existing_file.txt': Permission denied (os error 13)"); +} diff --git a/tests/common/macros.rs b/tests/common/macros.rs index 81878bf1b..03d2051d0 100644 --- a/tests/common/macros.rs +++ b/tests/common/macros.rs @@ -50,14 +50,14 @@ macro_rules! new_ucmd { /// Convenience macro for acquiring a [`UCommand`] builder and a test path. /// /// Returns a tuple containing the following: -/// - an [`AsPath`] that points to a unique temporary test directory +/// - an [`AtPath`] that points to a unique temporary test directory /// - a [`UCommand`] builder for invoking the binary to be tested /// /// This macro is intended for quick, single-call tests. For more complex tests /// that require multiple invocations of the tested binary, see [`TestScenario`] /// /// [`UCommand`]: crate::tests::common::util::UCommand -/// [`AsPath`]: crate::tests::common::util::AsPath +/// [`AtPath`]: crate::tests::common::util::AtPath /// [`TestScenario]: crate::tests::common::util::TestScenario #[macro_export] macro_rules! at_and_ucmd {