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:
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")
|
||||||
|
|
Loading…
Reference in New Issue