src/bin/pxar.rs: allow to pass paths and match patterns as args to pxar extract

To improve usability it is now possible to directly pass paths or match patterns
as arguments to pxar extract to partially restore an archive.
The patterns provided via CLI are appended to the ones read from file by the
--files-from option in order to have priority over those.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
Christian Ebner 2019-07-18 11:35:51 +02:00 committed by Dietmar Maurer
parent 9aa3f68278
commit a0ec687cd7
1 changed files with 31 additions and 12 deletions

View File

@ -12,6 +12,7 @@ use serde_json::{Value};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::fs::OpenOptions;
use std::sync::Arc;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
@ -91,6 +92,8 @@ fn extract_archive(
let no_fcaps = param["no-fcaps"].as_bool().unwrap_or(false);
let no_acls = param["no-acls"].as_bool().unwrap_or(false);
let files_from = param["files-from"].as_str();
let empty = Vec::new();
let arg_pattern = param["pattern"].as_array().unwrap_or(&empty);
let mut feature_flags = pxar::CA_FORMAT_DEFAULT;
if no_xattrs {
@ -103,15 +106,25 @@ fn extract_archive(
feature_flags ^= pxar::CA_FORMAT_WITH_ACL;
}
let pattern = match files_from {
Some(filename) => {
let mut pattern_list = Vec::new();
if let Some(filename) = files_from {
let dir = nix::dir::Dir::open("./", nix::fcntl::OFlag::O_RDONLY, nix::sys::stat::Mode::empty())?;
let fd = dir.as_raw_fd();
if let Some((mut pattern, _, _)) = pxar::PxarExcludePattern::from_file(dir.as_raw_fd(), filename)? {
pattern_list.append(&mut pattern);
}
}
pxar::PxarExcludePattern::from_file(fd, filename)?
.and_then(|(pattern, _, _)| Some(pattern))
},
None => None,
for s in arg_pattern {
let l = s.as_str().ok_or_else(|| format_err!("Invalid pattern string slice"))?;
let p = pxar::PxarExcludePattern::from_line(l.as_bytes())?
.ok_or_else(|| format_err!("Invalid match pattern in arguments"))?;
pattern_list.push(p);
}
let pattern = if pattern_list.len() > 0 {
Some(pattern_list)
} else {
None
};
if archive == "-" {
@ -197,6 +210,12 @@ fn main() {
extract_archive,
ObjectSchema::new("Extract an archive.")
.required("archive", StringSchema::new("Archive name."))
.optional("pattern", Arc::new(
ArraySchema::new(
"List of paths or pattern matching files to restore",
Arc::new(StringSchema::new("Path or pattern matching files to restore.").into())
).into()
))
.optional("target", StringSchema::new("Target directory."))
.optional("verbose", BooleanSchema::new("Verbose output.").default(false))
.optional("no-xattrs", BooleanSchema::new("Ignore extended file attributes.").default(false))
@ -204,7 +223,7 @@ fn main() {
.optional("no-acls", BooleanSchema::new("Ignore access control list entries.").default(false))
.optional("files-from", StringSchema::new("Match pattern for files to restore."))
))
.arg_param(vec!["archive"])
.arg_param(vec!["archive", "pattern"])
.completion_cb("archive", tools::complete_file_name)
.completion_cb("target", tools::complete_file_name)
.completion_cb("files-from", tools::complete_file_name)