`dir::copy` does not preserve symlinked directories
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
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.
Any news on this issue?
Any news on this issue?