fs_extra icon indicating copy to clipboard operation
fs_extra copied to clipboard

`dir::copy` does not preserve symlinked directories

Open edmorley opened this issue 3 years ago • 4 comments

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

edmorley avatar Jul 06 '22 13:07 edmorley

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.

vorporeal avatar Sep 30 '22 19:09 vorporeal

Any news on this issue?

Miha-Rozina avatar Jun 08 '23 12:06 Miha-Rozina

Any news on this issue?

driverxdw avatar Dec 13 '23 17:12 driverxdw