Skip to content

Commit ade9118

Browse files
committed
Fix install: invalid link at destination
also remove some FixMEs for FreeBsd
1 parent b3fd711 commit ade9118

File tree

3 files changed

+82
-10
lines changed

3 files changed

+82
-10
lines changed

src/uu/install/src/install.rs

+14
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,20 @@ fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
748748
/// Returns an empty Result or an error in case of failure.
749749
///
750750
fn copy_file(from: &Path, to: &Path) -> UResult<()> {
751+
// fs::copy fails if destination is a invalid symlink.
752+
// so lets just remove all existing files at destination before copy.
753+
match fs::remove_file(to) {
754+
Ok(()) => {}
755+
Err(e) if e.kind() == std::io::ErrorKind::NotFound => { /* expected */ }
756+
Err(e) => {
757+
show_error!(
758+
"Failed to remove existing file {}. Error: {:?}",
759+
to.display(),
760+
e
761+
);
762+
}
763+
}
764+
751765
if from.as_os_str() == "/dev/null" {
752766
/* workaround a limitation of fs::copy
753767
* https://github.com/rust-lang/rust/issues/79390

tests/by-util/test_install.rs

+68-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::common::util::{is_ci, run_ucmd_as_root, TestScenario};
88
use filetime::FileTime;
99
use std::fs;
1010
use std::os::unix::fs::{MetadataExt, PermissionsExt};
11-
#[cfg(not(any(windows, target_os = "freebsd")))]
11+
#[cfg(not(windows))]
1212
use std::process::Command;
1313
#[cfg(any(target_os = "linux", target_os = "android"))]
1414
use std::thread::sleep;
@@ -610,13 +610,17 @@ fn test_install_copy_then_compare_file_with_extra_mode() {
610610
}
611611

612612
const STRIP_TARGET_FILE: &str = "helloworld_installed";
613-
#[cfg(not(any(windows, target_os = "freebsd")))]
613+
#[cfg(all(not(windows), not(target_os = "freebsd")))]
614614
const SYMBOL_DUMP_PROGRAM: &str = "objdump";
615-
#[cfg(not(any(windows, target_os = "freebsd")))]
615+
#[cfg(target_os = "freebsd")]
616+
const SYMBOL_DUMP_PROGRAM: &str = "llvm-objdump";
617+
#[cfg(not(windows))]
616618
const STRIP_SOURCE_FILE_SYMBOL: &str = "main";
617619

618620
fn strip_source_file() -> &'static str {
619-
if cfg!(target_os = "macos") {
621+
if cfg!(target_os = "freebsd") {
622+
"helloworld_freebsd"
623+
} else if cfg!(target_os = "macos") {
620624
"helloworld_macos"
621625
} else if cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64") {
622626
"helloworld_android"
@@ -626,8 +630,7 @@ fn strip_source_file() -> &'static str {
626630
}
627631

628632
#[test]
629-
// FixME: Freebsd fails on 'No such file or directory'
630-
#[cfg(not(any(windows, target_os = "freebsd")))]
633+
#[cfg(not(windows))]
631634
fn test_install_and_strip() {
632635
let scene = TestScenario::new(util_name!());
633636
let at = &scene.fixtures;
@@ -650,8 +653,7 @@ fn test_install_and_strip() {
650653
}
651654

652655
#[test]
653-
// FixME: Freebsd fails on 'No such file or directory'
654-
#[cfg(not(any(windows, target_os = "freebsd")))]
656+
#[cfg(not(windows))]
655657
fn test_install_and_strip_with_program() {
656658
let scene = TestScenario::new(util_name!());
657659
let at = &scene.fixtures;
@@ -677,8 +679,6 @@ fn test_install_and_strip_with_program() {
677679

678680
#[cfg(all(unix, feature = "chmod"))]
679681
#[test]
680-
// FixME: Freebsd fails on 'No such file or directory'
681-
#[cfg(not(target_os = "freebsd"))]
682682
fn test_install_and_strip_with_program_hyphen() {
683683
let scene = TestScenario::new(util_name!());
684684

@@ -715,6 +715,64 @@ fn test_install_and_strip_with_program_hyphen() {
715715
.stdout_is("./-dest\n");
716716
}
717717

718+
#[cfg(all(unix, feature = "chmod"))]
719+
#[test]
720+
fn test_install_on_invalid_link_at_destination() {
721+
let scene = TestScenario::new(util_name!());
722+
723+
let at = &scene.fixtures;
724+
at.mkdir("src");
725+
at.mkdir("dest");
726+
let src_dir = at.plus("src");
727+
let dst_dir = at.plus("dest");
728+
729+
at.touch("test.sh");
730+
at.symlink_file(
731+
"/opt/FakeDestination",
732+
&dst_dir.join("test.sh").to_string_lossy(),
733+
);
734+
scene.ccmd("chmod").arg("+x").arg("test.sh").succeeds();
735+
at.symlink_file("test.sh", &src_dir.join("test.sh").to_string_lossy());
736+
737+
scene
738+
.ucmd()
739+
.current_dir(&src_dir)
740+
.arg(src_dir.join("test.sh"))
741+
.arg(dst_dir.join("test.sh"))
742+
.succeeds()
743+
.no_stderr()
744+
.no_stdout();
745+
}
746+
747+
#[cfg(all(unix, feature = "chmod"))]
748+
#[test]
749+
fn test_install_on_invalid_link_at_destination_and_dev_null_at_source() {
750+
let scene = TestScenario::new(util_name!());
751+
752+
let at = &scene.fixtures;
753+
at.mkdir("src");
754+
at.mkdir("dest");
755+
let src_dir = at.plus("src");
756+
let dst_dir = at.plus("dest");
757+
758+
at.touch("test.sh");
759+
at.symlink_file(
760+
"/opt/FakeDestination",
761+
&dst_dir.join("test.sh").to_string_lossy(),
762+
);
763+
scene.ccmd("chmod").arg("+x").arg("test.sh").succeeds();
764+
at.symlink_file("test.sh", &src_dir.join("test.sh").to_string_lossy());
765+
766+
scene
767+
.ucmd()
768+
.current_dir(&src_dir)
769+
.arg("/dev/null")
770+
.arg(dst_dir.join("test.sh"))
771+
.succeeds()
772+
.no_stderr()
773+
.no_stdout();
774+
}
775+
718776
#[test]
719777
#[cfg(not(windows))]
720778
fn test_install_and_strip_with_invalid_program() {
307 KB
Binary file not shown.

0 commit comments

Comments
 (0)