pxar: factor out PxarCreateOptions
containing the CLI parameters that are mostly passed-through from the client to our pxar archive creation wrapper in pxar::create Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						 Wolfgang Bumiller
						Wolfgang Bumiller
					
				
			
			
				
	
			
			
			
						parent
						
							e97025ab02
						
					
				
				
					commit
					77486a608e
				
			| @ -283,23 +283,15 @@ async fn backup_directory<P: AsRef<Path>>( | |||||||
|     dir_path: P, |     dir_path: P, | ||||||
|     archive_name: &str, |     archive_name: &str, | ||||||
|     chunk_size: Option<usize>, |     chunk_size: Option<usize>, | ||||||
|     device_set: Option<HashSet<u64>>, |  | ||||||
|     verbose: bool, |  | ||||||
|     skip_lost_and_found: bool, |  | ||||||
|     catalog: Arc<Mutex<CatalogWriter<crate::tools::StdChannelWriter>>>, |     catalog: Arc<Mutex<CatalogWriter<crate::tools::StdChannelWriter>>>, | ||||||
|     exclude_pattern: Vec<MatchEntry>, |     pxar_create_options: proxmox_backup::pxar::PxarCreateOptions, | ||||||
|     entries_max: usize, |  | ||||||
|     upload_options: UploadOptions, |     upload_options: UploadOptions, | ||||||
| ) -> Result<BackupStats, Error> { | ) -> Result<BackupStats, Error> { | ||||||
|  |  | ||||||
|     let pxar_stream = PxarBackupStream::open( |     let pxar_stream = PxarBackupStream::open( | ||||||
|         dir_path.as_ref(), |         dir_path.as_ref(), | ||||||
|         device_set, |  | ||||||
|         verbose, |  | ||||||
|         skip_lost_and_found, |  | ||||||
|         catalog, |         catalog, | ||||||
|         exclude_pattern, |         pxar_create_options, | ||||||
|         entries_max, |  | ||||||
|     )?; |     )?; | ||||||
|     let mut chunk_stream = ChunkStream::new(pxar_stream, chunk_size); |     let mut chunk_stream = ChunkStream::new(pxar_stream, chunk_size); | ||||||
|  |  | ||||||
| @ -1039,6 +1031,15 @@ async fn create_backup( | |||||||
|  |  | ||||||
|                 println!("Upload directory '{}' to '{}' as {}", filename, repo, target); |                 println!("Upload directory '{}' to '{}' as {}", filename, repo, target); | ||||||
|                 catalog.lock().unwrap().start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?; |                 catalog.lock().unwrap().start_directory(std::ffi::CString::new(target.as_str())?.as_c_str())?; | ||||||
|  |  | ||||||
|  |                 let pxar_options = proxmox_backup::pxar::PxarCreateOptions { | ||||||
|  |                     device_set: devices.clone(), | ||||||
|  |                     patterns: pattern_list.clone(), | ||||||
|  |                     entries_max: entries_max as usize, | ||||||
|  |                     skip_lost_and_found, | ||||||
|  |                     verbose, | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|                 let upload_options = UploadOptions { |                 let upload_options = UploadOptions { | ||||||
|                     previous_manifest: previous_manifest.clone(), |                     previous_manifest: previous_manifest.clone(), | ||||||
|                     compress: true, |                     compress: true, | ||||||
| @ -1051,12 +1052,8 @@ async fn create_backup( | |||||||
|                     &filename, |                     &filename, | ||||||
|                     &target, |                     &target, | ||||||
|                     chunk_size_opt, |                     chunk_size_opt, | ||||||
|                     devices.clone(), |  | ||||||
|                     verbose, |  | ||||||
|                     skip_lost_and_found, |  | ||||||
|                     catalog.clone(), |                     catalog.clone(), | ||||||
|                     pattern_list.clone(), |                     pxar_options, | ||||||
|                     entries_max as usize, |  | ||||||
|                     upload_options, |                     upload_options, | ||||||
|                 ).await?; |                 ).await?; | ||||||
|                 manifest.add_file(target, stats.size, stats.csum, crypt_mode)?; |                 manifest.add_file(target, stats.size, stats.csum, crypt_mode)?; | ||||||
|  | |||||||
| @ -311,16 +311,16 @@ fn create_archive( | |||||||
|     exclude: Option<Vec<String>>, |     exclude: Option<Vec<String>>, | ||||||
|     entries_max: isize, |     entries_max: isize, | ||||||
| ) -> Result<(), Error> { | ) -> Result<(), Error> { | ||||||
|     let pattern_list = { |     let patterns = { | ||||||
|         let input = exclude.unwrap_or_else(Vec::new); |         let input = exclude.unwrap_or_else(Vec::new); | ||||||
|         let mut pattern_list = Vec::with_capacity(input.len()); |         let mut patterns = Vec::with_capacity(input.len()); | ||||||
|         for entry in input { |         for entry in input { | ||||||
|             pattern_list.push( |             patterns.push( | ||||||
|                 MatchEntry::parse_pattern(entry, PatternFlag::PATH_NAME, MatchType::Exclude) |                 MatchEntry::parse_pattern(entry, PatternFlag::PATH_NAME, MatchType::Exclude) | ||||||
|                     .map_err(|err| format_err!("error in exclude pattern: {}", err))?, |                     .map_err(|err| format_err!("error in exclude pattern: {}", err))?, | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|         pattern_list |         patterns | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let device_set = if all_file_systems { |     let device_set = if all_file_systems { | ||||||
| @ -329,6 +329,15 @@ fn create_archive( | |||||||
|         Some(HashSet::new()) |         Some(HashSet::new()) | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     let options = proxmox_backup::pxar::PxarCreateOptions { | ||||||
|  |         entries_max: entries_max as usize, | ||||||
|  |         device_set, | ||||||
|  |         patterns, | ||||||
|  |         verbose, | ||||||
|  |         skip_lost_and_found: false, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|     let source = PathBuf::from(source); |     let source = PathBuf::from(source); | ||||||
|  |  | ||||||
|     let dir = nix::dir::Dir::open( |     let dir = nix::dir::Dir::open( | ||||||
| @ -368,18 +377,15 @@ fn create_archive( | |||||||
|     proxmox_backup::pxar::create_archive( |     proxmox_backup::pxar::create_archive( | ||||||
|         dir, |         dir, | ||||||
|         writer, |         writer, | ||||||
|         pattern_list, |  | ||||||
|         feature_flags, |         feature_flags, | ||||||
|         device_set, |  | ||||||
|         false, |  | ||||||
|         |path| { |         |path| { | ||||||
|             if verbose { |             if verbose { | ||||||
|                 println!("{:?}", path); |                 println!("{:?}", path); | ||||||
|             } |             } | ||||||
|             Ok(()) |             Ok(()) | ||||||
|         }, |         }, | ||||||
|         entries_max as usize, |  | ||||||
|         None, |         None, | ||||||
|  |         options, | ||||||
|     )?; |     )?; | ||||||
|  |  | ||||||
|     Ok(()) |     Ok(()) | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| use std::collections::HashSet; |  | ||||||
| use std::io::Write; | use std::io::Write; | ||||||
| //use std::os::unix::io::FromRawFd; | //use std::os::unix::io::FromRawFd; | ||||||
| use std::path::Path; | use std::path::Path; | ||||||
| @ -13,8 +12,6 @@ use nix::dir::Dir; | |||||||
| use nix::fcntl::OFlag; | use nix::fcntl::OFlag; | ||||||
| use nix::sys::stat::Mode; | use nix::sys::stat::Mode; | ||||||
|  |  | ||||||
| use pathpatterns::MatchEntry; |  | ||||||
|  |  | ||||||
| use crate::backup::CatalogWriter; | use crate::backup::CatalogWriter; | ||||||
|  |  | ||||||
| /// Stream implementation to encode and upload .pxar archives. | /// Stream implementation to encode and upload .pxar archives. | ||||||
| @ -38,12 +35,8 @@ impl Drop for PxarBackupStream { | |||||||
| impl PxarBackupStream { | impl PxarBackupStream { | ||||||
|     pub fn new<W: Write + Send + 'static>( |     pub fn new<W: Write + Send + 'static>( | ||||||
|         dir: Dir, |         dir: Dir, | ||||||
|         device_set: Option<HashSet<u64>>, |  | ||||||
|         verbose: bool, |  | ||||||
|         skip_lost_and_found: bool, |  | ||||||
|         catalog: Arc<Mutex<CatalogWriter<W>>>, |         catalog: Arc<Mutex<CatalogWriter<W>>>, | ||||||
|         patterns: Vec<MatchEntry>, |         options: crate::pxar::PxarCreateOptions, | ||||||
|         entries_max: usize, |  | ||||||
|     ) -> Result<Self, Error> { |     ) -> Result<Self, Error> { | ||||||
|         let (tx, rx) = std::sync::mpsc::sync_channel(10); |         let (tx, rx) = std::sync::mpsc::sync_channel(10); | ||||||
|  |  | ||||||
| @ -61,22 +54,21 @@ impl PxarBackupStream { | |||||||
|                         crate::tools::StdChannelWriter::new(tx), |                         crate::tools::StdChannelWriter::new(tx), | ||||||
|                     ); |                     ); | ||||||
|  |  | ||||||
|  |                     let verbose = options.verbose; | ||||||
|  |  | ||||||
|                     let writer = pxar::encoder::sync::StandardWriter::new(writer); |                     let writer = pxar::encoder::sync::StandardWriter::new(writer); | ||||||
|                     if let Err(err) = crate::pxar::create_archive( |                     if let Err(err) = crate::pxar::create_archive( | ||||||
|                         dir, |                         dir, | ||||||
|                         writer, |                         writer, | ||||||
|                         patterns, |  | ||||||
|                         crate::pxar::Flags::DEFAULT, |                         crate::pxar::Flags::DEFAULT, | ||||||
|                         device_set, |  | ||||||
|                         skip_lost_and_found, |  | ||||||
|                         |path| { |                         |path| { | ||||||
|                             if verbose { |                             if verbose { | ||||||
|                                 println!("{:?}", path); |                                 println!("{:?}", path); | ||||||
|                             } |                             } | ||||||
|                             Ok(()) |                             Ok(()) | ||||||
|                         }, |                         }, | ||||||
|                         entries_max, |  | ||||||
|                         Some(&mut *catalog_guard), |                         Some(&mut *catalog_guard), | ||||||
|  |                         options, | ||||||
|                     ) { |                     ) { | ||||||
|                         let mut error = error.lock().unwrap(); |                         let mut error = error.lock().unwrap(); | ||||||
|                         *error = Some(err.to_string()); |                         *error = Some(err.to_string()); | ||||||
| @ -93,23 +85,15 @@ impl PxarBackupStream { | |||||||
|  |  | ||||||
|     pub fn open<W: Write + Send + 'static>( |     pub fn open<W: Write + Send + 'static>( | ||||||
|         dirname: &Path, |         dirname: &Path, | ||||||
|         device_set: Option<HashSet<u64>>, |  | ||||||
|         verbose: bool, |  | ||||||
|         skip_lost_and_found: bool, |  | ||||||
|         catalog: Arc<Mutex<CatalogWriter<W>>>, |         catalog: Arc<Mutex<CatalogWriter<W>>>, | ||||||
|         patterns: Vec<MatchEntry>, |         options: crate::pxar::PxarCreateOptions, | ||||||
|         entries_max: usize, |  | ||||||
|     ) -> Result<Self, Error> { |     ) -> Result<Self, Error> { | ||||||
|         let dir = nix::dir::Dir::open(dirname, OFlag::O_DIRECTORY, Mode::empty())?; |         let dir = nix::dir::Dir::open(dirname, OFlag::O_DIRECTORY, Mode::empty())?; | ||||||
|  |  | ||||||
|         Self::new( |         Self::new( | ||||||
|             dir, |             dir, | ||||||
|             device_set, |  | ||||||
|             verbose, |  | ||||||
|             skip_lost_and_found, |  | ||||||
|             catalog, |             catalog, | ||||||
|             patterns, |             options, | ||||||
|             entries_max, |  | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,6 +27,22 @@ use crate::pxar::Flags; | |||||||
| use crate::pxar::tools::assert_single_path_component; | use crate::pxar::tools::assert_single_path_component; | ||||||
| use crate::tools::{acl, fs, xattr, Fd}; | use crate::tools::{acl, fs, xattr, Fd}; | ||||||
|  |  | ||||||
|  | /// Pxar options for creating a pxar archive/stream | ||||||
|  | #[derive(Default, Clone)] | ||||||
|  | pub struct PxarCreateOptions { | ||||||
|  |     /// Device/mountpoint st_dev numbers that should be included. None for no limitation. | ||||||
|  |     pub device_set: Option<HashSet<u64>>, | ||||||
|  |     /// Exclusion patterns | ||||||
|  |     pub patterns: Vec<MatchEntry>, | ||||||
|  |     /// Maximum number of entries to hold in memory | ||||||
|  |     pub entries_max: usize, | ||||||
|  |     /// Skip lost+found directory | ||||||
|  |     pub skip_lost_and_found: bool, | ||||||
|  |     /// Verbose output | ||||||
|  |     pub verbose: bool, | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| fn detect_fs_type(fd: RawFd) -> Result<i64, Error> { | fn detect_fs_type(fd: RawFd) -> Result<i64, Error> { | ||||||
|     let mut fs_stat = std::mem::MaybeUninit::uninit(); |     let mut fs_stat = std::mem::MaybeUninit::uninit(); | ||||||
|     let res = unsafe { libc::fstatfs(fd, fs_stat.as_mut_ptr()) }; |     let res = unsafe { libc::fstatfs(fd, fs_stat.as_mut_ptr()) }; | ||||||
| @ -136,13 +152,10 @@ type Encoder<'a, 'b> = pxar::encoder::Encoder<'a, &'b mut dyn pxar::encoder::Seq | |||||||
| pub fn create_archive<T, F>( | pub fn create_archive<T, F>( | ||||||
|     source_dir: Dir, |     source_dir: Dir, | ||||||
|     mut writer: T, |     mut writer: T, | ||||||
|     mut patterns: Vec<MatchEntry>, |  | ||||||
|     feature_flags: Flags, |     feature_flags: Flags, | ||||||
|     mut device_set: Option<HashSet<u64>>, |  | ||||||
|     skip_lost_and_found: bool, |  | ||||||
|     mut callback: F, |     mut callback: F, | ||||||
|     entry_limit: usize, |  | ||||||
|     catalog: Option<&mut dyn BackupCatalogWriter>, |     catalog: Option<&mut dyn BackupCatalogWriter>, | ||||||
|  |     options: PxarCreateOptions, | ||||||
| ) -> Result<(), Error> | ) -> Result<(), Error> | ||||||
| where | where | ||||||
|     T: pxar::encoder::SeqWrite, |     T: pxar::encoder::SeqWrite, | ||||||
| @ -164,6 +177,7 @@ where | |||||||
|     ) |     ) | ||||||
|     .map_err(|err| format_err!("failed to get metadata for source directory: {}", err))?; |     .map_err(|err| format_err!("failed to get metadata for source directory: {}", err))?; | ||||||
|  |  | ||||||
|  |     let mut device_set = options.device_set.clone(); | ||||||
|     if let Some(ref mut set) = device_set { |     if let Some(ref mut set) = device_set { | ||||||
|         set.insert(stat.st_dev); |         set.insert(stat.st_dev); | ||||||
|     } |     } | ||||||
| @ -171,7 +185,9 @@ where | |||||||
|     let writer = &mut writer as &mut dyn pxar::encoder::SeqWrite; |     let writer = &mut writer as &mut dyn pxar::encoder::SeqWrite; | ||||||
|     let mut encoder = Encoder::new(writer, &metadata)?; |     let mut encoder = Encoder::new(writer, &metadata)?; | ||||||
|  |  | ||||||
|     if skip_lost_and_found { |     let mut patterns = options.patterns.clone(); | ||||||
|  |  | ||||||
|  |     if options.skip_lost_and_found { | ||||||
|         patterns.push(MatchEntry::parse_pattern( |         patterns.push(MatchEntry::parse_pattern( | ||||||
|             "lost+found", |             "lost+found", | ||||||
|             PatternFlag::PATH_NAME, |             PatternFlag::PATH_NAME, | ||||||
| @ -188,7 +204,7 @@ where | |||||||
|         catalog, |         catalog, | ||||||
|         path: PathBuf::new(), |         path: PathBuf::new(), | ||||||
|         entry_counter: 0, |         entry_counter: 0, | ||||||
|         entry_limit, |         entry_limit: options.entries_max, | ||||||
|         current_st_dev: stat.st_dev, |         current_st_dev: stat.st_dev, | ||||||
|         device_set, |         device_set, | ||||||
|         hardlinks: HashMap::new(), |         hardlinks: HashMap::new(), | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ pub(crate) mod tools; | |||||||
| mod flags; | mod flags; | ||||||
| pub use flags::Flags; | pub use flags::Flags; | ||||||
|  |  | ||||||
| pub use create::create_archive; | pub use create::{create_archive, PxarCreateOptions}; | ||||||
| pub use extract::{extract_archive, ErrorHandler}; | pub use extract::{extract_archive, ErrorHandler}; | ||||||
|  |  | ||||||
| /// The format requires to build sorted directory lookup tables in | /// The format requires to build sorted directory lookup tables in | ||||||
|  | |||||||
| @ -25,16 +25,18 @@ fn run_test(dir_name: &str) -> Result<(), Error> { | |||||||
|         dir_name, nix::fcntl::OFlag::O_NOFOLLOW, |         dir_name, nix::fcntl::OFlag::O_NOFOLLOW, | ||||||
|         nix::sys::stat::Mode::empty())?; |         nix::sys::stat::Mode::empty())?; | ||||||
|  |  | ||||||
|  |     let options = PxarCreateOptions { | ||||||
|  |         entries_max: ENCODER_MAX_ENTRIES, | ||||||
|  |         ..PxarCreateOptions::default() | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     create_archive( |     create_archive( | ||||||
|         dir, |         dir, | ||||||
|         writer, |         writer, | ||||||
|         Vec::new(), |  | ||||||
|         Flags::DEFAULT, |         Flags::DEFAULT, | ||||||
|         None, |  | ||||||
|         false, |  | ||||||
|         |_| Ok(()), |         |_| Ok(()), | ||||||
|         ENCODER_MAX_ENTRIES, |  | ||||||
|         None, |         None, | ||||||
|  |         options, | ||||||
|     )?; |     )?; | ||||||
|  |  | ||||||
|     Command::new("cmp") |     Command::new("cmp") | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user