diff --git a/src/mv/mv.rs b/src/mv/mv.rs index 1b1ee68db..6cda48914 100644 --- a/src/mv/mv.rs +++ b/src/mv/mv.rs @@ -265,6 +265,12 @@ fn exec(files: &[PathBuf], b: Behaviour) -> i32 { } return move_files_into_dir(&[source.clone()], target, &b); + } else if target.exists() && source.is_dir() { + show_error!( + "cannot overwrite non-directory ‘{}’ with directory ‘{}’", + target.display(), source.display() + ); + return 1; } if let Err(e) = rename(source, target, &b) { @@ -360,6 +366,18 @@ fn rename(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<()> { } } + // "to" may no longer exist if it was backed up + if to.exists() && to.is_dir() { + // normalize behavior between *nix and windows + if from.is_dir() { + if is_empty_dir(to) { + try!(fs::remove_dir(to)) + } else { + return Err(std::io::Error::new(std::io::ErrorKind::Other, "Directory not empty")); + } + } + } + try!(fs::rename(from, to)); if b.verbose { @@ -405,3 +423,12 @@ fn existing_backup_path(path: &PathBuf, suffix: &str) -> PathBuf { simple_backup_path(path, suffix) } } + +fn is_empty_dir(path: &PathBuf) -> bool { + match fs::read_dir(path) { + Ok(contents) => { + return contents.peekable().peek().is_none(); + }, + Err(_e) => { return false; } + } +} diff --git a/tests/test_mv.rs b/tests/test_mv.rs index 870524b27..1cf56ce0b 100644 --- a/tests/test_mv.rs +++ b/tests/test_mv.rs @@ -368,8 +368,7 @@ fn test_mv_errors() { // $ mv -T -t a b // mv: cannot combine --target-directory (-t) and --no-target-directory (-T) scene.ucmd().arg("-T").arg("-t").arg(dir).arg(file_a).arg(file_b).fails() - .stderr_is("mv: error: cannot combine --target-directory (-t) and --no-target-directory \ - (-T)\n"); + .stderr_is("mv: error: cannot combine --target-directory (-t) and --no-target-directory (-T)\n"); // $ at.touch file && at.mkdir dir // $ mv -T file dir