pxar: match_pattern: refactor match_filename
The match_filename() in sequentail_decoder and encoder are moved to be static functions of MatchPattern. This allows to reuse the code also in the catalog find implementation. Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						 Dietmar Maurer
						Dietmar Maurer
					
				
			
			
				
	
			
			
			
						parent
						
							f084505ec5
						
					
				
				
					commit
					d3dbe52f37
				
			| @ -736,7 +736,11 @@ impl<'a, W: Write, C: BackupCatalogWriter> Encoder<'a, W, C> { | ||||
|                     Err(err) => bail!("fstat {:?} failed - {}", self.full_path(), err), | ||||
|                 }; | ||||
|  | ||||
|                 match match_filename(&filename, &stat, &local_match_pattern)? { | ||||
|                 match MatchPattern::match_filename_exclude( | ||||
|                     &filename, | ||||
|                     is_directory(&stat), | ||||
|                     &local_match_pattern, | ||||
|                 )? { | ||||
|                     (MatchType::Positive, _) => { | ||||
|                         let filename_osstr = std::ffi::OsStr::from_bytes(filename.to_bytes()); | ||||
|                         eprintln!( | ||||
| @ -1227,32 +1231,6 @@ impl<'a, W: Write, C: BackupCatalogWriter> Encoder<'a, W, C> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| // If there is a match, an updated MatchPattern list to pass to the matched child is returned. | ||||
| fn match_filename( | ||||
|     filename: &CStr, | ||||
|     stat: &FileStat, | ||||
|     match_pattern: &[MatchPattern], | ||||
| ) -> Result<(MatchType, Vec<MatchPattern>), Error> { | ||||
|     let mut child_pattern = Vec::new(); | ||||
|     let mut match_state = MatchType::None; | ||||
|  | ||||
|     for pattern in match_pattern { | ||||
|         match pattern.matches_filename(filename, is_directory(&stat))? { | ||||
|             MatchType::None => {} | ||||
|             MatchType::Positive => match_state = MatchType::Positive, | ||||
|             MatchType::Negative => match_state = MatchType::Negative, | ||||
|             match_type => { | ||||
|                 if match_state != MatchType::Positive && match_state != MatchType::Negative { | ||||
|                     match_state = match_type; | ||||
|                 } | ||||
|                 child_pattern.push(pattern.get_rest_pattern()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Ok((match_state, child_pattern)) | ||||
| } | ||||
|  | ||||
| fn errno_is_unsupported(errno: Errno) -> bool { | ||||
|     match errno { | ||||
|         Errno::ENOTTY | Errno::ENOSYS | Errno::EBADF | Errno::EOPNOTSUPP | Errno::EINVAL => true, | ||||
|  | ||||
| @ -290,6 +290,142 @@ impl MatchPattern { | ||||
|  | ||||
|         Ok(res) | ||||
|     } | ||||
|  | ||||
|     /// Match the given filename against the set of match patterns. | ||||
|     /// | ||||
|     /// A positive match is intended to includes the full subtree (unless another | ||||
|     /// negative match excludes entries later). | ||||
|     /// The `MatchType` together with an updated `MatchPattern` list for passing | ||||
|     /// to the matched child is returned. | ||||
|     /// ``` | ||||
|     /// # use std::ffi::CString; | ||||
|     /// # use self::proxmox_backup::pxar::{MatchPattern, MatchType}; | ||||
|     /// # fn main() -> Result<(), failure::Error> { | ||||
|     /// let patterns = vec![ | ||||
|     ///     MatchPattern::from_line(b"some/match/pattern/")?.unwrap(), | ||||
|     ///     MatchPattern::from_line(b"to_match/")?.unwrap() | ||||
|     /// ]; | ||||
|     /// let filename = CString::new("some")?; | ||||
|     /// let is_dir = true; | ||||
|     /// let (match_type, child_pattern) = MatchPattern::match_filename_include( | ||||
|     ///     &filename, | ||||
|     ///     is_dir, | ||||
|     ///     &patterns | ||||
|     /// )?; | ||||
|     /// assert_eq!(match_type, MatchType::PartialPositive); | ||||
|     /// /// child pattern will be the same as ... | ||||
|     /// let pattern = MatchPattern::from_line(b"match/pattern/")?.unwrap(); | ||||
|     /// | ||||
|     /// let filename = CString::new("to_match")?; | ||||
|     /// let is_dir = true; | ||||
|     /// let (match_type, child_pattern) = MatchPattern::match_filename_include( | ||||
|     ///     &filename, | ||||
|     ///     is_dir, | ||||
|     ///     &patterns | ||||
|     /// )?; | ||||
|     /// assert_eq!(match_type, MatchType::Positive); | ||||
|     /// /// child pattern will be the same as ... | ||||
|     /// let pattern = MatchPattern::from_line(b"**/*")?.unwrap(); | ||||
|     /// # Ok(()) | ||||
|     /// # } | ||||
|     /// ``` | ||||
|     pub fn match_filename_include( | ||||
|         filename: &CStr, | ||||
|         is_dir: bool, | ||||
|         match_pattern: &[MatchPattern], | ||||
|     ) -> Result<(MatchType, Vec<MatchPattern>), Error> { | ||||
|         let mut child_pattern = Vec::new(); | ||||
|         let mut match_state = MatchType::None; | ||||
|  | ||||
|         for pattern in match_pattern { | ||||
|             match pattern.matches_filename(filename, is_dir)? { | ||||
|                 MatchType::None => continue, | ||||
|                 MatchType::Positive => { | ||||
|                     match_state = MatchType::Positive; | ||||
|                     // Full match so lets include everything below this node | ||||
|                     let incl_pattern = MatchPattern::from_line(b"**/*").unwrap().unwrap(); | ||||
|                     child_pattern.push(incl_pattern); | ||||
|                 } | ||||
|                 MatchType::Negative => match_state = MatchType::Negative, | ||||
|                 MatchType::PartialPositive => { | ||||
|                     if match_state != MatchType::Negative && match_state != MatchType::Positive { | ||||
|                         match_state = MatchType::PartialPositive; | ||||
|                     } | ||||
|                     child_pattern.push(pattern.get_rest_pattern()); | ||||
|                 } | ||||
|                 MatchType::PartialNegative => { | ||||
|                     if match_state == MatchType::PartialPositive { | ||||
|                         match_state = MatchType::PartialNegative; | ||||
|                     } | ||||
|                     child_pattern.push(pattern.get_rest_pattern()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok((match_state, child_pattern)) | ||||
|     } | ||||
|  | ||||
|     /// Match the given filename against the set of match patterns. | ||||
|     /// | ||||
|     /// A positive match is intended to exclude the full subtree, independent of | ||||
|     /// matches deeper down the tree. | ||||
|     /// The `MatchType` together with an updated `MatchPattern` list for passing | ||||
|     /// to the matched child is returned. | ||||
|     /// ``` | ||||
|     /// # use std::ffi::CString; | ||||
|     /// # use self::proxmox_backup::pxar::{MatchPattern, MatchType}; | ||||
|     /// # fn main() -> Result<(), failure::Error> { | ||||
|     /// let patterns = vec![ | ||||
|     ///     MatchPattern::from_line(b"some/match/pattern/")?.unwrap(), | ||||
|     ///     MatchPattern::from_line(b"to_match/")?.unwrap() | ||||
|     /// ]; | ||||
|     /// let filename = CString::new("some")?; | ||||
|     /// let is_dir = true; | ||||
|     /// let (match_type, child_pattern) = MatchPattern::match_filename_exclude( | ||||
|     ///     &filename, | ||||
|     ///     is_dir, | ||||
|     ///     &patterns | ||||
|     /// )?; | ||||
|     /// assert_eq!(match_type, MatchType::PartialPositive); | ||||
|     /// /// child pattern will be the same as ... | ||||
|     /// let pattern = MatchPattern::from_line(b"match/pattern/")?.unwrap(); | ||||
|     /// | ||||
|     /// let filename = CString::new("to_match")?; | ||||
|     /// let is_dir = true; | ||||
|     /// let (match_type, child_pattern) = MatchPattern::match_filename_exclude( | ||||
|     ///     &filename, | ||||
|     ///     is_dir, | ||||
|     ///     &patterns | ||||
|     /// )?; | ||||
|     /// assert_eq!(match_type, MatchType::Positive); | ||||
|     /// /// child pattern will be empty | ||||
|     /// # Ok(()) | ||||
|     /// # } | ||||
|     /// ``` | ||||
|     pub fn match_filename_exclude( | ||||
|         filename: &CStr, | ||||
|         is_dir: bool, | ||||
|         match_pattern: &[MatchPattern], | ||||
|     ) -> Result<(MatchType, Vec<MatchPattern>), Error> { | ||||
|         let mut child_pattern = Vec::new(); | ||||
|         let mut match_state = MatchType::None; | ||||
|  | ||||
|         for pattern in match_pattern { | ||||
|             match pattern.matches_filename(filename, is_dir)? { | ||||
|                 MatchType::None => {} | ||||
|                 MatchType::Positive => match_state = MatchType::Positive, | ||||
|                 MatchType::Negative => match_state = MatchType::Negative, | ||||
|                 match_type => { | ||||
|                     if match_state != MatchType::Positive && match_state != MatchType::Negative { | ||||
|                         match_state = match_type; | ||||
|                     } | ||||
|                     child_pattern.push(pattern.get_rest_pattern()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok((match_state, child_pattern)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Splits the `CStr` slice at the first slash encountered and returns the | ||||
|  | ||||
| @ -819,7 +819,11 @@ impl<R: Read> SequentialDecoder<R> { | ||||
|         // there are no match pattern. | ||||
|         let mut matched = parent_matched; | ||||
|         if !match_pattern.is_empty() { | ||||
|             match match_filename(filename, ifmt == libc::S_IFDIR, match_pattern)? { | ||||
|             match MatchPattern::match_filename_include( | ||||
|                 &CString::new(filename.as_bytes())?, | ||||
|                 ifmt == libc::S_IFDIR, | ||||
|                 match_pattern, | ||||
|             )? { | ||||
|                 (MatchType::None, _) => matched = MatchType::None, | ||||
|                 (MatchType::Negative, _) => matched = MatchType::Negative, | ||||
|                 (match_type, pattern) => { | ||||
| @ -1111,43 +1115,6 @@ impl<R: Read> SequentialDecoder<R> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn match_filename( | ||||
|     filename: &OsStr, | ||||
|     is_dir: bool, | ||||
|     match_pattern: &[MatchPattern], | ||||
| ) -> Result<(MatchType, Vec<MatchPattern>), Error> { | ||||
|     let mut child_pattern = Vec::new(); | ||||
|     let mut match_state = MatchType::None; | ||||
|     // read_filename() checks for nul bytes, so it is save to unwrap here | ||||
|     let name = CString::new(filename.as_bytes()).unwrap(); | ||||
|  | ||||
|     for pattern in match_pattern { | ||||
|         match pattern.matches_filename(&name, is_dir)? { | ||||
|             MatchType::None => {} | ||||
|             MatchType::Positive => { | ||||
|                 match_state = MatchType::Positive; | ||||
|                 let incl_pattern = MatchPattern::from_line(b"**/*").unwrap().unwrap(); | ||||
|                 child_pattern.push(incl_pattern.get_rest_pattern()); | ||||
|             } | ||||
|             MatchType::Negative => match_state = MatchType::Negative, | ||||
|             MatchType::PartialPositive => { | ||||
|                 if match_state != MatchType::Negative && match_state != MatchType::Positive { | ||||
|                     match_state = MatchType::PartialPositive; | ||||
|                 } | ||||
|                 child_pattern.push(pattern.get_rest_pattern()); | ||||
|             } | ||||
|             MatchType::PartialNegative => { | ||||
|                 if match_state == MatchType::PartialPositive { | ||||
|                     match_state = MatchType::PartialNegative; | ||||
|                 } | ||||
|                 child_pattern.push(pattern.get_rest_pattern()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Ok((match_state, child_pattern)) | ||||
| } | ||||
|  | ||||
| fn file_openat( | ||||
|     parent: RawFd, | ||||
|     filename: &OsStr, | ||||
|  | ||||
		Reference in New Issue
	
	Block a user