mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
cp: fix -p to not preserve xattrs by default
Fixes #9704 The -p flag should only preserve mode, ownership, and timestamps, matching GNU cp behavior. Extended attributes require explicit --preserve=xattr or -a (archive mode). Changed Attributes::DEFAULT to set xattr preservation to No, preventing unintended security risks and filesystem compatibility issues. Adds regression test.
This commit is contained in:
parent
45f81bbae2
commit
68522d95fd
2 changed files with 107 additions and 1 deletions
|
|
@ -897,7 +897,7 @@ impl Attributes {
|
|||
ownership: Preserve::Yes { required: true },
|
||||
mode: Preserve::Yes { required: true },
|
||||
timestamps: Preserve::Yes { required: true },
|
||||
xattr: Preserve::Yes { required: true },
|
||||
xattr: Preserve::No { explicit: false },
|
||||
..Self::NONE
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1773,6 +1773,112 @@ fn test_cp_preserve_xattr() {
|
|||
}
|
||||
}
|
||||
|
||||
// -p preserves mode, ownership, and timestamps, but not xattrs
|
||||
// xattrs require explicit --preserve=xattr or -a
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "android", target_os = "macos", target_os = "openbsd"))
|
||||
))]
|
||||
fn test_cp_preserve_default_no_xattr() {
|
||||
use std::process::Command;
|
||||
use uutests::util::compare_xattrs;
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let source_file = "source_with_xattr";
|
||||
let dest_file_p = "dest_with_p_flag";
|
||||
let dest_file_explicit = "dest_with_explicit_xattr";
|
||||
|
||||
at.touch(source_file);
|
||||
|
||||
// set xattr on source
|
||||
let xattr_key = "user.test_preserve";
|
||||
let xattr_value = "test_value";
|
||||
match Command::new("setfattr")
|
||||
.args([
|
||||
"-n",
|
||||
xattr_key,
|
||||
"-v",
|
||||
xattr_value,
|
||||
&at.plus_as_string(source_file),
|
||||
])
|
||||
.status()
|
||||
.map(|status| status.code())
|
||||
{
|
||||
Ok(Some(0)) => {}
|
||||
Ok(_) => {
|
||||
println!("test skipped: setfattr failed");
|
||||
return;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("test skipped: setfattr failed with {e}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// verify xattr was set
|
||||
let getfattr_output = Command::new("getfattr")
|
||||
.args([&at.plus_as_string(source_file)])
|
||||
.output()
|
||||
.expect("failed to run getfattr");
|
||||
|
||||
assert!(
|
||||
getfattr_output.status.success(),
|
||||
"getfattr failed: {}",
|
||||
String::from_utf8_lossy(&getfattr_output.stderr)
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8_lossy(&getfattr_output.stdout);
|
||||
assert!(
|
||||
stdout.contains(xattr_key),
|
||||
"xattr not found on source: {xattr_key}"
|
||||
);
|
||||
|
||||
// -p should not preserve xattrs
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&[
|
||||
"-p",
|
||||
&at.plus_as_string(source_file),
|
||||
&at.plus_as_string(dest_file_p),
|
||||
])
|
||||
.succeeds()
|
||||
.no_output();
|
||||
|
||||
// xattrs should not be copied
|
||||
assert!(
|
||||
!compare_xattrs(&at.plus(source_file), &at.plus(dest_file_p)),
|
||||
"cp -p incorrectly preserved xattrs"
|
||||
);
|
||||
|
||||
// mode, ownership, and timestamps should be preserved
|
||||
#[cfg(not(any(target_os = "freebsd", target_os = "macos")))]
|
||||
{
|
||||
let metadata_src = at.metadata(source_file);
|
||||
let metadata_dst = at.metadata(dest_file_p);
|
||||
assert_metadata_eq!(metadata_src, metadata_dst);
|
||||
}
|
||||
|
||||
// --preserve=xattr should explicitly preserve xattrs
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&[
|
||||
"--preserve=xattr",
|
||||
&at.plus_as_string(source_file),
|
||||
&at.plus_as_string(dest_file_explicit),
|
||||
])
|
||||
.succeeds()
|
||||
.no_output();
|
||||
|
||||
// xattrs should be copied
|
||||
assert!(
|
||||
compare_xattrs(&at.plus(source_file), &at.plus(dest_file_explicit)),
|
||||
"cp --preserve=xattr did not preserve xattrs"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_os = "linux", not(feature = "feat_selinux")))]
|
||||
fn test_cp_preserve_all_context_fails_on_non_selinux() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue