Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/uu/install/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ install-error-extra-operand = extra operand { $operand }
install-error-not-permitted = cannot remove { $path }: Operation not permitted
install-error-invalid-mode = Invalid mode string: { $error }
install-error-mutually-exclusive-target = Options --target-directory and --no-target-directory are mutually exclusive
install-error-mutually-exclusive-compare-preserve = Options --compare and --preserve-timestamps are mutually exclusive
install-error-mutually-exclusive-compare-strip = Options --compare and --strip are mutually exclusive
install-error-missing-file-operand = missing file operand
install-error-missing-destination-operand = missing destination file operand after { $path }
Expand Down
1 change: 0 additions & 1 deletion src/uu/install/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ install-error-extra-operand = opérande supplémentaire { $operand }
{ $usage }
install-error-invalid-mode = Chaîne de mode invalide : { $error }
install-error-mutually-exclusive-target = Les options --target-directory et --no-target-directory sont mutuellement exclusives
install-error-mutually-exclusive-compare-preserve = Les options --compare et --preserve-timestamps sont mutuellement exclusives
install-error-mutually-exclusive-compare-strip = Les options --compare et --strip sont mutuellement exclusives
install-error-missing-file-operand = opérande de fichier manquant
install-error-missing-destination-operand = opérande de fichier de destination manquant après { $path }
Expand Down
13 changes: 6 additions & 7 deletions src/uu/install/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,6 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
}
.to_string();

if preserve_timestamps && compare {
show_error!(
"{}",
translate!("install-error-mutually-exclusive-compare-preserve")
);
return Err(1.into());
}
if compare && strip {
show_error!(
"{}",
Expand Down Expand Up @@ -1313,6 +1306,12 @@ fn need_copy(from: &Path, to: &Path, b: &Behavior) -> bool {
return true;
}

// When preserving timestamps, a difference in modification time also
// requires a copy so the destination ends up with the source's timestamp.
if b.preserve_timestamps && from_meta.modified().ok() != to_meta.modified().ok() {
return true;
}

if b.privileged {
#[cfg(all(feature = "selinux", any(target_os = "linux", target_os = "android")))]
if b.preserve_context && contexts_differ(from, to) {
Expand Down
32 changes: 30 additions & 2 deletions tests/by-util/test_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,33 @@ fn test_install_preserve_timestamps() {
);
}

#[test]
#[cfg(not(target_os = "openbsd"))]
fn test_install_compare_preserve_timestamps() {
use std::time::Duration;

let (at, mut ucmd) = at_and_ucmd!();
let source = "source_file";
let dest = "dest_file";

// Same contents, but destination has a newer timestamp than the source.
at.write(source, "data");
at.write(dest, "data");
let old = std::time::SystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000);
filetime::set_file_mtime(at.plus(source), FileTime::from_system_time(old)).unwrap();

// With --preserve-timestamps, the timestamp difference forces the copy so
// the destination ends up with the source's modification time.
ucmd.args(&["-C", "--preserve-timestamps", source, dest])
.succeeds()
.no_output();

assert_eq!(
at.metadata(source).modified().ok(),
at.metadata(dest).modified().ok()
);
}

// These two tests are failing but should work
#[test]
fn test_install_copy_file() {
Expand Down Expand Up @@ -1856,11 +1883,12 @@ fn test_install_compare_option() {
.args(&["-Cv", first, second])
.succeeds()
.stdout_contains(format!("removed '{second}'\n'{first}' -> '{second}'"));
// -C and --preserve-timestamps are no longer mutually exclusive
scene
.ucmd()
.args(&["-C", "--preserve-timestamps", first, second])
.fails_with_code(1)
.stderr_contains("Options --compare and --preserve-timestamps are mutually exclusive");
.succeeds()
.no_output();
scene
.ucmd()
.args(&["-C", "--strip", "--strip-program=echo", first, second])
Expand Down
Loading