Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data loss when moving directory on Windows #64

Open
rgwood opened this issue Sep 19, 2022 · 4 comments
Open

Data loss when moving directory on Windows #64

rgwood opened this issue Sep 19, 2022 · 4 comments
Assignees
Labels

Comments

@rgwood
Copy link

rgwood commented Sep 19, 2022

Hi, we use fs_extra in Nushell; thanks for writing it!

We recently had a scary bug report, and it looks like the root cause is fs_extra::dir::move_dir(). If you use move_dir() to change the case of a directory name on Windows (ex: "Test" -> "test"), the directory is deleted and fs_extra reports success.

For example:

// This deletes the directory named Test and does not panic!
fs_extra::dir::move_dir("Test", "test", &options).unwrap();

Steps to Reproduce

I've put together a minimal repro: https://github.com/rgwood/fs-extra-repro

Version Info

fs-extra v1.2.0
Windows 11 (can't reproduce on Linux)
rustc v1.63.0

@webdesus
Copy link
Owner

Hi @rgwood!
Thank you for the detail report. Sound awful. I will fix it on this week.

@webdesus webdesus added the bug label Sep 20, 2022
@webdesus webdesus self-assigned this Sep 20, 2022
@webdesus
Copy link
Owner

I tried to come up with a fast crutch, but I see you already fixed this moment in your app. In the near future, I will try to fix this the same way. 😃

@pczarn
Copy link

pczarn commented Sep 27, 2022

This also happens when source equals target when moving or copying.
Test case:

#[test]
fn it_move_work_same_path() {
    let test_dir = Path::new(TEST_FOLDER).join("it_move_work_same_path");
    let path_to = test_dir.join("dir1");
    let dir1 = (test_dir.join("dir1"), path_to.clone());
    let dir2 = (test_dir.join("dir2"), path_to.join("dir2"));
    let sub = (dir1.0.join("sub"), dir1.1.join("sub"));
    let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt"));
    let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt"));
    let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt"));
    let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt"));
    let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt"));

    match dir::create_all(&path_to, true) {
        Ok(_) => {}
        Err(_) => {}
    };
    dir::create_all(&dir1.0, true).unwrap();
    dir::create_all(&dir2.0, true).unwrap();
    dir::create_all(&sub.0, true).unwrap();

    assert!(dir1.0.exists());
    assert!(dir1.1.exists());
    assert!(dir2.0.exists());
    assert!(!dir2.1.exists());
    assert!(sub.0.exists());
    assert!(sub.1.exists());

    file::write_all(&file1.0, "content1").unwrap();
    file::write_all(&file2.0, "content2").unwrap();
    file::write_all(&file3.0, "content3").unwrap();
    file::write_all(&file4.0, "content4").unwrap();
    file::write_all(&file5.0, "content5").unwrap();

    assert!(file1.0.exists());
    assert!(file2.0.exists());
    assert!(file3.0.exists());
    assert!(file4.0.exists());
    assert!(file5.0.exists());
    assert!(!file1.1.exists());
    assert!(!file2.1.exists());
    assert!(file3.1.exists());
    assert!(file4.1.exists());
    assert!(!file5.1.exists());

    let options = dir::CopyOptions::new();
    let result = dir::move_dir(dir1.0, path_to, &options).unwrap();

    assert_eq!(16, result);
    assert!(dir1.1.exists()); // <-- panics
    assert!(file3.1.exists()); // <-- panics
    assert!(file4.1.exists()); // <-- panics
}

@pczarn
Copy link

pczarn commented Sep 27, 2022

For comparison, the behavior of cp and mv:

$ LANG=C mv out/ .
mv: 'out/' and './out' are the same file
$ LANG=C mv out/ out/
mv: cannot move 'out/' to a subdirectory of itself, 'out/out'
$ LANG=C cp -r out/ .
cp: 'out/' and './out' are the same file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants