From 832fd2d2c6915b3a60ff8d01d3919159992e4933 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 2 May 2023 23:22:13 +0200 Subject: [PATCH] cp: fix cp -f f loop when loop is a symlink loop Fix: tests/cp/thru-dangling.sh --- src/uu/cp/src/cp.rs | 7 ++++--- tests/by-util/test_cp.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 3ccff0303..00af0f251 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -38,7 +38,8 @@ use uucore::backup_control::{self, BackupMode}; use uucore::display::Quotable; use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError}; use uucore::fs::{ - canonicalize, paths_refer_to_same_file, FileInformation, MissingHandling, ResolveMode, + canonicalize, is_symlink_loop, paths_refer_to_same_file, FileInformation, MissingHandling, + ResolveMode, }; use uucore::{crash, format_usage, help_about, help_usage, prompt_yes, show_error, show_warning}; @@ -1388,11 +1389,10 @@ fn handle_existing_dest( backup_dest(dest, &backup_path)?; } } - match options.overwrite { // FIXME: print that the file was removed if --verbose is enabled OverwriteMode::Clobber(ClobberMode::Force) => { - if fs::metadata(dest)?.permissions().readonly() { + if is_symlink_loop(dest) || fs::metadata(dest)?.permissions().readonly() { fs::remove_file(dest)?; } } @@ -1498,6 +1498,7 @@ fn copy_file( options.overwrite, OverwriteMode::Clobber(ClobberMode::RemoveDestination) ) + && !is_symlink_loop(dest) && std::env::var_os("POSIXLY_CORRECT").is_none() { return Err(Error::Error(format!( diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index b77ad474e..c633ceea4 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -2309,6 +2309,20 @@ fn test_remove_destination_symbolic_link_loop() { assert!(at.file_exists("loop")); } +#[test] +#[cfg(not(windows))] +fn test_cp_symbolic_link_loop() { + let (at, mut ucmd) = at_and_ucmd!(); + at.symlink_file("loop", "loop"); + at.plus("loop"); + at.touch("f"); + ucmd.args(&["-f", "f", "loop"]) + .succeeds() + .no_stdout() + .no_stderr(); + assert!(at.file_exists("loop")); +} + /// Test that copying a directory to itself is disallowed. #[test] fn test_copy_directory_to_itself_disallowed() {