Skip to content

Commit

Permalink
cp: improve the support of --attributes-only (#6051)
Browse files Browse the repository at this point in the history
* cp: improve the support of --attributes-only

* remove useless comments

Co-authored-by: Daniel Hofstetter <[email protected]>

---------

Co-authored-by: Daniel Hofstetter <[email protected]>
  • Loading branch information
sylvestre and cakebaker authored Mar 11, 2024
1 parent 80702d5 commit 89b326f
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
28 changes: 26 additions & 2 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,11 @@ impl CopyMode {
{
Self::Update
} else if matches.get_flag(options::ATTRIBUTES_ONLY) {
Self::AttrOnly
if matches.get_flag(options::REMOVE_DESTINATION) {
Self::Copy
} else {
Self::AttrOnly
}
} else {
Self::Copy
}
Expand Down Expand Up @@ -1709,7 +1713,13 @@ fn copy_file(
fs::remove_file(dest)?;
}

if file_or_link_exists(dest) {
if file_or_link_exists(dest)
&& (!options.attributes_only
|| matches!(
options.overwrite,
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
))
{
if are_hardlinks_to_same_file(source, dest)
&& !options.force()
&& options.backup == BackupMode::NoBackup
Expand All @@ -1721,6 +1731,20 @@ fn copy_file(
handle_existing_dest(source, dest, options, source_in_command_line)?;
}

if options.attributes_only
&& source.is_symlink()
&& !matches!(
options.overwrite,
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
)
{
return Err(format!(
"cannot change attribute {}: Source file is a non regular file",
dest.quote()
)
.into());
}

if options.preserve_hard_links() {
// if we encounter a matching device/inode pair in the source tree
// we can arrange to create a hard link between the corresponding names
Expand Down
55 changes: 55 additions & 0 deletions tests/by-util/test_cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3800,3 +3800,58 @@ fn test_acl_preserve() {

assert!(compare_xattrs(&file, &file_target));
}

#[test]
fn test_cp_force_remove_destination_attributes_only_with_symlink() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;

at.write("file1", "1");
at.write("file2", "2");
at.symlink_file("file1", "sym1");

scene
.ucmd()
.args(&[
"-a",
"--remove-destination",
"--attributes-only",
"sym1",
"file2",
])
.succeeds();

assert!(
at.symlink_exists("file2"),
"file2 is not a symbolic link as expected"
);

assert_eq!(
at.read("file1"),
at.read("file2"),
"Contents of file1 and file2 do not match"
);
}

#[test]
fn test_cp_no_dereference_attributes_only_with_symlink() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.write("file1", "1");
at.write("file2", "2");
at.write("file2.exp", "2");
at.symlink_file("file1", "sym1");

let result = scene
.ucmd()
.args(&["--no-dereference", "--attributes-only", "sym1", "file2"])
.fails();

assert_eq!(result.code(), 1, "cp command did not fail");

assert_eq!(
at.read("file2"),
at.read("file2.exp"),
"file2 content does not match expected"
);
}

0 comments on commit 89b326f

Please sign in to comment.