From 6a87910949f7efaad588255760539fdf9e3938db Mon Sep 17 00:00:00 2001 From: Christian Ebner Date: Mon, 29 Jul 2019 14:01:45 +0200 Subject: [PATCH] pxar: implement allow_existing_dirs for pxar decoder By default, restoring an archive will fail if files with the same filename already exist in the target directory. By setting the allow_existing_dirs flag, the restore will not fail if an existing directory is encountered. The metadata (permissions, acls, ...) of the existing directory will be set to the ones from the archive. Signed-off-by: Christian Ebner --- src/bin/proxmox-backup-client.rs | 6 ++---- src/bin/pxar.rs | 8 ++++++-- src/pxar/sequential_decoder.rs | 8 +++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index 1b0133bf..dc0a6f10 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -739,10 +739,6 @@ fn restore( if let Some(target) = target { - if allow_existing_dirs { - unimplemented!(); - } - let feature_flags = pxar::CA_FORMAT_DEFAULT; let mut decoder = pxar::SequentialDecoder::new(&mut reader, feature_flags, |path| { if verbose { @@ -750,6 +746,8 @@ fn restore( } Ok(()) }); + decoder.set_allow_existing_dirs(allow_existing_dirs); + decoder.restore(Path::new(target), &Vec::new())?; } else { diff --git a/src/bin/pxar.rs b/src/bin/pxar.rs index 9641b118..095a2713 100644 --- a/src/bin/pxar.rs +++ b/src/bin/pxar.rs @@ -64,6 +64,7 @@ fn extract_archive_from_reader( reader: &mut R, target: &str, feature_flags: u64, + allow_existing_dirs: bool, verbose: bool, pattern: Option> ) -> Result<(), Error> { @@ -73,6 +74,7 @@ fn extract_archive_from_reader( } Ok(()) }); + decoder.set_allow_existing_dirs(allow_existing_dirs); let pattern = pattern.unwrap_or(Vec::new()); decoder.restore(Path::new(target), &pattern)?; @@ -92,6 +94,7 @@ fn extract_archive( let no_xattrs = param["no-xattrs"].as_bool().unwrap_or(false); let no_fcaps = param["no-fcaps"].as_bool().unwrap_or(false); let no_acls = param["no-acls"].as_bool().unwrap_or(false); + let allow_existing_dirs = param["allow-existing-dirs"].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); @@ -131,12 +134,12 @@ fn extract_archive( if archive == "-" { let stdin = std::io::stdin(); let mut reader = stdin.lock(); - extract_archive_from_reader(&mut reader, target, feature_flags, verbose, pattern)?; + extract_archive_from_reader(&mut reader, target, feature_flags, allow_existing_dirs, verbose, pattern)?; } else { if verbose { println!("PXAR extract: {}", archive); } let file = std::fs::File::open(archive)?; let mut reader = std::io::BufReader::new(file); - extract_archive_from_reader(&mut reader, target, feature_flags, verbose, pattern)?; + extract_archive_from_reader(&mut reader, target, feature_flags, allow_existing_dirs, verbose, pattern)?; } Ok(Value::Null) @@ -224,6 +227,7 @@ fn main() { .optional("no-xattrs", BooleanSchema::new("Ignore extended file attributes.").default(false)) .optional("no-fcaps", BooleanSchema::new("Ignore file capabilities.").default(false)) .optional("no-acls", BooleanSchema::new("Ignore access control list entries.").default(false)) + .optional("allow-existing-dirs", BooleanSchema::new("Allows directories to already exist on restore.").default(false)) .optional("files-from", StringSchema::new("Match pattern for files to restore.")) )) .arg_param(vec!["archive", "pattern"]) diff --git a/src/pxar/sequential_decoder.rs b/src/pxar/sequential_decoder.rs index 79ae2d53..cdeea2c7 100644 --- a/src/pxar/sequential_decoder.rs +++ b/src/pxar/sequential_decoder.rs @@ -34,6 +34,7 @@ use crate::tools::xattr; pub struct SequentialDecoder<'a, R: Read, F: Fn(&Path) -> Result<(), Error>> { reader: &'a mut R, feature_flags: u64, + allow_existing_dirs: bool, skip_buffer: Vec, callback: F, } @@ -48,11 +49,16 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F Self { reader, feature_flags, + allow_existing_dirs: false, skip_buffer, callback, } } + pub fn set_allow_existing_dirs(&mut self, allow: bool) { + self.allow_existing_dirs = allow; + } + pub (crate) fn get_reader_mut(&mut self) -> & mut R { self.reader } @@ -632,7 +638,7 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F let dir = if filename.is_empty() { nix::dir::Dir::openat(pfd, ".", OFlag::O_DIRECTORY, Mode::empty())? } else { - dir_mkdirat(pfd, filename, true) + dir_mkdirat(pfd, filename, !self.allow_existing_dirs) .map_err(|err| format_err!("unable to open directory {:?} - {}", full_path, err))? }; (Some(dir.as_raw_fd()), Some(dir))