[pbs-devel] [PATCH v3 proxmox-backup 02/10] client: pxar: move catalog lookup helper to pxar tools

Christian Ebner c.ebner at proxmox.com
Mon Aug 12 12:31:31 CEST 2024


The lookup helper used to generate catalog entries via the metadata
archive for split archive backups is pxar specific, therefore move it
to the appropriate pxar tools submodlue.
---
changes since version 2:
- not present in previous version

 pbs-client/src/pxar/tools.rs     | 86 +++++++++++++++++++++++++++++++-
 pbs-client/src/tools/mod.rs      | 84 -------------------------------
 proxmox-file-restore/src/main.rs |  8 ++-
 src/api2/admin/datastore.rs      |  2 +-
 4 files changed, 91 insertions(+), 89 deletions(-)

diff --git a/pbs-client/src/pxar/tools.rs b/pbs-client/src/pxar/tools.rs
index 9d4ad6a4f..c444a8941 100644
--- a/pbs-client/src/pxar/tools.rs
+++ b/pbs-client/src/pxar/tools.rs
@@ -3,11 +3,17 @@
 use std::ffi::OsStr;
 use std::os::unix::ffi::OsStrExt;
 use std::path::Path;
+use std::path::PathBuf;
 
-use anyhow::{bail, Context, Error};
+use anyhow::{bail, format_err, Context, Error};
 use nix::sys::stat::Mode;
 
-use pxar::{format::StatxTimestamp, mode, Entry, EntryKind, Metadata};
+use pxar::accessor::aio::Accessor;
+use pxar::accessor::ReadAt;
+use pxar::format::{SignedDuration, StatxTimestamp};
+use pxar::{mode, Entry, EntryKind, Metadata};
+
+use pbs_datastore::catalog::{ArchiveEntry, DirEntryAttribute};
 
 /// Get the file permissions as `nix::Mode`
 pub(crate) fn perms_from_metadata(meta: &Metadata) -> Result<Mode, Error> {
@@ -257,3 +263,79 @@ pub fn format_multi_line_entry(entry: &Entry) -> String {
         )
     }
 }
+
+/// Look up the directory entries of the given directory `path` in a pxar archive via it's given
+/// `accessor` and return the entries formatted as [`ArchiveEntry`]'s, compatible with reading
+/// entries from the catalog.
+///
+/// If the optional `path_prefix` is given, all returned entry paths will be prefixed with it.
+pub async fn pxar_metadata_catalog_lookup<T: Clone + ReadAt>(
+    accessor: Accessor<T>,
+    path: &OsStr,
+    path_prefix: Option<&str>,
+) -> Result<Vec<ArchiveEntry>, Error> {
+    let root = accessor.open_root().await?;
+    let dir_entry = root
+        .lookup(&path)
+        .await
+        .map_err(|err| format_err!("lookup failed - {err}"))?
+        .ok_or_else(|| format_err!("lookup failed - error opening '{path:?}'"))?;
+
+    let mut entries = Vec::new();
+    if let EntryKind::Directory = dir_entry.kind() {
+        let dir_entry = dir_entry
+            .enter_directory()
+            .await
+            .map_err(|err| format_err!("failed to enter directory - {err}"))?;
+
+        let mut entries_iter = dir_entry.read_dir();
+        while let Some(entry) = entries_iter.next().await {
+            let entry = entry?.decode_entry().await?;
+
+            let entry_attr = match entry.kind() {
+                EntryKind::Version(_) | EntryKind::Prelude(_) | EntryKind::GoodbyeTable => continue,
+                EntryKind::Directory => DirEntryAttribute::Directory {
+                    start: entry.entry_range_info().entry_range.start,
+                },
+                EntryKind::File { size, .. } => {
+                    let mtime = match entry.metadata().mtime_as_duration() {
+                        SignedDuration::Positive(val) => i64::try_from(val.as_secs())?,
+                        SignedDuration::Negative(val) => -i64::try_from(val.as_secs())?,
+                    };
+                    DirEntryAttribute::File { size: *size, mtime }
+                }
+                EntryKind::Device(_) => match entry.metadata().file_type() {
+                    mode::IFBLK => DirEntryAttribute::BlockDevice,
+                    mode::IFCHR => DirEntryAttribute::CharDevice,
+                    _ => bail!("encountered unknown device type"),
+                },
+                EntryKind::Symlink(_) => DirEntryAttribute::Symlink,
+                EntryKind::Hardlink(_) => DirEntryAttribute::Hardlink,
+                EntryKind::Fifo => DirEntryAttribute::Fifo,
+                EntryKind::Socket => DirEntryAttribute::Socket,
+            };
+
+            let entry_path = if let Some(prefix) = path_prefix {
+                let mut entry_path = PathBuf::from(prefix);
+                match entry.path().strip_prefix("/") {
+                    Ok(path) => entry_path.push(path),
+                    Err(_) => entry_path.push(entry.path()),
+                }
+                entry_path
+            } else {
+                PathBuf::from(entry.path())
+            };
+            entries.push(ArchiveEntry::new(
+                entry_path.as_os_str().as_bytes(),
+                Some(&entry_attr),
+            ));
+        }
+    } else {
+        bail!(format!(
+            "expected directory entry, got entry kind '{:?}'",
+            dir_entry.kind()
+        ));
+    }
+
+    Ok(entries)
+}
diff --git a/pbs-client/src/tools/mod.rs b/pbs-client/src/tools/mod.rs
index 772cc1263..87e74de6e 100644
--- a/pbs-client/src/tools/mod.rs
+++ b/pbs-client/src/tools/mod.rs
@@ -1,13 +1,10 @@
 //! Shared tools useful for common CLI clients.
 use std::collections::HashMap;
 use std::env::VarError::{NotPresent, NotUnicode};
-use std::ffi::OsStr;
 use std::fs::File;
 use std::io::{BufRead, BufReader};
-use std::os::unix::ffi::OsStrExt;
 use std::os::unix::fs::OpenOptionsExt;
 use std::os::unix::io::FromRawFd;
-use std::path::PathBuf;
 use std::process::Command;
 use std::sync::OnceLock;
 
@@ -21,12 +18,7 @@ use proxmox_schema::*;
 use proxmox_sys::fs::file_get_json;
 
 use pbs_api_types::{Authid, BackupNamespace, RateLimitConfig, UserWithTokens, BACKUP_REPO_URL};
-use pbs_datastore::catalog::{ArchiveEntry, DirEntryAttribute};
 use pbs_datastore::BackupManifest;
-use pxar::accessor::aio::Accessor;
-use pxar::accessor::ReadAt;
-use pxar::format::SignedDuration;
-use pxar::{mode, EntryKind};
 
 use crate::{BackupRepository, HttpClient, HttpClientOptions};
 
@@ -663,82 +655,6 @@ pub fn raise_nofile_limit() -> Result<libc::rlimit64, Error> {
     Ok(old)
 }
 
-/// Look up the directory entries of the given directory `path` in a pxar archive via it's given
-/// `accessor` and return the entries formatted as [`ArchiveEntry`]'s, compatible with reading
-/// entries from the catalog.
-///
-/// If the optional `path_prefix` is given, all returned entry paths will be prefixed with it.
-pub async fn pxar_metadata_catalog_lookup<T: Clone + ReadAt>(
-    accessor: Accessor<T>,
-    path: &OsStr,
-    path_prefix: Option<&str>,
-) -> Result<Vec<ArchiveEntry>, Error> {
-    let root = accessor.open_root().await?;
-    let dir_entry = root
-        .lookup(&path)
-        .await
-        .map_err(|err| format_err!("lookup failed - {err}"))?
-        .ok_or_else(|| format_err!("lookup failed - error opening '{path:?}'"))?;
-
-    let mut entries = Vec::new();
-    if let EntryKind::Directory = dir_entry.kind() {
-        let dir_entry = dir_entry
-            .enter_directory()
-            .await
-            .map_err(|err| format_err!("failed to enter directory - {err}"))?;
-
-        let mut entries_iter = dir_entry.read_dir();
-        while let Some(entry) = entries_iter.next().await {
-            let entry = entry?.decode_entry().await?;
-
-            let entry_attr = match entry.kind() {
-                EntryKind::Version(_) | EntryKind::Prelude(_) | EntryKind::GoodbyeTable => continue,
-                EntryKind::Directory => DirEntryAttribute::Directory {
-                    start: entry.entry_range_info().entry_range.start,
-                },
-                EntryKind::File { size, .. } => {
-                    let mtime = match entry.metadata().mtime_as_duration() {
-                        SignedDuration::Positive(val) => i64::try_from(val.as_secs())?,
-                        SignedDuration::Negative(val) => -i64::try_from(val.as_secs())?,
-                    };
-                    DirEntryAttribute::File { size: *size, mtime }
-                }
-                EntryKind::Device(_) => match entry.metadata().file_type() {
-                    mode::IFBLK => DirEntryAttribute::BlockDevice,
-                    mode::IFCHR => DirEntryAttribute::CharDevice,
-                    _ => bail!("encountered unknown device type"),
-                },
-                EntryKind::Symlink(_) => DirEntryAttribute::Symlink,
-                EntryKind::Hardlink(_) => DirEntryAttribute::Hardlink,
-                EntryKind::Fifo => DirEntryAttribute::Fifo,
-                EntryKind::Socket => DirEntryAttribute::Socket,
-            };
-
-            let entry_path = if let Some(prefix) = path_prefix {
-                let mut entry_path = PathBuf::from(prefix);
-                match entry.path().strip_prefix("/") {
-                    Ok(path) => entry_path.push(path),
-                    Err(_) => entry_path.push(entry.path()),
-                }
-                entry_path
-            } else {
-                PathBuf::from(entry.path())
-            };
-            entries.push(ArchiveEntry::new(
-                entry_path.as_os_str().as_bytes(),
-                Some(&entry_attr),
-            ));
-        }
-    } else {
-        bail!(format!(
-            "expected directory entry, got entry kind '{:?}'",
-            dir_entry.kind()
-        ));
-    }
-
-    Ok(entries)
-}
-
 /// Creates a temporary file (with `O_TMPFILE`) in `XDG_CACHE_HOME`. If we
 /// cannot create the file there it will be created in `/tmp` instead.
 pub fn create_tmp_file() -> std::io::Result<std::fs::File> {
diff --git a/proxmox-file-restore/src/main.rs b/proxmox-file-restore/src/main.rs
index 69d811fc1..40b063ebc 100644
--- a/proxmox-file-restore/src/main.rs
+++ b/proxmox-file-restore/src/main.rs
@@ -186,8 +186,12 @@ async fn list_files(
                 let accessor = Accessor::new(reader, archive_size).await?;
                 let path = OsStr::from_bytes(&path);
 
-                pbs_client::tools::pxar_metadata_catalog_lookup(accessor, path, Some(&archive_name))
-                    .await
+                pbs_client::pxar::tools::pxar_metadata_catalog_lookup(
+                    accessor,
+                    path,
+                    Some(&archive_name),
+                )
+                .await
             }
         }
         ExtractPath::VM(file, path) => {
diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 976617d9f..52b32dc48 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -1737,7 +1737,7 @@ pub async fn catalog(
         let accessor = Accessor::new(reader, archive_size).await?;
 
         let file_path = decode_path(&filepath)?;
-        pbs_client::tools::pxar_metadata_catalog_lookup(
+        pbs_client::pxar::tools::pxar_metadata_catalog_lookup(
             accessor,
             OsStr::from_bytes(&file_path),
             None,
-- 
2.39.2





More information about the pbs-devel mailing list