[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(¶m);
+
+ 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