Skip to content

Commit c3656e5

Browse files
committed
touch: -h -r should not fail when running on broken symlink
Fixes the beginning of: tests/touch/no-dereference.sh
1 parent afa5c15 commit c3656e5

2 files changed

Lines changed: 23 additions & 6 deletions

File tree

src/uu/touch/src/touch.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -305,13 +305,21 @@ pub fn uu_app() -> Command {
305305
)
306306
}
307307

308+
// Function to get metadata of the provided path
309+
// If `follow` is true, the function will try to follow symlinks
310+
// If `follow` is false or the symlink is broken, the function will return metadata of the symlink itself
308311
fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> {
309-
let metadata = if follow {
310-
fs::symlink_metadata(path)
311-
} else {
312-
fs::metadata(path)
313-
}
314-
.map_err_context(|| format!("failed to get attributes of {}", path.quote()))?;
312+
// Try to get metadata using fs::metadata
313+
// If the path is a symlink and `follow` is true, fs::metadata will follow the symlink
314+
let metadata = match fs::metadata(path) {
315+
// If successful, use the metadata
316+
Ok(metadata) => metadata,
317+
// If there's a NotFound error and `follow` is false, try to get metadata of the symlink itself
318+
Err(e) if e.kind() == std::io::ErrorKind::NotFound && !follow => fs::symlink_metadata(path)
319+
.map_err_context(|| format!("failed to get attributes of {}", path.quote()))?,
320+
// If it's any other error, return the error
321+
Err(e) => return Err(e.into()),
322+
};
315323

316324
Ok((
317325
FileTime::from_last_access_time(&metadata),

tests/by-util/test_touch.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,3 +816,12 @@ fn test_touch_trailing_slash_no_create() {
816816
at.relative_symlink_dir("dir2", "link2");
817817
ucmd.args(&["-c", "link2/"]).succeeds();
818818
}
819+
820+
#[test]
821+
fn test_touch_no_dereference_ref_dangling() {
822+
let (at, mut ucmd) = at_and_ucmd!();
823+
at.touch("file");
824+
at.relative_symlink_file("nowhere", "dangling");
825+
826+
ucmd.args(&["-h", "-r", "dangling", "file"]).succeeds();
827+
}

0 commit comments

Comments
 (0)