pxar: create .pxarexclude-cli file
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
ae66873ce9
commit
239e49f927
|
@ -37,7 +37,7 @@ pam = "0.7"
|
||||||
pam-sys = "0.5"
|
pam-sys = "0.5"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
pin-utils = "0.1.0"
|
pin-utils = "0.1.0"
|
||||||
pathpatterns = "0.1.0"
|
pathpatterns = "0.1.1"
|
||||||
proxmox = { version = "0.1.39", features = [ "sortable-macro", "api-macro" ] }
|
proxmox = { version = "0.1.39", features = [ "sortable-macro", "api-macro" ] }
|
||||||
#proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
|
#proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
|
||||||
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] }
|
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] }
|
||||||
|
|
|
@ -821,10 +821,10 @@ async fn create_backup(
|
||||||
let empty = Vec::new();
|
let empty = Vec::new();
|
||||||
let exclude_args = param["exclude"].as_array().unwrap_or(&empty);
|
let exclude_args = param["exclude"].as_array().unwrap_or(&empty);
|
||||||
|
|
||||||
let mut exclude_list = Vec::with_capacity(exclude_args.len());
|
let mut pattern_list = Vec::with_capacity(exclude_args.len());
|
||||||
for entry in exclude_args {
|
for entry in exclude_args {
|
||||||
let entry = entry.as_str().ok_or_else(|| format_err!("Invalid pattern string slice"))?;
|
let entry = entry.as_str().ok_or_else(|| format_err!("Invalid pattern string slice"))?;
|
||||||
exclude_list.push(
|
pattern_list.push(
|
||||||
MatchEntry::parse_pattern(entry, PatternFlag::PATH_NAME, MatchType::Exclude)
|
MatchEntry::parse_pattern(entry, PatternFlag::PATH_NAME, MatchType::Exclude)
|
||||||
.map_err(|err| format_err!("invalid exclude pattern entry: {}", err))?
|
.map_err(|err| format_err!("invalid exclude pattern entry: {}", err))?
|
||||||
);
|
);
|
||||||
|
@ -971,7 +971,7 @@ async fn create_backup(
|
||||||
skip_lost_and_found,
|
skip_lost_and_found,
|
||||||
crypt_config.clone(),
|
crypt_config.clone(),
|
||||||
catalog.clone(),
|
catalog.clone(),
|
||||||
exclude_list.clone(),
|
pattern_list.clone(),
|
||||||
entries_max as usize,
|
entries_max as usize,
|
||||||
).await?;
|
).await?;
|
||||||
manifest.add_file(target, stats.size, stats.csum)?;
|
manifest.add_file(target, stats.size, stats.csum)?;
|
||||||
|
|
|
@ -275,16 +275,16 @@ fn create_archive(
|
||||||
exclude: Option<Vec<String>>,
|
exclude: Option<Vec<String>>,
|
||||||
entries_max: isize,
|
entries_max: isize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let exclude_list = {
|
let pattern_list = {
|
||||||
let input = exclude.unwrap_or_else(Vec::new);
|
let input = exclude.unwrap_or_else(Vec::new);
|
||||||
let mut exclude = Vec::with_capacity(input.len());
|
let mut pattern_list = Vec::with_capacity(input.len());
|
||||||
for entry in input {
|
for entry in input {
|
||||||
exclude.push(
|
pattern_list.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))?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
exclude
|
pattern_list
|
||||||
};
|
};
|
||||||
|
|
||||||
let device_set = if all_file_systems {
|
let device_set = if all_file_systems {
|
||||||
|
@ -332,7 +332,7 @@ fn create_archive(
|
||||||
proxmox_backup::pxar::create_archive(
|
proxmox_backup::pxar::create_archive(
|
||||||
dir,
|
dir,
|
||||||
writer,
|
writer,
|
||||||
exclude_list,
|
pattern_list,
|
||||||
feature_flags,
|
feature_flags,
|
||||||
device_set,
|
device_set,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl PxarBackupStream {
|
||||||
_verbose: bool,
|
_verbose: bool,
|
||||||
skip_lost_and_found: bool,
|
skip_lost_and_found: bool,
|
||||||
catalog: Arc<Mutex<CatalogWriter<W>>>,
|
catalog: Arc<Mutex<CatalogWriter<W>>>,
|
||||||
exclude_pattern: Vec<MatchEntry>,
|
patterns: Vec<MatchEntry>,
|
||||||
entries_max: usize,
|
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);
|
||||||
|
@ -66,7 +66,7 @@ impl PxarBackupStream {
|
||||||
if let Err(err) = crate::pxar::create_archive(
|
if let Err(err) = crate::pxar::create_archive(
|
||||||
dir,
|
dir,
|
||||||
writer,
|
writer,
|
||||||
exclude_pattern,
|
patterns,
|
||||||
crate::pxar::flags::DEFAULT,
|
crate::pxar::flags::DEFAULT,
|
||||||
device_set,
|
device_set,
|
||||||
skip_lost_and_found,
|
skip_lost_and_found,
|
||||||
|
@ -93,7 +93,7 @@ impl PxarBackupStream {
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
skip_lost_and_found: bool,
|
skip_lost_and_found: bool,
|
||||||
catalog: Arc<Mutex<CatalogWriter<W>>>,
|
catalog: Arc<Mutex<CatalogWriter<W>>>,
|
||||||
exclude_pattern: Vec<MatchEntry>,
|
patterns: Vec<MatchEntry>,
|
||||||
entries_max: usize,
|
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())?;
|
||||||
|
@ -106,7 +106,7 @@ impl PxarBackupStream {
|
||||||
verbose,
|
verbose,
|
||||||
skip_lost_and_found,
|
skip_lost_and_found,
|
||||||
catalog,
|
catalog,
|
||||||
exclude_pattern,
|
patterns,
|
||||||
entries_max,
|
entries_max,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ struct Archiver<'a, 'b> {
|
||||||
feature_flags: u64,
|
feature_flags: u64,
|
||||||
fs_feature_flags: u64,
|
fs_feature_flags: u64,
|
||||||
fs_magic: i64,
|
fs_magic: i64,
|
||||||
excludes: &'a [MatchEntry],
|
patterns: &'a [MatchEntry],
|
||||||
callback: &'a mut dyn FnMut(&Path) -> Result<(), Error>,
|
callback: &'a mut dyn FnMut(&Path) -> Result<(), Error>,
|
||||||
catalog: Option<&'b mut dyn BackupCatalogWriter>,
|
catalog: Option<&'b mut dyn BackupCatalogWriter>,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -106,7 +106,7 @@ 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 excludes: Vec<MatchEntry>,
|
mut patterns: Vec<MatchEntry>,
|
||||||
feature_flags: u64,
|
feature_flags: u64,
|
||||||
mut device_set: Option<HashSet<u64>>,
|
mut device_set: Option<HashSet<u64>>,
|
||||||
skip_lost_and_found: bool,
|
skip_lost_and_found: bool,
|
||||||
|
@ -142,7 +142,7 @@ where
|
||||||
let mut encoder = Encoder::new(writer, &metadata)?;
|
let mut encoder = Encoder::new(writer, &metadata)?;
|
||||||
|
|
||||||
if skip_lost_and_found {
|
if skip_lost_and_found {
|
||||||
excludes.push(MatchEntry::parse_pattern(
|
patterns.push(MatchEntry::parse_pattern(
|
||||||
"**/lost+found",
|
"**/lost+found",
|
||||||
PatternFlag::PATH_NAME,
|
PatternFlag::PATH_NAME,
|
||||||
MatchType::Exclude,
|
MatchType::Exclude,
|
||||||
|
@ -154,7 +154,7 @@ where
|
||||||
fs_feature_flags,
|
fs_feature_flags,
|
||||||
fs_magic,
|
fs_magic,
|
||||||
callback: &mut callback,
|
callback: &mut callback,
|
||||||
excludes: &excludes,
|
patterns: &patterns,
|
||||||
catalog,
|
catalog,
|
||||||
path: PathBuf::new(),
|
path: PathBuf::new(),
|
||||||
entry_counter: 0,
|
entry_counter: 0,
|
||||||
|
@ -164,6 +164,18 @@ where
|
||||||
hardlinks: HashMap::new(),
|
hardlinks: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !patterns.is_empty() {
|
||||||
|
let content = generate_pxar_excludes_cli(&patterns);
|
||||||
|
let mut file = encoder.create_file(
|
||||||
|
&Metadata::default(),
|
||||||
|
".pxarexclude-cli",
|
||||||
|
content.len() as u64,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
file.write_all(&content)?;
|
||||||
|
}
|
||||||
|
|
||||||
archiver.archive_dir_contents(&mut encoder, source_dir)?;
|
archiver.archive_dir_contents(&mut encoder, source_dir)?;
|
||||||
encoder.finish()?;
|
encoder.finish()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -222,8 +234,6 @@ impl<'a, 'b> Archiver<'a, 'b> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: deal with `.pxarexclude-cli`
|
|
||||||
|
|
||||||
if file_name_bytes == b".pxarexclude" {
|
if file_name_bytes == b".pxarexclude" {
|
||||||
// FIXME: handle this file!
|
// FIXME: handle this file!
|
||||||
continue;
|
continue;
|
||||||
|
@ -244,7 +254,7 @@ impl<'a, 'b> Archiver<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.excludes
|
.patterns
|
||||||
.matches(full_path.as_os_str().as_bytes(), Some(stat.st_mode as u32))
|
.matches(full_path.as_os_str().as_bytes(), Some(stat.st_mode as u32))
|
||||||
== Some(MatchType::Exclude)
|
== Some(MatchType::Exclude)
|
||||||
{
|
{
|
||||||
|
@ -294,7 +304,7 @@ impl<'a, 'b> Archiver<'a, 'b> {
|
||||||
let metadata = get_metadata(fd.as_raw_fd(), &stat, self.flags(), self.fs_magic)?;
|
let metadata = get_metadata(fd.as_raw_fd(), &stat, self.flags(), self.fs_magic)?;
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.excludes
|
.patterns
|
||||||
.matches(self.path.as_os_str().as_bytes(), Some(stat.st_mode as u32))
|
.matches(self.path.as_os_str().as_bytes(), Some(stat.st_mode as u32))
|
||||||
== Some(MatchType::Exclude)
|
== Some(MatchType::Exclude)
|
||||||
{
|
{
|
||||||
|
@ -767,3 +777,32 @@ fn process_acl(
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Note that our pattern lists are "positive". `MatchType::Include` means the file is included.
|
||||||
|
/// Since we are generating an *exclude* list, we need to invert this, so includes get a `'!'`
|
||||||
|
/// prefix.
|
||||||
|
fn generate_pxar_excludes_cli(patterns: &[MatchEntry]) -> Vec<u8> {
|
||||||
|
use pathpatterns::{MatchFlag, MatchPattern};
|
||||||
|
|
||||||
|
let mut content = Vec::new();
|
||||||
|
|
||||||
|
for pattern in patterns {
|
||||||
|
match pattern.match_type() {
|
||||||
|
MatchType::Include => content.push(b'!'),
|
||||||
|
MatchType::Exclude => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match pattern.pattern() {
|
||||||
|
MatchPattern::Literal(lit) => content.extend(lit),
|
||||||
|
MatchPattern::Pattern(pat) => content.extend(pat.pattern().to_bytes()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if pattern.match_flags() == MatchFlag::MATCH_DIRECTORIES && content.last() != Some(&b'/') {
|
||||||
|
content.push(b'/');
|
||||||
|
}
|
||||||
|
|
||||||
|
content.push(b'\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue