Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ln: symlink --force, src and dst are same file #3724

Merged
merged 2 commits into from
Jul 18, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
ln: error on --force when src=dst and dst is regular file
niyaznigmatullin committed Jul 18, 2022
commit 4db08273b3815cde9b011023b84400f6a9a7d82f
13 changes: 1 addition & 12 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
@@ -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)?;
13 changes: 5 additions & 8 deletions src/uu/ln/src/ln.rs
Original file line number Diff line number Diff line change
@@ -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
}
11 changes: 11 additions & 0 deletions src/uucore/src/lib/features/fs.rs
Original file line number Diff line number Diff line change
@@ -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.