Skip to content

Commit d814ff8

Browse files
committed
cp: Added additional gnu test which *has* to work in combination with needed changes for the added test
1 parent 21bd978 commit d814ff8

File tree

3 files changed

+55
-49
lines changed

3 files changed

+55
-49
lines changed

src/uu/cp/src/copydir.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ pub(crate) fn copy_directory(
503503
copy_attributes(
504504
&entry.source_absolute,
505505
&entry.local_to_target,
506-
&options.attributes,
506+
options,
507507
)?;
508508
}
509509
}
@@ -520,7 +520,7 @@ pub(crate) fn copy_directory(
520520
// Fix permissions for all directories we created
521521
// This ensures that even sibling directories get their permissions fixed
522522
for (source_path, dest_path) in dirs_needing_permissions {
523-
copy_attributes(&source_path, &dest_path, &options.attributes)?;
523+
copy_attributes(&source_path, &dest_path, options)?;
524524
}
525525

526526
// Also fix permissions for parent directories,
@@ -529,7 +529,7 @@ pub(crate) fn copy_directory(
529529
let dest = target.join(root.file_name().unwrap());
530530
for (x, y) in aligned_ancestors(root, dest.as_path()) {
531531
if let Ok(src) = canonicalize(x, MissingHandling::Normal, ResolveMode::Physical) {
532-
copy_attributes(&src, y, &options.attributes)?;
532+
copy_attributes(&src, y, options)?;
533533
}
534534
}
535535
}

src/uu/cp/src/cp.rs

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,7 @@ fn copy_source(
15061506
if options.parents {
15071507
for (x, y) in aligned_ancestors(source, dest.as_path()) {
15081508
if let Ok(src) = canonicalize(x, MissingHandling::Normal, ResolveMode::Physical) {
1509-
copy_attributes(&src, y, &options.attributes)?;
1509+
copy_attributes(&src, y, options)?;
15101510
}
15111511
}
15121512
}
@@ -1655,25 +1655,14 @@ fn copy_extended_attrs(source: &Path, dest: &Path) -> CopyResult<()> {
16551655
}
16561656

16571657
/// Copy the specified attributes from one path to another.
1658-
pub(crate) fn copy_attributes(
1659-
source: &Path,
1660-
dest: &Path,
1661-
attributes: &Attributes,
1662-
) -> CopyResult<()> {
1658+
pub(crate) fn copy_attributes(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
16631659
let context = &*format!("{} -> {}", source.quote(), dest.quote());
16641660
let source_metadata =
16651661
fs::symlink_metadata(source).map_err(|e| CpError::IoErrContext(e, context.to_owned()))?;
16661662

1667-
// if --no-preserve wasn't explicitly passed and we're copying a directory by default we should preserve mode
1668-
let mode = if dest.is_dir() && attributes.mode == (Preserve::No { explicit: false }) {
1669-
Preserve::Yes { required: false }
1670-
} else {
1671-
attributes.mode
1672-
};
1673-
16741663
// Ownership must be changed first to avoid interfering with mode change.
16751664
#[cfg(unix)]
1676-
handle_preserve(&attributes.ownership, || -> CopyResult<()> {
1665+
handle_preserve(&options.attributes.ownership, || -> CopyResult<()> {
16771666
use std::os::unix::prelude::MetadataExt;
16781667
use uucore::perms::Verbosity;
16791668
use uucore::perms::VerbosityLevel;
@@ -1708,14 +1697,22 @@ pub(crate) fn copy_attributes(
17081697
Ok(())
17091698
})?;
17101699

1711-
handle_preserve(&mode, || -> CopyResult<()> {
1700+
handle_preserve(&options.attributes.mode, || -> CopyResult<()> {
17121701
// The `chmod()` system call that underlies the
17131702
// `fs::set_permissions()` call is unable to change the
17141703
// permissions of a symbolic link. In that case, we just
17151704
// do nothing, since every symbolic link has the same
17161705
// permissions.
17171706
if !dest.is_symlink() {
1718-
fs::set_permissions(dest, source_metadata.permissions())
1707+
// let dest_permissions = calculate_dest_permissions(
1708+
// fs::metadata(dest).ok().as_ref(),
1709+
// dest,
1710+
// &source_metadata,
1711+
// options,
1712+
// context,
1713+
// )?;
1714+
let dest_permissions = source_metadata.permissions();
1715+
fs::set_permissions(dest, dest_permissions)
17191716
.map_err(|e| CpError::IoErrContext(e, context.to_owned()))?;
17201717
// FIXME: Implement this for windows as well
17211718
#[cfg(feature = "feat_acl")]
@@ -1727,7 +1724,7 @@ pub(crate) fn copy_attributes(
17271724
Ok(())
17281725
})?;
17291726

1730-
handle_preserve(&attributes.timestamps, || -> CopyResult<()> {
1727+
handle_preserve(&options.attributes.timestamps, || -> CopyResult<()> {
17311728
let atime = FileTime::from_last_access_time(&source_metadata);
17321729
let mtime = FileTime::from_last_modification_time(&source_metadata);
17331730
if dest.is_symlink() {
@@ -1740,7 +1737,7 @@ pub(crate) fn copy_attributes(
17401737
})?;
17411738

17421739
#[cfg(feature = "selinux")]
1743-
handle_preserve(&attributes.context, || -> CopyResult<()> {
1740+
handle_preserve(&options.attributes.context, || -> CopyResult<()> {
17441741
// Get the source context and apply it to the destination
17451742
if let Ok(context) = selinux::SecurityContext::of_path(source, false, false) {
17461743
if let Some(context) = context {
@@ -1758,7 +1755,7 @@ pub(crate) fn copy_attributes(
17581755
Ok(())
17591756
})?;
17601757

1761-
handle_preserve(&attributes.xattr, || -> CopyResult<()> {
1758+
handle_preserve(&options.attributes.xattr, || -> CopyResult<()> {
17621759
#[cfg(all(unix, not(target_os = "android")))]
17631760
{
17641761
copy_extended_attrs(source, dest)?;
@@ -2519,7 +2516,7 @@ fn copy_file(
25192516
if options.dereference(source_in_command_line) {
25202517
if let Ok(src) = canonicalize(source, MissingHandling::Normal, ResolveMode::Physical) {
25212518
if src.exists() {
2522-
copy_attributes(&src, dest, &options.attributes)?;
2519+
copy_attributes(&src, dest, options)?;
25232520
}
25242521
}
25252522
} else if source_is_stream && !source.exists() {
@@ -2528,7 +2525,7 @@ fn copy_file(
25282525
// attributes. However, this is already handled in the stream
25292526
// copy function (see `copy_stream` under platform/linux.rs).
25302527
} else {
2531-
copy_attributes(source, dest, &options.attributes)?;
2528+
copy_attributes(source, dest, options)?;
25322529
}
25332530

25342531
#[cfg(feature = "selinux")]
@@ -2704,7 +2701,7 @@ fn copy_link(
27042701
delete_path(dest, options)?;
27052702
}
27062703
symlink_file(&link, dest, symlinked_files)?;
2707-
copy_attributes(source, dest, &options.attributes)
2704+
copy_attributes(source, dest, options)
27082705
}
27092706

27102707
/// Generate an error message if `target` is not the correct `target_type`

tests/by-util/test_cp.rs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7415,6 +7415,8 @@ fn test_cp_recurse_verbose_output_with_symlink_already_exists() {
74157415
#[test]
74167416
#[cfg(not(target_os = "windows"))]
74177417
fn test_cp_preserve_directory_permissions_by_default() {
7418+
use std::io;
7419+
74187420
let scene = TestScenario::new(util_name!());
74197421
let at = &scene.fixtures;
74207422

@@ -7430,7 +7432,13 @@ fn test_cp_preserve_directory_permissions_by_default() {
74307432
scene.cmd("chmod").arg("-R").arg("555").arg("a").succeeds();
74317433
scene.cmd("cp").arg("-r").arg("a").arg("b").succeeds();
74327434

7433-
scene.ucmd().arg("-r").arg("a").arg("c").succeeds();
7435+
scene
7436+
.ucmd()
7437+
.arg("-r")
7438+
.arg("a")
7439+
.arg("c")
7440+
.set_stdout(io::stdout())
7441+
.succeeds();
74347442

74357443
assert_eq!(get_mode(at.plus("b")), 0o40555);
74367444
assert_eq!(get_mode(at.plus("b/b")), 0o40555);
@@ -7445,37 +7453,38 @@ fn test_cp_preserve_directory_permissions_by_default() {
74457453

74467454
#[test]
74477455
#[cfg(not(target_os = "windows"))]
7448-
fn test_cp_no_preserve_directory_permissions() {
7456+
fn test_cp_existing_perm_dir() {
7457+
use std::io;
7458+
74497459
let scene = TestScenario::new(util_name!());
74507460
let at = &scene.fixtures;
74517461

7452-
let dir = "a/b/c/d";
7453-
let file = "foo.txt";
7454-
7455-
at.mkdir_all(dir);
7456-
7457-
let file_path = format!("{dir}/{file}");
7458-
7459-
at.touch(file_path);
7460-
7461-
scene.cmd("chmod").arg("-R").arg("555").arg("a").succeeds();
7462-
scene.cmd("cp").arg("-r").arg("a").arg("b").succeeds();
7462+
scene
7463+
.cmd("mkdir")
7464+
.arg("-p")
7465+
.arg("-m")
7466+
.arg("ug-s,u=rwx,g=rwx,o=rx")
7467+
.arg("src/dir")
7468+
.umask(0o022)
7469+
.succeeds();
7470+
scene
7471+
.cmd("mkdir")
7472+
.arg("-p")
7473+
.arg("-m")
7474+
.arg("ug-s,u=rwx,g=,o=")
7475+
.arg("dst/dir")
7476+
.umask(0o022)
7477+
.succeeds();
74637478

74647479
scene
74657480
.ucmd()
74667481
.arg("-r")
7467-
.arg("--no-preserve=mode")
7468-
.arg("a")
7469-
.arg("c")
7482+
.arg("src/.")
7483+
.arg("dst/")
7484+
.set_stdout(io::stdout())
74707485
.succeeds();
74717486

7472-
assert_eq!(get_mode(at.plus("b")), 0o40555);
7473-
assert_eq!(get_mode(at.plus("b/b")), 0o40555);
7474-
assert_eq!(get_mode(at.plus("b/b/c")), 0o40555);
7475-
assert_eq!(get_mode(at.plus("b/b/c/d")), 0o40555);
7487+
let mode = get_mode(at.plus("dst/dir"));
74767488

7477-
assert_eq!(get_mode(at.plus("c")), 0o40755);
7478-
assert_eq!(get_mode(at.plus("c/b")), 0o40755);
7479-
assert_eq!(get_mode(at.plus("c/b/c")), 0o40755);
7480-
assert_eq!(get_mode(at.plus("c/b/c/d")), 0o40755);
7489+
assert_eq!(mode, 0o40700);
74817490
}

0 commit comments

Comments
 (0)