all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 3/3] add restore of index files
Date: Tue, 15 Dec 2020 09:16:26 +0100	[thread overview]
Message-ID: <20201215081626.73888-4-h.laimer@proxmox.com> (raw)
In-Reply-To: <20201215081626.73888-1-h.laimer@proxmox.com>

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
Adds possibility to restore data from an index file. Options:
 - chunks: path to the directory where the chunks are saved
 - file: the index file that should be restored(must be either .fidx or
   didx)
 - [opt] keyfile: path to a keyfile, if the data was encrypted, a keyfile is
   needed
 - [opt] skip-crc: boolean, if true, read chunks wont be verified with their
   crc-sum, increases the restore speed by a lot

 src/bin/proxmox-backup-recovery.rs | 109 ++++++++++++++++++++++++++++-
 1 file changed, 107 insertions(+), 2 deletions(-)

diff --git a/src/bin/proxmox-backup-recovery.rs b/src/bin/proxmox-backup-recovery.rs
index ae8c18d5..c2b9fdfa 100644
--- a/src/bin/proxmox-backup-recovery.rs
+++ b/src/bin/proxmox-backup-recovery.rs
@@ -1,9 +1,21 @@
+use std::fs::File;
+use std::io::{Read, Write};
+use std::path::Path;
+
 use anyhow::Error;
 use proxmox::api::schema::{Schema, StringSchema};
-use proxmox::api::cli::*;
+use proxmox::api::{api, cli::*};
+use proxmox::tools::digest_to_hex;
+use serde_json::Value;
 
 use proxmox::sys::linux::tty;
+use proxmox_backup::backup::{
+    load_and_decrypt_key, CryptConfig, DataBlob, DynamicIndexReader, FixedIndexReader, IndexFile,
+};
+use proxmox_backup::tools;
 use proxmox_backup_recovery::*;
+use std::time::Instant;
+
 mod proxmox_backup_recovery;
 
 pub fn get_encryption_key_password() -> Result<Vec<u8>, Error> {
@@ -17,11 +29,104 @@ pub const KEYFILE_SCHEMA: Schema = StringSchema::new(
 )
 .schema();
 
+#[api(
+    input: {
+        properties: {
+            file: {
+                schema: PATH_SCHEMA,
+            },
+            chunks: {
+                schema: PATH_SCHEMA,
+            },
+            "keyfile": {
+                schema: KEYFILE_SCHEMA,
+                optional: true,
+            },
+            "skip-crc": {
+                type: Boolean,
+                optional: true,
+                default: false,
+                description: "Skip the crc verification, increases the restore speed immensely",
+            }
+        }
+    }
+)]
+/// Restore a index file
+fn restore(skip_crc: bool, param: Value) -> Result<Value, Error> {
+    let start = Instant::now();
+    let file_path = Path::new(tools::required_string_param(&param, "file")?);
+    let chunks_path = Path::new(tools::required_string_param(&param, "chunks")?);
+
+    let key_file_param = param["keyfile"].as_str();
+    let mut key_file_path = None;
+
+    if let Some(path) = key_file_param {
+        key_file_path = Some(Path::new(path))
+    };
+
+    let file_name = file_path.file_name().unwrap().to_str().unwrap();
+    let mut index: Option<Box<dyn IndexFile>> = None;
+
+    if file_name.ends_with(".fidx") {
+        index = match FixedIndexReader::open(file_path) {
+            Ok(index) => Some(Box::new(index)),
+            Err(_) => None,
+        };
+    }
+
+    if file_name.ends_with(".didx") {
+        index = match DynamicIndexReader::open(file_path) {
+            Ok(index) => Some(Box::new(index)),
+            Err(_) => None,
+        };
+    }
+
+    let mut crypt_conf_opt = None;
+    let mut crypt_conf;
+
+    let output_filename = &file_name[0..file_name.len() - 5];
+    let output_path = Path::new(output_filename);
+    let mut output_file = File::create(output_path)?;
+    if let Some(index) = index {
+        for pos in 0..index.index_count() {
+            let chunk_digest = index.index_digest(pos).unwrap();
+            let digest_str = digest_to_hex(chunk_digest);
+            let digest_prefix = &digest_str[0..4];
+            let chunk_path = chunks_path.join(digest_prefix).join(digest_str);
+            let mut chunk_file = std::fs::File::open(&chunk_path)?;
+
+            let mut data = Vec::with_capacity(1024 * 1024);
+            chunk_file.read_to_end(&mut data)?;
+            let chunk_blob = DataBlob::from_raw(data)?;
+
+            if !skip_crc {
+                chunk_blob.verify_crc()?;
+            }
+
+            if key_file_path.is_some() && chunk_blob.is_encrypted() && crypt_conf_opt.is_none() {
+                let (key, _created, _fingerprint) =
+                    load_and_decrypt_key(&key_file_path.unwrap(), &get_encryption_key_password)?;
+                crypt_conf = CryptConfig::new(key)?;
+                crypt_conf_opt = Some(&crypt_conf);
+            }
+
+            output_file.write_all(
+                chunk_blob
+                    .decode(crypt_conf_opt, Some(chunk_digest))?
+                    .as_slice(),
+            )?;
+        }
+    }
+    println!("{} sec.", start.elapsed().as_secs_f32());
+    Ok(Value::Null)
+}
+
 fn main() {
     proxmox_backup::tools::setup_safe_path_env();
 
     let cmd_def = CliCommandMap::new()
-        .insert("inspect", inspect_commands());
+        .insert("inspect", inspect_commands())
+        .insert("restore", CliCommand::new(&API_METHOD_RESTORE));
 
     let rpcenv = CliEnvironment::new();
     run_cli_command(
-- 
2.20.1





      parent reply	other threads:[~2020-12-15  8:17 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-15  8:16 [pbs-devel] [PATCH proxmox-backup 0/3] add proxmox-backup-recovery binary Hannes Laimer
2020-12-15  8:16 ` [pbs-devel] [PATCH proxmox-backup 1/3] add inspection of chunks Hannes Laimer
2020-12-15 10:14   ` Thomas Lamprecht
2020-12-15  8:16 ` [pbs-devel] [PATCH proxmox-backup 2/3] add inspection of .blob, .fidx and .didx files Hannes Laimer
2020-12-15  8:16 ` Hannes Laimer [this message]

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=20201215081626.73888-4-h.laimer@proxmox.com \
    --to=h.laimer@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal