aboutsummaryrefslogtreecommitdiff
path: root/hbak_common
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2024-02-14 18:35:05 +0100
committerHimbeerserverDE <himbeerserverde@gmail.com>2024-02-14 18:35:05 +0100
commitbe3e8bc51930913732a5b9c7e514635eb2a75745 (patch)
tree67a5466415b0841e0e4fae8f8b3341c0f8a8ea9b /hbak_common
parent90ee9e99e0ea2caf8f016ad527c2abf51af10312 (diff)
hbak: restore subcommand: restore latest snapshot to subvolume (opt-out)
Diffstat (limited to 'hbak_common')
-rw-r--r--hbak_common/src/proto.rs47
1 files changed, 47 insertions, 0 deletions
diff --git a/hbak_common/src/proto.rs b/hbak_common/src/proto.rs
index 573de6e..2da1a39 100644
--- a/hbak_common/src/proto.rs
+++ b/hbak_common/src/proto.rs
@@ -432,6 +432,18 @@ impl LocalNode {
.ok_or(LocalNodeError::NoIncrementalSnapshot(subvol))
}
+ /// Returns the latest snapshot, full or incremental, of the specified subvolume of this node.
+ pub fn latest_snapshot(&self, subvol: String) -> Result<Snapshot, LocalNodeError> {
+ [
+ Some(self.latest_snapshot_full(subvol.clone())?),
+ self.latest_snapshot_incremental(subvol.clone()).ok(),
+ ]
+ .into_iter()
+ .flatten()
+ .max_by_key(|snapshot| snapshot.taken())
+ .ok_or(LocalNodeError::NoFullSnapshot(subvol))
+ }
+
/// Returns all full snapshots of the specified subvolume of this node
/// taken after the provided timestamp.
pub fn snapshot_full_after(
@@ -686,6 +698,41 @@ impl LocalNode {
),
))
}
+
+ /// Restores the latest full or incremental snapshot, whichever is later,
+ /// of the specified subvolume. Only uses locally stored snapshots, remote recovery
+ /// with the help of [`LocalNode::recover`] may be necessary.
+ pub fn restore(&self, subvol: String) -> Result<(), LocalNodeError> {
+ let subvol_path = Path::new(self.mode.mountpoint()).join(&subvol);
+
+ if subvol_path.exists()
+ && !Command::new("btrfs")
+ .arg("subvolume")
+ .arg("delete")
+ .arg(&subvol_path)
+ .spawn()?
+ .wait()?
+ .success()
+ {
+ return Err(LocalNodeError::BtrfsCmd);
+ }
+
+ let snapshot = self.latest_snapshot(subvol)?;
+
+ if !Command::new("btrfs")
+ .arg("subvolume")
+ .arg("snapshot")
+ .arg(snapshot.snapshot_path(self.mode))
+ .arg(&subvol_path)
+ .spawn()?
+ .wait()?
+ .success()
+ {
+ return Err(LocalNodeError::BtrfsCmd);
+ }
+
+ Ok(())
+ }
}
impl Node for LocalNode {