Skip to content

Commit 8bff321

Browse files
baa-abletonRenjiSann
authored andcommitted
fix(cp): always create dest dirs with owner write bit before fixing permissions
1 parent 59288a7 commit 8bff321

2 files changed

Lines changed: 24 additions & 1 deletion

File tree

src/uu/cp/src/copydir.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,9 @@ fn build_dir(
667667
};
668668

669669
excluded_perms |= umask;
670-
let mode = !excluded_perms & 0o777; //use only the last three octet bits
670+
// Always keep the owner write bit so we can copy files into the directory.
671+
// The correct final permissions are applied afterward by dirs_needing_permissions.
672+
let mode = (!excluded_perms & 0o777) | 0o200; // mask to permission bits, always keep owner write
671673
std::os::unix::fs::DirBuilderExt::mode(&mut builder, mode);
672674
}
673675

tests/by-util/test_cp.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3795,6 +3795,27 @@ fn test_copy_dir_preserve_subdir_permissions() {
37953795
assert_metadata_eq!(at.metadata("a1/a2"), at.metadata("b1/a2"));
37963796
}
37973797

3798+
/// cp should successfully copy a read-only source directory containing files.
3799+
/// Regression test: build_dir previously created the destination with the source's
3800+
/// read-only mode, causing EPERM when copying files into it.
3801+
#[cfg(all(not(windows), not(target_os = "freebsd"), not(target_os = "openbsd")))]
3802+
#[test]
3803+
fn test_copy_dir_preserve_readonly_source_with_files() {
3804+
let (at, mut ucmd) = at_and_ucmd!();
3805+
at.mkdir("src");
3806+
at.write("src/file.txt", "hello");
3807+
at.set_mode("src", 0o0555);
3808+
3809+
ucmd.args(&["-p", "-r", "src", "dest"])
3810+
.succeeds()
3811+
.no_stderr()
3812+
.no_stdout();
3813+
3814+
assert!(at.dir_exists("dest"));
3815+
assert_eq!(at.read("dest/file.txt"), "hello");
3816+
assert_metadata_eq!(at.metadata("src"), at.metadata("dest"));
3817+
}
3818+
37983819
/// Test for preserving permissions when copying a directory, even in
37993820
/// the face of an inaccessible file in that directory.
38003821
#[cfg(all(not(windows), not(target_os = "freebsd"), not(target_os = "openbsd")))]

0 commit comments

Comments
 (0)