From c9efbfac5f8ca60af29ef97edcbcf96b26a3220b Mon Sep 17 00:00:00 2001 From: Chaganti-Reddy Date: Fri, 10 Jul 2026 16:43:59 +0530 Subject: [PATCH] cp: don't hang forever when the backup destination is a fifo. Fixes #13162 --- src/uu/cp/src/cp.rs | 5 +++++ tests/by-util/test_cp.rs | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 7129e82522..e118714218 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -2015,6 +2015,11 @@ fn backup_dest(dest: &Path, backup_path: &Path, is_dest_symlink: bool) -> CopyRe if is_dest_symlink { fs::rename(dest, backup_path)?; } else { + match fs::remove_file(backup_path) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => return Err(err.into()), + } fs::copy(dest, backup_path)?; } Ok(()) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index d973c39366..48e093e60c 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1243,6 +1243,27 @@ fn test_cp_backup_existing() { ); } +#[test] +#[cfg(unix)] +fn test_cp_backup_existing_target_is_fifo() { + let (at, mut ucmd) = at_and_ucmd!(); + at.mkfifo(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")); + + ucmd.arg("--backup=simple") + .arg(TEST_HELLO_WORLD_SOURCE) + .arg(TEST_HOW_ARE_YOU_SOURCE) + .timeout(Duration::from_secs(10)) + .succeeds() + .no_stderr(); + + assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); + assert!(!at.is_fifo(&format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); + assert_eq!( + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), + "How are you?\n" + ); +} + #[test] fn test_cp_backup_nil() { let (at, mut ucmd) = at_and_ucmd!();