mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
mv: manages the 'seen' file list before moving
Should help with tests/mv/childproof.sh
This commit is contained in:
parent
06c98fbdd3
commit
3af8ad0fe6
2 changed files with 43 additions and 0 deletions
|
@ -10,6 +10,7 @@ mod error;
|
||||||
use clap::builder::ValueParser;
|
use clap::builder::ValueParser;
|
||||||
use clap::{crate_version, error::ErrorKind, Arg, ArgAction, ArgMatches, Command};
|
use clap::{crate_version, error::ErrorKind, Arg, ArgAction, ArgMatches, Command};
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -434,6 +435,9 @@ pub fn mv(files: &[OsString], opts: &Options) -> UResult<()> {
|
||||||
|
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, opts: &Options) -> UResult<()> {
|
fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, opts: &Options) -> UResult<()> {
|
||||||
|
// remember the moved destinations for further usage
|
||||||
|
let mut moved_destinations: HashSet<PathBuf> = HashSet::with_capacity(files.len());
|
||||||
|
|
||||||
if !target_dir.is_dir() {
|
if !target_dir.is_dir() {
|
||||||
return Err(MvError::NotADirectory(target_dir.quote().to_string()).into());
|
return Err(MvError::NotADirectory(target_dir.quote().to_string()).into());
|
||||||
}
|
}
|
||||||
|
@ -471,6 +475,18 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, opts: &Options) ->
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if moved_destinations.contains(&targetpath) && opts.backup != BackupMode::NumberedBackup {
|
||||||
|
// If the target file was already created in this mv call, do not overwrite
|
||||||
|
return Err(USimpleError::new(
|
||||||
|
1,
|
||||||
|
format!(
|
||||||
|
"will not overwrite just-created '{}' with '{}'",
|
||||||
|
targetpath.display(),
|
||||||
|
sourcepath.display()
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have mv dir1 dir2 dir2
|
// Check if we have mv dir1 dir2 dir2
|
||||||
// And generate an error if this is the case
|
// And generate an error if this is the case
|
||||||
if let Ok(canonicalized_source) = sourcepath.canonicalize() {
|
if let Ok(canonicalized_source) = sourcepath.canonicalize() {
|
||||||
|
@ -513,6 +529,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, opts: &Options) ->
|
||||||
if let Some(ref pb) = count_progress {
|
if let Some(ref pb) = count_progress {
|
||||||
pb.inc(1);
|
pb.inc(1);
|
||||||
}
|
}
|
||||||
|
moved_destinations.insert(targetpath.clone());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1469,6 +1469,32 @@ fn test_mv_file_into_dir_where_both_are_files() {
|
||||||
.stderr_contains("mv: failed to access 'b/': Not a directory");
|
.stderr_contains("mv: failed to access 'b/': Not a directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mv_seen_file() {
|
||||||
|
let ts = TestScenario::new(util_name!());
|
||||||
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
|
at.mkdir("a");
|
||||||
|
at.mkdir("b");
|
||||||
|
at.mkdir("c");
|
||||||
|
at.write("a/f", "a");
|
||||||
|
at.write("b/f", "b");
|
||||||
|
|
||||||
|
ts.ucmd()
|
||||||
|
.arg("a/f")
|
||||||
|
.arg("b/f")
|
||||||
|
.arg("c")
|
||||||
|
.fails()
|
||||||
|
.stderr_contains("will not overwrite just-created 'c/f' with 'b/f'");
|
||||||
|
|
||||||
|
// a/f has been moved into c/f
|
||||||
|
assert!(at.plus("c").join("f").exists());
|
||||||
|
// b/f still exists
|
||||||
|
assert!(at.plus("b").join("f").exists());
|
||||||
|
// a/f no longer exists
|
||||||
|
assert!(!at.plus("a").join("f").exists());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mv_dir_into_file_where_both_are_files() {
|
fn test_mv_dir_into_file_where_both_are_files() {
|
||||||
let scene = TestScenario::new(util_name!());
|
let scene = TestScenario::new(util_name!());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue