From 5fc421aa037c78e358937691a1bf50e3871054a7 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jul 2024 17:41:03 +0800 Subject: [PATCH 1/4] fix-issue#6266 --- src/uu/cp/src/cp.rs | 6 +++++- tests/by-util/test_cp.rs | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 33c16a0fa71..505a17dd6c0 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1266,7 +1266,11 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult let dest = construct_dest_path(source, target, target_type, options) .unwrap_or_else(|_| target.to_path_buf()); - if fs::metadata(&dest).is_ok() && !fs::symlink_metadata(&dest)?.file_type().is_symlink() + if (fs::metadata(&dest).is_ok() + && !fs::symlink_metadata(&dest)?.file_type().is_symlink()) + // if both `source` and `dest` are symlinks, it should be considered as an overwrite. + || (fs::metadata(source).is_ok() + && fs::symlink_metadata(source)?.file_type().is_symlink()) { // There is already a file and it isn't a symlink (managed in a different place) if copied_destinations.contains(&dest) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 0b5c8174624..962d88489ce 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -5696,3 +5696,26 @@ fn test_cp_parents_absolute_path() { let res = format!("dest{}/a/b/f", at.root_dir_resolved()); at.file_exists(res); } + +#[test] +fn test_copy_symlink_overwrite() { + let (at, mut ucmd) = at_and_ucmd!(); + at.mkdir("a"); + at.mkdir("b"); + at.mkdir("c"); + at.write("t", "hello"); + at.relative_symlink_file("../t", "a/1"); + at.relative_symlink_file("../t", "b/1"); + + ucmd.arg("--no-dereference") + .arg("a/1") + .arg("b/1") + .arg("c") + .fails() + .stderr_only(if cfg!(not(target_os = "windows")) { + "cp: will not overwrite just-created 'c/1' with 'b/1'\n" + } else { + "cp: will not overwrite just-created 'c\\1' with 'b/1'\n" + }); + assert_eq!(at.read("c/1"), "hello"); +} From aeae84bebef875ad5026286c2df48aef8502a6e6 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jul 2024 22:08:39 +0800 Subject: [PATCH 2/4] symlink mode --- src/uu/cp/src/cp.rs | 9 +++++---- tests/by-util/test_cp.rs | 25 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 505a17dd6c0..7f8a58c09cb 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1266,11 +1266,12 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult let dest = construct_dest_path(source, target, target_type, options) .unwrap_or_else(|_| target.to_path_buf()); - if (fs::metadata(&dest).is_ok() - && !fs::symlink_metadata(&dest)?.file_type().is_symlink()) + if fs::metadata(&dest).is_ok() + && !fs::symlink_metadata(&dest)?.file_type().is_symlink() // if both `source` and `dest` are symlinks, it should be considered as an overwrite. - || (fs::metadata(source).is_ok() - && fs::symlink_metadata(source)?.file_type().is_symlink()) + || fs::metadata(source).is_ok() + && fs::symlink_metadata(source)?.file_type().is_symlink() + || matches!(options.copy_mode, CopyMode::SymLink) { // There is already a file and it isn't a symlink (managed in a different place) if copied_destinations.contains(&dest) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 962d88489ce..2f7bc0ddae4 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -5703,6 +5703,7 @@ fn test_copy_symlink_overwrite() { at.mkdir("a"); at.mkdir("b"); at.mkdir("c"); + at.write("t", "hello"); at.relative_symlink_file("../t", "a/1"); at.relative_symlink_file("../t", "b/1"); @@ -5717,5 +5718,27 @@ fn test_copy_symlink_overwrite() { } else { "cp: will not overwrite just-created 'c\\1' with 'b/1'\n" }); - assert_eq!(at.read("c/1"), "hello"); +} + +#[test] +fn test_symlink_mode_overwrite() { + let (at, mut ucmd) = at_and_ucmd!(); + at.mkdir("a"); + at.mkdir("b"); + + at.write("a/1", "hello"); + at.write("b/1", "hello"); + + ucmd.arg("-s") + .arg("a/1") + .arg("b/1") + .arg(".") + .fails() + .stderr_only(if cfg!(not(target_os = "windows")) { + "cp: will not overwrite just-created './1' with 'b/1'\n" + } else { + "cp: will not overwrite just-created '.\\1' with 'b/1'\n" + }); + + assert_eq!(at.read("./1"), "hello"); } From 31882f06b71326f3bc7bf12544e7c31b7ebc9fbd Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jul 2024 22:30:29 +0800 Subject: [PATCH 3/4] fix windows test --- tests/by-util/test_cp.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 2f7bc0ddae4..b1b16cd51ea 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -5718,6 +5718,8 @@ fn test_copy_symlink_overwrite() { } else { "cp: will not overwrite just-created 'c\\1' with 'b/1'\n" }); + + assert_eq!(at.read("a/1"), "hello"); } #[test] @@ -5726,19 +5728,19 @@ fn test_symlink_mode_overwrite() { at.mkdir("a"); at.mkdir("b"); - at.write("a/1", "hello"); - at.write("b/1", "hello"); + at.write("a/t", "hello"); + at.write("b/t", "hello"); ucmd.arg("-s") - .arg("a/1") - .arg("b/1") + .arg("a/t") + .arg("b/t") .arg(".") .fails() .stderr_only(if cfg!(not(target_os = "windows")) { - "cp: will not overwrite just-created './1' with 'b/1'\n" + "cp: will not overwrite just-created './t' with 'b/t'\n" } else { - "cp: will not overwrite just-created '.\\1' with 'b/1'\n" + "cp: will not overwrite just-created '.\\t' with 'b/t'\n" }); - assert_eq!(at.read("./1"), "hello"); + assert_eq!(at.read("t"), "hello"); } From 0d9d919d65d03686dda4e3737bad8b3ec61b6ecb Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jul 2024 22:55:46 +0800 Subject: [PATCH 4/4] windows test --- tests/by-util/test_cp.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index b1b16cd51ea..5ba4821df18 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -5718,8 +5718,6 @@ fn test_copy_symlink_overwrite() { } else { "cp: will not overwrite just-created 'c\\1' with 'b/1'\n" }); - - assert_eq!(at.read("a/1"), "hello"); } #[test] @@ -5731,16 +5729,23 @@ fn test_symlink_mode_overwrite() { at.write("a/t", "hello"); at.write("b/t", "hello"); - ucmd.arg("-s") - .arg("a/t") - .arg("b/t") - .arg(".") - .fails() - .stderr_only(if cfg!(not(target_os = "windows")) { - "cp: will not overwrite just-created './t' with 'b/t'\n" - } else { - "cp: will not overwrite just-created '.\\t' with 'b/t'\n" - }); + if cfg!(not(target_os = "windows")) { + ucmd.arg("-s") + .arg("a/t") + .arg("b/t") + .arg(".") + .fails() + .stderr_only("cp: will not overwrite just-created './t' with 'b/t'\n"); - assert_eq!(at.read("t"), "hello"); + assert_eq!(at.read("./t"), "hello"); + } else { + ucmd.arg("-s") + .arg("a\\t") + .arg("b\\t") + .arg(".") + .fails() + .stderr_only("cp: will not overwrite just-created '.\\t' with 'b\\t'\n"); + + assert_eq!(at.read(".\\t"), "hello"); + } }