mirror of
git://git.proxmox.com/git/proxmox-backup.git
synced 2025-02-25 17:57:35 +03:00
pbs-client: extract: rewrite create_zip with sequential decoder
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@proxmox.com>
This commit is contained in:
parent
f37d8540e1
commit
7098f5d885
@ -7,11 +7,9 @@ use std::io;
|
|||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use futures::future::Future;
|
|
||||||
use nix::dir::Dir;
|
use nix::dir::Dir;
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use nix::sys::stat::Mode;
|
use nix::sys::stat::Mode;
|
||||||
@ -699,7 +697,7 @@ where
|
|||||||
|
|
||||||
pub async fn create_zip<T, W, P>(
|
pub async fn create_zip<T, W, P>(
|
||||||
output: W,
|
output: W,
|
||||||
decoder: Accessor<T>,
|
accessor: Accessor<T>,
|
||||||
path: P,
|
path: P,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
@ -708,7 +706,7 @@ where
|
|||||||
W: tokio::io::AsyncWrite + Unpin + Send + 'static,
|
W: tokio::io::AsyncWrite + Unpin + Send + 'static,
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
{
|
{
|
||||||
let root = decoder.open_root().await?;
|
let root = accessor.open_root().await?;
|
||||||
let file = root
|
let file = root
|
||||||
.lookup(&path)
|
.lookup(&path)
|
||||||
.await?
|
.await?
|
||||||
@ -720,91 +718,87 @@ where
|
|||||||
components.as_path().to_owned()
|
components.as_path().to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut zipencoder = ZipEncoder::new(output);
|
let mut zip = 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
|
|
||||||
})?;
|
|
||||||
|
|
||||||
zipencoder.finish().await.map_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?;
|
||||||
|
}
|
||||||
|
|
||||||
|
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))?;
|
||||||
|
}
|
||||||
|
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))?;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zip.finish().await.map_err(|err| {
|
||||||
eprintln!("error during finishing of zip: {}", err);
|
eprintln!("error during finishing of zip: {}", err);
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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 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());
|
|
||||||
}
|
|
||||||
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?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {} // ignore all else
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_extractor<DEST>(destination: DEST, metadata: Metadata) -> Result<Extractor, Error>
|
fn get_extractor<DEST>(destination: DEST, metadata: Metadata) -> Result<Extractor, Error>
|
||||||
where
|
where
|
||||||
DEST: AsRef<Path>,
|
DEST: AsRef<Path>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user