1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

mv: preserve the xattr

Should make tests/mv/acl pass
This commit is contained in:
Sylvestre Ledru 2024-01-14 00:39:00 +01:00
parent 238fb776ad
commit 2ec4e9f784
5 changed files with 60 additions and 1 deletions

View file

@ -42,6 +42,7 @@ fileio
filesystem filesystem
filesystems filesystems
flamegraph flamegraph
fsxattr
fullblock fullblock
getfacl getfacl
gibi gibi
@ -133,6 +134,7 @@ urand
whitespace whitespace
wordlist wordlist
wordlists wordlists
xattrs
# * abbreviations # * abbreviations
consts consts

View file

@ -21,6 +21,7 @@ indicatif = { workspace = true }
uucore = { workspace = true, features = [ uucore = { workspace = true, features = [
"backup-control", "backup-control",
"fs", "fs",
"fsxattr",
"update-control", "update-control",
] } ] }

View file

@ -27,7 +27,10 @@ use uucore::fs::{
are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file, are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file,
path_ends_with_terminator, path_ends_with_terminator,
}; };
#[cfg(all(unix, not(target_os = "macos")))]
use uucore::fsxattr;
use uucore::update_control; use uucore::update_control;
// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which // These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
// requires these enums // requires these enums
pub use uucore::{backup_control::BackupMode, update_control::UpdateMode}; pub use uucore::{backup_control::BackupMode, update_control::UpdateMode};
@ -631,6 +634,10 @@ fn rename_with_fallback(
None None
}; };
#[cfg(all(unix, not(target_os = "macos")))]
let xattrs =
fsxattr::retrieve_xattrs(from).unwrap_or_else(|_| std::collections::HashMap::new());
let result = if let Some(ref pb) = progress_bar { let result = if let Some(ref pb) = progress_bar {
move_dir_with_progress(from, to, &options, |process_info: TransitProcess| { move_dir_with_progress(from, to, &options, |process_info: TransitProcess| {
pb.set_position(process_info.copied_bytes); pb.set_position(process_info.copied_bytes);
@ -641,6 +648,9 @@ fn rename_with_fallback(
move_dir(from, to, &options) move_dir(from, to, &options)
}; };
#[cfg(all(unix, not(target_os = "macos")))]
fsxattr::apply_xattrs(to, xattrs).unwrap();
if let Err(err) = result { if let Err(err) = result {
return match err.kind { return match err.kind {
fs_extra::error::ErrorKind::PermissionDenied => Err(io::Error::new( fs_extra::error::ErrorKind::PermissionDenied => Err(io::Error::new(
@ -651,6 +661,11 @@ fn rename_with_fallback(
}; };
} }
} else { } else {
#[cfg(all(unix, not(target_os = "macos")))]
fs::copy(from, to)
.and_then(|_| fsxattr::copy_xattrs(&from, &to))
.and_then(|_| fs::remove_file(from))?;
#[cfg(any(target_os = "macos", not(unix)))]
fs::copy(from, to).and_then(|_| fs::remove_file(from))?; fs::copy(from, to).and_then(|_| fs::remove_file(from))?;
} }
} }

View file

@ -78,7 +78,7 @@ encoding = ["data-encoding", "data-encoding-macro", "z85", "thiserror"]
entries = ["libc"] entries = ["libc"]
fs = ["dunce", "libc", "winapi-util", "windows-sys"] fs = ["dunce", "libc", "winapi-util", "windows-sys"]
fsext = ["libc", "time", "windows-sys"] fsext = ["libc", "time", "windows-sys"]
fsxattr = [ "xattr" ] fsxattr = ["xattr"]
lines = [] lines = []
format = ["itertools"] format = ["itertools"]
mode = ["libc"] mode = ["libc"]

View file

@ -1569,6 +1569,47 @@ fn test_mv_dir_into_path_slash() {
assert!(at.dir_exists("f/b")); assert!(at.dir_exists("f/b"));
} }
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn test_acl() {
use std::process::Command;
use crate::common::util::compare_xattrs;
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().arg(&path).arg(path2).succeeds();
assert!(compare_xattrs(&file, &file_target));
}
// Todo: // Todo:
// $ at.touch a b // $ at.touch a b