diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index 18949185..36020d45 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -256,6 +256,7 @@ async fn backup_directory>( skip_lost_and_found: bool, crypt_config: Option>, catalog: Arc>>, + exclude_pattern: Vec, entries_max: usize, ) -> Result { @@ -265,6 +266,7 @@ async fn backup_directory>( verbose, skip_lost_and_found, catalog, + exclude_pattern, entries_max, )?; let mut chunk_stream = ChunkStream::new(pxar_stream, chunk_size); @@ -770,6 +772,15 @@ fn spawn_catalog_upload( schema: CHUNK_SIZE_SCHEMA, optional: true, }, + "exclude": { + type: Array, + description: "List of paths or patterns for matching files to exclude.", + optional: true, + items: { + type: String, + description: "Path or match pattern.", + } + }, "entries-max": { type: Integer, description: "Max number of entries to hold in memory.", @@ -819,6 +830,17 @@ async fn create_backup( let entries_max = param["entries-max"].as_u64().unwrap_or(pxar::ENCODER_MAX_ENTRIES as u64); + let empty = Vec::new(); + let arg_pattern = param["exclude"].as_array().unwrap_or(&empty); + + let mut pattern_list = Vec::with_capacity(arg_pattern.len()); + for s in arg_pattern { + let l = s.as_str().ok_or_else(|| format_err!("Invalid pattern string slice"))?; + let p = pxar::MatchPattern::from_line(l.as_bytes())? + .ok_or_else(|| format_err!("Invalid match pattern in arguments"))?; + pattern_list.push(p); + } + let mut devices = if all_file_systems { None } else { Some(HashSet::new()) }; if let Some(include_dev) = include_dev { @@ -967,6 +989,7 @@ async fn create_backup( skip_lost_and_found, crypt_config.clone(), catalog.clone(), + pattern_list.clone(), entries_max as usize, ).await?; manifest.add_file(target, stats.size, stats.csum)?; diff --git a/src/client/pxar_backup_stream.rs b/src/client/pxar_backup_stream.rs index 5c1c8bae..80ba52f0 100644 --- a/src/client/pxar_backup_stream.rs +++ b/src/client/pxar_backup_stream.rs @@ -45,6 +45,7 @@ impl PxarBackupStream { verbose: bool, skip_lost_and_found: bool, catalog: Arc>>, + exclude_pattern: Vec, entries_max: usize, ) -> Result { @@ -56,7 +57,6 @@ impl PxarBackupStream { let error2 = error.clone(); let catalog = catalog.clone(); - let exclude_pattern = Vec::new(); let child = std::thread::Builder::new().name("PxarBackupStream".to_string()).spawn(move || { let mut guard = catalog.lock().unwrap(); let mut writer = std::io::BufWriter::with_capacity(buffer_size, crate::tools::StdChannelWriter::new(tx)); @@ -91,13 +91,14 @@ impl PxarBackupStream { verbose: bool, skip_lost_and_found: bool, catalog: Arc>>, + exclude_pattern: Vec, entries_max: usize, ) -> Result { let dir = nix::dir::Dir::open(dirname, OFlag::O_DIRECTORY, Mode::empty())?; let path = std::path::PathBuf::from(dirname); - Self::new(dir, path, device_set, verbose, skip_lost_and_found, catalog, entries_max) + Self::new(dir, path, device_set, verbose, skip_lost_and_found, catalog, exclude_pattern, entries_max) } } diff --git a/src/pxar/match_pattern.rs b/src/pxar/match_pattern.rs index 066b876d..e14036b3 100644 --- a/src/pxar/match_pattern.rs +++ b/src/pxar/match_pattern.rs @@ -60,7 +60,7 @@ pub enum MatchType { /// # Ok(()) /// # } /// ``` -#[derive(Eq, PartialOrd)] +#[derive(Clone, Eq, PartialOrd)] pub struct MatchPattern { pattern: Vec, match_positive: bool,