Skip to content

Commit

Permalink
remove symlinks at target to avoid issue with invalid symlinks at target
Browse files Browse the repository at this point in the history
  • Loading branch information
cre4ture committed Jan 17, 2024
1 parent 55b7b2f commit 5d5b430
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
23 changes: 20 additions & 3 deletions src/uu/install/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ use file_diff::diff;
use filetime::{set_file_times, FileTime};
use std::error::Error;
use std::fmt::{Debug, Display};
use std::fs;
use std::fs::File;
use std::os::unix::fs::MetadataExt;
#[cfg(unix)]
use std::os::unix::prelude::OsStrExt;
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process;
use std::{fs, io};
use uucore::backup_control::{self, BackupMode};
use uucore::display::Quotable;
use uucore::entries::{grp2gid, usr2uid};
Expand Down Expand Up @@ -736,6 +736,18 @@ fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
}
}

fn copy_file_source_not_dev_null(from: &Path, to: &Path) -> io::Result<()> {
let dest_meta_res = fs::symlink_metadata(to);
if let Ok(dest_meta) = dest_meta_res {
if dest_meta.is_symlink() {
// fs::copy fails if destination is a invalid symlink
// so lets just remove all symlinks at destination before copy
fs::remove_file(to)?;
}
}
fs::copy(from, to).map(|_| ())
}

/// Copy a file from one path to another.
///
/// # Parameters
Expand All @@ -757,8 +769,13 @@ fn copy_file(from: &Path, to: &Path) -> UResult<()> {
InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),
);
}
} else if let Err(err) = fs::copy(from, to) {
return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
} else {
let result = copy_file_source_not_dev_null(from, to);
if let Err(err) = result {
return Err(
InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),

Check warning on line 776 in src/uu/install/src/install.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/install/src/install.rs#L775-L776

Added lines #L775 - L776 were not covered by tests
);
}
}
Ok(())
}
Expand Down
31 changes: 31 additions & 0 deletions tests/by-util/test_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,37 @@ fn test_install_and_strip_with_program_hyphen() {
.no_stderr();
}

#[cfg(all(unix, feature = "chmod"))]
#[test]
// FixME: Freebsd fails on 'No such file or directory'
#[cfg(not(target_os = "freebsd"))]
fn test_install_on_invalid_link_at_destination() {
let scene = TestScenario::new(util_name!());

let at = &scene.fixtures;
at.mkdir("src");
at.mkdir("dest");
let src_dir = at.plus("src");
let dst_dir = at.plus("dest");

at.touch("test.sh");
at.symlink_file(
"/opt/FakeDestination",
&dst_dir.join("test.sh").to_string_lossy(),
);
scene.ccmd("chmod").arg("+x").arg("test.sh").succeeds();
at.symlink_file("test.sh", &src_dir.join("test.sh").to_string_lossy());

scene
.ucmd()
.current_dir(&src_dir)
.arg(src_dir.join("test.sh"))
.arg(dst_dir.join("test.sh"))
.succeeds()
.no_stderr()
.no_stdout();
}

#[test]
#[cfg(not(windows))]
fn test_install_and_strip_with_invalid_program() {
Expand Down

0 comments on commit 5d5b430

Please sign in to comment.