use super::*;
pub fn vcopy_impl_default<F: VectorBackend + ?Sized>(
backend: &mut F,
pairs: &[ExtentPair],
options: CopyOptions,
) -> VfRes {
if pairs.is_empty() {
return Ok(());
}
if !options.follow_source_symlinks() {
return Err(VfError::unsupported(0));
}
backend.vcopy_data_impl(pairs)
}
pub fn copy_tree_with<F: VectorBackend + ?Sized>(
backend: &mut F,
source: &Path,
destination: &Path,
symlinks: bool,
masks: AttrMask,
copy_file: impl FnMut(&mut F, &ExtentPair) -> VfRes,
map_error: impl Fn(VfError) -> VfError,
) -> VfRes {
copy_tree_with_listdir(
backend,
source,
destination,
symlinks,
masks,
|backend, path, masks| backend.listdir_impl(path, masks, 0, false),
copy_file,
map_error,
)
}
#[allow(clippy::too_many_arguments)] pub fn copy_tree_with_listdir<F: VectorBackend + ?Sized>(
backend: &mut F,
source: &Path,
destination: &Path,
symlinks: bool,
masks: AttrMask,
mut list_directory: impl FnMut(&mut F, &Path, AttrMask) -> VfResult<Vec<VfAttrs>>,
mut copy_file: impl FnMut(&mut F, &ExtentPair) -> VfRes,
map_error: impl Fn(VfError) -> VfError,
) -> VfRes {
let directory_mode = if backend
.capabilities()
.contains(Capabilities::POSIX_METADATA)
{
0o755
} else {
0o777
};
if !backend.exists_impl(destination)? {
backend
.ensure_dir_impl(destination, directory_mode)
.map_err(&map_error)?;
}
let mut pending = vec![(source.to_path_buf(), destination.to_path_buf())];
while let Some((source, destination)) = pending.pop() {
let entries = list_directory(backend, &source, masks)?;
let mut directories = Vec::new();
for entry in entries {
let name = entry
.file
.path()
.and_then(Path::file_name)
.ok_or_else(|| VfError::failure(0, ERR_INVAL))?;
let source_child = source.join(name);
let destination_child = destination.join(name);
if entry.ftype == VfType::Directory {
backend
.ensure_dir_impl(&destination_child, directory_mode)
.map_err(&map_error)?;
directories.push((source_child, destination_child));
} else if entry.ftype == VfType::Symlink && symlinks {
let target = backend
.readlink_raw_impl(&source_child)
.map_err(&map_error)?;
backend
.symlink_raw_impl(&bytes_to_path(target), &destination_child)
.map_err(&map_error)?;
} else {
let pair = ExtentPair::from_os_paths(&source_child, 0, &destination_child, 0, None);
copy_file(backend, &pair).map_err(&map_error)?;
}
}
pending.extend(directories.into_iter().rev());
}
Ok(())
}