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

dir::copy does not preserve symlinked directories #61

Open
edmorley opened this issue Jul 6, 2022 · 4 comments
Open

dir::copy does not preserve symlinked directories #61

edmorley opened this issue Jul 6, 2022 · 4 comments

Comments

@edmorley
Copy link
Contributor

edmorley commented Jul 6, 2022

Summary

If one of the file entries being copied by fs_extra::dir::copy happens to be a symlink to a directory, then that symlink is converted to a real directory as part of copying, resulting in (a) duplicate file contents in the destination directory, (b) non-identical contents between source and destination (which defeats the point of copying a directory verbatim).

Note: Symlinks to files are preserved, this is just about symlinks that target directories.

Steps to reproduce

Using fs_extra = "=1.2.0" with rustc 1.63.0-beta.3 on macOS 12.4, run the following:

use fs_extra::dir::CopyOptions;
use std::fs::{self, File};
use std::path::{Path, PathBuf};

fn main() {
    let source_dir = PathBuf::from("source");
    let destination_dir = PathBuf::from("destination");
    if source_dir.exists() {
        fs::remove_dir_all(&source_dir).unwrap();
    }
    if destination_dir.exists() {
        fs::remove_dir_all(&destination_dir).unwrap();
    }

    let subdir = source_dir.join("subdir");
    fs::create_dir_all(&subdir).unwrap();
    File::create(&subdir.join("file.txt")).unwrap();
    create_dir_symlink("subdir", &source_dir.join("symlink-to-subdir")).unwrap();

    let options = &CopyOptions {
        content_only: true,
        ..CopyOptions::default()
    };
    fs_extra::dir::copy(source_dir, destination_dir, options).unwrap();
}

#[cfg(target_family = "unix")]
fn create_dir_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> std::io::Result<()> {
    std::os::unix::fs::symlink(original.as_ref(), link.as_ref())
}

#[cfg(target_family = "windows")]
fn create_dir_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> std::io::Result<()> {
    std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref())
}

Expected

The contents of source/ and destination/ to be identical, and for any symlinks targetting directories to be preserved as symlinks.

Actual

The source/ and destination/ directories have different contents, with the symlinked directory now being a real directory containing duplicate files.

Source:

$ ls -alR source/
source/:
total 0
drwxr-xr-x  4 emorley staff 128 Jul  6 14:03 .
drwxr-xr-x 10 emorley staff 320 Jul  6 14:03 ..
drwxr-xr-x  3 emorley staff  96 Jul  6 14:03 subdir
lrwxr-xr-x  1 emorley staff   6 Jul  6 14:03 symlink-to-subdir -> subdir

source/subdir:
total 0
drwxr-xr-x 3 emorley staff  96 Jul  6 14:03 .
drwxr-xr-x 4 emorley staff 128 Jul  6 14:03 ..
-rw-r--r-- 1 emorley staff   0 Jul  6 14:03 file.txt

Destination:

$ ls -alR destination/
destination/:
total 0
drwxr-xr-x  4 emorley staff 128 Jul  6 14:03 .
drwxr-xr-x 10 emorley staff 320 Jul  6 14:03 ..
drwxr-xr-x  3 emorley staff  96 Jul  6 14:03 subdir
drwxr-xr-x  3 emorley staff  96 Jul  6 14:03 symlink-to-subdir

destination/subdir:
total 0
drwxr-xr-x 3 emorley staff  96 Jul  6 14:03 .
drwxr-xr-x 4 emorley staff 128 Jul  6 14:03 ..
-rw-r--r-- 1 emorley staff   0 Jul  6 14:03 file.txt

destination/symlink-to-subdir:
total 0
drwxr-xr-x 3 emorley staff  96 Jul  6 14:03 .
drwxr-xr-x 4 emorley staff 128 Jul  6 14:03 ..
-rw-r--r-- 1 emorley staff   0 Jul  6 14:03 file.txt
@vorporeal
Copy link

Any sense of whether or not this will get addressed? We're using dir::copy to copy the contents of a MacOS application bundle, which contains directory symlinks and requires symlink preservation for codesigning.

@Miha-Rozina
Copy link

Any news on this issue?

1 similar comment
@driverxdw
Copy link

Any news on this issue?

@kanpov
Copy link

kanpov commented Oct 3, 2024

For anyone looking for a workaround, the only one I found is just to fork the cp/mv coreutil

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

No branches or pull requests

5 participants