8000 touch: improve support for dangling link by sylvestre · Pull Request #4769 · uutils/coreutils · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

touch: improve support for dangling link #4769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions src/uu/touch/src/touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())));
}
Expand Down Expand Up @@ -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(())
}

Expand Down Expand Up @@ -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),
Expand Down
24 changes: 24 additions & 0 deletions tests/by-util/test_touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,3 +816,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();
}
2 changes: 1 addition & 1 deletion util/build-gnu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
0