mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
cp: allow removing symbolic link loop destination
Allow `cp --remove-destination` to remove a symbolic link loop (or a symbolic link that initiates a chain of too many symbolic links). Before this commit, if `loop` were a symbolic link to itself, then cp --remove-destination file loop would fail with an error message. After this commit, it succeeds. This matches the behaviotr of GNU cp.
This commit is contained in:
parent
e523a56dab
commit
24630db45e
2 changed files with 23 additions and 1 deletions
|
@ -1383,6 +1383,15 @@ fn handle_existing_dest(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Decide whether the given path exists.
|
||||
fn file_or_link_exists(path: &Path) -> bool {
|
||||
// Using `Path.exists()` or `Path.try_exists()` is not sufficient,
|
||||
// because if `path` is a symbolic link and there are too many
|
||||
// levels of symbolic link, then those methods will return false
|
||||
// or an OS error.
|
||||
path.symlink_metadata().is_ok()
|
||||
}
|
||||
|
||||
/// Copy the a file from `source` to `dest`. `source` will be dereferenced if
|
||||
/// `options.dereference` is set to true. `dest` will be dereferenced only if
|
||||
/// the source was not a symlink.
|
||||
|
@ -1400,7 +1409,7 @@ fn copy_file(
|
|||
symlinked_files: &mut HashSet<FileInformation>,
|
||||
source_in_command_line: bool,
|
||||
) -> CopyResult<()> {
|
||||
if dest.exists() {
|
||||
if file_or_link_exists(dest) {
|
||||
handle_existing_dest(source, dest, options, source_in_command_line)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -2095,3 +2095,16 @@ fn test_cp_mode_hardlink_no_dereference() {
|
|||
assert!(at.symlink_exists("z"));
|
||||
assert_eq!(at.read_symlink("z"), "slink");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_destination_symbolic_link_loop() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.symlink_file("loop", "loop");
|
||||
at.plus("loop");
|
||||
at.touch("f");
|
||||
ucmd.args(&["--remove-destination", "f", "loop"])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert!(at.file_exists("loop"));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue