[pbs-devel] [PATCH proxmox-backup] fix #3613: catalog_shell: include matched dir's contents on restore
Dylan Whyte
d.whyte at proxmox.com
Mon Apr 4 18:19:20 CEST 2022
Prior to this, during an interactive restore, if a directory was matched
via a pattern match or selection, only the empty directory would be
restored, and not its contents. Now the entire contents is restored on
directory match
Signed-off-by: Dylan Whyte <d.whyte at proxmox.com>
---
pbs-client/src/catalog_shell.rs | 56 ++++++++++++++++++++++-----------
1 file changed, 37 insertions(+), 19 deletions(-)
diff --git a/pbs-client/src/catalog_shell.rs b/pbs-client/src/catalog_shell.rs
index c9c9da67..d0658def 100644
--- a/pbs-client/src/catalog_shell.rs
+++ b/pbs-client/src/catalog_shell.rs
@@ -997,6 +997,9 @@ impl Shell {
&self.accessor,
)?;
+ // Clear match list following restore
+ self.selected.clear();
+
extractor.extract().await
}
}
@@ -1007,9 +1010,7 @@ struct ExtractorState<'a> {
path_len_stack: Vec<usize>,
dir_stack: Vec<PathStackEntry>,
-
- matches: bool,
- matches_stack: Vec<bool>,
+ match_pos: Option<usize>,
read_dir: <Vec<catalog::DirEntry> as IntoIterator>::IntoIter,
read_dir_stack: Vec<<Vec<catalog::DirEntry> as IntoIterator>::IntoIter>,
@@ -1029,6 +1030,7 @@ impl<'a> ExtractorState<'a> {
match_list: &'a [MatchEntry],
accessor: &'a Accessor,
) -> Result<Self, Error> {
+ let match_pos = None;
let read_dir = catalog
.read_dir(&dir_stack.last().unwrap().catalog)?
.into_iter();
@@ -1038,9 +1040,7 @@ impl<'a> ExtractorState<'a> {
path_len_stack: Vec::new(),
dir_stack,
-
- matches: match_list.is_empty(),
- matches_stack: Vec::new(),
+ match_pos,
read_dir,
read_dir_stack: Vec::new(),
@@ -1084,11 +1084,6 @@ impl<'a> ExtractorState<'a> {
None => return Ok(ControlFlow::Break(())), // out of root directory
};
- self.matches = self
- .matches_stack
- .pop()
- .ok_or_else(|| format_err!("internal iterator error (matches_stack)"))?;
-
self.dir_stack
.pop()
.ok_or_else(|| format_err!("internal iterator error (dir_stack)"))?;
@@ -1106,14 +1101,14 @@ impl<'a> ExtractorState<'a> {
async fn handle_new_directory(
&mut self,
entry: catalog::DirEntry,
- match_result: Option<MatchType>,
+ create_dir: bool,
) -> Result<(), Error> {
// enter a new directory:
self.read_dir_stack.push(mem::replace(
&mut self.read_dir,
self.catalog.read_dir(&entry)?.into_iter(),
));
- self.matches_stack.push(self.matches);
+
self.dir_stack.push(PathStackEntry::new(entry));
self.path_len_stack.push(self.path_len);
self.path_len = self.path.len();
@@ -1121,23 +1116,46 @@ impl<'a> ExtractorState<'a> {
Shell::walk_pxar_archive(self.accessor, &mut self.dir_stack).await?;
let dir_pxar = self.dir_stack.last().unwrap().pxar.as_ref().unwrap();
let dir_meta = dir_pxar.entry().metadata().clone();
- let create = self.matches && match_result != Some(MatchType::Exclude);
- self.extractor.enter_directory(dir_pxar.file_name().to_os_string(), dir_meta, create)?;
+ self.extractor.enter_directory(dir_pxar.file_name().to_os_string(), dir_meta, create_dir)?;
Ok(())
}
pub async fn handle_entry(&mut self, entry: catalog::DirEntry) -> Result<(), Error> {
let match_result = self.match_list.matches(&self.path, entry.get_file_mode());
+
+ let current_pos = self.dir_stack.len();
+
let did_match = match match_result {
- Some(MatchType::Include) => true,
- Some(MatchType::Exclude) => false,
- None => self.matches,
+ Some(MatchType::Include) => {
+ // Only update match position for items lower in the directory stack
+ if let Some(match_pos) = self.match_pos {
+ self.match_pos = Some(usize::min(current_pos, match_pos));
+ } else {
+ self.match_pos = Some(current_pos)
+ }
+ true
+ },
+ Some(MatchType::Exclude) => return Ok(()), // no need to continue for excluded item
+ None => {
+ // Restore items contained within a matched directory
+ if let Some(match_pos) = self.match_pos {
+ if current_pos > match_pos {
+ true
+ } else {
+ self.match_pos = None;
+ false
+ }
+ } else {
+ // Restore everything if no matches were specified
+ self.match_list.is_empty()
+ }
+ }
};
match (did_match, &entry.attr) {
(_, DirEntryAttribute::Directory { .. }) => {
- self.handle_new_directory(entry, match_result).await?;
+ self.handle_new_directory(entry, did_match).await?;
}
(true, DirEntryAttribute::File { .. }) => {
self.dir_stack.push(PathStackEntry::new(entry));
--
2.30.2
More information about the pbs-devel
mailing list