use failure::*;
use endian_trait::Endian;
-use std::collections::HashMap;
+use std::collections::{HashSet, HashMap};
use super::format_definition::*;
use super::binary_search_tree::*;
writer_pos: usize,
_size: usize,
file_copy_buffer: Vec<u8>,
- all_file_systems: bool,
- root_st_dev: u64,
+ device_set: Option<HashSet<u64>>,
verbose: bool,
// Flags set by the user
feature_flags: u64,
self.base_path.join(&self.relative_path)
}
+ /// Create archive, write result data to ``writer``.
+ ///
+ /// The ``device_set`` can be use used to limit included mount points.
+ ///
+ /// - ``None``: include all mount points
+ /// - ``Some(set)``: only include devices listed in this set (the
+ /// root path device is automathically added to this list, so
+ /// you can pass an empty set if you want to archive a single
+ /// mount point.)
pub fn encode(
path: PathBuf,
dir: &mut nix::dir::Dir,
writer: &'a mut W,
- all_file_systems: bool,
+ device_set: Option<HashSet<u64>>,
verbose: bool,
feature_flags: u64,
) -> Result<(), Error> {
bail!("got unexpected file type {:?} (not a directory)", path);
}
+ let mut device_set = device_set.clone();
+ if let Some(ref mut set) = device_set {
+ set.insert(stat.st_dev);
+ }
+
let magic = detect_fs_type(dir_fd)?;
if is_virtual_file_system(magic) {
writer_pos: 0,
_size: 0,
file_copy_buffer,
- all_file_systems,
- root_st_dev: stat.st_dev,
+ device_set,
verbose,
feature_flags,
fs_feature_flags,
self.write_quota_project_id(projid)?;
}
- let mut dir_count = 0;
-
let include_children;
if is_virtual_file_system(magic) {
include_children = false;
} else {
- include_children = (self.root_st_dev == dir_stat.st_dev) || self.all_file_systems;
+ if let Some(set) = &self.device_set {
+ include_children = set.contains(&dir_stat.st_dev);
+ } else {
+ include_children = true;
+ }
}
// Expand the exclude match pattern inherited from the parent by local entries, if present
Err(err) => bail!("fstat {:?} failed - {}", self.full_path(), err),
};
- match self.match_exclude_pattern(&filename, &stat, &local_match_pattern) {
+ match match_exclude_pattern(&filename, &stat, &local_match_pattern) {
(MatchType::Exclude, _) => {
let filename_osstr = std::ffi::OsStr::from_bytes(filename.to_bytes());
eprintln!("matched by .pxarexclude entry - skipping: {:?}", self.full_path().join(filename_osstr));
},
- (_, pattern_list) => name_list.push((filename, stat, pattern_list)),
+ (_, child_pattern) => name_list.push((filename, stat, child_pattern)),
}
- dir_count += 1;
- if dir_count > MAX_DIRECTORY_ENTRIES {
+ if name_list.len() > MAX_DIRECTORY_ENTRIES {
bail!("too many directory items in {:?} (> {})", self.full_path(), MAX_DIRECTORY_ENTRIES);
}
}
Ok(())
}
- // If there is a match, an updated PxarExcludePattern list to pass to the matched child is returned.
- fn match_exclude_pattern(&mut self, filename: &CStr, stat: &FileStat, match_pattern: &Vec<PxarExcludePattern>) -> (MatchType, Vec<PxarExcludePattern>) {
- let mut child_pattern = Vec::new();
- let mut match_type = MatchType::None;
- let is_dir = is_directory(&stat);
-
- for pattern in match_pattern {
- match pattern.matches_filename(filename, is_dir) {
- MatchType::None => {},
- MatchType::Exclude => match_type = MatchType::Exclude,
- MatchType::Include => match_type = MatchType::Include,
- MatchType::PartialExclude => {
- if match_type != MatchType::Include && match_type != MatchType::Exclude {
- match_type = MatchType::PartialExclude;
- }
- child_pattern.push(pattern.get_rest_pattern());
- },
- MatchType::PartialInclude => {
- if match_type != MatchType::Include && match_type != MatchType::Exclude {
- // always include partial matches, as we need to match children to decide
- match_type = MatchType::PartialInclude;
- }
- child_pattern.push(pattern.get_rest_pattern());
- },
- }
- }
-
- (match_type, child_pattern)
- }
-
fn encode_file(&mut self, filefd: RawFd, stat: &FileStat, magic: i64) -> Result<(), Error> {
//println!("encode_file: {:?}", self.full_path());
if is_virtual_file_system(magic) {
include_payload = false;
} else {
- include_payload = (stat.st_dev == self.root_st_dev) || self.all_file_systems;
+ if let Some(ref set) = &self.device_set {
+ include_payload = set.contains(&stat.st_dev);
+ } else {
+ include_payload = true;
+ }
}
if !include_payload {
if is_virtual_file_system(magic) {
include_payload = false;
} else {
- include_payload = (stat.st_dev == self.root_st_dev) || self.all_file_systems;
+ if let Some(set) = &self.device_set {
+ include_payload = set.contains(&stat.st_dev);
+ } else {
+ include_payload = true;
+ }
}
if !include_payload {
}
}
+// If there is a match, an updated PxarExcludePattern list to pass to the matched child is returned.
+fn match_exclude_pattern(
+ filename: &CStr,
+ stat: &FileStat,
+ match_pattern: &Vec<PxarExcludePattern>
+) -> (MatchType, Vec<PxarExcludePattern>) {
+ 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::Exclude => match_state = MatchType::Exclude,
+ MatchType::Include => match_state = MatchType::Include,
+ MatchType::PartialExclude => {
+ if match_state != MatchType::Exclude && match_state != MatchType::Include {
+ match_state = MatchType::PartialExclude;
+ }
+ child_pattern.push(pattern.get_rest_pattern());
+ },
+ MatchType::PartialInclude => {
+ if match_state != MatchType::Exclude && match_state != MatchType::Include {
+ match_state = MatchType::PartialInclude;
+ }
+ child_pattern.push(pattern.get_rest_pattern());
+ },
+ }
+ }
+
+ (match_state, child_pattern)
+}
+
fn errno_is_unsupported(errno: Errno) -> bool {
match errno {