Skip to content

Commit

Permalink
mv: moving directory itself should fail (uutils#5429)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
dmatos2012 and cakebaker authored Oct 24, 2023
1 parent b9c54f8 commit 769eb29
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/uu/mv/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum MvError {
NoSuchFile(String),
SameFile(String, String),
SelfSubdirectory(String),
SelfTargetSubdirectory(String, String),
DirectoryToNonDirectory(String),
NonDirectoryToDirectory(String, String),
NotADirectory(String),
Expand All @@ -29,6 +30,10 @@ impl Display for MvError {
f,
"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) => {
write!(f, "cannot overwrite directory {t} with non-directory")
}
Expand Down
22 changes: 22 additions & 0 deletions src/uu/mv/src/mv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,28 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into())
}
} 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)
}
} else if target.exists() && source.is_dir() {
Expand Down
25 changes: 25 additions & 0 deletions tests/by-util/test_mv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//
// spell-checker:ignore mydir
use crate::common::util::TestScenario;
use filetime::FileTime;
use std::thread::sleep;
Expand Down Expand Up @@ -1389,6 +1391,29 @@ fn test_mv_into_self_data() {
assert!(at.file_exists(file2));
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:

// $ at.touch a b
Expand Down

0 comments on commit 769eb29

Please sign in to comment.