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 <c.ebner@proxmox.com>
This commit is contained in:
Christian Ebner 2019-07-29 14:01:45 +02:00 committed by Dietmar Maurer
parent 46d5aa0a09
commit 6a87910949
3 changed files with 15 additions and 7 deletions

View File

@ -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 {

View File

@ -64,6 +64,7 @@ fn extract_archive_from_reader<R: std::io::Read>(
reader: &mut R,
target: &str,
feature_flags: u64,
allow_existing_dirs: bool,
verbose: bool,
pattern: Option<Vec<pxar::PxarExcludePattern>>
) -> Result<(), Error> {
@ -73,6 +74,7 @@ fn extract_archive_from_reader<R: std::io::Read>(
}
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"])

View File

@ -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<u8>,
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))