[pbs-devel] [PATCH v6 proxmox-backup 2/3] add file inspection to pb-debug

Hannes Laimer h.laimer at proxmox.com
Fri Jul 30 10:00:11 CEST 2021


Adds possibility to inspect .blob, .fidx and .didx files. For index
files a list of the chunks referenced will be printed in addition to
some other inforation. .blob files can be decoded into file or directly
into stdout. Options:
 - file: path to the file
 - [opt] decode: path to a file or stdout(-), if specidied, the file will be
   decoded into the specified location [only for blob files, no effect
   with index files]
 - [opt] keyfile: path to a keyfile, needed if decode is specified and the
   data was encrypted

Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
---
v6:
 - remove SCHEMA ref.
 - drop to_stdout variable
 - add "file" with .arg_param()

v5:
 - compair digests directly
 - use KEYFILE_SCHEMA from proxmox_client_tools
 - outfile_out_stdout now returns something that is writebale, instead
   of writing directly

v4:
 - left the two schemas here since they are quite specific to this binary
 - output_or_stdout() directly outputs the data instead of returning
   stdout or an open file (could not find a type that allows to properly
   return either stdout or a file)

 src/bin/proxmox_backup_debug/inspect.rs | 116 +++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 5 deletions(-)

diff --git a/src/bin/proxmox_backup_debug/inspect.rs b/src/bin/proxmox_backup_debug/inspect.rs
index 35f7dfa5..1817efc7 100644
--- a/src/bin/proxmox_backup_debug/inspect.rs
+++ b/src/bin/proxmox_backup_debug/inspect.rs
@@ -1,6 +1,9 @@
+use std::collections::HashSet;
+use std::fs::File;
+use std::io::{Read, Seek, SeekFrom};
 use std::path::Path;
 
-use anyhow::{format_err, Error};
+use anyhow::{bail, format_err, Error};
 use proxmox::api::cli::{
     format_and_print_result, get_output_format, CliCommand, CliCommandMap, CommandLineInterface,
 };
@@ -10,6 +13,8 @@ use walkdir::WalkDir;
 
 use proxmox_backup::backup::{
     load_and_decrypt_key, CryptConfig, DataBlob, DynamicIndexReader, FixedIndexReader, IndexFile,
+    COMPRESSED_BLOB_MAGIC_1_0, DYNAMIC_SIZED_CHUNK_INDEX_1_0, ENCRYPTED_BLOB_MAGIC_1_0,
+    ENCR_COMPR_BLOB_MAGIC_1_0, FIXED_SIZED_CHUNK_INDEX_1_0, UNCOMPRESSED_BLOB_MAGIC_1_0,
 };
 
 use pbs_client::tools::key_source::get_encryption_key_password;
@@ -192,11 +197,112 @@ fn inspect_chunk(
     Ok(())
 }
 
+#[api(
+    input: {
+        properties: {
+            file: {
+                description: "Path to the file.",
+                type: String,
+            },
+            "decode": {
+                description: "Path to the file to which the file should be decoded, '-' -> decode to stdout.",
+                type: String,
+                optional: true,
+            },
+            "keyfile": {
+                description: "Path to the keyfile with which the file was encrypted.",
+                type: String,
+                optional: true,
+            },
+            "output-format": {
+                schema: OUTPUT_FORMAT,
+                optional: true,
+            },
+        }
+    }
+)]
+/// Inspect a file
+fn inspect_file(
+    file: String,
+    decode: Option<String>,
+    keyfile: Option<String>,
+    param: Value,
+) -> Result<(), Error> {
+    let output_format = get_output_format(&param);
+
+    let mut file = File::open(Path::new(&file))?;
+    let mut magic = [0; 8];
+    file.read_exact(&mut magic)?;
+    file.seek(SeekFrom::Start(0))?;
+    let val = match magic {
+        UNCOMPRESSED_BLOB_MAGIC_1_0
+        | COMPRESSED_BLOB_MAGIC_1_0
+        | ENCRYPTED_BLOB_MAGIC_1_0
+        | ENCR_COMPR_BLOB_MAGIC_1_0 => {
+            let data_blob = DataBlob::load_from_reader(&mut file)?;
+            let key_file_path = keyfile.as_ref().map(Path::new);
+
+            let decode_output_path = decode.as_ref().map(Path::new);
+
+            if decode_output_path.is_some() {
+                decode_blob(decode_output_path, key_file_path, None, &data_blob)?;
+            }
+
+            let crypt_mode = data_blob.crypt_mode()?;
+            json!({
+                "encryption": crypt_mode,
+                "raw_size": data_blob.raw_size(),
+            })
+        }
+        FIXED_SIZED_CHUNK_INDEX_1_0 | DYNAMIC_SIZED_CHUNK_INDEX_1_0 => {
+            let index: Box<dyn IndexFile> = match magic {
+                FIXED_SIZED_CHUNK_INDEX_1_0 => {
+                    Box::new(FixedIndexReader::new(file)?) as Box<dyn IndexFile>
+                }
+                DYNAMIC_SIZED_CHUNK_INDEX_1_0 => {
+                    Box::new(DynamicIndexReader::new(file)?) as Box<dyn IndexFile>
+                }
+                _ => bail!(format_err!("This is technically not possible")),
+            };
+
+            let mut ctime_str = index.index_ctime().to_string();
+            if let Ok(s) = proxmox::tools::time::strftime_local("%c", index.index_ctime()) {
+                ctime_str = s;
+            }
+
+            let mut chunk_digests = HashSet::new();
+
+            for pos in 0..index.index_count() {
+                let digest = index.index_digest(pos).unwrap();
+                chunk_digests.insert(proxmox::tools::digest_to_hex(digest));
+            }
+
+            json!({
+                "size": index.index_size(),
+                "ctime": ctime_str,
+                "chunk-digests": chunk_digests
+            })
+        }
+        _ => bail!(format_err!(
+            "Only .blob, .fidx and .didx files may be inspected"
+        )),
+    };
+
+    format_and_print_result(&val, &output_format);
+
+    Ok(())
+}
+
 pub fn inspect_commands() -> CommandLineInterface {
-    let cmd_def = CliCommandMap::new().insert(
-        "chunk",
-        CliCommand::new(&API_METHOD_INSPECT_CHUNK).arg_param(&["chunk"]),
-    );
+    let cmd_def = CliCommandMap::new()
+        .insert(
+            "chunk",
+            CliCommand::new(&API_METHOD_INSPECT_CHUNK).arg_param(&["chunk"]),
+        )
+        .insert(
+            "file",
+            CliCommand::new(&API_METHOD_INSPECT_FILE).arg_param(&["file"]),
+        );
 
     cmd_def.into()
 }
-- 
2.30.2






More information about the pbs-devel mailing list