Skip to content

Commit b7d7aba

Browse files
committed
fix(cp): add temp write/exec perm to built dirs
1 parent 107dc44 commit b7d7aba

2 files changed

Lines changed: 37 additions & 5 deletions

File tree

src/uu/cp/src/copydir.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,12 +618,11 @@ fn build_dir(
618618
#[cfg(unix)]
619619
{
620620
use crate::Preserve;
621-
use std::os::unix::fs::PermissionsExt;
622621

623622
// we need to allow trivial casts here because some systems like linux have u32 constants in
624623
// in libc while others don't.
625624
#[allow(clippy::unnecessary_cast)]
626-
let mut excluded_perms = if matches!(options.attributes.ownership, Preserve::Yes { .. }) {
625+
let excluded_perms = if matches!(options.attributes.ownership, Preserve::Yes { .. }) {
627626
libc::S_IRWXG | libc::S_IRWXO // exclude rwx for group and other
628627
} else if matches!(options.attributes.mode, Preserve::Yes { .. }) {
629628
libc::S_IWGRP | libc::S_IWOTH //exclude w for group and other
@@ -634,13 +633,16 @@ fn build_dir(
634633
let umask = if let (Some(from), Preserve::Yes { .. }) =
635634
(copy_attributes_from, options.attributes.mode)
636635
{
637-
!fs::symlink_metadata(from)?.permissions().mode()
636+
// temporary u+wx permission before true permission is set by
637+
// `dirs_needing_permissions`.
638+
!0o300
638639
} else {
639640
uucore::mode::get_umask()
640641
};
641642

642-
excluded_perms |= umask;
643-
let mode = !excluded_perms & 0o777; //use only the last three octet bits
643+
let mode = !(excluded_perms | umask);
644+
// use only the last three octet bits
645+
let mode = mode & 0o777;
644646
std::os::unix::fs::DirBuilderExt::mode(&mut builder, mode);
645647
}
646648

tests/by-util/test_cp.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6470,6 +6470,36 @@ fn test_cp_preserve_xattr_readonly_source() {
64706470
);
64716471
}
64726472

6473+
#[test]
6474+
#[cfg(unix)]
6475+
fn test_cp_archive_dir_no_write_permission() {
6476+
// Test for issue #10787
6477+
let (at, mut ucmd) = at_and_ucmd!();
6478+
6479+
// test-dir/inner/test: all without write permission (500)
6480+
at.mkdir("test-dir");
6481+
at.mkdir("test-dir/inner");
6482+
at.touch("test-dir/inner/test");
6483+
at.set_mode("test-dir/inner/test", 0o500);
6484+
at.set_mode("test-dir/inner", 0o500);
6485+
at.set_mode("test-dir", 0o500);
6486+
6487+
ucmd.arg("-a")
6488+
.arg("test-dir")
6489+
.arg("test-dir-copy")
6490+
.succeeds();
6491+
6492+
assert_eq!(at.metadata("test-dir").permissions().mode() & 0o777, 0o500);
6493+
assert_eq!(
6494+
at.metadata("test-dir/inner").permissions().mode() & 0o777,
6495+
0o500
6496+
);
6497+
assert_eq!(
6498+
at.metadata("test-dir/inner/test").permissions().mode() & 0o777,
6499+
0o500
6500+
);
6501+
}
6502+
64736503
#[test]
64746504
#[cfg(unix)]
64756505
fn test_cp_archive_preserves_directory_permissions() {

0 commit comments

Comments
 (0)