From: Dylan Whyte <d.whyte@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup] fix #3613: catalog_shell: include matched dir's contents on restore
Date: Mon, 4 Apr 2022 18:19:20 +0200 [thread overview]
Message-ID: <20220404161920.241543-1-d.whyte@proxmox.com> (raw)
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@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
next reply other threads:[~2022-04-04 16:22 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-04 16:19 Dylan Whyte [this message]
2022-04-06 8:26 Dietmar Maurer
2022-04-06 9:15 ` Dylan Whyte
2022-04-06 9:30 ` Wolfgang Bumiller
2022-04-06 10:09 ` Dylan Whyte
2022-04-06 12:20 ` Wolfgang Bumiller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220404161920.241543-1-d.whyte@proxmox.com \
--to=d.whyte@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.