diff --git a/src/server/pull.rs b/src/server/pull.rs index 616d45eb..8fb491cd 100644 --- a/src/server/pull.rs +++ b/src/server/pull.rs @@ -28,8 +28,8 @@ use pbs_datastore::{check_backup_owner, DataStore, StoreProgress}; use pbs_tools::sha::sha256; use super::sync::{ - check_namespace_depth_limit, LocalSource, RemoteSource, RemovedVanishedStats, SkipInfo, - SkipReason, SyncSource, SyncSourceReader, SyncStats, + check_namespace_depth_limit, ignore_not_verified_or_encrypted, LocalSource, RemoteSource, + RemovedVanishedStats, SkipInfo, SkipReason, SyncSource, SyncSourceReader, SyncStats, }; use crate::backup::{check_ns_modification_privs, check_ns_privs}; use crate::tools::parallel_handler::ParallelHandler; @@ -344,6 +344,7 @@ async fn pull_single_archive<'a>( /// -- if not, pull it from the remote /// - Download log if not already existing async fn pull_snapshot<'a>( + params: &PullParameters, reader: Arc, snapshot: &'a pbs_datastore::BackupDir, downloaded_chunks: Arc>>, @@ -402,6 +403,22 @@ async fn pull_snapshot<'a>( let manifest = BackupManifest::try_from(tmp_manifest_blob)?; + if ignore_not_verified_or_encrypted( + &manifest, + snapshot.dir(), + params.verified_only, + params.encrypted_only, + ) { + if is_new { + let path = snapshot.full_path(); + // safe to remove as locked by caller + std::fs::remove_dir_all(&path).map_err(|err| { + format_err!("removing temporary backup snapshot {path:?} failed - {err}") + })?; + } + return Ok(sync_stats); + } + for item in manifest.files() { let mut path = snapshot.full_path(); path.push(&item.filename); @@ -466,6 +483,7 @@ async fn pull_snapshot<'a>( /// The `reader` is configured to read from the source backup directory, while the /// `snapshot` is pointing to the local datastore and target namespace. async fn pull_snapshot_from<'a>( + params: &PullParameters, reader: Arc, snapshot: &'a pbs_datastore::BackupDir, downloaded_chunks: Arc>>, @@ -475,7 +493,7 @@ async fn pull_snapshot_from<'a>( .datastore() .create_locked_backup_dir(snapshot.backup_ns(), snapshot.as_ref())?; - let result = pull_snapshot(reader, snapshot, downloaded_chunks, corrupt, is_new).await; + let result = pull_snapshot(params, reader, snapshot, downloaded_chunks, corrupt, is_new).await; if is_new { // Cleanup directory on error if snapshot was not present before @@ -621,8 +639,14 @@ async fn pull_group( .source .reader(source_namespace, &from_snapshot) .await?; - let result = - pull_snapshot_from(reader, &to_snapshot, downloaded_chunks.clone(), corrupt).await; + let result = pull_snapshot_from( + params, + reader, + &to_snapshot, + downloaded_chunks.clone(), + corrupt, + ) + .await; progress.done_snapshots = pos as u64 + 1; info!("percentage done: {progress}"); diff --git a/src/server/push.rs b/src/server/push.rs index 1fb447b5..e71012ed 100644 --- a/src/server/push.rs +++ b/src/server/push.rs @@ -26,8 +26,8 @@ use pbs_datastore::read_chunk::AsyncReadChunk; use pbs_datastore::{DataStore, StoreProgress}; use super::sync::{ - check_namespace_depth_limit, LocalSource, RemovedVanishedStats, SkipInfo, SkipReason, - SyncSource, SyncStats, + check_namespace_depth_limit, ignore_not_verified_or_encrypted, LocalSource, + RemovedVanishedStats, SkipInfo, SkipReason, SyncSource, SyncStats, }; use crate::api2::config::remote; @@ -810,6 +810,15 @@ pub(crate) async fn push_snapshot( } }; + if ignore_not_verified_or_encrypted( + &source_manifest, + snapshot, + params.verified_only, + params.encrypted_only, + ) { + return Ok(stats); + } + // Writer instance locks the snapshot on the remote side let backup_writer = BackupWriter::start( ¶ms.target.client, diff --git a/src/server/sync.rs b/src/server/sync.rs index d424a6b4..528e2054 100644 --- a/src/server/sync.rs +++ b/src/server/sync.rs @@ -20,13 +20,13 @@ use proxmox_router::HttpError; use pbs_api_types::{ Authid, BackupDir, BackupGroup, BackupNamespace, CryptMode, GroupListItem, SnapshotListItem, - SyncDirection, SyncJobConfig, CLIENT_LOG_BLOB_NAME, MAX_NAMESPACE_DEPTH, PRIV_DATASTORE_BACKUP, - PRIV_DATASTORE_READ, + SyncDirection, SyncJobConfig, VerifyState, CLIENT_LOG_BLOB_NAME, MAX_NAMESPACE_DEPTH, + PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_READ, }; use pbs_client::{BackupReader, BackupRepository, HttpClient, RemoteChunkReader}; use pbs_datastore::data_blob::DataBlob; use pbs_datastore::read_chunk::AsyncReadChunk; -use pbs_datastore::{DataStore, ListNamespacesRecursive, LocalChunkReader}; +use pbs_datastore::{BackupManifest, DataStore, ListNamespacesRecursive, LocalChunkReader}; use crate::backup::ListAccessibleBackupGroups; use crate::server::jobstate::Job; @@ -732,3 +732,34 @@ pub fn do_sync_job( Ok(upid_str) } + +pub(super) fn ignore_not_verified_or_encrypted( + manifest: &BackupManifest, + snapshot: &BackupDir, + verified_only: bool, + encrypted_only: bool, +) -> bool { + if verified_only { + match manifest.verify_state() { + Ok(Some(verify_state)) if verify_state.state == VerifyState::Ok => (), + _ => { + info!("Snapshot {snapshot} not verified but verified-only set, snapshot skipped"); + return true; + } + } + } + + if encrypted_only { + // Consider only encrypted if all files in the manifest are marked as encrypted + if !manifest + .files() + .iter() + .all(|file| file.chunk_crypt_mode() == CryptMode::Encrypt) + { + info!("Snapshot {snapshot} not encrypted but encrypted-only set, snapshot skipped"); + return true; + } + } + + false +}