From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v4 proxmox-backup 02/10] client: pxar: move catalog lookup helper to pxar tools
Date: Mon, 21 Oct 2024 17:47:36 +0200 [thread overview]
Message-ID: <20241021154744.325556-3-c.ebner@proxmox.com> (raw)
In-Reply-To: <20241021154744.325556-1-c.ebner@proxmox.com>
Since this code is specific to handling of pxar archives, move it
from the common client related helper module to the pxar specific
one.
This is for code clenup purposes only.
No functional changes.
Suggested-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
changes since version 3:
- s/submodule/module
- Reword commit message in order to clarify intend of this and
subsequent patches
- Add missing git trailers
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 cda4e911c..3d93f1710 100644
--- a/proxmox-file-restore/src/main.rs
+++ b/proxmox-file-restore/src/main.rs
@@ -187,8 +187,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 7660dd7f6..b73ad0ff0 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.5
_______________________________________________
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-10-21 15:48 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-21 15:47 [pbs-devel] [PATCH v4 proxmox-backup 00/10] fix catalog dump and shell for split pxar archives Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 01/10] client: tools: make tools module public Christian Ebner
2024-10-21 15:47 ` Christian Ebner [this message]
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 03/10] client: tools: move pxar root entry helper to pxar module Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 04/10] client: make helper to get remote pxar reader reusable Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 05/10] client: tools: factor out entry path prefix helper Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 06/10] client: tools: factor out pxar entry to dir entry mapping Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 07/10] client: add helper to dump catalog from metadata archive Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 08/10] client: catalog: fallback to metadata archives for catalog dump Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 09/10] client: helper to mimic catalog find using metadata archive Christian Ebner
2024-10-21 15:47 ` [pbs-devel] [PATCH v4 proxmox-backup 10/10] client: catalog shell: fallback to accessor for navigation Christian Ebner
2024-10-23 14:13 ` [pbs-devel] applied: [PATCH v4 proxmox-backup 00/10] fix catalog dump and shell for split pxar archives Fabian Grünbichler
2024-10-23 18:37 ` Christian Ebner
2024-10-24 7:44 ` Fabian Grünbichler
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=20241021154744.325556-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