From c3656e561cde70c2a860d11a5747c24387105b20 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 21 Apr 2023 23:54:08 +0200 Subject: [PATCH] touch: -h -r should not fail when running on broken symlink Fixes the beginning of: tests/touch/no-dereference.sh --- src/uu/touch/src/touch.rs | 20 ++++++++++++++------ tests/by-util/test_touch.rs | 9 +++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index eeb1dd13a..8d96b1b16 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -305,13 +305,21 @@ pub fn uu_app() -> Command { ) } +// Function to get metadata of the provided path +// 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 = if follow { - fs::symlink_metadata(path) - } else { - fs::metadata(path) - } - .map_err_context(|| format!("failed to get attributes of {}", path.quote()))?; + // Try to get metadata using fs::metadata + // If the path is a symlink and `follow` is true, fs::metadata will follow the symlink + let metadata = match fs::metadata(path) { + // If successful, use the metadata + Ok(metadata) => metadata, + // If there's a NotFound error and `follow` is false, try to get metadata of the symlink itself + 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()))?, + // If it's any other error, return the error + Err(e) => return Err(e.into()), + }; Ok(( FileTime::from_last_access_time(&metadata), diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index ae3a28e49..89a7cacaf 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -816,3 +816,12 @@ fn test_touch_trailing_slash_no_create() { at.relative_symlink_dir("dir2", "link2"); ucmd.args(&["-c", "link2/"]).succeeds(); } + +#[test] +fn test_touch_no_dereference_ref_dangling() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("file"); + at.relative_symlink_file("nowhere", "dangling"); + + ucmd.args(&["-h", "-r", "dangling", "file"]).succeeds(); +}