mirror of
https://git.proxmox.com/git/proxmox-backup
synced 2025-08-07 16:00:09 +00:00
pbs-client: added overwrite parameter to PxarExtractOptions.
If overwrite is true, O_TRUNC is set (to clean the leftovers) instead of O_EXCL and therefore overwrites the files and does not error out. Signed-off-by: Markus Frank <m.frank@proxmox.com>
This commit is contained in:
parent
5574114a2a
commit
95e910f153
@ -984,7 +984,7 @@ impl Shell {
|
|||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let extractor =
|
let extractor =
|
||||||
crate::pxar::extract::Extractor::new(rootdir, root_meta, true, Flags::DEFAULT);
|
crate::pxar::extract::Extractor::new(rootdir, root_meta, true, false, Flags::DEFAULT);
|
||||||
|
|
||||||
let mut extractor = ExtractorState::new(
|
let mut extractor = ExtractorState::new(
|
||||||
&mut self.catalog,
|
&mut self.catalog,
|
||||||
@ -1172,7 +1172,7 @@ impl<'a> ExtractorState<'a> {
|
|||||||
let file_name = CString::new(entry.file_name().as_bytes())?;
|
let file_name = CString::new(entry.file_name().as_bytes())?;
|
||||||
let mut contents = entry.contents().await?;
|
let mut contents = entry.contents().await?;
|
||||||
self.extractor
|
self.extractor
|
||||||
.async_extract_file(&file_name, entry.metadata(), *size, &mut contents)
|
.async_extract_file(&file_name, entry.metadata(), *size, &mut contents, false)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -34,6 +34,7 @@ pub struct PxarExtractOptions<'a> {
|
|||||||
pub match_list: &'a [MatchEntry],
|
pub match_list: &'a [MatchEntry],
|
||||||
pub extract_match_default: bool,
|
pub extract_match_default: bool,
|
||||||
pub allow_existing_dirs: bool,
|
pub allow_existing_dirs: bool,
|
||||||
|
pub overwrite: bool,
|
||||||
pub on_error: Option<ErrorHandler>,
|
pub on_error: Option<ErrorHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ where
|
|||||||
dir,
|
dir,
|
||||||
root.metadata().clone(),
|
root.metadata().clone(),
|
||||||
options.allow_existing_dirs,
|
options.allow_existing_dirs,
|
||||||
|
options.overwrite,
|
||||||
feature_flags,
|
feature_flags,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -198,6 +200,7 @@ where
|
|||||||
&mut decoder.contents().ok_or_else(|| {
|
&mut decoder.contents().ok_or_else(|| {
|
||||||
format_err!("found regular file entry without contents in archive")
|
format_err!("found regular file entry without contents in archive")
|
||||||
})?,
|
})?,
|
||||||
|
extractor.overwrite,
|
||||||
),
|
),
|
||||||
(false, _) => Ok(()), // skip this
|
(false, _) => Ok(()), // skip this
|
||||||
}
|
}
|
||||||
@ -215,6 +218,7 @@ where
|
|||||||
pub struct Extractor {
|
pub struct Extractor {
|
||||||
feature_flags: Flags,
|
feature_flags: Flags,
|
||||||
allow_existing_dirs: bool,
|
allow_existing_dirs: bool,
|
||||||
|
overwrite: bool,
|
||||||
dir_stack: PxarDirStack,
|
dir_stack: PxarDirStack,
|
||||||
|
|
||||||
/// For better error output we need to track the current path in the Extractor state.
|
/// For better error output we need to track the current path in the Extractor state.
|
||||||
@ -231,11 +235,13 @@ impl Extractor {
|
|||||||
root_dir: Dir,
|
root_dir: Dir,
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
allow_existing_dirs: bool,
|
allow_existing_dirs: bool,
|
||||||
|
overwrite: bool,
|
||||||
feature_flags: Flags,
|
feature_flags: Flags,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dir_stack: PxarDirStack::new(root_dir, metadata),
|
dir_stack: PxarDirStack::new(root_dir, metadata),
|
||||||
allow_existing_dirs,
|
allow_existing_dirs,
|
||||||
|
overwrite,
|
||||||
feature_flags,
|
feature_flags,
|
||||||
current_path: Arc::new(Mutex::new(OsString::new())),
|
current_path: Arc::new(Mutex::new(OsString::new())),
|
||||||
on_error: Box::new(Err),
|
on_error: Box::new(Err),
|
||||||
@ -392,14 +398,21 @@ impl Extractor {
|
|||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
size: u64,
|
size: u64,
|
||||||
contents: &mut dyn io::Read,
|
contents: &mut dyn io::Read,
|
||||||
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let parent = self.parent_fd()?;
|
let parent = self.parent_fd()?;
|
||||||
|
let mut oflags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_CLOEXEC;
|
||||||
|
if overwrite {
|
||||||
|
oflags = oflags | OFlag::O_TRUNC;
|
||||||
|
} else {
|
||||||
|
oflags = oflags | OFlag::O_EXCL;
|
||||||
|
}
|
||||||
let mut file = unsafe {
|
let mut file = unsafe {
|
||||||
std::fs::File::from_raw_fd(
|
std::fs::File::from_raw_fd(
|
||||||
nix::fcntl::openat(
|
nix::fcntl::openat(
|
||||||
parent,
|
parent,
|
||||||
file_name,
|
file_name,
|
||||||
OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY | OFlag::O_CLOEXEC,
|
oflags,
|
||||||
Mode::from_bits(0o600).unwrap(),
|
Mode::from_bits(0o600).unwrap(),
|
||||||
)
|
)
|
||||||
.map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?,
|
.map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?,
|
||||||
@ -448,14 +461,21 @@ impl Extractor {
|
|||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
size: u64,
|
size: u64,
|
||||||
contents: &mut T,
|
contents: &mut T,
|
||||||
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let parent = self.parent_fd()?;
|
let parent = self.parent_fd()?;
|
||||||
|
let mut oflags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_CLOEXEC;
|
||||||
|
if overwrite {
|
||||||
|
oflags = oflags | OFlag::O_TRUNC;
|
||||||
|
} else {
|
||||||
|
oflags = oflags | OFlag::O_EXCL;
|
||||||
|
}
|
||||||
let mut file = tokio::fs::File::from_std(unsafe {
|
let mut file = tokio::fs::File::from_std(unsafe {
|
||||||
std::fs::File::from_raw_fd(
|
std::fs::File::from_raw_fd(
|
||||||
nix::fcntl::openat(
|
nix::fcntl::openat(
|
||||||
parent,
|
parent,
|
||||||
file_name,
|
file_name,
|
||||||
OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY | OFlag::O_CLOEXEC,
|
oflags,
|
||||||
Mode::from_bits(0o600).unwrap(),
|
Mode::from_bits(0o600).unwrap(),
|
||||||
)
|
)
|
||||||
.map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?,
|
.map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?,
|
||||||
@ -818,7 +838,7 @@ where
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Extractor::new(dir, metadata, false, Flags::DEFAULT))
|
Ok(Extractor::new(dir, metadata, false, false, Flags::DEFAULT))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_sub_dir<T, DEST, PATH>(
|
pub async fn extract_sub_dir<T, DEST, PATH>(
|
||||||
@ -951,6 +971,7 @@ where
|
|||||||
&mut file.contents().await.map_err(|_| {
|
&mut file.contents().await.map_err(|_| {
|
||||||
format_err!("found regular file entry without contents in archive")
|
format_err!("found regular file entry without contents in archive")
|
||||||
})?,
|
})?,
|
||||||
|
extractor.overwrite,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
@ -998,6 +1019,7 @@ where
|
|||||||
&mut decoder.contents().ok_or_else(|| {
|
&mut decoder.contents().ok_or_else(|| {
|
||||||
format_err!("found regular file entry without contents in archive")
|
format_err!("found regular file entry without contents in archive")
|
||||||
})?,
|
})?,
|
||||||
|
extractor.overwrite,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,11 @@ fn extract_archive_from_reader<R: std::io::Read>(
|
|||||||
optional: true,
|
optional: true,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
"overwrite": {
|
||||||
|
description: "overwrite already existing files",
|
||||||
|
optional: true,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
"files-from": {
|
"files-from": {
|
||||||
description: "File containing match pattern for files to restore.",
|
description: "File containing match pattern for files to restore.",
|
||||||
optional: true,
|
optional: true,
|
||||||
@ -112,6 +117,7 @@ fn extract_archive(
|
|||||||
no_fcaps: bool,
|
no_fcaps: bool,
|
||||||
no_acls: bool,
|
no_acls: bool,
|
||||||
allow_existing_dirs: bool,
|
allow_existing_dirs: bool,
|
||||||
|
overwrite: bool,
|
||||||
files_from: Option<String>,
|
files_from: Option<String>,
|
||||||
no_device_nodes: bool,
|
no_device_nodes: bool,
|
||||||
no_fifos: bool,
|
no_fifos: bool,
|
||||||
@ -179,6 +185,7 @@ fn extract_archive(
|
|||||||
let options = PxarExtractOptions {
|
let options = PxarExtractOptions {
|
||||||
match_list: &match_list,
|
match_list: &match_list,
|
||||||
allow_existing_dirs,
|
allow_existing_dirs,
|
||||||
|
overwrite,
|
||||||
extract_match_default,
|
extract_match_default,
|
||||||
on_error,
|
on_error,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user