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 AA8871FF18A for ; Mon, 26 May 2025 16:14:54 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 828F333FF7; Mon, 26 May 2025 16:15:07 +0200 (CEST) From: Hannes Laimer To: pbs-devel@lists.proxmox.com Date: Mon, 26 May 2025 16:14:38 +0200 Message-Id: <20250526141445.228717-6-h.laimer@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250526141445.228717-1-h.laimer@proxmox.com> References: <20250526141445.228717-1-h.laimer@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.026 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 Subject: [pbs-devel] [PATCH proxmox-backup v2 05/12] backup_info: add generics and separate functions into impl blocks 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" Signed-off-by: Hannes Laimer --- pbs-datastore/src/backup_info.rs | 583 ++++++++++++++++--------------- pbs-datastore/src/datastore.rs | 26 +- 2 files changed, 313 insertions(+), 296 deletions(-) diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs index d4732fdd..f3ca283c 100644 --- a/pbs-datastore/src/backup_info.rs +++ b/pbs-datastore/src/backup_info.rs @@ -18,7 +18,10 @@ use pbs_api_types::{ use pbs_config::{open_backup_lockfile, BackupLockGuard}; use crate::manifest::{BackupManifest, MANIFEST_LOCK_NAME}; -use crate::{DataBlob, DataStore}; +use crate::{ + chunk_store::{CanRead, CanWrite}, + DataBlob, DataStore, +}; pub const DATASTORE_LOCKS_DIR: &str = "/run/proxmox-backup/locks"; @@ -34,14 +37,14 @@ pub(crate) static OLD_LOCKING: LazyLock = LazyLock::new(|| { /// BackupGroup is a directory containing a list of BackupDir #[derive(Clone)] -pub struct BackupGroup { - store: Arc, +pub struct BackupGroup { + store: Arc>, ns: BackupNamespace, group: pbs_api_types::BackupGroup, } -impl fmt::Debug for BackupGroup { +impl fmt::Debug for BackupGroup { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BackupGroup") .field("store", &self.store.name()) @@ -51,45 +54,12 @@ impl fmt::Debug for BackupGroup { } } -impl BackupGroup { - pub(crate) fn new( - store: Arc, - ns: BackupNamespace, - group: pbs_api_types::BackupGroup, - ) -> Self { - Self { store, ns, group } - } - - /// Access the underlying [`BackupGroup`](pbs_api_types::BackupGroup). - #[inline] - pub fn group(&self) -> &pbs_api_types::BackupGroup { - &self.group - } - - #[inline] - pub fn backup_ns(&self) -> &BackupNamespace { - &self.ns - } - - #[inline] - pub fn backup_type(&self) -> BackupType { - self.group.ty - } - - #[inline] - pub fn backup_id(&self) -> &str { - &self.group.id - } - - pub fn full_group_path(&self) -> PathBuf { - self.store.group_path(&self.ns, &self.group) - } - - pub fn relative_group_path(&self) -> PathBuf { - let mut path = self.ns.path(); - path.push(self.group.ty.as_str()); - path.push(&self.group.id); - path +impl BackupGroup { + /// Returns the backup owner. + /// + /// The backup owner is the entity who first created the backup group. + pub fn get_owner(&self) -> Result { + self.store.get_owner(&self.ns, self.as_ref()) } /// Simple check whether a group exists. This does not check whether there are any snapshots, @@ -98,7 +68,7 @@ impl BackupGroup { self.full_group_path().exists() } - pub fn list_backups(&self) -> Result, Error> { + pub fn list_backups(&self) -> Result>, Error> { let mut list = vec![]; let path = self.full_group_path(); @@ -130,7 +100,7 @@ impl BackupGroup { } /// Finds the latest backup inside a backup group - pub fn last_backup(&self, only_finished: bool) -> Result, Error> { + pub fn last_backup(&self, only_finished: bool) -> Result>, Error> { let backups = self.list_backups()?; Ok(backups .into_iter() @@ -190,24 +160,13 @@ impl BackupGroup { Ok(last) } +} - pub fn matches(&self, filter: &GroupFilter) -> bool { - self.group.matches(filter) - } - - pub fn backup_dir(&self, time: i64) -> Result { - BackupDir::with_group(self.clone(), time) - } - - pub fn backup_dir_with_rfc3339>( - &self, - time_string: T, - ) -> Result { - BackupDir::with_rfc3339(self.clone(), time_string.into()) - } - - pub fn iter_snapshots(&self) -> Result { - crate::ListSnapshots::new(self.clone()) +impl BackupGroup { + /// Set the backup owner. + pub fn set_owner(&self, auth_id: &Authid, force: bool) -> Result<(), Error> { + self.store + .set_owner(&self.ns, self.as_ref(), auth_id, force) } /// Destroy the group inclusive all its backup snapshots (BackupDir's) @@ -260,32 +219,6 @@ impl BackupGroup { Ok(()) } - /// Returns the backup owner. - /// - /// The backup owner is the entity who first created the backup group. - pub fn get_owner(&self) -> Result { - self.store.get_owner(&self.ns, self.as_ref()) - } - - /// Set the backup owner. - pub fn set_owner(&self, auth_id: &Authid, force: bool) -> Result<(), Error> { - self.store - .set_owner(&self.ns, self.as_ref(), auth_id, force) - } - - /// Returns a file name for locking a group. - /// - /// The lock file will be located in: - /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}` - /// where `rpath` is the relative path of the group. - fn lock_path(&self) -> PathBuf { - let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name()); - - let rpath = Path::new(self.group.ty.as_str()).join(&self.group.id); - - path.join(lock_file_path_helper(&self.ns, rpath)) - } - /// Locks a group exclusively. pub fn lock(&self) -> Result { if *OLD_LOCKING { @@ -304,34 +237,108 @@ impl BackupGroup { } } -impl AsRef for BackupGroup { +impl BackupGroup { + pub(crate) fn new( + store: Arc>, + ns: BackupNamespace, + group: pbs_api_types::BackupGroup, + ) -> Self { + Self { store, ns, group } + } + + /// Access the underlying [`BackupGroup`](pbs_api_types::BackupGroup). + #[inline] + pub fn group(&self) -> &pbs_api_types::BackupGroup { + &self.group + } + + #[inline] + pub fn backup_ns(&self) -> &BackupNamespace { + &self.ns + } + + #[inline] + pub fn backup_type(&self) -> BackupType { + self.group.ty + } + + #[inline] + pub fn backup_id(&self) -> &str { + &self.group.id + } + + pub fn full_group_path(&self) -> PathBuf { + self.store.group_path(&self.ns, &self.group) + } + + pub fn relative_group_path(&self) -> PathBuf { + let mut path = self.ns.path(); + path.push(self.group.ty.as_str()); + path.push(&self.group.id); + path + } + + pub fn matches(&self, filter: &GroupFilter) -> bool { + self.group.matches(filter) + } + + pub fn backup_dir(&self, time: i64) -> Result, Error> { + BackupDir::with_group(self.clone(), time) + } + + pub fn backup_dir_with_rfc3339>( + &self, + time_string: D, + ) -> Result, Error> { + BackupDir::with_rfc3339(self.clone(), time_string.into()) + } + + pub fn iter_snapshots(&self) -> Result { + crate::ListSnapshots::new(self.clone()) + } + + /// Returns a file name for locking a group. + /// + /// The lock file will be located in: + /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}` + /// where `rpath` is the relative path of the group. + fn lock_path(&self) -> PathBuf { + let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name()); + + let rpath = Path::new(self.group.ty.as_str()).join(&self.group.id); + + path.join(lock_file_path_helper(&self.ns, rpath)) + } +} + +impl AsRef for BackupGroup { #[inline] fn as_ref(&self) -> &pbs_api_types::BackupNamespace { &self.ns } } -impl AsRef for BackupGroup { +impl AsRef for BackupGroup { #[inline] fn as_ref(&self) -> &pbs_api_types::BackupGroup { &self.group } } -impl From<&BackupGroup> for pbs_api_types::BackupGroup { - fn from(group: &BackupGroup) -> pbs_api_types::BackupGroup { +impl From<&BackupGroup> for pbs_api_types::BackupGroup { + fn from(group: &BackupGroup) -> pbs_api_types::BackupGroup { group.group.clone() } } -impl From for pbs_api_types::BackupGroup { - fn from(group: BackupGroup) -> pbs_api_types::BackupGroup { +impl From> for pbs_api_types::BackupGroup { + fn from(group: BackupGroup) -> pbs_api_types::BackupGroup { group.group } } -impl From for BackupGroup { - fn from(dir: BackupDir) -> BackupGroup { +impl From> for BackupGroup { + fn from(dir: BackupDir) -> BackupGroup { BackupGroup { store: dir.store, ns: dir.ns, @@ -340,8 +347,8 @@ impl From for BackupGroup { } } -impl From<&BackupDir> for BackupGroup { - fn from(dir: &BackupDir) -> BackupGroup { +impl From<&BackupDir> for BackupGroup { + fn from(dir: &BackupDir) -> BackupGroup { BackupGroup { store: Arc::clone(&dir.store), ns: dir.ns.clone(), @@ -354,15 +361,15 @@ impl From<&BackupDir> for BackupGroup { /// /// We also call this a backup snaphost. #[derive(Clone)] -pub struct BackupDir { - store: Arc, +pub struct BackupDir { + store: Arc>, ns: BackupNamespace, dir: pbs_api_types::BackupDir, // backup_time as rfc3339 backup_time_string: String, } -impl fmt::Debug for BackupDir { +impl fmt::Debug for BackupDir { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BackupDir") .field("store", &self.store.name()) @@ -373,102 +380,12 @@ impl fmt::Debug for BackupDir { } } -impl BackupDir { - /// Temporarily used for tests. - #[doc(hidden)] - pub fn new_test(dir: pbs_api_types::BackupDir) -> Self { - Self { - store: unsafe { DataStore::new_test() }, - backup_time_string: Self::backup_time_to_string(dir.time).unwrap(), - ns: BackupNamespace::root(), - dir, - } - } - - pub(crate) fn with_group(group: BackupGroup, backup_time: i64) -> Result { - let backup_time_string = Self::backup_time_to_string(backup_time)?; - Ok(Self { - store: group.store, - ns: group.ns, - dir: (group.group, backup_time).into(), - backup_time_string, - }) - } - - pub(crate) fn with_rfc3339( - group: BackupGroup, - backup_time_string: String, - ) -> Result { - let backup_time = proxmox_time::parse_rfc3339(&backup_time_string)?; - Ok(Self { - store: group.store, - ns: group.ns, - dir: (group.group, backup_time).into(), - backup_time_string, - }) - } - - #[inline] - pub fn backup_ns(&self) -> &BackupNamespace { - &self.ns - } - - #[inline] - pub fn backup_type(&self) -> BackupType { - self.dir.group.ty - } - - #[inline] - pub fn backup_id(&self) -> &str { - &self.dir.group.id - } - - #[inline] - pub fn backup_time(&self) -> i64 { - self.dir.time - } - - pub fn backup_time_string(&self) -> &str { - &self.backup_time_string - } - - pub fn dir(&self) -> &pbs_api_types::BackupDir { - &self.dir - } - - pub fn group(&self) -> &pbs_api_types::BackupGroup { - &self.dir.group - } - - pub fn relative_path(&self) -> PathBuf { - let mut path = self.ns.path(); - path.push(self.dir.group.ty.as_str()); - path.push(&self.dir.group.id); - path.push(&self.backup_time_string); - path - } - - /// Returns the absolute path for backup_dir, using the cached formatted time string. - pub fn full_path(&self) -> PathBuf { - let mut path = self.store.base_path(); - path.push(self.relative_path()); - path - } - - pub fn protected_file(&self) -> PathBuf { - let mut path = self.full_path(); - path.push(".protected"); - path - } - - pub fn is_protected(&self) -> bool { - let path = self.protected_file(); - path.exists() - } - - pub fn backup_time_to_string(backup_time: i64) -> Result { - // fixme: can this fail? (avoid unwrap) - proxmox_time::epoch_to_rfc3339_utc(backup_time) +impl BackupDir { + /// Returns the backup owner. + /// + /// The backup owner is the entity who first created the backup group. + pub fn get_owner(&self) -> Result { + self.store.get_owner(&self.ns, self.as_ref()) } /// load a `DataBlob` from this snapshot's backup dir. @@ -483,22 +400,38 @@ impl BackupDir { .map_err(|err| format_err!("unable to load blob '{:?}' - {}", path, err)) } - /// Returns the filename to lock a manifest - /// - /// Also creates the basedir. The lockfile is located in - /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}.index.json.lck` - /// where rpath is the relative path of the snapshot. - fn manifest_lock_path(&self) -> PathBuf { - let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name()); + /// Acquires a shared lock on a snapshot. + pub fn lock_shared(&self) -> Result { + if *OLD_LOCKING { + lock_dir_noblock_shared( + &self.full_path(), + "snapshot", + "backup is running or snapshot is in use, could not acquire shared lock", + ) + .map(BackupLockGuard::from) + } else { + lock_helper(self.store.name(), &self.lock_path(), |p| { + open_backup_lockfile(p, Some(Duration::from_secs(0)), false) + .with_context(|| format!("unable to acquire shared snapshot lock {p:?}")) + }) + } + } - let rpath = Path::new(self.dir.group.ty.as_str()) - .join(&self.dir.group.id) - .join(&self.backup_time_string) - .join(MANIFEST_LOCK_NAME); + /// Load the manifest without a lock. Must not be written back. + pub fn load_manifest(&self) -> Result<(BackupManifest, u64), Error> { + let blob = self.load_blob(MANIFEST_BLOB_NAME.as_ref())?; + let raw_size = blob.raw_size(); + let manifest = BackupManifest::try_from(blob)?; + Ok((manifest, raw_size)) + } - path.join(lock_file_path_helper(&self.ns, rpath)) + /// Load the verify state from the manifest. + pub fn verify_state(&self) -> Result, anyhow::Error> { + Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state)) } +} +impl BackupDir { /// Locks the manifest of a snapshot, for example, to update or delete it. pub(crate) fn lock_manifest(&self) -> Result { let path = if *OLD_LOCKING { @@ -523,21 +456,6 @@ impl BackupDir { }) } - /// Returns a file name for locking a snapshot. - /// - /// The lock file will be located in: - /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}` - /// where `rpath` is the relative path of the snapshot. - fn lock_path(&self) -> PathBuf { - let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name()); - - let rpath = Path::new(self.dir.group.ty.as_str()) - .join(&self.dir.group.id) - .join(&self.backup_time_string); - - path.join(lock_file_path_helper(&self.ns, rpath)) - } - /// Locks a snapshot exclusively. pub fn lock(&self) -> Result { if *OLD_LOCKING { @@ -555,23 +473,6 @@ impl BackupDir { } } - /// Acquires a shared lock on a snapshot. - pub fn lock_shared(&self) -> Result { - if *OLD_LOCKING { - lock_dir_noblock_shared( - &self.full_path(), - "snapshot", - "backup is running or snapshot is in use, could not acquire shared lock", - ) - .map(BackupLockGuard::from) - } else { - lock_helper(self.store.name(), &self.lock_path(), |p| { - open_backup_lockfile(p, Some(Duration::from_secs(0)), false) - .with_context(|| format!("unable to acquire shared snapshot lock {p:?}")) - }) - } - } - /// Destroy the whole snapshot, bails if it's protected /// /// Setting `force` to true skips locking and thus ignores if the backup is currently in use. @@ -624,31 +525,6 @@ impl BackupDir { Ok(()) } - /// Get the datastore. - pub fn datastore(&self) -> &Arc { - &self.store - } - - /// Returns the backup owner. - /// - /// The backup owner is the entity who first created the backup group. - pub fn get_owner(&self) -> Result { - self.store.get_owner(&self.ns, self.as_ref()) - } - - /// Lock the snapshot and open a reader. - pub fn locked_reader(&self) -> Result { - crate::SnapshotReader::new_do(self.clone()) - } - - /// Load the manifest without a lock. Must not be written back. - pub fn load_manifest(&self) -> Result<(BackupManifest, u64), Error> { - let blob = self.load_blob(MANIFEST_BLOB_NAME.as_ref())?; - let raw_size = blob.raw_size(); - let manifest = BackupManifest::try_from(blob)?; - Ok((manifest, raw_size)) - } - /// Update the manifest of the specified snapshot. Never write a manifest directly, /// only use this method - anything else may break locking guarantees. pub fn update_manifest( @@ -706,68 +582,203 @@ impl BackupDir { Ok(()) } +} + +impl BackupDir { + /// Temporarily used for tests. + #[doc(hidden)] + pub fn new_test(dir: pbs_api_types::BackupDir) -> Self { + Self { + store: DataStore::new_test(), + backup_time_string: Self::backup_time_to_string(dir.time).unwrap(), + ns: BackupNamespace::root(), + dir, + } + } - /// Load the verify state from the manifest. - pub fn verify_state(&self) -> Result, anyhow::Error> { - Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state)) + pub(crate) fn with_group(group: BackupGroup, backup_time: i64) -> Result { + let backup_time_string = Self::backup_time_to_string(backup_time)?; + Ok(Self { + store: group.store, + ns: group.ns, + dir: (group.group, backup_time).into(), + backup_time_string, + }) + } + + pub(crate) fn with_rfc3339( + group: BackupGroup, + backup_time_string: String, + ) -> Result { + let backup_time = proxmox_time::parse_rfc3339(&backup_time_string)?; + Ok(Self { + store: group.store, + ns: group.ns, + dir: (group.group, backup_time).into(), + backup_time_string, + }) + } + + #[inline] + pub fn backup_ns(&self) -> &BackupNamespace { + &self.ns + } + + #[inline] + pub fn backup_type(&self) -> BackupType { + self.dir.group.ty + } + + #[inline] + pub fn backup_id(&self) -> &str { + &self.dir.group.id + } + + #[inline] + pub fn backup_time(&self) -> i64 { + self.dir.time + } + + pub fn backup_time_string(&self) -> &str { + &self.backup_time_string + } + + pub fn dir(&self) -> &pbs_api_types::BackupDir { + &self.dir + } + + pub fn group(&self) -> &pbs_api_types::BackupGroup { + &self.dir.group + } + + pub fn relative_path(&self) -> PathBuf { + let mut path = self.ns.path(); + path.push(self.dir.group.ty.as_str()); + path.push(&self.dir.group.id); + path.push(&self.backup_time_string); + path + } + + /// Returns the absolute path for backup_dir, using the cached formatted time string. + pub fn full_path(&self) -> PathBuf { + let mut path = self.store.base_path(); + path.push(self.relative_path()); + path + } + + pub fn protected_file(&self) -> PathBuf { + let mut path = self.full_path(); + path.push(".protected"); + path + } + + pub fn is_protected(&self) -> bool { + let path = self.protected_file(); + path.exists() + } + + pub fn backup_time_to_string(backup_time: i64) -> Result { + // fixme: can this fail? (avoid unwrap) + proxmox_time::epoch_to_rfc3339_utc(backup_time) + } + + /// Returns the filename to lock a manifest + /// + /// Also creates the basedir. The lockfile is located in + /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}.index.json.lck` + /// where rpath is the relative path of the snapshot. + fn manifest_lock_path(&self) -> PathBuf { + let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name()); + + let rpath = Path::new(self.dir.group.ty.as_str()) + .join(&self.dir.group.id) + .join(&self.backup_time_string) + .join(MANIFEST_LOCK_NAME); + + path.join(lock_file_path_helper(&self.ns, rpath)) + } + + /// Returns a file name for locking a snapshot. + /// + /// The lock file will be located in: + /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}` + /// where `rpath` is the relative path of the snapshot. + fn lock_path(&self) -> PathBuf { + let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name()); + + let rpath = Path::new(self.dir.group.ty.as_str()) + .join(&self.dir.group.id) + .join(&self.backup_time_string); + + path.join(lock_file_path_helper(&self.ns, rpath)) + } + + /// Get the datastore. + pub fn datastore(&self) -> &Arc> { + &self.store + } + + /// Lock the snapshot and open a reader. + pub fn locked_reader(&self) -> Result { + crate::SnapshotReader::new_do(self.clone()) } } -impl AsRef for BackupDir { +impl AsRef for BackupDir { fn as_ref(&self) -> &pbs_api_types::BackupNamespace { &self.ns } } -impl AsRef for BackupDir { +impl AsRef for BackupDir { fn as_ref(&self) -> &pbs_api_types::BackupDir { &self.dir } } -impl AsRef for BackupDir { +impl AsRef for BackupDir { fn as_ref(&self) -> &pbs_api_types::BackupGroup { &self.dir.group } } -impl From<&BackupDir> for pbs_api_types::BackupGroup { - fn from(dir: &BackupDir) -> pbs_api_types::BackupGroup { +impl From<&BackupDir> for pbs_api_types::BackupGroup { + fn from(dir: &BackupDir) -> pbs_api_types::BackupGroup { dir.dir.group.clone() } } -impl From for pbs_api_types::BackupGroup { - fn from(dir: BackupDir) -> pbs_api_types::BackupGroup { +impl From> for pbs_api_types::BackupGroup { + fn from(dir: BackupDir) -> pbs_api_types::BackupGroup { dir.dir.group } } -impl From<&BackupDir> for pbs_api_types::BackupDir { - fn from(dir: &BackupDir) -> pbs_api_types::BackupDir { +impl From<&BackupDir> for pbs_api_types::BackupDir { + fn from(dir: &BackupDir) -> pbs_api_types::BackupDir { dir.dir.clone() } } -impl From for pbs_api_types::BackupDir { - fn from(dir: BackupDir) -> pbs_api_types::BackupDir { +impl From> for pbs_api_types::BackupDir { + fn from(dir: BackupDir) -> pbs_api_types::BackupDir { dir.dir } } /// Detailed Backup Information, lists files inside a BackupDir #[derive(Clone, Debug)] -pub struct BackupInfo { +pub struct BackupInfo { /// the backup directory - pub backup_dir: BackupDir, + pub backup_dir: BackupDir, /// List of data files pub files: Vec, /// Protection Status pub protected: bool, } -impl BackupInfo { - pub fn new(backup_dir: BackupDir) -> Result { +impl BackupInfo { + pub fn new(backup_dir: BackupDir) -> Result, Error> { let path = backup_dir.full_path(); let files = list_backup_files(libc::AT_FDCWD, &path)?; @@ -779,8 +790,10 @@ impl BackupInfo { protected, }) } +} - pub fn sort_list(list: &mut [BackupInfo], ascendending: bool) { +impl BackupInfo { + pub fn sort_list(list: &mut [BackupInfo], ascendending: bool) { if ascendending { // oldest first list.sort_unstable_by(|a, b| a.backup_dir.dir.time.cmp(&b.backup_dir.dir.time)); diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs index 66a2e209..9356750b 100644 --- a/pbs-datastore/src/datastore.rs +++ b/pbs-datastore/src/datastore.rs @@ -303,7 +303,7 @@ impl DataStore { self: &Arc>, ns: BackupNamespace, ty: BackupType, - ) -> Result + 'static, Error> { + ) -> Result> + 'static, Error> { Ok(self.iter_backup_type(ns, ty)?.ok()) } @@ -314,7 +314,7 @@ impl DataStore { pub fn iter_backup_groups_ok( self: &Arc>, ns: BackupNamespace, - ) -> Result + 'static, Error> { + ) -> Result> + 'static, Error> { Ok(self.iter_backup_groups(ns)?.ok()) } } @@ -644,7 +644,7 @@ impl DataStore { pub fn list_backup_groups( self: &Arc>, ns: BackupNamespace, - ) -> Result, Error> { + ) -> Result>, Error> { ListGroups::new(Arc::clone(self), ns)?.collect() } @@ -837,7 +837,7 @@ impl DataStore { ty: BackupType, id: D, time: i64, - ) -> Result + ) -> Result, Error> where D: Into, { @@ -847,10 +847,10 @@ impl DataStore { /// Open a snapshot (backup directory) from this datastore with a cached rfc3339 time string. pub fn backup_dir_with_rfc3339>( self: &Arc, - group: BackupGroup, + group: BackupGroup, time_string: D, - ) -> Result { - BackupDir::with_rfc3339(group, time_string.into()) + ) -> Result, Error> { + BackupDir::::with_rfc3339(group, time_string.into()) } /// Open a backup group from this datastore. @@ -859,7 +859,7 @@ impl DataStore { ns: BackupNamespace, ty: BackupType, id: D, - ) -> BackupGroup + ) -> BackupGroup where D: Into, { @@ -889,7 +889,7 @@ impl DataStore { self: &Arc, ns: BackupNamespace, dir: pbs_api_types::BackupDir, - ) -> Result { + ) -> Result, Error> { BackupDir::with_group(self.backup_group(ns, dir.group), dir.time) } } @@ -1258,7 +1258,7 @@ impl DataStore { _ => bail!("exhausted retries and unexpected counter overrun"), }; - let mut snapshots = match group.list_backups() { + let mut snapshots: Vec> = match group.list_backups() { Ok(snapshots) => snapshots, Err(err) => { if group.exists() { @@ -1526,7 +1526,11 @@ impl DataStore { } /// Updates the protection status of the specified snapshot. - pub fn update_protection(&self, backup_dir: &BackupDir, protection: bool) -> Result<(), Error> { + pub fn update_protection( + &self, + backup_dir: &BackupDir, + protection: bool, + ) -> Result<(), Error> { let full_path = backup_dir.full_path(); if !full_path.exists() { -- 2.39.5 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel