src/bin/proxmox-backup-client.rs: implement catalog command
This commit is contained in:
		| @ -389,6 +389,55 @@ fn forget_snapshots( | |||||||
|     Ok(result) |     Ok(result) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn dump_catalog( | ||||||
|  |     param: Value, | ||||||
|  |     _info: &ApiMethod, | ||||||
|  |     _rpcenv: &mut dyn RpcEnvironment, | ||||||
|  | ) -> Result<Value, Error> { | ||||||
|  |  | ||||||
|  |     let repo = extract_repository_from_value(¶m)?; | ||||||
|  |  | ||||||
|  |     let path = tools::required_string_param(¶m, "snapshot")?; | ||||||
|  |     let snapshot = BackupDir::parse(path)?; | ||||||
|  |  | ||||||
|  |     let keyfile = param["keyfile"].as_str().map(|p| PathBuf::from(p)); | ||||||
|  |  | ||||||
|  |     let crypt_config = match keyfile { | ||||||
|  |         None => None, | ||||||
|  |         Some(path) => { | ||||||
|  |             let (key, _) = load_and_decrtypt_key(&path, get_encryption_key_password)?; | ||||||
|  |             Some(Arc::new(CryptConfig::new(key)?)) | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let client = HttpClient::new(repo.host(), repo.user())?; | ||||||
|  |  | ||||||
|  |     let client = client.start_backup_reader( | ||||||
|  |         repo.store(), | ||||||
|  |         &snapshot.group().backup_type(), | ||||||
|  |         &snapshot.group().backup_id(), | ||||||
|  |         snapshot.backup_time(), true).wait()?; | ||||||
|  |  | ||||||
|  |     let writer = Vec::with_capacity(1024*1024); | ||||||
|  |     let blob_data = client.download("catalog.blob", writer).wait()?; | ||||||
|  |     let blob = DataBlob::from_raw(blob_data)?; | ||||||
|  |     blob.verify_crc()?; | ||||||
|  |  | ||||||
|  |     let raw_data = match crypt_config { | ||||||
|  |         Some(ref crypt_config) => blob.decode(Some(crypt_config))?, | ||||||
|  |         None => blob.decode(None)?, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let slice = &raw_data[..]; | ||||||
|  |     let mut catalog_reader = pxar::catalog::SimpleCatalogReader::new(slice); | ||||||
|  |  | ||||||
|  |     catalog_reader.dump()?; | ||||||
|  |  | ||||||
|  |     record_repository(&repo); | ||||||
|  |  | ||||||
|  |     Ok(Value::Null) | ||||||
|  | } | ||||||
|  |  | ||||||
| fn list_snapshot_files( | fn list_snapshot_files( | ||||||
|     param: Value, |     param: Value, | ||||||
|     _info: &ApiMethod, |     _info: &ApiMethod, | ||||||
| @ -616,8 +665,8 @@ fn create_backup( | |||||||
|             } |             } | ||||||
|             BackupType::PXAR => { |             BackupType::PXAR => { | ||||||
|                 upload_catalog = true; |                 upload_catalog = true; | ||||||
|                 catalog.lock().unwrap().start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?; |  | ||||||
|                 println!("Upload directory '{}' to '{:?}' as {}", filename, repo, target); |                 println!("Upload directory '{}' to '{:?}' as {}", filename, repo, target); | ||||||
|  |                 catalog.lock().unwrap().start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?; | ||||||
|                 let stats = backup_directory( |                 let stats = backup_directory( | ||||||
|                     &client, |                     &client, | ||||||
|                     &filename, |                     &filename, | ||||||
| @ -1558,6 +1607,17 @@ We do not extraxt '.pxar' archives when writing to stdandard output. | |||||||
|         .completion_cb("repository", complete_repository) |         .completion_cb("repository", complete_repository) | ||||||
|         .completion_cb("snapshot", complete_backup_snapshot); |         .completion_cb("snapshot", complete_backup_snapshot); | ||||||
|  |  | ||||||
|  |     let catalog_cmd_def = CliCommand::new( | ||||||
|  |         ApiMethod::new( | ||||||
|  |             dump_catalog, | ||||||
|  |             ObjectSchema::new("Dump catalog.") | ||||||
|  |                 .required("snapshot", StringSchema::new("Snapshot path.")) | ||||||
|  |                 .optional("repository", REPO_URL_SCHEMA.clone()) | ||||||
|  |         )) | ||||||
|  |         .arg_param(vec!["snapshot"]) | ||||||
|  |         .completion_cb("repository", complete_repository) | ||||||
|  |         .completion_cb("snapshot", complete_backup_snapshot); | ||||||
|  |  | ||||||
|     let prune_cmd_def = CliCommand::new( |     let prune_cmd_def = CliCommand::new( | ||||||
|         ApiMethod::new( |         ApiMethod::new( | ||||||
|             prune, |             prune, | ||||||
| @ -1584,6 +1644,7 @@ We do not extraxt '.pxar' archives when writing to stdandard output. | |||||||
|         .insert("backup".to_owned(), backup_cmd_def.into()) |         .insert("backup".to_owned(), backup_cmd_def.into()) | ||||||
|         .insert("upload-log".to_owned(), upload_log_cmd_def.into()) |         .insert("upload-log".to_owned(), upload_log_cmd_def.into()) | ||||||
|         .insert("forget".to_owned(), forget_cmd_def.into()) |         .insert("forget".to_owned(), forget_cmd_def.into()) | ||||||
|  |         .insert("catalog".to_owned(), catalog_cmd_def.into()) | ||||||
|         .insert("garbage-collect".to_owned(), garbage_collect_cmd_def.into()) |         .insert("garbage-collect".to_owned(), garbage_collect_cmd_def.into()) | ||||||
|         .insert("list".to_owned(), list_cmd_def.into()) |         .insert("list".to_owned(), list_cmd_def.into()) | ||||||
|         .insert("prune".to_owned(), prune_cmd_def.into()) |         .insert("prune".to_owned(), prune_cmd_def.into()) | ||||||
|  | |||||||
| @ -5,8 +5,7 @@ | |||||||
|  |  | ||||||
| use failure::*; | use failure::*; | ||||||
|  |  | ||||||
| use std::io::{Read, BufRead, Write, BufReader}; | use std::io::{Read, BufRead, Write}; | ||||||
| use std::fs::File; |  | ||||||
| use std::convert::TryFrom; | use std::convert::TryFrom; | ||||||
|  |  | ||||||
| use std::ffi::{CStr, CString}; | use std::ffi::{CStr, CString}; | ||||||
| @ -139,18 +138,16 @@ impl BackupCatalogWriter for SimpleCatalog { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct SimpleCatalogReader { | pub struct SimpleCatalogReader<R> { | ||||||
|     reader: BufReader<File>, |     reader: R, | ||||||
|     dir_stack: Vec<CString>, |     dir_stack: Vec<CString>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl SimpleCatalogReader { | impl <R: Read + BufRead> SimpleCatalogReader<R> { | ||||||
|  |  | ||||||
|     pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Error> { |     pub fn new(reader: R) -> Self { | ||||||
|         let file = std::fs::File::open(path)?; |  | ||||||
|         let reader = BufReader::new(file); |  | ||||||
|         let dir_stack = Vec::new(); |         let dir_stack = Vec::new(); | ||||||
|         Ok(Self { reader, dir_stack }) |         Self { reader, dir_stack } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn read_filename(&mut self) ->  Result<std::ffi::CString, Error> { |     fn read_filename(&mut self) ->  Result<std::ffi::CString, Error> { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user