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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox