mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
touch: Respect -h when getting metadata (#5951)
* 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>
This commit is contained in:
parent
8c7940260b
commit
d11d595fda
2 changed files with 44 additions and 7 deletions
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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…
Add table
Add a link
Reference in a new issue