From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v3 proxmox-backup 3/5] client/server: use dedicated api type for all archive names
Date: Thu, 24 Oct 2024 10:01:48 +0200 [thread overview]
Message-ID: <20241024080150.30200-4-c.ebner@proxmox.com> (raw)
In-Reply-To: <20241024080150.30200-1-c.ebner@proxmox.com>
Instead of using the plain String or slices of it, use the dedicated
api type and its methods to parse and check for archive type based on
archive filename extension.
Thereby, keeping the checks and mappings in the api type and
resticting function parameters by the narrower wrapper type to reduce
potential misuse.
A positive ergonomic side effect of this is that commands now also
accept the archive type extension optionally, when passing the archive
name.
E.g.
```
proxmox-backup-client restore <snapshot> <name>.pxar.didx <target>
```
is equal to
```
proxmox-backup-client restore <snapshot> <name>.pxar <target>
```
Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
changes since version 2:
- rebased onto current master
- reworded commit message
pbs-client/src/backup_reader.rs | 14 ++--
pbs-client/src/backup_writer.rs | 39 +++++-----
pbs-client/src/pxar/tools.rs | 3 +-
pbs-client/src/tools/mod.rs | 24 +++---
pbs-datastore/src/manifest.rs | 30 +++++---
proxmox-backup-client/src/catalog.rs | 31 ++++----
proxmox-backup-client/src/helper.rs | 7 +-
proxmox-backup-client/src/main.rs | 111 ++++++++++++++++-----------
proxmox-backup-client/src/mount.rs | 33 ++++----
proxmox-file-restore/src/main.rs | 12 ++-
src/api2/admin/datastore.rs | 60 +++++++--------
src/bin/proxmox_backup_debug/diff.rs | 16 ++--
src/server/pull.rs | 15 ++--
13 files changed, 214 insertions(+), 181 deletions(-)
diff --git a/pbs-client/src/backup_reader.rs b/pbs-client/src/backup_reader.rs
index 4706abc78..533b9dc45 100644
--- a/pbs-client/src/backup_reader.rs
+++ b/pbs-client/src/backup_reader.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
use futures::future::AbortHandle;
use serde_json::{json, Value};
-use pbs_api_types::{BackupDir, BackupNamespace};
+use pbs_api_types::{BackupArchiveName, BackupDir, BackupNamespace};
use pbs_datastore::data_blob::DataBlob;
use pbs_datastore::data_blob_reader::DataBlobReader;
use pbs_datastore::dynamic_index::DynamicIndexReader;
@@ -145,11 +145,11 @@ impl BackupReader {
pub async fn download_blob(
&self,
manifest: &BackupManifest,
- name: &str,
+ name: &BackupArchiveName,
) -> Result<DataBlobReader<'_, File>, Error> {
let mut tmpfile = crate::tools::create_tmp_file()?;
- self.download(name, &mut tmpfile).await?;
+ self.download(name.as_ref(), &mut tmpfile).await?;
tmpfile.seek(SeekFrom::Start(0))?;
let (csum, size) = sha256(&mut tmpfile)?;
@@ -167,11 +167,11 @@ impl BackupReader {
pub async fn download_dynamic_index(
&self,
manifest: &BackupManifest,
- name: &str,
+ name: &BackupArchiveName,
) -> Result<DynamicIndexReader, Error> {
let mut tmpfile = crate::tools::create_tmp_file()?;
- self.download(name, &mut tmpfile).await?;
+ self.download(name.as_ref(), &mut tmpfile).await?;
let index = DynamicIndexReader::new(tmpfile)
.map_err(|err| format_err!("unable to read dynamic index '{}' - {}", name, err))?;
@@ -190,11 +190,11 @@ impl BackupReader {
pub async fn download_fixed_index(
&self,
manifest: &BackupManifest,
- name: &str,
+ name: &BackupArchiveName,
) -> Result<FixedIndexReader, Error> {
let mut tmpfile = crate::tools::create_tmp_file()?;
- self.download(name, &mut tmpfile).await?;
+ self.download(name.as_ref(), &mut tmpfile).await?;
let index = FixedIndexReader::new(tmpfile)
.map_err(|err| format_err!("unable to read fixed index '{}' - {}", name, err))?;
diff --git a/pbs-client/src/backup_writer.rs b/pbs-client/src/backup_writer.rs
index 8adaf9ef2..6eca0092b 100644
--- a/pbs-client/src/backup_writer.rs
+++ b/pbs-client/src/backup_writer.rs
@@ -11,7 +11,7 @@ use tokio::io::AsyncReadExt;
use tokio::sync::{mpsc, oneshot};
use tokio_stream::wrappers::ReceiverStream;
-use pbs_api_types::{ArchiveType, BackupDir, BackupNamespace};
+use pbs_api_types::{ArchiveType, BackupArchiveName, BackupDir, BackupNamespace};
use pbs_datastore::data_blob::{ChunkInfo, DataBlob, DataChunkBuilder};
use pbs_datastore::dynamic_index::DynamicIndexReader;
use pbs_datastore::fixed_index::FixedIndexReader;
@@ -270,7 +270,7 @@ impl BackupWriter {
pub async fn upload_stream(
&self,
- archive_name: &str,
+ archive_name: &BackupArchiveName,
stream: impl Stream<Item = Result<bytes::BytesMut, Error>>,
options: UploadOptions,
injections: Option<std::sync::mpsc::Receiver<InjectChunks>>,
@@ -296,13 +296,13 @@ impl BackupWriter {
if !manifest
.files()
.iter()
- .any(|file| file.filename == archive_name)
+ .any(|file| file.filename == archive_name.as_ref())
{
log::info!("Previous manifest does not contain an archive called '{archive_name}', skipping download..");
} else {
// try, but ignore errors
- match ArchiveType::from_path(archive_name) {
- Ok(ArchiveType::FixedIndex) => {
+ match archive_name.archive_type() {
+ ArchiveType::FixedIndex => {
if let Err(err) = self
.download_previous_fixed_index(
archive_name,
@@ -314,7 +314,7 @@ impl BackupWriter {
log::warn!("Error downloading .fidx from previous manifest: {}", err);
}
}
- Ok(ArchiveType::DynamicIndex) => {
+ ArchiveType::DynamicIndex => {
if let Err(err) = self
.download_previous_dynamic_index(
archive_name,
@@ -338,12 +338,6 @@ impl BackupWriter {
.as_u64()
.unwrap();
- let archive = if log::log_enabled!(log::Level::Debug) {
- archive_name
- } else {
- pbs_tools::format::strip_server_file_extension(archive_name)
- };
-
let upload_stats = Self::upload_chunk_info_stream(
self.h2.clone(),
wid,
@@ -357,12 +351,17 @@ impl BackupWriter {
},
options.compress,
injections,
- archive,
+ archive_name,
)
.await?;
let size_dirty = upload_stats.size - upload_stats.size_reused;
let size: HumanByte = upload_stats.size.into();
+ let archive = if log::log_enabled!(log::Level::Debug) {
+ archive_name.to_string()
+ } else {
+ archive_name.without_type_extension()
+ };
if upload_stats.chunk_injected > 0 {
log::info!(
@@ -372,7 +371,7 @@ impl BackupWriter {
);
}
- if archive_name != CATALOG_NAME {
+ if archive_name.as_ref() != CATALOG_NAME {
let speed: HumanByte =
((size_dirty * 1_000_000) / (upload_stats.duration.as_micros() as usize)).into();
let size_dirty: HumanByte = size_dirty.into();
@@ -541,7 +540,7 @@ impl BackupWriter {
pub async fn download_previous_fixed_index(
&self,
- archive_name: &str,
+ archive_name: &BackupArchiveName,
manifest: &BackupManifest,
known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
) -> Result<FixedIndexReader, Error> {
@@ -576,7 +575,7 @@ impl BackupWriter {
pub async fn download_previous_dynamic_index(
&self,
- archive_name: &str,
+ archive_name: &BackupArchiveName,
manifest: &BackupManifest,
known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
) -> Result<DynamicIndexReader, Error> {
@@ -651,7 +650,7 @@ impl BackupWriter {
crypt_config: Option<Arc<CryptConfig>>,
compress: bool,
injections: Option<std::sync::mpsc::Receiver<InjectChunks>>,
- archive: &str,
+ archive: &BackupArchiveName,
) -> impl Future<Output = Result<UploadStats, Error>> {
let total_chunks = Arc::new(AtomicUsize::new(0));
let total_chunks2 = total_chunks.clone();
@@ -683,9 +682,9 @@ impl BackupWriter {
let index_csum = Arc::new(Mutex::new(Some(openssl::sha::Sha256::new())));
let index_csum_2 = index_csum.clone();
- let progress_handle = if archive.ends_with(".img")
- || archive.ends_with(".pxar")
- || archive.ends_with(".ppxar")
+ let progress_handle = if archive.ends_with(".img.fidx")
+ || archive.ends_with(".pxar.didx")
+ || archive.ends_with(".ppxar.didx")
{
Some(tokio::spawn(async move {
loop {
diff --git a/pbs-client/src/pxar/tools.rs b/pbs-client/src/pxar/tools.rs
index 7a4d75522..2deee5056 100644
--- a/pbs-client/src/pxar/tools.rs
+++ b/pbs-client/src/pxar/tools.rs
@@ -14,6 +14,7 @@ use pxar::accessor::ReadAt;
use pxar::format::StatxTimestamp;
use pxar::{mode, Entry, EntryKind, Metadata};
+use pbs_api_types::BackupArchiveName;
use pbs_datastore::catalog::{ArchiveEntry, CatalogEntryType, DirEntryAttribute};
use pbs_datastore::dynamic_index::{BufferedDynamicReader, LocalDynamicReadAt};
@@ -358,7 +359,7 @@ pub fn handle_root_with_optional_format_version_prelude<R: pxar::decoder::SeqRea
}
pub async fn get_remote_pxar_reader(
- archive_name: &str,
+ archive_name: &BackupArchiveName,
client: Arc<BackupReader>,
manifest: &BackupManifest,
crypt_config: Option<Arc<CryptConfig>>,
diff --git a/pbs-client/src/tools/mod.rs b/pbs-client/src/tools/mod.rs
index 28db6f348..4b1d7a910 100644
--- a/pbs-client/src/tools/mod.rs
+++ b/pbs-client/src/tools/mod.rs
@@ -17,7 +17,10 @@ use proxmox_router::cli::{complete_file_name, shellword_split};
use proxmox_schema::*;
use proxmox_sys::fs::file_get_json;
-use pbs_api_types::{Authid, BackupNamespace, RateLimitConfig, UserWithTokens, BACKUP_REPO_URL};
+use pbs_api_types::{
+ ArchiveType, Authid, BackupArchiveName, BackupNamespace, RateLimitConfig, UserWithTokens,
+ BACKUP_REPO_URL,
+};
use pbs_datastore::BackupManifest;
use crate::{BackupRepository, HttpClient, HttpClientOptions};
@@ -548,12 +551,12 @@ pub fn place_xdg_file(
}
pub fn get_pxar_archive_names(
- archive_name: &str,
+ archive_name: &BackupArchiveName,
manifest: &BackupManifest,
-) -> Result<(String, Option<String>), Error> {
- let (filename, ext) = match archive_name.strip_suffix(".didx") {
- Some(filename) => (filename, ".didx"),
- None => (archive_name, ""),
+) -> Result<(BackupArchiveName, Option<BackupArchiveName>), Error> {
+ let (filename, ext) = match archive_name.archive_type() {
+ ArchiveType::DynamicIndex => (archive_name.without_type_extension(), ".didx"),
+ _ => (archive_name.to_string(), ""),
};
// Check if archive with given extension is present
@@ -568,8 +571,8 @@ pub fn get_pxar_archive_names(
.or_else(|| filename.strip_suffix(".ppxar"))
{
return Ok((
- format!("{base}.mpxar{ext}"),
- Some(format!("{base}.ppxar{ext}")),
+ format!("{base}.mpxar{ext}").as_str().try_into()?,
+ Some(format!("{base}.ppxar{ext}").as_str().try_into()?),
));
}
return Ok((archive_name.to_owned(), None));
@@ -577,7 +580,10 @@ pub fn get_pxar_archive_names(
// if not, try fallback from regular to split archive
if let Some(base) = filename.strip_suffix(".pxar") {
- return get_pxar_archive_names(&format!("{base}.mpxar{ext}"), manifest);
+ return get_pxar_archive_names(
+ &format!("{base}.mpxar{ext}").as_str().try_into()?,
+ manifest,
+ );
}
bail!("archive not found in manifest");
diff --git a/pbs-datastore/src/manifest.rs b/pbs-datastore/src/manifest.rs
index 823c85003..647f213d7 100644
--- a/pbs-datastore/src/manifest.rs
+++ b/pbs-datastore/src/manifest.rs
@@ -3,7 +3,7 @@ use anyhow::{bail, format_err, Error};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
-use pbs_api_types::{ArchiveType, BackupType, CryptMode, Fingerprint};
+use pbs_api_types::{BackupArchiveName, BackupType, CryptMode, Fingerprint};
use pbs_tools::crypt_config::CryptConfig;
pub const MANIFEST_BLOB_NAME: &str = "index.json.blob";
@@ -68,14 +68,13 @@ impl BackupManifest {
pub fn add_file(
&mut self,
- filename: String,
+ filename: &BackupArchiveName,
size: u64,
csum: [u8; 32],
crypt_mode: CryptMode,
) -> Result<(), Error> {
- let _archive_type = ArchiveType::from_path(&filename)?; // check type
self.files.push(FileInfo {
- filename,
+ filename: filename.to_string(),
size,
csum,
crypt_mode,
@@ -87,8 +86,11 @@ impl BackupManifest {
&self.files[..]
}
- pub fn lookup_file_info(&self, name: &str) -> Result<&FileInfo, Error> {
- let info = self.files.iter().find(|item| item.filename == name);
+ pub fn lookup_file_info(&self, name: &BackupArchiveName) -> Result<&FileInfo, Error> {
+ let info = self
+ .files
+ .iter()
+ .find(|item| item.filename == name.as_ref());
match info {
None => bail!("manifest does not contain file '{}'", name),
@@ -96,7 +98,12 @@ impl BackupManifest {
}
}
- pub fn verify_file(&self, name: &str, csum: &[u8; 32], size: u64) -> Result<(), Error> {
+ pub fn verify_file(
+ &self,
+ name: &BackupArchiveName,
+ csum: &[u8; 32],
+ size: u64,
+ ) -> Result<(), Error> {
let info = self.lookup_file_info(name)?;
if size != info.size {
@@ -256,8 +263,13 @@ fn test_manifest_signature() -> Result<(), Error> {
let mut manifest = BackupManifest::new("host/elsa/2020-06-26T13:56:05Z".parse()?);
- manifest.add_file("test1.img.fidx".into(), 200, [1u8; 32], CryptMode::Encrypt)?;
- manifest.add_file("abc.blob".into(), 200, [2u8; 32], CryptMode::None)?;
+ manifest.add_file(
+ &"test1.img.fidx".try_into()?,
+ 200,
+ [1u8; 32],
+ CryptMode::Encrypt,
+ )?;
+ manifest.add_file(&"abc.blob".try_into()?, 200, [2u8; 32], CryptMode::None)?;
manifest.unprotected["note"] = "This is not protected by the signature.".into();
diff --git a/proxmox-backup-client/src/catalog.rs b/proxmox-backup-client/src/catalog.rs
index a55c9effe..6e2421d1a 100644
--- a/proxmox-backup-client/src/catalog.rs
+++ b/proxmox-backup-client/src/catalog.rs
@@ -7,9 +7,8 @@ use serde_json::Value;
use proxmox_router::cli::*;
use proxmox_schema::api;
-use pbs_api_types::BackupNamespace;
+use pbs_api_types::{BackupArchiveName, BackupNamespace};
use pbs_client::pxar::tools::get_remote_pxar_reader;
-use pbs_client::tools::has_pxar_filename_extension;
use pbs_client::tools::key_source::get_encryption_key_password;
use pbs_client::{BackupReader, RemoteChunkReader};
use pbs_tools::crypt_config::CryptConfig;
@@ -90,7 +89,8 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
let (manifest, _) = client.download_manifest().await?;
manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
- let file_info = match manifest.lookup_file_info(CATALOG_NAME) {
+ let catalog_name: BackupArchiveName = CATALOG_NAME.try_into()?;
+ let file_info = match manifest.lookup_file_info(&catalog_name) {
Ok(file_info) => file_info,
Err(err) => {
let mut metadata_archives = Vec::new();
@@ -104,7 +104,7 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
for archive in &metadata_archives {
let (reader, archive_size) = get_remote_pxar_reader(
- &archive,
+ &archive.as_str().try_into()?,
client.clone(),
&manifest,
crypt_config.clone(),
@@ -128,7 +128,7 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
};
let index = client
- .download_dynamic_index(&manifest, CATALOG_NAME)
+ .download_dynamic_index(&manifest, &catalog_name)
.await?;
let most_used = index.find_most_used_chunks(8);
@@ -170,8 +170,7 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
description: "Group/Snapshot path.",
},
"archive-name": {
- type: String,
- description: "Backup archive name.",
+ type: BackupArchiveName,
},
"repository": {
optional: true,
@@ -195,7 +194,8 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
let client = connect(&repo)?;
let backup_ns = optional_ns_param(¶m)?;
let path = required_string_param(¶m, "snapshot")?;
- let archive_name = required_string_param(¶m, "archive-name")?;
+ let server_archive_name: BackupArchiveName =
+ required_string_param(¶m, "archive-name")?.try_into()?;
let backup_dir = dir_or_last_from_group(&client, &repo, &backup_ns, path).await?;
@@ -214,9 +214,7 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
}
};
- let server_archive_name = if has_pxar_filename_extension(archive_name, false) {
- format!("{}.didx", archive_name)
- } else {
+ if !server_archive_name.has_pxar_filename_extension() {
bail!("Can only mount pxar archives.");
};
@@ -233,7 +231,8 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
let (manifest, _) = client.download_manifest().await?;
manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
- if let Err(_err) = manifest.lookup_file_info(CATALOG_NAME) {
+ let catalog_name: BackupArchiveName = CATALOG_NAME.try_into().unwrap();
+ if let Err(_err) = manifest.lookup_file_info(&catalog_name) {
// No catalog, fallback to pxar archive accessor if present
let accessor = helper::get_pxar_fuse_accessor(
&server_archive_name,
@@ -243,7 +242,7 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
)
.await?;
- let state = Shell::new(None, &server_archive_name, accessor).await?;
+ let state = Shell::new(None, &server_archive_name.as_ref(), accessor).await?;
log::info!("Starting interactive shell");
state.shell().await?;
record_repository(&repo);
@@ -267,11 +266,11 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
// Note: do not use values stored in index (not trusted) - instead, computed them again
let (csum, size) = index.compute_csum();
- manifest.verify_file(CATALOG_NAME, &csum, size)?;
+ manifest.verify_file(&catalog_name, &csum, size)?;
let most_used = index.find_most_used_chunks(8);
- let file_info = manifest.lookup_file_info(CATALOG_NAME)?;
+ let file_info = manifest.lookup_file_info(&catalog_name)?;
let chunk_reader = RemoteChunkReader::new(
client.clone(),
crypt_config,
@@ -286,7 +285,7 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
catalogfile.seek(SeekFrom::Start(0))?;
let catalog_reader = CatalogReader::new(catalogfile);
- let state = Shell::new(Some(catalog_reader), &server_archive_name, decoder).await?;
+ let state = Shell::new(Some(catalog_reader), &server_archive_name.as_ref(), decoder).await?;
log::info!("Starting interactive shell");
state.shell().await?;
diff --git a/proxmox-backup-client/src/helper.rs b/proxmox-backup-client/src/helper.rs
index 60355d7d0..642d66a7b 100644
--- a/proxmox-backup-client/src/helper.rs
+++ b/proxmox-backup-client/src/helper.rs
@@ -1,6 +1,7 @@
use std::sync::Arc;
use anyhow::Error;
+use pbs_api_types::BackupArchiveName;
use pbs_client::{BackupReader, RemoteChunkReader};
use pbs_datastore::BackupManifest;
use pbs_tools::crypt_config::CryptConfig;
@@ -8,7 +9,7 @@ use pbs_tools::crypt_config::CryptConfig;
use crate::{BufferedDynamicReadAt, BufferedDynamicReader, IndexFile};
pub(crate) async fn get_pxar_fuse_accessor(
- archive_name: &str,
+ archive_name: &BackupArchiveName,
client: Arc<BackupReader>,
manifest: &BackupManifest,
crypt_config: Option<Arc<CryptConfig>>,
@@ -44,7 +45,7 @@ pub(crate) async fn get_pxar_fuse_accessor(
}
pub(crate) async fn get_pxar_fuse_reader(
- archive_name: &str,
+ archive_name: &BackupArchiveName,
client: Arc<BackupReader>,
manifest: &BackupManifest,
crypt_config: Option<Arc<CryptConfig>>,
@@ -57,7 +58,7 @@ pub(crate) async fn get_pxar_fuse_reader(
}
pub(crate) async fn get_buffered_pxar_reader(
- archive_name: &str,
+ archive_name: &BackupArchiveName,
client: Arc<BackupReader>,
manifest: &BackupManifest,
crypt_config: Option<Arc<CryptConfig>>,
diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs
index f6fb3555e..c699e7687 100644
--- a/proxmox-backup-client/src/main.rs
+++ b/proxmox-backup-client/src/main.rs
@@ -25,10 +25,10 @@ use pxar::accessor::aio::Accessor;
use pxar::accessor::{MaybeReady, ReadAt, ReadAtOperation};
use pbs_api_types::{
- ArchiveType, Authid, BackupDir, BackupGroup, BackupNamespace, BackupPart, BackupType,
- ClientRateLimitConfig, CryptMode, Fingerprint, GroupListItem, PruneJobOptions, PruneListItem,
- RateLimitConfig, SnapshotListItem, StorageStatus, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA,
- BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA,
+ ArchiveType, Authid, BackupArchiveName, BackupDir, BackupGroup, BackupNamespace, BackupPart,
+ BackupType, ClientRateLimitConfig, CryptMode, Fingerprint, GroupListItem, PruneJobOptions,
+ PruneListItem, RateLimitConfig, SnapshotListItem, StorageStatus, BACKUP_ID_SCHEMA,
+ BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA,
};
use pbs_client::catalog_shell::Shell;
use pbs_client::pxar::{ErrorHandler as PxarErrorHandler, MetadataArchiveReader, PxarPrevRef};
@@ -36,7 +36,7 @@ use pbs_client::tools::{
complete_archive_name, complete_auth_id, complete_backup_group, complete_backup_snapshot,
complete_backup_source, complete_chunk_size, complete_group_or_snapshot,
complete_img_archive_name, complete_namespace, complete_pxar_archive_name, complete_repository,
- connect, connect_rate_limited, extract_repository_from_value, has_pxar_filename_extension,
+ connect, connect_rate_limited, extract_repository_from_value,
key_source::{
crypto_parameters, format_key_source, get_encryption_key_password, KEYFD_SCHEMA,
KEYFILE_SCHEMA, MASTER_PUBKEY_FD_SCHEMA, MASTER_PUBKEY_FILE_SCHEMA,
@@ -196,8 +196,8 @@ pub async fn dir_or_last_from_group(
async fn backup_directory<P: AsRef<Path>>(
client: &BackupWriter,
dir_path: P,
- archive_name: &str,
- payload_target: Option<&str>,
+ archive_name: &BackupArchiveName,
+ payload_target: Option<&BackupArchiveName>,
chunk_size: Option<usize>,
catalog: Option<Arc<Mutex<CatalogWriter<TokioWriterAdapter<StdChannelWriter<Error>>>>>>,
pxar_create_options: pbs_client::pxar::PxarCreateOptions,
@@ -276,7 +276,7 @@ async fn backup_directory<P: AsRef<Path>>(
async fn backup_image<P: AsRef<Path>>(
client: &BackupWriter,
image_path: P,
- archive_name: &str,
+ archive_name: &BackupArchiveName,
chunk_size: Option<usize>,
upload_options: UploadOptions,
) -> Result<BackupStats, Error> {
@@ -605,8 +605,9 @@ fn spawn_catalog_upload(
};
tokio::spawn(async move {
+ let catalog_name: BackupArchiveName = CATALOG_NAME.try_into().unwrap();
let catalog_upload_result = client
- .upload_stream(CATALOG_NAME, catalog_chunk_stream, upload_options, None)
+ .upload_stream(&catalog_name, catalog_chunk_stream, upload_options, None)
.await;
if let Err(ref err) = catalog_upload_result {
@@ -1005,13 +1006,21 @@ async fn create_backup(
};
for (backup_type, filename, target_base, extension, size) in upload_list {
- let target = format!("{target_base}.{extension}");
+ let target: BackupArchiveName = format!("{target_base}.{extension}").as_str().try_into()?;
match (backup_type, dry_run) {
// dry-run
- (BackupSpecificationType::CONFIG, true) => log_file("config file", &filename, &target),
- (BackupSpecificationType::LOGFILE, true) => log_file("log file", &filename, &target),
- (BackupSpecificationType::PXAR, true) => log_file("directory", &filename, &target),
- (BackupSpecificationType::IMAGE, true) => log_file("image", &filename, &target),
+ (BackupSpecificationType::CONFIG, true) => {
+ log_file("config file", &filename, target.as_ref())
+ }
+ (BackupSpecificationType::LOGFILE, true) => {
+ log_file("log file", &filename, target.as_ref())
+ }
+ (BackupSpecificationType::PXAR, true) => {
+ log_file("directory", &filename, target.as_ref())
+ }
+ (BackupSpecificationType::IMAGE, true) => {
+ log_file("image", &filename, &target.as_ref())
+ }
// no dry-run
(BackupSpecificationType::CONFIG, false) => {
let upload_options = UploadOptions {
@@ -1020,11 +1029,11 @@ async fn create_backup(
..UploadOptions::default()
};
- log_file("config file", &filename, &target);
+ log_file("config file", &filename, target.as_ref());
let stats = client
- .upload_blob_from_file(&filename, &target, upload_options)
+ .upload_blob_from_file(&filename, target.as_ref(), upload_options)
.await?;
- manifest.add_file(target, stats.size, stats.csum, crypto.mode)?;
+ manifest.add_file(&target, stats.size, stats.csum, crypto.mode)?;
}
(BackupSpecificationType::LOGFILE, false) => {
// fixme: remove - not needed anymore ?
@@ -1034,11 +1043,11 @@ async fn create_backup(
..UploadOptions::default()
};
- log_file("log file", &filename, &target);
+ log_file("log file", &filename, target.as_ref());
let stats = client
- .upload_blob_from_file(&filename, &target, upload_options)
+ .upload_blob_from_file(&filename, target.as_ref(), upload_options)
.await?;
- manifest.add_file(target, stats.size, stats.csum, crypto.mode)?;
+ manifest.add_file(&target, stats.size, stats.csum, crypto.mode)?;
}
(BackupSpecificationType::PXAR, false) => {
let target_base = if let Some(base) = target_base.strip_suffix(".pxar") {
@@ -1050,8 +1059,14 @@ async fn create_backup(
let (target, payload_target) =
if detection_mode.is_metadata() || detection_mode.is_data() {
(
- format!("{target_base}.mpxar.{extension}"),
- Some(format!("{target_base}.ppxar.{extension}")),
+ format!("{target_base}.mpxar.{extension}")
+ .as_str()
+ .try_into()?,
+ Some(
+ format!("{target_base}.ppxar.{extension}")
+ .as_str()
+ .try_into()?,
+ ),
)
} else {
(target, None)
@@ -1065,12 +1080,12 @@ async fn create_backup(
catalog_result_rx = Some(catalog_upload_res.result);
}
- log_file("directory", &filename, &target);
+ log_file("directory", &filename, target.as_ref());
if let Some(catalog) = catalog.as_ref() {
catalog
.lock()
.unwrap()
- .start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?;
+ .start_directory(std::ffi::CString::new(target.as_ref())?.as_c_str())?;
}
let mut previous_ref = None;
@@ -1137,7 +1152,7 @@ async fn create_backup(
&client,
&filename,
&target,
- payload_target.as_deref(),
+ payload_target.as_ref().as_deref(),
chunk_size_opt,
catalog.as_ref().cloned(),
pxar_options,
@@ -1147,20 +1162,20 @@ async fn create_backup(
if let Some(payload_stats) = payload_stats {
manifest.add_file(
- payload_target
+ &payload_target
.ok_or_else(|| format_err!("missing payload target archive"))?,
payload_stats.size,
payload_stats.csum,
crypto.mode,
)?;
}
- manifest.add_file(target, stats.size, stats.csum, crypto.mode)?;
+ manifest.add_file(&target, stats.size, stats.csum, crypto.mode)?;
if let Some(catalog) = catalog.as_ref() {
catalog.lock().unwrap().end_directory()?;
}
}
(BackupSpecificationType::IMAGE, false) => {
- log_file("image", &filename, &target);
+ log_file("image", &filename, target.as_ref());
let upload_options = UploadOptions {
previous_manifest: previous_manifest.clone(),
@@ -1172,7 +1187,7 @@ async fn create_backup(
let stats =
backup_image(&client, &filename, &target, chunk_size_opt, upload_options)
.await?;
- manifest.add_file(target, stats.size, stats.csum, crypto.mode)?;
+ manifest.add_file(&target, stats.size, stats.csum, crypto.mode)?;
}
}
}
@@ -1194,12 +1209,17 @@ async fn create_backup(
if let Some(catalog_result_rx) = catalog_result_rx {
let stats = catalog_result_rx.await??;
- manifest.add_file(CATALOG_NAME.to_owned(), stats.size, stats.csum, crypto.mode)?;
+ manifest.add_file(
+ &CATALOG_NAME.try_into()?,
+ stats.size,
+ stats.csum,
+ crypto.mode,
+ )?;
}
}
if let Some(rsa_encrypted_key) = rsa_encrypted_key {
- let target = ENCRYPTED_KEY_BLOB_NAME;
+ let target: BackupArchiveName = ENCRYPTED_KEY_BLOB_NAME.try_into()?;
log::info!("Upload RSA encoded key to '{}' as {}", repo, target);
let options = UploadOptions {
compress: false,
@@ -1207,9 +1227,9 @@ async fn create_backup(
..UploadOptions::default()
};
let stats = client
- .upload_blob_from_data(rsa_encrypted_key, target, options)
+ .upload_blob_from_data(rsa_encrypted_key, target.as_ref(), options)
.await?;
- manifest.add_file(target.to_string(), stats.size, stats.csum, crypto.mode)?;
+ manifest.add_file(&target, stats.size, stats.csum, crypto.mode)?;
}
// create manifest (index.json)
// manifests are never encrypted, but include a signature
@@ -1238,7 +1258,7 @@ async fn create_backup(
}
async fn prepare_reference(
- target: &str,
+ target: &BackupArchiveName,
manifest: Arc<BackupManifest>,
backup_writer: &BackupWriter,
backup_reader: Arc<BackupReader>,
@@ -1250,7 +1270,11 @@ async fn prepare_reference(
Ok((target, payload_target)) => (target, payload_target),
Err(_) => return Ok(None),
};
- let payload_target = payload_target.unwrap_or_default();
+ let payload_target = if let Some(payload_target) = payload_target {
+ payload_target
+ } else {
+ return Ok(None);
+ };
let metadata_ref_index = if let Ok(index) = backup_reader
.download_dynamic_index(&manifest, &target)
@@ -1299,7 +1323,7 @@ async fn prepare_reference(
Ok(Some(pbs_client::pxar::PxarPrevRef {
accessor,
payload_index: payload_ref_index,
- archive_name: target,
+ archive_name: target.to_string(),
}))
}
@@ -1486,7 +1510,8 @@ async fn restore(
) -> Result<Value, Error> {
let repo = extract_repository_from_value(¶m)?;
- let archive_name = json::required_string_param(¶m, "archive-name")?;
+ let archive_name: BackupArchiveName =
+ json::required_string_param(¶m, "archive-name")?.try_into()?;
let rate_limit = RateLimitConfig::from_client_config(limit);
@@ -1525,11 +1550,9 @@ async fn restore(
)
.await?;
- let (archive_name, archive_type) = parse_archive_type(archive_name);
-
let (manifest, backup_index_data) = client.download_manifest().await?;
- if archive_name == ENCRYPTED_KEY_BLOB_NAME && crypt_config.is_none() {
+ if archive_name.as_ref() == ENCRYPTED_KEY_BLOB_NAME && crypt_config.is_none() {
log::info!("Restoring encrypted key blob without original key - skipping manifest fingerprint check!")
} else {
if manifest.signature.is_some() {
@@ -1543,7 +1566,7 @@ async fn restore(
manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
}
- if archive_name == MANIFEST_BLOB_NAME {
+ if archive_name.as_ref() == MANIFEST_BLOB_NAME {
if let Some(target) = target {
replace_file(target, &backup_index_data, CreateOptions::new(), false)?;
} else {
@@ -1557,7 +1580,7 @@ async fn restore(
return Ok(Value::Null);
}
- if archive_type == ArchiveType::Blob {
+ if archive_name.archive_type() == ArchiveType::Blob {
let mut reader = client.download_blob(&manifest, &archive_name).await?;
if let Some(target) = target {
@@ -1576,7 +1599,7 @@ async fn restore(
std::io::copy(&mut reader, &mut writer)
.map_err(|err| format_err!("unable to pipe data - {}", err))?;
}
- } else if archive_type == ArchiveType::DynamicIndex {
+ } else if archive_name.archive_type() == ArchiveType::DynamicIndex {
let (archive_name, payload_archive_name) =
pbs_client::tools::get_pxar_archive_names(&archive_name, &manifest)?;
@@ -1680,7 +1703,7 @@ async fn restore(
std::io::copy(&mut reader, &mut writer)
.map_err(|err| format_err!("unable to pipe data - {}", err))?;
}
- } else if archive_type == ArchiveType::FixedIndex {
+ } else if archive_name.archive_type() == ArchiveType::FixedIndex {
let file_info = manifest.lookup_file_info(&archive_name)?;
let index = client
.download_fixed_index(&manifest, &archive_name)
diff --git a/proxmox-backup-client/src/mount.rs b/proxmox-backup-client/src/mount.rs
index c15e030f5..0048a8ad4 100644
--- a/proxmox-backup-client/src/mount.rs
+++ b/proxmox-backup-client/src/mount.rs
@@ -18,8 +18,7 @@ use proxmox_schema::*;
use proxmox_sortable_macro::sortable;
use proxmox_systemd;
-use pbs_api_types::BackupNamespace;
-use pbs_client::tools::has_pxar_filename_extension;
+use pbs_api_types::{ArchiveType, BackupArchiveName, BackupNamespace};
use pbs_client::tools::key_source::get_encryption_key_password;
use pbs_client::{BackupReader, RemoteChunkReader};
use pbs_datastore::cached_chunk_reader::CachedChunkReader;
@@ -47,11 +46,7 @@ const API_METHOD_MOUNT: ApiMethod = ApiMethod::new(
false,
&StringSchema::new("Group/Snapshot path.").schema()
),
- (
- "archive-name",
- false,
- &StringSchema::new("Backup archive name.").schema()
- ),
+ ("archive-name", false, &BackupArchiveName::API_SCHEMA),
(
"target",
false,
@@ -87,11 +82,7 @@ WARNING: Only do this with *trusted* backups!",
false,
&StringSchema::new("Group/Snapshot path.").schema()
),
- (
- "archive-name",
- false,
- &StringSchema::new("Backup archive name.").schema()
- ),
+ ("archive-name", false, &BackupArchiveName::API_SCHEMA),
("repository", true, &REPO_URL_SCHEMA),
(
"keyfile",
@@ -208,7 +199,8 @@ fn mount(
async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
let repo = extract_repository_from_value(¶m)?;
- let archive_name = required_string_param(¶m, "archive-name")?;
+ let server_archive_name: BackupArchiveName =
+ required_string_param(¶m, "archive-name")?.try_into()?;
let client = connect(&repo)?;
let target = param["target"].as_str();
@@ -230,16 +222,14 @@ async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
}
};
- let server_archive_name = if has_pxar_filename_extension(archive_name, false) {
+ if server_archive_name.has_pxar_filename_extension() {
if target.is_none() {
bail!("use the 'mount' command to mount pxar archives");
}
- format!("{}.didx", archive_name)
- } else if archive_name.ends_with(".img") {
+ } else if server_archive_name.ends_with(".img.fidx") {
if target.is_some() {
bail!("use the 'map' command to map drive images");
}
- format!("{}.fidx", archive_name)
} else {
bail!("Can only mount/map pxar archives and drive images.");
};
@@ -291,7 +281,7 @@ async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
let mut interrupt =
futures::future::select(interrupt_int.recv().boxed(), interrupt_term.recv().boxed());
- if server_archive_name.ends_with(".didx") {
+ if server_archive_name.archive_type() == ArchiveType::DynamicIndex {
let decoder = helper::get_pxar_fuse_accessor(
&server_archive_name,
client.clone(),
@@ -312,7 +302,7 @@ async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
// exit on interrupted
}
}
- } else if server_archive_name.ends_with(".fidx") {
+ } else if server_archive_name.archive_type() == ArchiveType::FixedIndex {
let file_info = manifest.lookup_file_info(&server_archive_name)?;
let index = client
.download_fixed_index(&manifest, &server_archive_name)
@@ -326,7 +316,10 @@ async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
);
let reader = CachedChunkReader::new(chunk_reader, index, 8).seekable();
- let name = &format!("{}:{}/{}", repo, path, archive_name);
+ let name = &format!(
+ "{repo}:{path}/{}",
+ server_archive_name.without_type_extension(),
+ );
let name_escaped = proxmox_systemd::escape_unit(name, false);
let mut session =
diff --git a/proxmox-file-restore/src/main.rs b/proxmox-file-restore/src/main.rs
index 08354b454..c4bde0699 100644
--- a/proxmox-file-restore/src/main.rs
+++ b/proxmox-file-restore/src/main.rs
@@ -5,6 +5,7 @@ use std::sync::Arc;
use anyhow::{bail, format_err, Error};
use futures::StreamExt;
+use pbs_api_types::BackupArchiveName;
use serde_json::{json, Value};
use tokio::io::AsyncWriteExt;
@@ -149,9 +150,10 @@ async fn list_files(
Ok(entries)
}
ExtractPath::Pxar(file, mut path) => {
- if let Ok(file_info) = manifest.lookup_file_info(CATALOG_NAME) {
+ let catalog_name: BackupArchiveName = CATALOG_NAME.try_into()?;
+ if let Ok(file_info) = manifest.lookup_file_info(&catalog_name) {
let index = client
- .download_dynamic_index(&manifest, CATALOG_NAME)
+ .download_dynamic_index(&manifest, &catalog_name)
.await?;
let most_used = index.find_most_used_chunks(8);
let chunk_reader = RemoteChunkReader::new(
@@ -172,6 +174,7 @@ async fn list_files(
path = vec![b'/'];
}
+ let file: BackupArchiveName = file.as_str().try_into()?;
let (archive_name, _payload_archive_name) =
pbs_client::tools::get_pxar_archive_names(&file, &manifest)?;
@@ -191,7 +194,7 @@ async fn list_files(
pbs_client::pxar::tools::pxar_metadata_catalog_lookup(
accessor,
path,
- Some(&archive_name),
+ Some(archive_name.as_ref()),
)
.await
}
@@ -476,10 +479,11 @@ async fn extract(
match path {
ExtractPath::Pxar(archive_name, path) => {
+ let archive_name: BackupArchiveName = archive_name.as_str().try_into()?;
let (archive_name, payload_archive_name) =
pbs_client::tools::get_pxar_archive_names(&archive_name, &manifest)?;
let (reader, archive_size) = get_remote_pxar_reader(
- &archive_name,
+ &archive_name.try_into()?,
client.clone(),
&manifest,
crypt_config.clone(),
diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index b73ad0ff0..f8856e855 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -34,15 +34,15 @@ use pxar::accessor::aio::Accessor;
use pxar::EntryKind;
use pbs_api_types::{
- print_ns_and_snapshot, print_store_and_ns, Authid, BackupContent, BackupNamespace, BackupType,
- Counts, CryptMode, DataStoreConfig, DataStoreListItem, DataStoreStatus,
- GarbageCollectionJobStatus, GroupListItem, JobScheduleStatus, KeepOptions, Operation,
- PruneJobOptions, SnapshotListItem, SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA,
- BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA,
- DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA, MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA,
- PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE,
- PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID, UPID_SCHEMA,
- VERIFICATION_OUTDATED_AFTER_SCHEMA,
+ print_ns_and_snapshot, print_store_and_ns, ArchiveType, Authid, BackupArchiveName,
+ BackupContent, BackupNamespace, BackupType, Counts, CryptMode, DataStoreConfig,
+ DataStoreListItem, DataStoreStatus, GarbageCollectionJobStatus, GroupListItem,
+ JobScheduleStatus, KeepOptions, Operation, PruneJobOptions, SnapshotListItem,
+ SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA,
+ BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA,
+ MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
+ PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID,
+ UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA,
};
use pbs_client::pxar::{create_tar, create_zip};
use pbs_config::CachedUserInfo;
@@ -1468,12 +1468,13 @@ pub fn download_file_decoded(
&backup_dir_api.group,
)?;
- let file_name = required_string_param(¶m, "file-name")?.to_owned();
+ let file_name: BackupArchiveName =
+ required_string_param(¶m, "file-name")?.try_into()?;
let backup_dir = datastore.backup_dir(backup_ns.clone(), backup_dir_api.clone())?;
let (manifest, files) = read_backup_index(&backup_dir)?;
for file in files {
- if file.filename == file_name && file.crypt_mode == Some(CryptMode::Encrypt) {
+ if file.filename == file_name.as_ref() && file.crypt_mode == Some(CryptMode::Encrypt) {
bail!("cannot decode '{}' - is encrypted", file_name);
}
}
@@ -1488,12 +1489,10 @@ pub fn download_file_decoded(
let mut path = datastore.base_path();
path.push(backup_dir.relative_path());
- path.push(&file_name);
+ path.push(file_name.as_ref());
- let (_, extension) = file_name.rsplit_once('.').unwrap();
-
- let body = match extension {
- "didx" => {
+ let body = match file_name.archive_type() {
+ ArchiveType::DynamicIndex => {
let index = DynamicIndexReader::open(&path).map_err(|err| {
format_err!("unable to read dynamic index '{:?}' - {}", &path, err)
})?;
@@ -1507,7 +1506,7 @@ pub fn download_file_decoded(
err
}))
}
- "fidx" => {
+ ArchiveType::FixedIndex => {
let index = FixedIndexReader::open(&path).map_err(|err| {
format_err!("unable to read fixed index '{:?}' - {}", &path, err)
})?;
@@ -1526,7 +1525,7 @@ pub fn download_file_decoded(
),
)
}
- "blob" => {
+ ArchiveType::Blob => {
let file = std::fs::File::open(&path)
.map_err(|err| http_err!(BAD_REQUEST, "File open failed: {}", err))?;
@@ -1541,9 +1540,6 @@ pub fn download_file_decoded(
),
)
}
- extension => {
- bail!("cannot download '{}' files", extension);
- }
};
// fixme: set other headers ?
@@ -1658,7 +1654,7 @@ fn decode_path(path: &str) -> Result<Vec<u8>, Error> {
type: String,
},
"archive-name": {
- schema: BACKUP_ARCHIVE_NAME_SCHEMA,
+ type: BackupArchiveName,
optional: true,
},
},
@@ -1675,12 +1671,12 @@ pub async fn catalog(
ns: Option<BackupNamespace>,
backup_dir: pbs_api_types::BackupDir,
filepath: String,
- archive_name: Option<String>,
+ archive_name: Option<BackupArchiveName>,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<Vec<ArchiveEntry>, Error> {
let file_name = archive_name
.clone()
- .unwrap_or_else(|| CATALOG_NAME.to_string());
+ .unwrap_or_else(|| CATALOG_NAME.try_into().unwrap());
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
@@ -1700,7 +1696,7 @@ pub async fn catalog(
let (manifest, files) = read_backup_index(&backup_dir)?;
for file in files {
- if file.filename == file_name && file.crypt_mode == Some(CryptMode::Encrypt) {
+ if file.filename == file_name.as_ref() && file.crypt_mode == Some(CryptMode::Encrypt) {
bail!("cannot decode '{file_name}' - is encrypted");
}
}
@@ -1709,7 +1705,7 @@ pub async fn catalog(
tokio::task::spawn_blocking(move || {
let mut path = datastore.base_path();
path.push(backup_dir.relative_path());
- path.push(&file_name);
+ path.push(file_name.as_ref());
let index = DynamicIndexReader::open(&path)
.map_err(|err| format_err!("unable to read dynamic index '{path:?}' - {err}"))?;
@@ -1759,7 +1755,7 @@ pub const API_METHOD_PXAR_FILE_DOWNLOAD: ApiMethod = ApiMethod::new(
("backup-time", false, &BACKUP_TIME_SCHEMA),
("filepath", false, &StringSchema::new("Base64 encoded path").schema()),
("tar", true, &BooleanSchema::new("Download as .tar.zst").schema()),
- ("archive-name", true, &BACKUP_ARCHIVE_NAME_SCHEMA),
+ ("archive-name", true, &BackupArchiveName::API_SCHEMA),
]),
)
).access(
@@ -1774,11 +1770,11 @@ fn get_local_pxar_reader(
datastore: Arc<DataStore>,
manifest: &BackupManifest,
backup_dir: &BackupDir,
- pxar_name: &str,
+ pxar_name: &BackupArchiveName,
) -> Result<(LocalDynamicReadAt<LocalChunkReader>, u64), Error> {
let mut path = datastore.base_path();
path.push(backup_dir.relative_path());
- path.push(pxar_name);
+ path.push(pxar_name.as_ref());
let index = DynamicIndexReader::open(&path)
.map_err(|err| format_err!("unable to read dynamic index '{:?}' - {}", &path, err))?;
@@ -1836,16 +1832,16 @@ pub fn pxar_file_download(
let file_path = split.next().unwrap_or(b"/");
(pxar_name.to_owned(), file_path.to_owned())
};
- let pxar_name = std::str::from_utf8(&pxar_name)?;
+ let pxar_name: BackupArchiveName = std::str::from_utf8(&pxar_name)?.try_into()?;
let (manifest, files) = read_backup_index(&backup_dir)?;
for file in files {
- if file.filename == pxar_name && file.crypt_mode == Some(CryptMode::Encrypt) {
+ if file.filename == pxar_name.as_ref() && file.crypt_mode == Some(CryptMode::Encrypt) {
bail!("cannot decode '{}' - is encrypted", pxar_name);
}
}
let (pxar_name, payload_archive_name) =
- pbs_client::tools::get_pxar_archive_names(pxar_name, &manifest)?;
+ pbs_client::tools::get_pxar_archive_names(&pxar_name, &manifest)?;
let (reader, archive_size) =
get_local_pxar_reader(datastore.clone(), &manifest, &backup_dir, &pxar_name)?;
diff --git a/src/bin/proxmox_backup_debug/diff.rs b/src/bin/proxmox_backup_debug/diff.rs
index b0436d048..dcd351d93 100644
--- a/src/bin/proxmox_backup_debug/diff.rs
+++ b/src/bin/proxmox_backup_debug/diff.rs
@@ -13,7 +13,7 @@ use proxmox_human_byte::HumanByte;
use proxmox_router::cli::{CliCommand, CliCommandMap, CommandLineInterface};
use proxmox_schema::api;
-use pbs_api_types::{BackupNamespace, BackupPart};
+use pbs_api_types::{BackupArchiveName, BackupNamespace, BackupPart};
use pbs_client::tools::key_source::{
crypto_parameters, format_key_source, get_encryption_key_password, KEYFD_SCHEMA,
};
@@ -70,8 +70,7 @@ pub fn diff_commands() -> CommandLineInterface {
type: String,
},
"archive-name": {
- description: "Name of the .pxar archive",
- type: String,
+ type: BackupArchiveName,
},
"repository": {
optional: true,
@@ -106,7 +105,7 @@ pub fn diff_commands() -> CommandLineInterface {
async fn diff_archive_cmd(
prev_snapshot: String,
snapshot: String,
- archive_name: String,
+ archive_name: BackupArchiveName,
compare_content: bool,
color: Option<ColorMode>,
ns: Option<BackupNamespace>,
@@ -140,12 +139,11 @@ async fn diff_archive_cmd(
let output_params = OutputParams { color };
- if archive_name.ends_with(".pxar") {
- let file_name = format!("{}.didx", archive_name);
+ if archive_name.ends_with(".pxar.didx") {
diff_archive(
&prev_snapshot,
&snapshot,
- &file_name,
+ &archive_name,
&repo_params,
compare_content,
&output_params,
@@ -161,7 +159,7 @@ async fn diff_archive_cmd(
async fn diff_archive(
snapshot_a: &str,
snapshot_b: &str,
- file_name: &str,
+ file_name: &BackupArchiveName,
repo_params: &RepoParams,
compare_contents: bool,
output_params: &OutputParams,
@@ -249,7 +247,7 @@ struct OutputParams {
async fn open_dynamic_index(
snapshot: &str,
- archive_name: &str,
+ archive_name: &BackupArchiveName,
params: &RepoParams,
) -> Result<(DynamicIndexReader, Accessor), Error> {
let backup_reader = create_backup_reader(snapshot, params).await?;
diff --git a/src/server/pull.rs b/src/server/pull.rs
index 8cbfdb399..baaedbffe 100644
--- a/src/server/pull.rs
+++ b/src/server/pull.rs
@@ -11,9 +11,9 @@ use proxmox_human_byte::HumanByte;
use tracing::info;
use pbs_api_types::{
- print_store_and_ns, ArchiveType, Authid, BackupDir, BackupGroup, BackupNamespace, GroupFilter,
- Operation, RateLimitConfig, Remote, MAX_NAMESPACE_DEPTH, PRIV_DATASTORE_AUDIT,
- PRIV_DATASTORE_BACKUP,
+ print_store_and_ns, ArchiveType, Authid, BackupArchiveName, BackupDir, BackupGroup,
+ BackupNamespace, GroupFilter, Operation, RateLimitConfig, Remote, MAX_NAMESPACE_DEPTH,
+ PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
};
use pbs_client::BackupRepository;
use pbs_config::CachedUserInfo;
@@ -381,11 +381,12 @@ async fn pull_snapshot<'a>(
path.push(&item.filename);
if path.exists() {
- match ArchiveType::from_path(&item.filename)? {
+ let filename: BackupArchiveName = item.filename.as_str().try_into()?;
+ match filename.archive_type() {
ArchiveType::DynamicIndex => {
let index = DynamicIndexReader::open(&path)?;
let (csum, size) = index.compute_csum();
- match manifest.verify_file(&item.filename, &csum, size) {
+ match manifest.verify_file(&filename, &csum, size) {
Ok(_) => continue,
Err(err) => {
info!("detected changed file {path:?} - {err}");
@@ -395,7 +396,7 @@ async fn pull_snapshot<'a>(
ArchiveType::FixedIndex => {
let index = FixedIndexReader::open(&path)?;
let (csum, size) = index.compute_csum();
- match manifest.verify_file(&item.filename, &csum, size) {
+ match manifest.verify_file(&filename, &csum, size) {
Ok(_) => continue,
Err(err) => {
info!("detected changed file {path:?} - {err}");
@@ -405,7 +406,7 @@ async fn pull_snapshot<'a>(
ArchiveType::Blob => {
let mut tmpfile = std::fs::File::open(&path)?;
let (csum, size) = sha256(&mut tmpfile)?;
- match manifest.verify_file(&item.filename, &csum, size) {
+ match manifest.verify_file(&filename, &csum, size) {
Ok(_) => continue,
Err(err) => {
info!("detected changed file {path:?} - {err}");
--
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-24 8:01 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-24 8:01 [pbs-devel] [PATCH v3 proxmox-backup 0/5] introduce dedcated archive name api type Christian Ebner
2024-10-24 8:01 ` [pbs-devel] [PATCH v3 proxmox-backup 1/5] datastore: move `ArchiveType` to api types Christian Ebner
2024-10-24 8:01 ` [pbs-devel] [PATCH v3 proxmox-backup 2/5] api types: introduce `BackupArchiveName` type Christian Ebner
2024-10-25 12:15 ` Fabian Grünbichler
2024-11-04 11:56 ` Christian Ebner
2024-11-04 12:23 ` Fabian Grünbichler
2024-10-24 8:01 ` Christian Ebner [this message]
2024-10-24 8:01 ` [pbs-devel] [PATCH v3 proxmox-backup 4/5] client: drop unused parse_archive_type helper Christian Ebner
2024-10-24 8:01 ` [pbs-devel] [PATCH v3 proxmox-backup 5/5] api types: add unit tests for backup archive name parsing Christian Ebner
2024-10-24 9:21 ` [pbs-devel] [PATCH v3 proxmox-backup 0/5] introduce dedcated archive name api type Gabriel Goller
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=20241024080150.30200-4-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