ln: error on --force when src=dst and dst is regular file

This commit is contained in:
Niyaz Nigmatullin 2022-07-18 00:21:16 +03:00
parent ef6182d209
commit 4db08273b3
3 changed files with 17 additions and 20 deletions

View file

@ -18,7 +18,7 @@ extern crate uucore;
use uucore::display::Quotable;
use uucore::format_usage;
use uucore::fs::FileInformation;
use uucore::fs::{paths_refer_to_same_file, FileInformation};
use std::borrow::Cow;
@ -1657,17 +1657,6 @@ pub fn localize_to_target(root: &Path, source: &Path, target: &Path) -> CopyResu
Ok(target.join(&local_to_root))
}
pub fn paths_refer_to_same_file(p1: &Path, p2: &Path, dereference: bool) -> bool {
// We have to take symlinks and relative paths into account.
let res1 = FileInformation::from_path(p1, dereference);
let res2 = FileInformation::from_path(p2, dereference);
match (res1, res2) {
(Ok(info1), Ok(info2)) => info1 == info2,
_ => false,
}
}
pub fn path_has_prefix(p1: &Path, p2: &Path) -> io::Result<bool> {
let pathbuf1 = canonicalize(p1, MissingHandling::Normal, ResolveMode::Logical)?;
let pathbuf2 = canonicalize(p2, MissingHandling::Normal, ResolveMode::Logical)?;

View file

@ -14,7 +14,7 @@ use clap::{crate_version, Arg, Command};
use uucore::display::Quotable;
use uucore::error::{UError, UResult};
use uucore::format_usage;
use uucore::fs::is_symlink;
use uucore::fs::{is_symlink, paths_refer_to_same_file};
use std::borrow::Cow;
use std::error::Error;
@ -435,13 +435,7 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> {
};
if settings.backup == BackupMode::ExistingBackup && !settings.symbolic {
// when ln --backup f f, it should detect that it is the same file
let dst_abs = canonicalize(dst, MissingHandling::Normal, ResolveMode::Logical)?;
let source_abs = canonicalize(
source.clone(),
MissingHandling::Normal,
ResolveMode::Logical,
)?;
if dst_abs == source_abs {
if paths_refer_to_same_file(src, dst, true) {
return Err(LnError::SameFile().into());
}
}
@ -460,6 +454,9 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> {
// In case of error, don't do anything
}
OverwriteMode::Force => {
if !is_symlink(dst) && paths_refer_to_same_file(src, dst, true) {
return Err(LnError::SameFile().into());
}
if fs::remove_file(dst).is_ok() {};
// In case of error, don't do anything
}

View file

@ -477,6 +477,17 @@ pub fn dir_strip_dot_for_creation(path: &Path) -> PathBuf {
}
}
/// Checks if `p1` and `p2` are the same file.
/// If error happens when trying to get files' metadata, returns false
pub fn paths_refer_to_same_file<P: AsRef<Path>>(p1: P, p2: P, dereference: bool) -> bool {
if let Ok(info1) = FileInformation::from_path(p1, dereference) {
if let Ok(info2) = FileInformation::from_path(p2, dereference) {
return info1 == info2;
}
}
false
}
#[cfg(test)]
mod tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.