mirror of
https://github.com/uutils/coreutils
synced 2024-12-12 22:32:53 +00:00
cp: --preserve should keep xattr (#5834)
* cp: --preserve should keep xattr Should help with tests/cp/acl.sh * Update tests/by-util/test_cp.rs Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * Update tests/by-util/test_cp.rs Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * Update tests/by-util/test_cp.rs Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> --------- Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
This commit is contained in:
parent
e340d8177e
commit
fff83995fb
4 changed files with 62 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -507,6 +507,7 @@ dependencies = [
|
|||
"uucore",
|
||||
"uuhelp_parser",
|
||||
"walkdir",
|
||||
"xattr",
|
||||
"zip",
|
||||
]
|
||||
|
||||
|
|
|
@ -500,6 +500,7 @@ rlimit = "0.10.1"
|
|||
[target.'cfg(unix)'.dev-dependencies]
|
||||
nix = { workspace = true, features = ["process", "signal", "user"] }
|
||||
rand_pcg = "0.3"
|
||||
xattr = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
phf_codegen = { workspace = true }
|
||||
|
|
|
@ -826,6 +826,7 @@ impl Attributes {
|
|||
ownership: Preserve::Yes { required: true },
|
||||
mode: Preserve::Yes { required: true },
|
||||
timestamps: Preserve::Yes { required: true },
|
||||
xattr: Preserve::Yes { required: true },
|
||||
..Self::NONE
|
||||
};
|
||||
|
||||
|
@ -1441,7 +1442,7 @@ pub(crate) fn copy_attributes(
|
|||
})?;
|
||||
|
||||
handle_preserve(&attributes.xattr, || -> CopyResult<()> {
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
{
|
||||
let xattrs = xattr::list(source)?;
|
||||
for attr in xattrs {
|
||||
|
@ -1450,7 +1451,7 @@ pub(crate) fn copy_attributes(
|
|||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
#[cfg(not(all(unix, not(target_os = "android"))))]
|
||||
{
|
||||
// The documentation for GNU cp states:
|
||||
//
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs ROOTDIR USERDIR procfs outfile uufs
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs ROOTDIR USERDIR procfs outfile uufs xattrs
|
||||
|
||||
use crate::common::util::TestScenario;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -56,6 +56,8 @@ static TEST_MOUNT_MOUNTPOINT: &str = "mount";
|
|||
static TEST_MOUNT_OTHER_FILESYSTEM_FILE: &str = "mount/DO_NOT_copy_me.txt";
|
||||
#[cfg(unix)]
|
||||
static TEST_NONEXISTENT_FILE: &str = "nonexistent_file.txt";
|
||||
#[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
|
||||
use xattr;
|
||||
|
||||
/// Assert that mode, ownership, and permissions of two metadata objects match.
|
||||
#[cfg(all(not(windows), not(target_os = "freebsd")))]
|
||||
|
@ -3736,3 +3738,57 @@ fn test_cp_no_such() {
|
|||
.fails()
|
||||
.stderr_is("cp: 'no-such/' is not a directory\n");
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
|
||||
fn compare_xattrs<P: AsRef<Path>>(path1: P, path2: P) -> bool {
|
||||
let get_sorted_xattrs = |path: P| {
|
||||
xattr::list(path)
|
||||
.map(|attrs| {
|
||||
let mut attrs = attrs.collect::<Vec<_>>();
|
||||
attrs.sort();
|
||||
attrs
|
||||
})
|
||||
.unwrap_or_else(|_| Vec::new())
|
||||
};
|
||||
|
||||
get_sorted_xattrs(path1) == get_sorted_xattrs(path2)
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
|
||||
#[test]
|
||||
fn test_acl_preserve() {
|
||||
use std::process::Command;
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let path1 = "a";
|
||||
let path2 = "b";
|
||||
let file = "a/file";
|
||||
let file_target = "b/file";
|
||||
at.mkdir(path1);
|
||||
at.mkdir(path2);
|
||||
at.touch(file);
|
||||
|
||||
let path = at.plus_as_string(file);
|
||||
// calling the command directly. xattr requires some dev packages to be installed
|
||||
// and it adds a complex dependency just for a test
|
||||
match Command::new("setfacl")
|
||||
.args(["-m", "group::rwx", &path1])
|
||||
.status()
|
||||
.map(|status| status.code())
|
||||
{
|
||||
Ok(Some(0)) => {}
|
||||
Ok(_) => {
|
||||
println!("test skipped: setfacl failed");
|
||||
return;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("test skipped: setfacl failed with {}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scene.ucmd().args(&["-p", &path, path2]).succeeds();
|
||||
|
||||
assert!(compare_xattrs(&file, &file_target));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue