zip_extensions/
preserve_symlinks_handler.rs

1use crate::default_entry_handler::DefaultEntryHandler;
2use crate::entry_handler::EntryHandler;
3use crate::file_utils::make_relative_path;
4use std::io;
5use std::io::Write;
6use std::path::PathBuf;
7use zip::result::ZipResult;
8use zip::write::{FileOptionExtension, FileOptions};
9use zip::ZipWriter;
10
11pub struct PreserveSymlinksHandler;
12
13impl<T: FileOptionExtension> EntryHandler<T> for PreserveSymlinksHandler {
14    fn handle_entry<W: Write + io::Seek>(
15        &self,
16        writer: &mut ZipWriter<W>,
17        root: &PathBuf,
18        entry_path: &PathBuf,
19        file_options: FileOptions<T>,
20        buffer: &mut Vec<u8>,
21    ) -> ZipResult<()> {
22        let symlink_metadata = std::fs::symlink_metadata(entry_path)?;
23        let relative = make_relative_path(root, entry_path);
24
25        if symlink_metadata.is_symlink() {
26            let target = std::fs::read_link(entry_path)?;
27            writer.add_symlink(
28                relative.to_str().unwrap(),
29                target.to_str().unwrap(),
30                file_options,
31            )?;
32            return Ok(());
33        }
34
35        // fallback to default behavior
36        DefaultEntryHandler.handle_entry(writer, root, entry_path, file_options, buffer)
37    }
38}