1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

cp: force link between two files that exist

Allow `cp` to link files that exist. For example,

    $ touch src dest
    $ cp -f --link src dest

Before this commit, an error was raised.
This commit is contained in:
Jeffrey Finkelstein 2022-12-04 16:37:21 -05:00
parent 122cdc270d
commit 682667fd1d
2 changed files with 36 additions and 0 deletions

View file

@ -1429,6 +1429,9 @@ fn copy_file(
backup_dest(dest, &backup_path)?; backup_dest(dest, &backup_path)?;
fs::remove_file(dest)?; fs::remove_file(dest)?;
} }
if options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
fs::remove_file(dest)?;
}
} }
if options.dereference(source_in_command_line) && source.is_symlink() { if options.dereference(source_in_command_line) && source.is_symlink() {
let resolved = let resolved =
@ -1451,6 +1454,9 @@ fn copy_file(
)?; )?;
} }
CopyMode::SymLink => { CopyMode::SymLink => {
if dest.exists() && options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
fs::remove_file(dest)?;
}
symlink_file(source, dest, context, symlinked_files)?; symlink_file(source, dest, context, symlinked_files)?;
} }
CopyMode::Update => { CopyMode::Update => {

View file

@ -13,6 +13,8 @@ use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
#[cfg(windows)] #[cfg(windows)]
use std::os::windows::fs::symlink_file; use std::os::windows::fs::symlink_file;
#[cfg(not(windows))]
use std::path::Path;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
use filetime::FileTime; use filetime::FileTime;
@ -2389,3 +2391,31 @@ fn test_preserve_hardlink_attributes_in_directory() {
at.metadata("dest/src/link").ino() at.metadata("dest/src/link").ino()
); );
} }
#[test]
#[cfg(not(windows))]
fn test_hard_link_file() {
let (at, mut ucmd) = at_and_ucmd!();
at.touch("src");
at.touch("dest");
ucmd.args(&["-f", "--link", "src", "dest"])
.succeeds()
.no_output();
#[cfg(all(unix, not(target_os = "freebsd")))]
assert_eq!(at.metadata("src").ino(), at.metadata("dest").ino());
}
#[test]
#[cfg(not(windows))]
fn test_symbolic_link_file() {
let (at, mut ucmd) = at_and_ucmd!();
at.touch("src");
at.touch("dest");
ucmd.args(&["-f", "--symbolic-link", "src", "dest"])
.succeeds()
.no_output();
assert_eq!(
std::fs::read_link(at.plus("dest")).unwrap(),
Path::new("src")
);
}