Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

touch: Respect -h when getting metadata #5951

Merged
merged 8 commits into from
Mar 10, 2024
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
12 changes: 6 additions & 6 deletions src/uu/touch/src/touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,12 @@ fn update_times(
// If `follow` is `true`, the function will try to follow symlinks
// If `follow` is `false` or the symlink is broken, the function will return metadata of the symlink itself
fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> {
let metadata = match fs::metadata(path) {
Ok(metadata) => metadata,
Err(e) if e.kind() == std::io::ErrorKind::NotFound && !follow => fs::symlink_metadata(path)
.map_err_context(|| format!("failed to get attributes of {}", path.quote()))?,
Err(e) => return Err(e.into()),
};
let metadata = if follow {
fs::metadata(path).or_else(|_| fs::symlink_metadata(path))
} else {
fs::symlink_metadata(path)
}
.map_err_context(|| format!("failed to get attributes of {}", path.quote()))?;

Ok((
FileTime::from_last_access_time(&metadata),
Expand Down
39 changes: 38 additions & 1 deletion tests/by-util/test_touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms datetime mktime

use crate::common::util::{AtPath, TestScenario};
use filetime::FileTime;
use filetime::{self, set_symlink_file_times, FileTime};
use std::fs::remove_file;
use std::path::PathBuf;

Expand Down Expand Up @@ -854,3 +854,40 @@ fn test_touch_invalid_date_format() {
.fails()
.stderr_contains("touch: invalid date format '+1000000000000 years'");
}

#[test]
#[cfg(not(target_os = "freebsd"))]
fn test_touch_symlink_with_no_deref() {
let (at, mut ucmd) = at_and_ucmd!();
let target = "foo.txt";
let symlink = "bar.txt";
let time = FileTime::from_unix_time(123, 0);

at.touch(target);
at.relative_symlink_file(target, symlink);
set_symlink_file_times(at.plus(symlink), time, time).unwrap();

ucmd.args(&["-a", "--no-dereference", symlink]).succeeds();
// Modification time shouldn't be set to the destination's modification time
assert_eq!(time, get_symlink_times(&at, symlink).1);
}

#[test]
#[cfg(not(target_os = "freebsd"))]
fn test_touch_reference_symlink_with_no_deref() {
let (at, mut ucmd) = at_and_ucmd!();
let target = "foo.txt";
let symlink = "bar.txt";
let arg = "baz.txt";
let time = FileTime::from_unix_time(123, 0);

at.touch(target);
at.relative_symlink_file(target, symlink);
set_symlink_file_times(at.plus(symlink), time, time).unwrap();
at.touch(arg);

ucmd.args(&["--reference", symlink, "--no-dereference", arg])
.succeeds();
// Times should be taken from the symlink, not the destination
assert_eq!((time, time), get_symlink_times(&at, arg));
}
Loading