diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index 8c4a8d808..11220cf85 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -101,6 +101,9 @@ enum InstallError { #[error("cannot overwrite directory {} with non-directory {}", .0.quote(), .1.quote())] OverrideDirectoryFailed(PathBuf, PathBuf), + + #[error("'{0}' and '{1}' are the same file")] + SameFile(PathBuf, PathBuf), } impl UError for InstallError { @@ -751,6 +754,12 @@ fn copy_normal_file(from: &Path, to: &Path) -> UResult<()> { /// Returns an empty Result or an error in case of failure. /// fn copy_file(from: &Path, to: &Path) -> UResult<()> { + if let Ok(to_abs) = to.canonicalize() { + if from.canonicalize()? == to_abs { + return Err(InstallError::SameFile(from.to_path_buf(), to.to_path_buf()).into()); + } + } + if to.is_dir() && !from.is_dir() { return Err(InstallError::OverrideDirectoryFailed( to.to_path_buf().clone(), diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index 1270460d8..57ac74aff 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -1778,3 +1778,33 @@ fn test_install_failing_copy_file_to_target_contain_subdir_with_same_name() { .fails() .stderr_contains("cannot overwrite directory"); } + +#[test] +fn test_install_same_file() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "file"; + + at.touch(file); + ucmd.arg(file) + .arg(".") + .fails() + .stderr_contains("'file' and './file' are the same file"); +} + +#[test] +fn test_install_symlink_same_file() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "file"; + let target_dir = "target_dir"; + let target_link = "target_link"; + + at.mkdir(target_dir); + at.touch(format!("{target_dir}/{file}")); + at.symlink_file(target_dir, target_link); + ucmd.arg(format!("{target_dir}/{file}")) + .arg(target_link) + .fails() + .stderr_contains(format!( + "'{target_dir}/{file}' and '{target_link}/{file}' are the same file" + )); +}