1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

mv: moving directory itself should fail (#5429)

* mv: moving directory itself should fail

* mv: Check trailing slash also fails on target containing itself

* mv: add "spell-checker:ignore mydir" to test

---------

Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
This commit is contained in:
David Matos 2023-10-24 10:54:23 +02:00 committed by GitHub
parent b9c54f8b5f
commit 769eb29cd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 0 deletions

View file

@ -12,6 +12,7 @@ pub enum MvError {
NoSuchFile(String), NoSuchFile(String),
SameFile(String, String), SameFile(String, String),
SelfSubdirectory(String), SelfSubdirectory(String),
SelfTargetSubdirectory(String, String),
DirectoryToNonDirectory(String), DirectoryToNonDirectory(String),
NonDirectoryToDirectory(String, String), NonDirectoryToDirectory(String, String),
NotADirectory(String), NotADirectory(String),
@ -29,6 +30,10 @@ impl Display for MvError {
f, f,
"cannot move '{s}' to a subdirectory of itself, '{s}/{s}'" "cannot move '{s}' to a subdirectory of itself, '{s}/{s}'"
), ),
Self::SelfTargetSubdirectory(s, t) => write!(
f,
"cannot move '{s}' to a subdirectory of itself, '{t}/{s}'"
),
Self::DirectoryToNonDirectory(t) => { Self::DirectoryToNonDirectory(t) => {
write!(f, "cannot overwrite directory {t} with non-directory") write!(f, "cannot overwrite directory {t} with non-directory")
} }

View file

@ -326,6 +326,28 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into()) Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into())
} }
} else { } else {
// Check that source & target do not contain same subdir/dir when both exist
// mkdir dir1/dir2; mv dir1 dir1/dir2
let target_contains_itself = target
.as_os_str()
.to_str()
.ok_or("not a valid unicode string")
.and_then(|t| {
source
.as_os_str()
.to_str()
.ok_or("not a valid unicode string")
.map(|s| t.contains(s))
})
.unwrap();
if target_contains_itself {
return Err(MvError::SelfTargetSubdirectory(
source.display().to_string(),
target.display().to_string(),
)
.into());
}
move_files_into_dir(&[source.to_path_buf()], target, opts) move_files_into_dir(&[source.to_path_buf()], target, opts)
} }
} else if target.exists() && source.is_dir() { } else if target.exists() && source.is_dir() {

View file

@ -2,6 +2,8 @@
// //
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
//
// spell-checker:ignore mydir
use crate::common::util::TestScenario; use crate::common::util::TestScenario;
use filetime::FileTime; use filetime::FileTime;
use std::thread::sleep; use std::thread::sleep;
@ -1389,6 +1391,29 @@ fn test_mv_into_self_data() {
assert!(at.file_exists(file2)); assert!(at.file_exists(file2));
assert!(!at.file_exists(file1)); assert!(!at.file_exists(file1));
} }
#[test]
fn test_mv_directory_into_subdirectory_of_itself_fails() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let dir1 = "mydir";
let dir2 = "mydir/mydir_2";
at.mkdir(dir1);
at.mkdir(dir2);
scene.ucmd().arg(dir1).arg(dir2).fails().stderr_contains(
"mv: cannot move 'mydir' to a subdirectory of itself, 'mydir/mydir_2/mydir'",
);
// check that it also errors out with /
scene
.ucmd()
.arg(format!("{}/", dir1))
.arg(dir2)
.fails()
.stderr_contains(
"mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/mydir_2/mydir/'",
);
}
// Todo: // Todo:
// $ at.touch a b // $ at.touch a b