From b49fac30c81bc1ff044ae21e70c29fdef6adcffb Mon Sep 17 00:00:00 2001 From: mhead Date: Sat, 25 May 2024 21:25:59 +0530 Subject: [PATCH] cp: gnu test case preserve-mode fix --- src/uu/cp/src/cp.rs | 138 +++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 41 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 49e85265599..782bc1c1fa0 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -556,11 +556,6 @@ pub fn uu_app() -> Command { .num_args(0..) .require_equals(true) .value_name("ATTR_LIST") - .overrides_with_all([ - options::ARCHIVE, - options::PRESERVE_DEFAULT_ATTRIBUTES, - options::NO_PRESERVE, - ]) // -d sets this option // --archive sets this option .help( @@ -572,19 +567,18 @@ pub fn uu_app() -> Command { Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES) .short('p') .long(options::PRESERVE_DEFAULT_ATTRIBUTES) - .overrides_with_all([options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE]) .help("same as --preserve=mode,ownership(unix only),timestamps") .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_PRESERVE) .long(options::NO_PRESERVE) + .action(ArgAction::Append) + .use_value_delimiter(true) + .value_parser(ShortcutValueParser::new(PRESERVABLE_ATTRIBUTES)) + .num_args(0..) + .require_equals(true) .value_name("ATTR_LIST") - .overrides_with_all([ - options::PRESERVE_DEFAULT_ATTRIBUTES, - options::PRESERVE, - options::ARCHIVE, - ]) .help("don't preserve the specified attributes"), ) .arg( @@ -621,11 +615,6 @@ pub fn uu_app() -> Command { Arg::new(options::ARCHIVE) .short('a') .long(options::ARCHIVE) - .overrides_with_all([ - options::PRESERVE_DEFAULT_ATTRIBUTES, - options::PRESERVE, - options::NO_PRESERVE, - ]) .help("Same as -dR --preserve=all") .action(ArgAction::SetTrue), ) @@ -839,6 +828,42 @@ impl Attributes { } } + pub fn diff(self, other: &Self) -> Self { + Self { + #[cfg(unix)] + ownership: if matches!(other.ownership, Preserve::Yes { .. }) { + Preserve::No { explicit: true } + } else { + self.ownership + }, + mode: if matches!(other.mode, Preserve::Yes { .. }) { + Preserve::No { explicit: true } + } else { + self.mode + }, + timestamps: if matches!(other.timestamps, Preserve::Yes { .. }) { + Preserve::No { explicit: true } + } else { + self.timestamps + }, + context: if matches!(other.context, Preserve::Yes { .. }) { + Preserve::No { explicit: true } + } else { + self.context + }, + links: if matches!(other.links, Preserve::Yes { .. }) { + Preserve::No { explicit: true } + } else { + self.links + }, + xattr: if matches!(other.xattr, Preserve::Yes { .. }) { + Preserve::No { explicit: true } + } else { + self.xattr + }, + } + } + pub fn parse_iter(values: impl Iterator) -> Result where T: AsRef, @@ -926,34 +951,65 @@ impl Options { } }; - // Parse attributes to preserve - let mut attributes = - if let Some(attribute_strs) = matches.get_many::(options::PRESERVE) { - if attribute_strs.len() == 0 { - Attributes::DEFAULT - } else { - Attributes::parse_iter(attribute_strs)? + let mut overiding_priority = [ + options::ARCHIVE, + options::PRESERVE, + options::NO_PRESERVE, + options::PRESERVE_DEFAULT_ATTRIBUTES, + options::NO_DEREFERENCE_PRESERVE_LINKS, + ]; + overiding_priority.sort_by(|a, b| { + let a_index = matches.indices_of(a).and_then(|v| v.last()); + let b_index = matches.indices_of(b).and_then(|v| v.last()); + match (a_index, b_index) { + (None, None) => Ordering::Equal, + (None, Some(_)) => Ordering::Greater, + (Some(_), None) => Ordering::Less, + (Some(a), Some(b)) => { + if a < b { + Ordering::Less + } else { + Ordering::Greater + } } - } else if matches.get_flag(options::ARCHIVE) { - // --archive is used. Same as --preserve=all - Attributes::ALL - } else if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) { - Attributes::LINKS - } else if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) { - Attributes::DEFAULT - } else { - Attributes::NONE - }; + } + }); - // handling no-preserve options and adjusting the attributes - if let Some(attribute_strs) = matches.get_many::(options::NO_PRESERVE) { - if attribute_strs.len() > 0 { - let no_preserve_attributes = Attributes::parse_iter(attribute_strs)?; - if matches!(no_preserve_attributes.links, Preserve::Yes { .. }) { - attributes.links = Preserve::No { explicit: true }; - } else if matches!(no_preserve_attributes.mode, Preserve::Yes { .. }) { - attributes.mode = Preserve::No { explicit: true }; + let mut attributes = Attributes::NONE; + + for option in overiding_priority { + match option { + options::ARCHIVE => { + if matches.get_flag(options::ARCHIVE) { + attributes = Attributes::ALL; + } + } + options::PRESERVE_DEFAULT_ATTRIBUTES => { + if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) { + attributes = attributes.union(&Attributes::DEFAULT); + } + } + options::NO_DEREFERENCE_PRESERVE_LINKS => { + if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) { + attributes = attributes.union(&Attributes::LINKS); + } + } + options::PRESERVE => { + if let Some(attribute_strs) = matches.get_many::(options::PRESERVE) { + if attribute_strs.len() == 0 { + attributes = attributes.union(&Attributes::DEFAULT); + } + attributes = attributes.union(&Attributes::parse_iter(attribute_strs)?); + } + } + options::NO_PRESERVE => { + if let Some(attribute_strs) = matches.get_many::(options::NO_PRESERVE) { + if attribute_strs.len() > 0 { + attributes = attributes.diff(&Attributes::parse_iter(attribute_strs)?); + } + } } + _ => (), } }