Skip to content

Commit

Permalink
cp: with -i, delete destination if needed
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewliebenow committed Sep 15, 2024
1 parent e2a8e86 commit 5414039
Showing 1 changed file with 40 additions and 36 deletions.
76 changes: 40 additions & 36 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1729,44 +1729,48 @@ fn handle_existing_dest(
}
if !is_dest_removed {
match options.overwrite {
// FIXME: print that the file was removed if --verbose is enabled
OverwriteMode::Clobber(ClobberMode::Force) => {
if is_symlink_loop(dest) || fs::metadata(dest)?.permissions().readonly() {
fs::remove_file(dest)?;
}
}
OverwriteMode::Clobber(ClobberMode::RemoveDestination) => {
fs::remove_file(dest)?;
}
OverwriteMode::Clobber(ClobberMode::Standard) => {
// Consider the following files:
//
// * `src/f` - a regular file
// * `src/link` - a hard link to `src/f`
// * `dest/src/f` - a different regular file
//
// In this scenario, if we do `cp -a src/ dest/`, it is
// possible that the order of traversal causes `src/link`
// to get copied first (to `dest/src/link`). In that case,
// in order to make sure `dest/src/link` is a hard link to
// `dest/src/f` and `dest/src/f` has the contents of
// `src/f`, we delete the existing file to allow the hard
// linking.

if options.preserve_hard_links()
// only try to remove dest file only if the current source
// is hardlink to a file that is already copied
&& copied_files.contains_key(
&FileInformation::from_path(
source,
options.dereference(source_in_command_line),
)
.context(format!("cannot stat {}", source.quote()))?,
) {
fs::remove_file(dest)?;
OverwriteMode::Clobber(cl) | OverwriteMode::Interactive(cl) => {
match cl {
// FIXME: print that the file was removed if --verbose is enabled
ClobberMode::Force => {
if is_symlink_loop(dest) || fs::metadata(dest)?.permissions().readonly() {
fs::remove_file(dest)?;
}
}
ClobberMode::RemoveDestination => {
fs::remove_file(dest)?;
}
ClobberMode::Standard => {
// Consider the following files:
//
// * `src/f` - a regular file
// * `src/link` - a hard link to `src/f`
// * `dest/src/f` - a different regular file
//
// In this scenario, if we do `cp -a src/ dest/`, it is
// possible that the order of traversal causes `src/link`
// to get copied first (to `dest/src/link`). In that case,
// in order to make sure `dest/src/link` is a hard link to
// `dest/src/f` and `dest/src/f` has the contents of
// `src/f`, we delete the existing file to allow the hard
// linking.

if options.preserve_hard_links() &&
// only try to remove dest file only if the current source
// is hardlink to a file that is already copied
copied_files.contains_key(
&FileInformation::from_path(
source,
options.dereference(source_in_command_line)
).context(format!("cannot stat {}", source.quote()))?
)
{
fs::remove_file(dest)?;
}
}
}
}
_ => (),
OverwriteMode::NoClobber => {}
};
}

Expand Down

0 comments on commit 5414039

Please sign in to comment.