1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Merge pull request #3972 from jfinkels/cp-symbolic-link-loop

cp: allow removing symbolic link loop destination
This commit is contained in:
Sylvestre Ledru 2022-10-10 08:15:22 +02:00 committed by GitHub
commit d205823c8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 1 deletions

View file

@ -1372,6 +1372,15 @@ fn handle_existing_dest(
Ok(()) 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 /// 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 /// `options.dereference` is set to true. `dest` will be dereferenced only if
/// the source was not a symlink. /// the source was not a symlink.
@ -1389,7 +1398,7 @@ fn copy_file(
symlinked_files: &mut HashSet<FileInformation>, symlinked_files: &mut HashSet<FileInformation>,
source_in_command_line: bool, source_in_command_line: bool,
) -> CopyResult<()> { ) -> CopyResult<()> {
if dest.exists() { if file_or_link_exists(dest) {
handle_existing_dest(source, dest, options, source_in_command_line)?; handle_existing_dest(source, dest, options, source_in_command_line)?;
} }

View file

@ -2096,6 +2096,19 @@ fn test_cp_mode_hardlink_no_dereference() {
assert_eq!(at.read_symlink("z"), "slink"); 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"));
}
/// Test that copying a directory to itself is disallowed. /// Test that copying a directory to itself is disallowed.
#[test] #[test]
fn test_copy_directory_to_itself_disallowed() { fn test_copy_directory_to_itself_disallowed() {