all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: Gabriel Goller <g.goller@proxmox.com>
Cc: pbs-devel@lists.proxmox.com
Subject: Re: [pbs-devel] [PATCH proxmox-backup v5] fix #4380: check if file is excluded before running `stat()`
Date: Mon, 21 Aug 2023 14:18:02 +0200	[thread overview]
Message-ID: <umze2k5sg3v756xwyfk4efa6mzltidmeenr3kp4mmptqhiyist@roxcxlsfxfsq> (raw)
In-Reply-To: <e865b83b-f33c-b980-5543-8f6dcb6b9154@proxmox.com>

On Mon, Aug 21, 2023 at 01:03:56PM +0200, Gabriel Goller wrote:
> 
> On 8/21/23 10:41, Wolfgang Bumiller wrote:
> > needs a rebase, and comments inline:
> > 
> > On Fri, Aug 18, 2023 at 04:32:12PM +0200, Gabriel Goller wrote:
> > > @@ -1108,7 +1108,7 @@ impl<'a> ExtractorState<'a> {
> > >       async fn handle_new_directory(
> > >           &mut self,
> > >           entry: catalog::DirEntry,
> > > -        match_result: Option<MatchType>,
> > > +        match_result: Result<Option<MatchType>, FileModeRequired>,
> > ^ This is not needed, let's not take errors with us throughout the
> > process.
> > 
> > This is our catalog shell. The catalog file always contains file types
> > for its contents except for hardlinks, since we cannot resolve them.
> > However, hardlinks also cannot recurse down any further, since they're
> > also never directories, so `handle_new_directory` will never actually
> > get `Err()` passed here.
> > 
> > >       ) -> Result<(), Error> {
> > >           // enter a new directory:
> > >           self.read_dir_stack.push(mem::replace(
> > > @@ -1123,7 +1123,7 @@ 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);
> > > +        let create = self.matches && match_result != Ok(Some(MatchType::Exclude));
> > ^ so no need for this change
> > 
> > >           self.extractor
> > >               .enter_directory(dir_pxar.file_name().to_os_string(), dir_meta, create)?;
> > > @@ -1133,9 +1133,9 @@ impl<'a> ExtractorState<'a> {
> > >       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());
> > I'd like to point out that if we don't know what to do, we should fail,
> > so, just use `?` here.
> > 
> > Since this is an interactive tool, we *may* get away with just logging
> > this and continuing with the matches you wrote out below here.
> > 
> > But we should not just be silent about it :-)
> > 
> > Personally, I'm fine with erroring and telling the user to investigate.
> > In practice I doubt anyone will really run into this. The catalog shell
> > is too awkward to have many users (I think???)
> How about we introduce this log message, then use the question mark
> operator?

This would produce both a warning and an error message then, no?
Or did you mean something else?

> 
>     match (did_match, &entry.attr) {
>         (_, DirEntryAttribute::Directory { .. }) => {
>             if match_result.is_err() {
>                 log::error!("error while matching file paths");
>             }
>             self.handle_new_directory(entry, match_result?).await?;
>         }
>         ...
>     }
> > >           let did_match = match match_result {
> > > -            Some(MatchType::Include) => true,
> > > -            Some(MatchType::Exclude) => false,
> > > -            None => self.matches,
> > > +            Ok(Some(MatchType::Include)) => true,
> > > +            Ok(Some(MatchType::Exclude)) => false,
> > > +            _ => self.matches,
> > >           };
> > >           match (did_match, &entry.attr) {
> > > diff --git a/pbs-client/src/pxar/create.rs b/pbs-client/src/pxar/create.rs
> > > index 2577cf98..4a844599 100644
> > > --- a/pbs-client/src/pxar/create.rs
> > > +++ b/pbs-client/src/pxar/create.rs
(...)
> > > +            if stat_results.is_none() {
> > > +                match nix::sys::stat::fstatat(
> > > +                    dir_fd,
> > > +                    file_name.to_owned().as_c_str(),
> > > +                    nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW,
> > > +                ) {
> > > +                    Ok(stat) => {
> > > +                        stat_results = Some(stat);
> > > +                    }
> > > +                    Err(err) => {
> > > +                        return Err(err).context(format!(
> > > +                            "stat failed on {:?} with {:?}",
> > > +                            full_path,
> > > +                            err.desc()
> > > +                        ));
> > > +                    }
> > > +                }
> > > +            }
> > ^ Instead of this large block we then only need:
> > 
> >      let stat = stat_results.map(Ok).unwrap_or_else(get_file_mode)?;
> > 
> > > +
> > >               self.entry_counter += 1;
> > >               if self.entry_counter > self.entry_limit {
> > >                   bail!(
> > > @@ -462,9 +493,9 @@ impl Archiver {
> > >               }
> > >               file_list.push(FileListEntry {
> > > -                name: file_name,
> > > +                name: file_name.to_owned(),
> > >                   path: full_path,
> > > -                stat,
> > > +                stat: stat_results.unwrap(),
> > ^ and this change can just be dropped :-)
> > 
> > >               });
> > >           }
> > > @@ -534,7 +565,7 @@ impl Archiver {
> > >           if self
> > >               .patterns
> > >               .matches(match_path.as_os_str().as_bytes(), Some(stat.st_mode))
> > > -            == Some(MatchType::Exclude)
> > > +            == Ok(Some(MatchType::Exclude))
> > ^ Please don't just ignore errors, just put a `?` onto the call.
> > 
> > On the one hand we know that this cannot error since we pass `Some`, so
> > we could even unwrap, but that's worse, since there's no guarantee that
> > no other errors can happen.
> > We *may* be able to guarantee this by adding a `GetFileMode` impl
> > in pathpatterns directly to `u32` with `type Error =
> > std::convert::Infallible`, and then drop the `Some()` wrapping around
> > this piece?
> 
> Yes, that's nice. Adding this implementation to pathpatterns:
> 
>     impl GetFileMode for u32 {
>         type Error = std::convert::Infallible;
>         fn get(self) -> Result<u32, Self::Error> {
>             Ok(self)
>         }
>     }
> 
> then it should look like this:
> 
>     if self
>         .patterns
>         .matches(match_path.as_os_str().as_bytes(), stat.st_mode)?
>             == Some(MatchType::Exclude)
>     {
>         return Ok(());
>     }
> 
> > >           {
> > >               return Ok(());
> > >           }
> > > diff --git a/pbs-client/src/pxar/extract.rs b/pbs-client/src/pxar/extract.rs
> > > index 4dbaf52d..e08af3c0 100644
> > > --- a/pbs-client/src/pxar/extract.rs
> > > +++ b/pbs-client/src/pxar/extract.rs
> > > @@ -244,16 +244,17 @@ where
> > >           );
> > >           let did_match = match match_result {
> > > -            Some(MatchType::Include) => true,
> > > -            Some(MatchType::Exclude) => false,
> > > -            None => self.state.current_match,
> > > +            Ok(Some(MatchType::Include)) => true,
> > > +            Ok(Some(MatchType::Exclude)) => false,
> > > +            _ => self.state.current_match,
> > Same here, 3 lines above we pass `Some(file_type)` to `matches()`.
> > We should not just use `_` here, but rather, the above should fail.
> 
> Here we can write this:
> 
>     let match_result = self.match_list.matches(
>         entry.path().as_os_str().as_bytes(),
>         metadata.file_type() as u32
>     ).unwrap();
>     let did_match = match match_result {
>         Some(MatchType::Include) => true,
>         Some(MatchType::Exclude) => false,
>         _ => self.state.current_match,
> 
>     };
> 
> Unwrapping should (?) be safe because the `Err` is `Infallible`.

Yeah I guess that's fine. Note: please add comments above unwraps ;-)

Somehow I'm thinking the stdlib should have a separate function for
this... like fn Result<T, Infallible>::unwrap_infallible(self) -> T...
But I don't really feel like it's worth it pulling in another crate for
this ;-)




  reply	other threads:[~2023-08-21 12:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-18 14:32 [pbs-devel] [PATCH pathpatterns v3] match_list: updated `matches()`, to only retrieve file mode if necessary Gabriel Goller
2023-08-18 14:32 ` [pbs-devel] [PATCH proxmox-backup v5] fix #4380: check if file is excluded before running `stat()` Gabriel Goller
2023-08-21  8:41   ` Wolfgang Bumiller
2023-08-21 11:03     ` Gabriel Goller
2023-08-21 12:18       ` Wolfgang Bumiller [this message]
2023-08-21 12:48         ` Gabriel Goller
2023-08-21  7:57 ` [pbs-devel] [PATCH pathpatterns v3] match_list: updated `matches()`, to only retrieve file mode if necessary 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=umze2k5sg3v756xwyfk4efa6mzltidmeenr3kp4mmptqhiyist@roxcxlsfxfsq \
    --to=w.bumiller@proxmox.com \
    --cc=g.goller@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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal