Skip to content

Commit 9ff8273

Browse files
authored
Merge pull request #8589 from yuankunzhang/mv-to-symlink-directory
mv: support moving source to a symlink directory
2 parents 2e083a8 + 62ae994 commit 9ff8273

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

src/uu/mv/src/mv.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,12 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
374374
});
375375
}
376376

377-
let target_is_dir = target.is_dir() && !target.is_symlink();
378377
let source_is_dir = source.is_dir() && !source.is_symlink();
378+
let target_is_dir = if target.is_symlink() {
379+
fs::canonicalize(target).is_ok_and(|p| p.is_dir())
380+
} else {
381+
target.is_dir()
382+
};
379383

380384
if path_ends_with_terminator(target)
381385
&& (!target_is_dir && !source_is_dir)

tests/by-util/test_mv.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -429,12 +429,11 @@ fn test_mv_replace_symlink_with_symlink() {
429429
fn test_mv_replace_symlink_with_directory() {
430430
let (at, mut ucmd) = at_and_ucmd!();
431431

432-
at.mkdir("a");
432+
at.touch("a");
433433
at.mkdir("b");
434-
at.touch("a/empty_file_a");
435434
at.touch("b/empty_file_b");
436435

437-
at.symlink_dir("a", "symlink");
436+
at.symlink_file("a", "symlink");
438437

439438
ucmd.arg("-T")
440439
.arg("b")
@@ -449,25 +448,44 @@ fn test_mv_replace_symlink_with_directory() {
449448
fn test_mv_replace_symlink_with_file() {
450449
let (at, mut ucmd) = at_and_ucmd!();
451450

452-
at.mkdir("a");
453-
at.touch("a/empty_file_a");
454-
at.touch("empty_file_b");
455-
456-
at.symlink_dir("a", "symlink");
451+
at.touch("a");
452+
at.touch("b");
457453

458-
assert!(at.file_exists("symlink/empty_file_a"));
454+
at.symlink_file("a", "symlink");
459455

460456
ucmd.arg("-T")
461-
.arg("empty_file_b")
457+
.arg("b")
462458
.arg("symlink")
463459
.succeeds()
464460
.no_stderr();
465461

466462
assert!(at.file_exists("symlink"));
467463
assert!(!at.is_symlink("symlink"));
468-
assert!(!at.file_exists("empty_file_b"));
464+
assert!(!at.file_exists("b"));
465+
assert!(at.file_exists("a"));
466+
}
467+
468+
#[test]
469+
#[cfg(all(unix, not(target_os = "android")))]
470+
fn test_mv_file_to_symlink_directory() {
471+
let (at, mut ucmd) = at_and_ucmd!();
472+
473+
at.mkdir("a");
474+
at.touch("a/empty_file_a");
475+
at.touch("b");
476+
477+
at.symlink_dir("a", "symlink");
478+
479+
assert!(at.file_exists("symlink/empty_file_a"));
480+
481+
ucmd.arg("b").arg("symlink").succeeds().no_stderr();
482+
483+
assert!(at.dir_exists("symlink"));
484+
assert!(at.is_symlink("symlink"));
485+
assert!(at.file_exists("symlink/b"));
486+
assert!(!at.file_exists("b"));
469487
assert!(at.dir_exists("a"));
470-
assert!(at.file_exists("a/empty_file_a"));
488+
assert!(at.file_exists("a/b"));
471489
}
472490

473491
#[test]

0 commit comments

Comments
 (0)