Skip to content

Commit

Permalink
cp: make --b=simple protective of source
Browse files Browse the repository at this point in the history
When `--backup` is supplied, `cp` will take a backup of *destination* before *source* is copied. When `--backup=simple` is supplied, it is possible for the backup path for *destination* to equal the path for *source*, destroying source before the copy is made. This change prevents this by returning an error instead.

This fixes uutils#3629
  • Loading branch information
philgebhardt committed Jun 18, 2022
1 parent fa51f8b commit c49d8e6
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,16 @@ fn handle_existing_dest(source: &Path, dest: &Path, options: &Options) -> CopyRe

let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
if let Some(backup_path) = backup_path {
backup_dest(dest, &backup_path)?;
if paths_refer_to_same_file(source, &backup_path)? {
return Err(format!(
"backing up {} might destroy source; {} not copied",
dest.quote(),
source.quote()
)
.into());
} else {
backup_dest(dest, &backup_path)?;
}
}

match options.overwrite {
Expand Down
21 changes: 21 additions & 0 deletions tests/by-util/test_cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ static TEST_COPY_FROM_FOLDER: &str = "hello_dir_with_file/";
static TEST_COPY_FROM_FOLDER_FILE: &str = "hello_dir_with_file/hello_world.txt";
static TEST_COPY_TO_FOLDER_NEW: &str = "hello_dir_new";
static TEST_COPY_TO_FOLDER_NEW_FILE: &str = "hello_dir_new/hello_world.txt";
static TEST_PROTECT_BACKUP_SRC: &str = "protected.txt.bak";
static TEST_PROTECT_BACKUP_DEST: &str = "protected.txt";
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
static TEST_MOUNT_COPY_FROM_FOLDER: &str = "dir_with_mount";
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
Expand Down Expand Up @@ -558,6 +560,25 @@ fn test_cp_backup_simple() {
);
}

#[test]
fn test_cp_backup_simple_protect_source() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("--backup=simple")
.arg("--suffix")
.arg(".bak")
.arg(TEST_PROTECT_BACKUP_SRC)
.arg(TEST_PROTECT_BACKUP_DEST)
.fails()
.stderr_only(format!(
"cp: backing up '{}' might destroy source; '{}' not copied",
TEST_PROTECT_BACKUP_DEST,
TEST_PROTECT_BACKUP_SRC,
));

assert_eq!(at.read(TEST_PROTECT_BACKUP_SRC), "original text\n");
assert_eq!(at.read(TEST_PROTECT_BACKUP_DEST), "new text\n");
}

#[test]
fn test_cp_backup_never() {
let (at, mut ucmd) = at_and_ucmd!();
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/cp/protected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
new text
1 change: 1 addition & 0 deletions tests/fixtures/cp/protected.txt.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
original text

0 comments on commit c49d8e6

Please sign in to comment.