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)?;
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() {
let resolved =
@ -1451,6 +1454,9 @@ fn copy_file(
)?;
}
CopyMode::SymLink => {
if dest.exists() && options.overwrite == OverwriteMode::Clobber(ClobberMode::Force) {
fs::remove_file(dest)?;
}
symlink_file(source, dest, context, symlinked_files)?;
}
CopyMode::Update => {

View file

@ -13,6 +13,8 @@ use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::PermissionsExt;
#[cfg(windows)]
use std::os::windows::fs::symlink_file;
#[cfg(not(windows))]
use std::path::Path;
#[cfg(any(target_os = "linux", target_os = "android"))]
use filetime::FileTime;
@ -2389,3 +2391,31 @@ fn test_preserve_hardlink_attributes_in_directory() {
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")
);
}