zip_extensions/deflate/
preserve_symlinks_handler.rs1use 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::ZipWriter;
8use zip::result::ZipResult;
9use zip::write::{FileOptionExtension, FileOptions};
10
11pub struct PreserveSymlinksHandler<H = DefaultEntryHandler> {
18 inner: H,
19}
20
21impl PreserveSymlinksHandler<DefaultEntryHandler> {
22 pub fn new() -> Self {
23 Self {
24 inner: DefaultEntryHandler,
25 }
26 }
27
28 pub fn with_default_inner() -> Self {
29 Self::new()
30 }
31}
32
33impl<H> PreserveSymlinksHandler<H> {
34 pub fn with_inner(inner: H) -> Self {
35 Self { inner }
36 }
37}
38
39impl<T: FileOptionExtension, H> EntryHandler<T> for PreserveSymlinksHandler<H>
40where
41 H: EntryHandler<T>,
42{
43 fn handle_entry<W: Write + io::Seek>(
44 &self,
45 writer: &mut ZipWriter<W>,
46 root: &PathBuf,
47 entry_path: &PathBuf,
48 file_options: FileOptions<T>,
49 buffer: &mut Vec<u8>,
50 ) -> ZipResult<()> {
51 let symlink_metadata = std::fs::symlink_metadata(entry_path)?;
52 let relative = make_relative_path(root, entry_path);
53
54 if symlink_metadata.is_symlink() {
55 let target = std::fs::read_link(entry_path)?;
56 writer.add_symlink(
57 relative.to_str().unwrap(),
58 target.to_str().unwrap(),
59 file_options,
60 )?;
61 return Ok(());
62 }
63
64 self.inner
65 .handle_entry(writer, root, entry_path, file_options, buffer)
66 }
67}