From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 31DD71FF15F for ; Mon, 12 Aug 2024 12:32:17 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A7284307C9; Mon, 12 Aug 2024 12:32:29 +0200 (CEST) From: Christian Ebner To: pbs-devel@lists.proxmox.com Date: Mon, 12 Aug 2024 12:31:31 +0200 Message-Id: <20240812103139.288854-3-c.ebner@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240812103139.288854-1-c.ebner@proxmox.com> References: <20240812103139.288854-1-c.ebner@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.027 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pbs-devel] [PATCH v3 proxmox-backup 02/10] client: pxar: move catalog lookup helper to pxar tools X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" 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 { @@ -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( + accessor: Accessor, + path: &OsStr, + path_prefix: Option<&str>, +) -> Result, 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 { 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( - accessor: Accessor, - path: &OsStr, - path_prefix: Option<&str>, -) -> Result, 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 { 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