From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v3 proxmox-backup 02/10] client: pxar: move catalog lookup helper to pxar tools
Date: Mon, 12 Aug 2024 12:31:31 +0200 [thread overview]
Message-ID: <20240812103139.288854-3-c.ebner@proxmox.com> (raw)
In-Reply-To: <20240812103139.288854-1-c.ebner@proxmox.com>
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
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
next prev parent reply other threads:[~2024-08-12 10:32 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-12 10:31 [pbs-devel] [PATCH v3 proxmox-backup 00/10] fix catalog dump and shell for split pxar archives Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 01/10] client: tools: make tools module public Christian Ebner
2024-08-12 10:31 ` Christian Ebner [this message]
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 03/10] client: tools: move pxar root entry helper to pxar submodule Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 04/10] client: make helper to get remote pxar reader reusable Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 05/10] client: tools: factor out entry path prefix helper Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 06/10] client: tools: factor out pxar entry to dir entry mapping Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 07/10] client: add helper to dump catalog from metadata archive Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 08/10] client: catalog: fallback to metadata archives for catalog dump Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 09/10] client: helper to mimic catalog find using metadata archive Christian Ebner
2024-08-12 10:31 ` [pbs-devel] [PATCH v3 proxmox-backup 10/10] client: catalog shell: fallback to accessor for navigation Christian Ebner
2024-10-21 14:09 ` Thomas Lamprecht
2024-10-21 9:09 ` [pbs-devel] [PATCH v3 proxmox-backup 00/10] fix catalog dump and shell for split pxar archives Christian Ebner
2024-10-21 14:07 ` Thomas Lamprecht
2024-10-21 14:09 ` Thomas Lamprecht
2024-10-21 14:16 ` Christian Ebner
2024-10-21 15:50 ` Christian Ebner
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=20240812103139.288854-3-c.ebner@proxmox.com \
--to=c.ebner@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.