Merge pull request #4769 from sylvestre/touch

touch: improve support for dangling link
This commit is contained in:
Sylvestre Ledru 2023-04-25 08:26:23 +02:00 committed by GitHub
commit 6115af6386
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 10 deletions

View file

@ -139,7 +139,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let path = pathbuf.as_path();
if let Err(e) = path.metadata() {
let metadata_result = if matches.get_flag(options::NO_DEREF) {
path.symlink_metadata()
} else {
path.metadata()
};
if let Err(e) = metadata_result {
if e.kind() != std::io::ErrorKind::NotFound {
return Err(e.map_err_context(|| format!("setting times of {}", filename.quote())));
}
@ -198,14 +204,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}
}
if matches.get_flag(options::NO_DEREF) {
// sets the file access and modification times for a file or a symbolic link.
// The filename, access time (atime), and modification time (mtime) are provided as inputs.
// If the filename is not "-", indicating a special case for touch -h -,
// the code checks if the NO_DEREF flag is set, which means the user wants to
// set the times for a symbolic link itself, rather than the file it points to.
if filename == "-" {
filetime::set_file_times(path, atime, mtime)
} else if matches.get_flag(options::NO_DEREF) {
set_symlink_file_times(path, atime, mtime)
} else {
filetime::set_file_times(path, atime, mtime)
}
.map_err_context(|| format!("setting times of {}", path.quote()))?;
}
Ok(())
}
@ -305,13 +318,16 @@ pub fn uu_app() -> Command {
)
}
// 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()))?;
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()),
};
Ok((
FileTime::from_last_access_time(&metadata),

View file

@ -829,3 +829,27 @@ 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();
}
#[test]
fn test_touch_no_dereference_dangling() {
let (at, mut ucmd) = at_and_ucmd!();
at.relative_symlink_file("nowhere", "dangling");
ucmd.args(&["-h", "dangling"]).succeeds();
}
#[test]
fn test_touch_dash() {
let (_, mut ucmd) = at_and_ucmd!();
ucmd.args(&["-h", "-"]).succeeds().no_stderr().no_stdout();
}

View file

@ -67,7 +67,7 @@ if test -f gnu-built; then
echo "'rm -f $(pwd)/gnu-built' to force the build"
echo "Note: the customization of the tests will still happen"
else
./bootstrap
./bootstrap --skip-po
./configure --quiet --disable-gcc-warnings
#Add timeout to to protect against hangs
sed -i 's|^"\$@|/usr/bin/timeout 600 "\$@|' build-aux/test-driver