[pbs-devel] [PATCH proxmox-backup 1/2] pbs-client: extract: rewrite create_zip with sequential decoder

Dominik Csapak d.csapak at proxmox.com
Tue Apr 19 12:28:27 CEST 2022


instead of an async recursive function. Not only is it less code,
recursive futures are not really nice and it should be faster too.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 pbs-client/src/pxar/extract.rs | 154 ++++++++++++++++-----------------
 1 file changed, 74 insertions(+), 80 deletions(-)

diff --git a/pbs-client/src/pxar/extract.rs b/pbs-client/src/pxar/extract.rs
index 7898e255..90ce88bd 100644
--- a/pbs-client/src/pxar/extract.rs
+++ b/pbs-client/src/pxar/extract.rs
@@ -7,11 +7,9 @@ use std::io;
 use std::os::unix::ffi::OsStrExt;
 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 use std::path::{Path, PathBuf};
-use std::pin::Pin;
 use std::sync::{Arc, Mutex};
 
 use anyhow::{bail, format_err, Error};
-use futures::future::Future;
 use nix::dir::Dir;
 use nix::fcntl::OFlag;
 use nix::sys::stat::Mode;
@@ -699,7 +697,7 @@ where
 
 pub async fn create_zip<T, W, P>(
     output: W,
-    decoder: Accessor<T>,
+    accessor: Accessor<T>,
     path: P,
     verbose: bool,
 ) -> Result<(), Error>
@@ -708,7 +706,7 @@ where
     W: tokio::io::AsyncWrite + Unpin + Send + 'static,
     P: AsRef<Path>,
 {
-    let root = decoder.open_root().await?;
+    let root = accessor.open_root().await?;
     let file = root
         .lookup(&path)
         .await?
@@ -720,88 +718,84 @@ where
         components.as_path().to_owned()
     };
 
-    let mut zipencoder = ZipEncoder::new(output);
-    let mut decoder = decoder;
-    recurse_files_zip(&mut zipencoder, &mut decoder, &prefix, file, verbose)
-        .await
-        .map_err(|err| {
-            eprintln!("error during creating of zip: {}", err);
-            err
-        })?;
+    let mut zip = ZipEncoder::new(output);
 
-    zipencoder.finish().await.map_err(|err| {
-        eprintln!("error during finishing of zip: {}", err);
-        err
-    })
-}
+    if let Ok(dir) = file.enter_directory().await {
+        let entry = dir.lookup_self().await?;
+        let path = entry.path().strip_prefix(&prefix)?;
+        if path != Path::new("/") {
+            let metadata = entry.metadata();
+            let entry = ZipEntry::new(
+                path,
+                metadata.stat.mtime.secs,
+                metadata.stat.mode as u16,
+                false,
+            );
+            zip.add_entry::<FileContents<T>>(entry, None).await?;
+        }
 
-fn recurse_files_zip<'a, T, W>(
-    zip: &'a mut ZipEncoder<W>,
-    decoder: &'a mut Accessor<T>,
-    prefix: &'a Path,
-    file: FileEntry<T>,
-    verbose: bool,
-) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>
-where
-    T: Clone + pxar::accessor::ReadAt + Unpin + Send + Sync + 'static,
-    W: tokio::io::AsyncWrite + Unpin + Send + 'static,
-{
-    Box::pin(async move {
-        let metadata = file.entry().metadata();
-        let path = file.entry().path().strip_prefix(&prefix)?;
-
-        match file.kind() {
-            EntryKind::File { .. } => {
-                if verbose {
-                    eprintln!("adding '{}' to zip", path.display());
-                }
-                let entry = ZipEntry::new(
-                    path,
-                    metadata.stat.mtime.secs,
-                    metadata.stat.mode as u16,
-                    true,
-                );
-                zip.add_entry(entry, Some(file.contents().await?))
-                    .await
-                    .map_err(|err| format_err!("could not send file entry: {}", err))?;
-            }
-            EntryKind::Hardlink(_) => {
-                let realfile = decoder.follow_hardlink(&file).await?;
-                if verbose {
-                    eprintln!("adding '{}' to zip", path.display());
+        let mut decoder = dir.decode_full().await?;
+        decoder.enable_goodbye_entries(false);
+        while let Some(entry) = decoder.next().await {
+            let entry = entry?;
+            let metadata = entry.metadata();
+            let path = entry.path().strip_prefix(&prefix)?;
+
+            match entry.kind() {
+                EntryKind::File { .. } => {
+                    if verbose {
+                        eprintln!("adding '{}' to zip", path.display());
+                    }
+                    let entry = ZipEntry::new(
+                        path,
+                        metadata.stat.mtime.secs,
+                        metadata.stat.mode as u16,
+                        true,
+                    );
+                    zip.add_entry(entry, decoder.contents())
+                        .await
+                        .map_err(|err| format_err!("could not send file entry: {}", err))?;
                 }
-                let entry = ZipEntry::new(
-                    path,
-                    metadata.stat.mtime.secs,
-                    metadata.stat.mode as u16,
-                    true,
-                );
-                zip.add_entry(entry, Some(realfile.contents().await?))
-                    .await
-                    .map_err(|err| format_err!("could not send file entry: {}", err))?;
-            }
-            EntryKind::Directory => {
-                let dir = file.enter_directory().await?;
-                let mut readdir = dir.read_dir();
-                if verbose {
-                    eprintln!("adding '{}' to zip", path.display());
+                EntryKind::Hardlink(_) => {
+                    let entry = root
+                        .lookup(&path)
+                        .await?
+                        .ok_or(format_err!("error looking up '{:?}'", path))?;
+                    let realfile = accessor.follow_hardlink(&entry).await?;
+                    let metadata = realfile.entry().metadata();
+                    if verbose {
+                        eprintln!("adding '{}' to zip", path.display());
+                    }
+                    let entry = ZipEntry::new(
+                        path,
+                        metadata.stat.mtime.secs,
+                        metadata.stat.mode as u16,
+                        true,
+                    );
+                    zip.add_entry(entry, decoder.contents())
+                        .await
+                        .map_err(|err| format_err!("could not send file entry: {}", err))?;
                 }
-                let entry = ZipEntry::new(
-                    path,
-                    metadata.stat.mtime.secs,
-                    metadata.stat.mode as u16,
-                    false,
-                );
-                zip.add_entry::<FileContents<T>>(entry, None).await?;
-                while let Some(entry) = readdir.next().await {
-                    let entry = entry?.decode_entry().await?;
-                    recurse_files_zip(zip, decoder, prefix, entry, verbose).await?;
+                EntryKind::Directory => {
+                    if verbose {
+                        eprintln!("adding '{}' to zip", path.display());
+                    }
+                    let entry = ZipEntry::new(
+                        path,
+                        metadata.stat.mtime.secs,
+                        metadata.stat.mode as u16,
+                        false,
+                    );
+                    zip.add_entry::<FileContents<T>>(entry, None).await?;
                 }
-            }
-            _ => {} // ignore all else
-        };
+                _ => {} // ignore all else
+            };
+        }
+    }
 
-        Ok(())
+    zip.finish().await.map_err(|err| {
+        eprintln!("error during finishing of zip: {}", err);
+        err
     })
 }
 
-- 
2.30.2






More information about the pbs-devel mailing list