Skip to content

Commit

Permalink
touch: Respect -h when getting metadata (#5951)
Browse files Browse the repository at this point in the history
* Add tests that stat symlinks

* Check follow first in stat

* Don't run tests on FreeBSD

It would be possible to get them to run on FreeBSD by avoiding
get_symlink_times, but the behavior we're testing is not
platform-specific, so it's fine to not test it on FreeBSD.

---------

Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
  • Loading branch information
ysthakur and sylvestre committed Mar 10, 2024
1 parent 8c79402 commit d11d595
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 7 deletions.
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));
}

0 comments on commit d11d595

Please sign in to comment.