public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: Proxmox Backup Server development discussion
	<pbs-devel@lists.proxmox.com>,
	Filip Schauer <f.schauer@proxmox.com>
Subject: Re: [pbs-devel] [PATCH v2 proxmox 1/1] fix #4995: compression: Include symlinks in zip file restore
Date: Fri, 24 Nov 2023 08:56:59 +0100	[thread overview]
Message-ID: <0f719e51-3407-4923-bd22-502efb4bca4d@proxmox.com> (raw)
In-Reply-To: <20231123130652.416129-2-f.schauer@proxmox.com>

a few high level comments (did not look too closely on the code):

* if we change the function/struct parameters anyway wouldn't it make more sense
   to add a 'filetype' enum instead of having a 'is_file' bool and a symlink option?
   i used the bool because we only had files + dirs, but now we add a third type,
   but imho representing the types properly would be better
   we even could put the content into the various enum parts
   (or even make the ZipEntry an enum altogether?)
   i know this refactoring is much more work than slapping just a new parameter on,
   but it makes it easier to understand the code and expand it if we need it
   (honestly i probably should have done so initially when adding the code)


* what i'm missing here a bit is the source on how to encode symlinks in zip.
   the "official" zip spec[0] only talks about (symbolic) links in the description
   of a "-UNIX Extra Field" but you simply encode it here into the content
   how did you arrive at that solution?
   (also generally a commit message is a good idea ;) )

* for these things i'd also like a short comment (does not have to be in the
   commit message) on which systems you did test this, e.g. zipinfo/zip/unar on linux
   explorer on windows, mac (?), etc.

* if you want to go the extra mile, i guess this would be a good time to add tests
   that create a new zip from test data, to see if they don't break with your changes

0: https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT

On 11/23/23 14:06, Filip Schauer wrote:
> Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
> ---
>   proxmox-compression/src/zip.rs | 46 ++++++++++++++++++++++++++--------
>   1 file changed, 35 insertions(+), 11 deletions(-)
> 
> diff --git a/proxmox-compression/src/zip.rs b/proxmox-compression/src/zip.rs
> index d2d3fd8..e30f50a 100644
> --- a/proxmox-compression/src/zip.rs
> +++ b/proxmox-compression/src/zip.rs
> @@ -204,6 +204,7 @@ pub struct ZipEntry {
>       offset: u64,
>       is_file: bool,
>       is_utf8_filename: bool,
> +    symlink_target: Option<OsString>,
>   }
>   
>   impl ZipEntry {
> @@ -211,7 +212,13 @@ impl ZipEntry {
>       ///
>       /// if is_file is false the path will contain an trailing separator,
>       /// so that the zip file understands that it is a directory
> -    pub fn new<P: AsRef<Path>>(path: P, mtime: i64, mode: u16, is_file: bool) -> Self {
> +    pub fn new<P: AsRef<Path>>(
> +        path: P,
> +        mtime: i64,
> +        mode: u16,
> +        is_file: bool,
> +        symlink_target: Option<P>,
> +    ) -> Self {
>           let mut relpath = PathBuf::new();
>   
>           for comp in path.as_ref().components() {
> @@ -226,6 +233,7 @@ impl ZipEntry {
>   
>           let filename: OsString = relpath.into();
>           let is_utf8_filename = filename.to_str().is_some();
> +        let symlink_target_osstr =  symlink_target.map(|x| x.as_ref().into());
>   
>           Self {
>               filename,
> @@ -237,6 +245,7 @@ impl ZipEntry {
>               offset: 0,
>               is_file,
>               is_utf8_filename,
> +            symlink_target: symlink_target_osstr,
>           }
>       }
>   
> @@ -360,7 +369,9 @@ impl ZipEntry {
>                   comment_len: 0,
>                   start_disk: 0,
>                   internal_flags: 0,
> -                external_flags: (self.mode as u32) << 16 | (!self.is_file as u32) << 4,
> +                external_flags: (self.mode as u32) << 16
> +                | (self.symlink_target.is_some() as u32) << 5
> +                | (!self.is_file as u32) << 4,
>                   offset,
>               },
>           )
> @@ -486,23 +497,30 @@ impl<W: AsyncWrite + Unpin> ZipEncoder<W> {
>               .ok_or_else(|| format_err!("had no target during add entry"))?;
>           entry.offset = self.byte_count.try_into()?;
>           self.byte_count += entry.write_local_header(&mut target).await?;
> -        if let Some(content) = content {
> -            let mut reader = HashWrapper::new(content);
> +
> +        if content.is_some() || entry.symlink_target.is_some() {
>               let mut enc = DeflateEncoder::with_quality(target, Level::Fastest);
>   
> -            enc.compress(&mut reader).await?;
> +            if let Some(content) = content {
> +                let mut reader = HashWrapper::new(content);
> +                enc.compress(&mut reader).await?;
> +                entry.crc32 = reader.finish().0;
> +            } else if let Some(symlink_target) = entry.symlink_target.as_ref() {
> +                let cursor = std::io::Cursor::new(symlink_target.as_bytes());
> +                let mut reader = HashWrapper::new(cursor);
> +                enc.compress(&mut reader).await?;
> +                entry.crc32 = reader.finish().0;
> +            }
> +
>               let total_in = enc.total_in();
>               let total_out = enc.total_out();
>               target = enc.into_inner();
>   
> -            let (crc32, _reader) = reader.finish();
> -
>               self.byte_count += total_out as usize;
>               entry.compressed_size = total_out;
>               entry.uncompressed_size = total_in;
> -
> -            entry.crc32 = crc32;
>           }
> +
>           self.byte_count += entry.write_data_descriptor(&mut target).await?;
>           self.target = Some(target);
>   
> @@ -658,10 +676,16 @@ where
>   
>               if entry.file_type().is_file() {
>                   let file = tokio::fs::File::open(entry.path()).await?;
> -                let ze = ZipEntry::new(entry_path_no_base, mtime, mode, true);
> +                let ze = ZipEntry::new(entry_path_no_base, mtime, mode, true, None);
>                   Ok(Some((ze, Some(file))))
>               } else if entry.file_type().is_dir() {
> -                let ze = ZipEntry::new(entry_path_no_base, mtime, mode, false);
> +                let ze = ZipEntry::new(entry_path_no_base, mtime, mode, false, None);
> +                let content: Option<tokio::fs::File> = None;
> +                Ok(Some((ze, content)))
> +            } else if entry.file_type().is_symlink() {
> +                let target = std::fs::read_link(entry.path())?;
> +                let ze =
> +                    ZipEntry::new(entry_path_no_base, mtime, mode, true, Some(target.as_ref()));
>                   let content: Option<tokio::fs::File> = None;
>                   Ok(Some((ze, content)))
>               } else {





  reply	other threads:[~2023-11-24  7:57 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-23 13:06 [pbs-devel] [PATCH v2 many] fix #4995: " Filip Schauer
2023-11-23 13:06 ` [pbs-devel] [PATCH v2 proxmox 1/1] fix #4995: compression: " Filip Schauer
2023-11-24  7:56   ` Dominik Csapak [this message]
2023-11-24 11:03     ` Lukas Wagner
2023-12-14 14:50       ` Filip Schauer
2023-11-23 13:06 ` [pbs-devel] [PATCH v2 backup 1/1] fix #4995: pxar: " Filip Schauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0f719e51-3407-4923-bd22-502efb4bca4d@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=f.schauer@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal