diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index d73dbec8..71f72a2d 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -799,7 +799,7 @@ fn restore( if let Some(target) = target { - let feature_flags = pxar::CA_FORMAT_DEFAULT; + let feature_flags = pxar::flags::DEFAULT; let mut decoder = pxar::SequentialDecoder::new(&mut reader, feature_flags, |path| { if verbose { println!("{:?}", path); diff --git a/src/bin/pxar.rs b/src/bin/pxar.rs index df573ae8..c5d7ace0 100644 --- a/src/bin/pxar.rs +++ b/src/bin/pxar.rs @@ -44,7 +44,7 @@ fn dump_archive( let archive = tools::required_string_param(¶m, "archive")?; let verbose = param["verbose"].as_bool().unwrap_or(false); - let feature_flags = pxar::CA_FORMAT_DEFAULT; + let feature_flags = pxar::flags::DEFAULT; if archive == "-" { let stdin = std::io::stdin(); @@ -102,24 +102,24 @@ fn extract_archive( let empty = Vec::new(); let arg_pattern = param["pattern"].as_array().unwrap_or(&empty); - let mut feature_flags = pxar::CA_FORMAT_DEFAULT; + let mut feature_flags = pxar::flags::DEFAULT; if no_xattrs { - feature_flags ^= pxar::CA_FORMAT_WITH_XATTRS; + feature_flags ^= pxar::flags::WITH_XATTRS; } if no_fcaps { - feature_flags ^= pxar::CA_FORMAT_WITH_FCAPS; + feature_flags ^= pxar::flags::WITH_FCAPS; } if no_acls { - feature_flags ^= pxar::CA_FORMAT_WITH_ACL; + feature_flags ^= pxar::flags::WITH_ACL; } if no_device_nodes { - feature_flags ^= pxar::CA_FORMAT_WITH_DEVICE_NODES; + feature_flags ^= pxar::flags::WITH_DEVICE_NODES; } if no_fifos { - feature_flags ^= pxar::CA_FORMAT_WITH_FIFOS; + feature_flags ^= pxar::flags::WITH_FIFOS; } if no_sockets { - feature_flags ^= pxar::CA_FORMAT_WITH_SOCKETS; + feature_flags ^= pxar::flags::WITH_SOCKETS; } let mut pattern_list = Vec::new(); @@ -188,24 +188,24 @@ fn create_archive( .open(archive)?; let mut writer = std::io::BufWriter::with_capacity(1024*1024, file); - let mut feature_flags = pxar::CA_FORMAT_DEFAULT; + let mut feature_flags = pxar::flags::DEFAULT; if no_xattrs { - feature_flags ^= pxar::CA_FORMAT_WITH_XATTRS; + feature_flags ^= pxar::flags::WITH_XATTRS; } if no_fcaps { - feature_flags ^= pxar::CA_FORMAT_WITH_FCAPS; + feature_flags ^= pxar::flags::WITH_FCAPS; } if no_acls { - feature_flags ^= pxar::CA_FORMAT_WITH_ACL; + feature_flags ^= pxar::flags::WITH_ACL; } if no_device_nodes { - feature_flags ^= pxar::CA_FORMAT_WITH_DEVICE_NODES; + feature_flags ^= pxar::flags::WITH_DEVICE_NODES; } if no_fifos { - feature_flags ^= pxar::CA_FORMAT_WITH_FIFOS; + feature_flags ^= pxar::flags::WITH_FIFOS; } if no_sockets { - feature_flags ^= pxar::CA_FORMAT_WITH_SOCKETS; + feature_flags ^= pxar::flags::WITH_SOCKETS; } pxar::Encoder::encode(source, &mut dir, &mut writer, devices, verbose, false, feature_flags)?; diff --git a/src/client/pxar_backup_stream.rs b/src/client/pxar_backup_stream.rs index e80db69c..123eb3de 100644 --- a/src/client/pxar_backup_stream.rs +++ b/src/client/pxar_backup_stream.rs @@ -49,7 +49,7 @@ impl PxarBackupStream { let child = thread::spawn(move|| { let mut writer = unsafe { std::fs::File::from_raw_fd(tx) }; - if let Err(err) = pxar::Encoder::encode(path, &mut dir, &mut writer, device_set, verbose, skip_lost_and_found, pxar::CA_FORMAT_DEFAULT) { + if let Err(err) = pxar::Encoder::encode(path, &mut dir, &mut writer, device_set, verbose, skip_lost_and_found, pxar::flags::DEFAULT) { let mut error = error2.lock().unwrap(); *error = Some(err.to_string()); } diff --git a/src/client/pxar_decode_writer.rs b/src/client/pxar_decode_writer.rs index edf2bfdf..efb1c708 100644 --- a/src/client/pxar_decode_writer.rs +++ b/src/client/pxar_decode_writer.rs @@ -31,7 +31,7 @@ impl PxarDecodeWriter { let child = thread::spawn(move|| { let mut reader = unsafe { std::fs::File::from_raw_fd(rx) }; - let mut decoder = pxar::SequentialDecoder::new(&mut reader, pxar::CA_FORMAT_DEFAULT, |path| { + let mut decoder = pxar::SequentialDecoder::new(&mut reader, pxar::flags::DEFAULT, |path| { if verbose { println!("{:?}", path); } diff --git a/src/pxar.rs b/src/pxar.rs index 7123d834..286b572b 100644 --- a/src/pxar.rs +++ b/src/pxar.rs @@ -50,6 +50,9 @@ mod binary_search_tree; pub use binary_search_tree::*; +pub mod flags; +pub use flags::*; + mod format_definition; pub use format_definition::*; diff --git a/src/pxar/decoder.rs b/src/pxar/decoder.rs index 0c767977..da7f1121 100644 --- a/src/pxar/decoder.rs +++ b/src/pxar/decoder.rs @@ -36,7 +36,7 @@ impl <'a, R: Read + Seek, F: Fn(&Path) -> Result<(), Error>> Decoder<'a, R, F> { let root_end = reader.seek(SeekFrom::End(0))?; Ok(Self { - inner: SequentialDecoder::new(reader, CA_FORMAT_DEFAULT, callback), + inner: SequentialDecoder::new(reader, super::flags::DEFAULT, callback), root_start: 0, root_end: root_end, }) diff --git a/src/pxar/encoder.rs b/src/pxar/encoder.rs index 15ff761b..eee26e9a 100644 --- a/src/pxar/encoder.rs +++ b/src/pxar/encoder.rs @@ -6,6 +6,7 @@ use failure::*; use endian_trait::Endian; use std::collections::{HashSet, HashMap}; +use super::flags; use super::format_definition::*; use super::binary_search_tree::*; use super::helper::*; @@ -110,7 +111,7 @@ impl <'a, W: Write> Encoder<'a, W> { bail!("backup virtual file systems is disabled!"); } - let fs_feature_flags = feature_flags_from_magic(magic); + let fs_feature_flags = flags::feature_flags_from_magic(magic); let mut me = Self { base_path: path, @@ -217,7 +218,7 @@ impl <'a, W: Write> Encoder<'a, W> { bail!("read_attr_fd failed for {:?} - {}", self.full_path(), err); } - let flags = ca_feature_flags_from_chattr(attr as u32); + let flags = flags::feature_flags_from_chattr(attr as u32); entry.flags = entry.flags | flags; Ok(()) @@ -240,7 +241,7 @@ impl <'a, W: Write> Encoder<'a, W> { bail!("read_fat_attr_fd failed for {:?} - {}", self.full_path(), err); } - let flags = ca_feature_flags_from_fat_attr(attr); + let flags = flags::feature_flags_from_fat_attr(attr); entry.flags = entry.flags | flags; Ok(()) @@ -260,7 +261,7 @@ impl <'a, W: Write> Encoder<'a, W> { let mut xattrs = Vec::new(); let mut fcaps = None; - let flags = CA_FORMAT_WITH_XATTRS | CA_FORMAT_WITH_FCAPS; + let flags = flags::WITH_XATTRS | flags::WITH_FCAPS; if !self.has_some_features(flags) { return Ok((xattrs, fcaps)); } @@ -292,13 +293,13 @@ impl <'a, W: Write> Encoder<'a, W> { }; if xattr::is_security_capability(&name) { - if self.has_features(CA_FORMAT_WITH_FCAPS) { + if self.has_features(flags::WITH_FCAPS) { // fcaps are stored in own format within the archive fcaps = Some(CaFormatFCaps { data: value, }); } - } else if self.has_features(CA_FORMAT_WITH_XATTRS) { + } else if self.has_features(flags::WITH_XATTRS) { xattrs.push(CaFormatXAttr { name: name.to_vec(), value: value, @@ -318,7 +319,7 @@ impl <'a, W: Write> Encoder<'a, W> { default: None, }; - if !self.has_features(CA_FORMAT_WITH_ACL) { + if !self.has_features(flags::WITH_ACL) { return Ok(ret); } if is_symlink(&stat) { @@ -427,7 +428,7 @@ impl <'a, W: Write> Encoder<'a, W> { if !(is_directory(&stat) || is_reg_file(&stat)) { return Ok(None); } - if !self.has_features(CA_FORMAT_WITH_QUOTA_PROJID) { + if !self.has_features(flags::WITH_QUOTA_PROJID) { return Ok(None); } @@ -598,7 +599,7 @@ impl <'a, W: Write> Encoder<'a, W> { // for each node in the directory tree, the filesystem features are // checked based on the fs magic number. - self.fs_feature_flags = feature_flags_from_magic(magic); + self.fs_feature_flags = flags::feature_flags_from_magic(magic); let (xattrs, fcaps) = self.read_xattrs(rawfd, &dir_stat)?; let acl_access = self.read_acl(rawfd, &dir_stat, acl::ACL_TYPE_ACCESS)?; @@ -815,21 +816,21 @@ impl <'a, W: Write> Encoder<'a, W> { Err(err) => bail!("readlink {:?} failed - {}", self.full_path(), err), } } else if is_block_dev(&stat) || is_char_dev(&stat) { - if self.has_features(CA_FORMAT_WITH_DEVICE_NODES) { + if self.has_features(flags::WITH_DEVICE_NODES) { self.write_filename(&filename)?; self.encode_device(&stat)?; } else { eprintln!("skip device node: {:?}", self.full_path()); } } else if is_fifo(&stat) { - if self.has_features(CA_FORMAT_WITH_FIFOS) { + if self.has_features(flags::WITH_FIFOS) { self.write_filename(&filename)?; self.encode_special(&stat)?; } else { eprintln!("skip fifo: {:?}", self.full_path()); } } else if is_socket(&stat) { - if self.has_features(CA_FORMAT_WITH_SOCKETS) { + if self.has_features(flags::WITH_SOCKETS) { self.write_filename(&filename)?; self.encode_special(&stat)?; } else { diff --git a/src/pxar/flags.rs b/src/pxar/flags.rs new file mode 100644 index 00000000..86c57559 --- /dev/null +++ b/src/pxar/flags.rs @@ -0,0 +1,320 @@ +//! Feature flags for *pxar* allow to control what is stored/restored in/from the +//! archive. +//! Flags for known supported features for a given filesystem can be derived +//! from the superblocks magic number. + +/// FAT-style 2s time granularity +pub const WITH_2SEC_TIME: u64 = 0x40; +/// Preserve read only flag of files +pub const WITH_READ_ONLY: u64 = 0x80; +/// Preserve unix permissions +pub const WITH_PERMISSIONS: u64 = 0x100; +/// Include symbolik links +pub const WITH_SYMLINKS: u64 = 0x200; +/// Include device nodes +pub const WITH_DEVICE_NODES: u64 = 0x400; +/// Include FIFOs +pub const WITH_FIFOS: u64 = 0x800; +/// Include Sockets +pub const WITH_SOCKETS: u64 = 0x1000; + +/// Preserve DOS file flag `HIDDEN` +pub const WITH_FLAG_HIDDEN: u64 = 0x2000; +/// Preserve DOS file flag `SYSTEM` +pub const WITH_FLAG_SYSTEM: u64 = 0x4000; +/// Preserve DOS file flag `ARCHIVE` +pub const WITH_FLAG_ARCHIVE: u64 = 0x8000; + +// chattr() flags +/// Linux file attribute `APPEND` +pub const WITH_FLAG_APPEND: u64 = 0x10000; +/// Linux file attribute `NOATIME` +pub const WITH_FLAG_NOATIME: u64 = 0x20000; +/// Linux file attribute `COMPR` +pub const WITH_FLAG_COMPR: u64 = 0x40000; +/// Linux file attribute `NOCOW` +pub const WITH_FLAG_NOCOW: u64 = 0x80000; +/// Linux file attribute `NODUMP` +pub const WITH_FLAG_NODUMP: u64 = 0x100000; +/// Linux file attribute `DIRSYNC` +pub const WITH_FLAG_DIRSYNC: u64 = 0x200000; +/// Linux file attribute `IMMUTABLE` +pub const WITH_FLAG_IMMUTABLE: u64 = 0x400000; +/// Linux file attribute `SYNC` +pub const WITH_FLAG_SYNC: u64 = 0x800000; +/// Linux file attribute `NOCOMP` +pub const WITH_FLAG_NOCOMP: u64 = 0x1000000; +/// Linux file attribute `PROJINHERIT` +pub const WITH_FLAG_PROJINHERIT: u64 = 0x2000000; + + +/// Preserve BTRFS subvolume flag +pub const WITH_SUBVOLUME: u64 = 0x4000000; +/// Preserve BTRFS read-only subvolume flag +pub const WITH_SUBVOLUME_RO: u64 = 0x8000000; + +/// Preserve Extended Attribute metadata +pub const WITH_XATTRS: u64 = 0x10000000; +/// Preserve Access Control List metadata +pub const WITH_ACL: u64 = 0x20000000; +/// Preserve SELinux security context +pub const WITH_SELINUX: u64 = 0x40000000; +/// Preserve "security.capability" xattr +pub const WITH_FCAPS: u64 = 0x80000000; + +/// Preserve XFS/ext4/ZFS project quota ID +pub const WITH_QUOTA_PROJID: u64 = 0x100000000; + +/// Support ".pxarexclude" files +pub const EXCLUDE_FILE: u64 = 0x1000000000000000; +/// the purpose of this flag is still unclear +pub const SHA512_256: u64 = 0x2000000000000000; +/// Exclude submounts +pub const EXCLUDE_SUBMOUNTS: u64 = 0x4000000000000000; +/// Exclude entries with chattr flag NODUMP +pub const EXCLUDE_NODUMP: u64 = 0x8000000000000000; + +/// Definitions of typical feature flags for the *pxar* encoder/decoder. +/// By this expensive syscalls for unsupported features are avoided. + +/// All chattr file attributes +pub const WITH_CHATTR: u64 = + WITH_FLAG_APPEND| + WITH_FLAG_NOATIME| + WITH_FLAG_COMPR| + WITH_FLAG_NOCOW| + WITH_FLAG_NODUMP| + WITH_FLAG_DIRSYNC| + WITH_FLAG_IMMUTABLE| + WITH_FLAG_SYNC| + WITH_FLAG_NOCOMP| + WITH_FLAG_PROJINHERIT; + +/// All FAT file attributes +pub const WITH_FAT_ATTRS: u64 = + WITH_FLAG_HIDDEN| + WITH_FLAG_SYSTEM| + WITH_FLAG_ARCHIVE; + +/// All bits that may also be exposed via fuse +pub const WITH_FUSE: u64 = + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_FAT_ATTRS| + WITH_CHATTR| + WITH_XATTRS; + + +/// Default feature flags for encoder/decoder +pub const DEFAULT: u64 = + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_FLAG_HIDDEN| + WITH_FLAG_SYSTEM| + WITH_FLAG_ARCHIVE| + WITH_FLAG_APPEND| + WITH_FLAG_NOATIME| + WITH_FLAG_COMPR| + WITH_FLAG_NOCOW| + //WITH_FLAG_NODUMP| + WITH_FLAG_DIRSYNC| + WITH_FLAG_IMMUTABLE| + WITH_FLAG_SYNC| + WITH_FLAG_NOCOMP| + WITH_FLAG_PROJINHERIT| + WITH_SUBVOLUME| + WITH_SUBVOLUME_RO| + WITH_XATTRS| + WITH_ACL| + WITH_SELINUX| + WITH_FCAPS| + WITH_QUOTA_PROJID| + EXCLUDE_NODUMP| + EXCLUDE_FILE| + SHA512_256; + +// form /usr/include/linux/fs.h +const FS_APPEND_FL: u32 = 0x00000020; +const FS_NOATIME_FL: u32 = 0x00000080; +const FS_COMPR_FL: u32 = 0x00000004; +const FS_NOCOW_FL: u32 = 0x00800000; +const FS_NODUMP_FL: u32 = 0x00000040; +const FS_DIRSYNC_FL: u32 = 0x00010000; +const FS_IMMUTABLE_FL: u32 = 0x00000010; +const FS_SYNC_FL: u32 = 0x00000008; +const FS_NOCOMP_FL: u32 = 0x00000400; +const FS_PROJINHERIT_FL: u32 = 0x20000000; + +static CHATTR_MAP: [(u64, u32); 10] = [ + ( WITH_FLAG_APPEND, FS_APPEND_FL ), + ( WITH_FLAG_NOATIME, FS_NOATIME_FL ), + ( WITH_FLAG_COMPR, FS_COMPR_FL ), + ( WITH_FLAG_NOCOW, FS_NOCOW_FL ), + ( WITH_FLAG_NODUMP, FS_NODUMP_FL ), + ( WITH_FLAG_DIRSYNC, FS_DIRSYNC_FL ), + ( WITH_FLAG_IMMUTABLE, FS_IMMUTABLE_FL ), + ( WITH_FLAG_SYNC, FS_SYNC_FL ), + ( WITH_FLAG_NOCOMP, FS_NOCOMP_FL ), + ( WITH_FLAG_PROJINHERIT, FS_PROJINHERIT_FL ), +]; + +pub fn feature_flags_from_chattr(attr: u32) -> u64 { + + let mut flags = 0u64; + + for (fe_flag, fs_flag) in &CHATTR_MAP { + if (attr & fs_flag) != 0 { flags = flags | fe_flag; } + } + + flags +} + +// from /usr/include/linux/msdos_fs.h +const ATTR_HIDDEN: u32 = 2; +const ATTR_SYS: u32 = 4; +const ATTR_ARCH: u32 = 32; + +static FAT_ATTR_MAP: [(u64, u32); 3] = [ + ( WITH_FLAG_HIDDEN, ATTR_HIDDEN ), + ( WITH_FLAG_SYSTEM, ATTR_SYS ), + ( WITH_FLAG_ARCHIVE, ATTR_ARCH ), +]; + +pub fn feature_flags_from_fat_attr(attr: u32) -> u64 { + + let mut flags = 0u64; + + for (fe_flag, fs_flag) in &FAT_ATTR_MAP { + if (attr & fs_flag) != 0 { flags = flags | fe_flag; } + } + + flags +} + + +/// Return the supported *pxar* feature flags based on the magic number of the filesystem. +pub fn feature_flags_from_magic(magic: i64) -> u64 { + use crate::tools::fs::magic::*; + match magic { + MSDOS_SUPER_MAGIC => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_FAT_ATTRS + }, + EXT4_SUPER_MAGIC => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_FLAG_APPEND| + WITH_FLAG_NOATIME| + WITH_FLAG_NODUMP| + WITH_FLAG_DIRSYNC| + WITH_FLAG_IMMUTABLE| + WITH_FLAG_SYNC| + WITH_XATTRS| + WITH_ACL| + WITH_SELINUX| + WITH_FCAPS| + WITH_QUOTA_PROJID + }, + XFS_SUPER_MAGIC => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_FLAG_APPEND| + WITH_FLAG_NOATIME| + WITH_FLAG_NODUMP| + WITH_FLAG_IMMUTABLE| + WITH_FLAG_SYNC| + WITH_XATTRS| + WITH_ACL| + WITH_SELINUX| + WITH_FCAPS| + WITH_QUOTA_PROJID + }, + ZFS_SUPER_MAGIC => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_FLAG_APPEND| + WITH_FLAG_NOATIME| + WITH_FLAG_NODUMP| + WITH_FLAG_DIRSYNC| + WITH_FLAG_IMMUTABLE| + WITH_FLAG_SYNC| + WITH_XATTRS| + WITH_ACL| + WITH_SELINUX| + WITH_FCAPS| + WITH_QUOTA_PROJID + }, + BTRFS_SUPER_MAGIC => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_FLAG_APPEND| + WITH_FLAG_NOATIME| + WITH_FLAG_COMPR| + WITH_FLAG_NOCOW| + WITH_FLAG_NODUMP| + WITH_FLAG_DIRSYNC| + WITH_FLAG_IMMUTABLE| + WITH_FLAG_SYNC| + WITH_FLAG_NOCOMP| + WITH_XATTRS| + WITH_ACL| + WITH_SELINUX| + WITH_SUBVOLUME| + WITH_SUBVOLUME_RO| + WITH_FCAPS + }, + TMPFS_MAGIC => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS| + WITH_ACL| + WITH_SELINUX + }, + // FUSE mounts are special as the supported feature set + // is not clear a priori. + FUSE_SUPER_MAGIC => { + WITH_FUSE + }, + _ => { + WITH_2SEC_TIME| + WITH_READ_ONLY| + WITH_PERMISSIONS| + WITH_SYMLINKS| + WITH_DEVICE_NODES| + WITH_FIFOS| + WITH_SOCKETS + }, + } +} diff --git a/src/pxar/format_definition.rs b/src/pxar/format_definition.rs index 0986d5c9..13d5e043 100644 --- a/src/pxar/format_definition.rs +++ b/src/pxar/format_definition.rs @@ -35,80 +35,6 @@ pub const CA_FORMAT_GOODBYE: u64 = 0xdfd35c5e8327c403; pub const CA_FORMAT_GOODBYE_TAIL_MARKER: u64 = 0x57446fa533702943; -// Feature flags - -pub const CA_FORMAT_WITH_SEC_TIME: u64 = 0x8; -pub const CA_FORMAT_WITH_USEC_TIME: u64 = 0x10; -pub const CA_FORMAT_WITH_NSEC_TIME: u64 = 0x20; -/// FAT-style 2s time granularity -pub const CA_FORMAT_WITH_2SEC_TIME: u64 = 0x40; -pub const CA_FORMAT_WITH_READ_ONLY: u64 = 0x80; -pub const CA_FORMAT_WITH_PERMISSIONS: u64 = 0x100; -/// include symbolik links -pub const CA_FORMAT_WITH_SYMLINKS: u64 = 0x200; -/// include device nodes -pub const CA_FORMAT_WITH_DEVICE_NODES: u64 = 0x400; -/// include FIFOs -pub const CA_FORMAT_WITH_FIFOS: u64 = 0x800; -/// include Sockets -pub const CA_FORMAT_WITH_SOCKETS: u64 = 0x1000; - -/// DOS file flag `HIDDEN` -pub const CA_FORMAT_WITH_FLAG_HIDDEN: u64 = 0x2000; -/// DOS file flag `SYSTEM` -pub const CA_FORMAT_WITH_FLAG_SYSTEM: u64 = 0x4000; -/// DOS file flag `ARCHIVE` -pub const CA_FORMAT_WITH_FLAG_ARCHIVE: u64 = 0x8000; - -// chattr() flags -/// Linux file attribute `APPEND` -pub const CA_FORMAT_WITH_FLAG_APPEND: u64 = 0x10000; -/// Linux file attribute `NOATIME` -pub const CA_FORMAT_WITH_FLAG_NOATIME: u64 = 0x20000; -/// Linux file attribute `COMPR` -pub const CA_FORMAT_WITH_FLAG_COMPR: u64 = 0x40000; -/// Linux file attribute `NOCOW` -pub const CA_FORMAT_WITH_FLAG_NOCOW: u64 = 0x80000; -/// Linux file attribute `NODUMP` -pub const CA_FORMAT_WITH_FLAG_NODUMP: u64 = 0x100000; -/// Linux file attribute `DIRSYNC` -pub const CA_FORMAT_WITH_FLAG_DIRSYNC: u64 = 0x200000; -/// Linux file attribute `IMMUTABLE` -pub const CA_FORMAT_WITH_FLAG_IMMUTABLE: u64 = 0x400000; -/// Linux file attribute `SYNC` -pub const CA_FORMAT_WITH_FLAG_SYNC: u64 = 0x800000; -/// Linux file attribute `NOCOMP` -pub const CA_FORMAT_WITH_FLAG_NOCOMP: u64 = 0x1000000; -/// Linux file attribute `PROJINHERIT` -pub const CA_FORMAT_WITH_FLAG_PROJINHERIT: u64 = 0x2000000; - - -// Include BTRFS subvolume flag -pub const CA_FORMAT_WITH_SUBVOLUME: u64 = 0x4000000; -// Include BTRFS read-only subvolume flag -pub const CA_FORMAT_WITH_SUBVOLUME_RO: u64 = 0x8000000; - -/// Include Extended Attribute metadata -pub const CA_FORMAT_WITH_XATTRS: u64 = 0x10000000; -/// Include Access Control List metadata -pub const CA_FORMAT_WITH_ACL: u64 = 0x20000000; -/// Include SELinux security context -pub const CA_FORMAT_WITH_SELINUX: u64 = 0x40000000; -/// Include "security.capability" xattr -pub const CA_FORMAT_WITH_FCAPS: u64 = 0x80000000; - -/// XFS/ext4 project quota ID -pub const CA_FORMAT_WITH_QUOTA_PROJID: u64 = 0x100000000; - -/// Support ".caexclude" files -pub const CA_FORMAT_EXCLUDE_FILE: u64 = 0x1000000000000000; -/// the purpose of this flag is still unclear -pub const CA_FORMAT_SHA512_256: u64 = 0x2000000000000000; -/// Exclude submounts -pub const CA_FORMAT_EXCLUDE_SUBMOUNTS: u64 = 0x4000000000000000; -/// Exclude entries with chattr flag NODUMP -pub const CA_FORMAT_EXCLUDE_NODUMP: u64 = 0x8000000000000000; - #[derive(Debug)] #[derive(Endian)] #[repr(C)] @@ -329,270 +255,3 @@ pub fn check_ca_header(head: &CaFormatHeader, htype: u64) -> Result<(), Error Ok(()) } -// form /usr/include/linux/fs.h -const FS_APPEND_FL: u32 = 0x00000020; -const FS_NOATIME_FL: u32 = 0x00000080; -const FS_COMPR_FL: u32 = 0x00000004; -const FS_NOCOW_FL: u32 = 0x00800000; -const FS_NODUMP_FL: u32 = 0x00000040; -const FS_DIRSYNC_FL: u32 = 0x00010000; -const FS_IMMUTABLE_FL: u32 = 0x00000010; -const FS_SYNC_FL: u32 = 0x00000008; -const FS_NOCOMP_FL: u32 = 0x00000400; -const FS_PROJINHERIT_FL: u32 = 0x20000000; - -static CHATTR_MAP: [(u64, u32); 10] = [ - ( CA_FORMAT_WITH_FLAG_APPEND, FS_APPEND_FL ), - ( CA_FORMAT_WITH_FLAG_NOATIME, FS_NOATIME_FL ), - ( CA_FORMAT_WITH_FLAG_COMPR, FS_COMPR_FL ), - ( CA_FORMAT_WITH_FLAG_NOCOW, FS_NOCOW_FL ), - ( CA_FORMAT_WITH_FLAG_NODUMP, FS_NODUMP_FL ), - ( CA_FORMAT_WITH_FLAG_DIRSYNC, FS_DIRSYNC_FL ), - ( CA_FORMAT_WITH_FLAG_IMMUTABLE, FS_IMMUTABLE_FL ), - ( CA_FORMAT_WITH_FLAG_SYNC, FS_SYNC_FL ), - ( CA_FORMAT_WITH_FLAG_NOCOMP, FS_NOCOMP_FL ), - ( CA_FORMAT_WITH_FLAG_PROJINHERIT, FS_PROJINHERIT_FL ), -]; - -pub fn ca_feature_flags_from_chattr(attr: u32) -> u64 { - - let mut flags = 0u64; - - for (ca_flag, fs_flag) in &CHATTR_MAP { - if (attr & fs_flag) != 0 { flags = flags | ca_flag; } - } - - flags -} - - - -// from /usr/include/linux/msdos_fs.h -const ATTR_HIDDEN: u32 = 2; -const ATTR_SYS: u32 = 4; -const ATTR_ARCH: u32 = 32; - -static FAT_ATTR_MAP: [(u64, u32); 3] = [ - ( CA_FORMAT_WITH_FLAG_HIDDEN, ATTR_HIDDEN ), - ( CA_FORMAT_WITH_FLAG_SYSTEM, ATTR_SYS ), - ( CA_FORMAT_WITH_FLAG_ARCHIVE, ATTR_ARCH ), -]; - -pub fn ca_feature_flags_from_fat_attr(attr: u32) -> u64 { - - let mut flags = 0u64; - - for (ca_flag, fs_flag) in &FAT_ATTR_MAP { - if (attr & fs_flag) != 0 { flags = flags | ca_flag; } - } - - flags -} - -/// Definitions of typical feature flags for the *pxar* encoder/decoder. -/// By this expensive syscalls for unsupported features are avoided. - -/// All chattr file attributes -pub const CA_FORMAT_WITH_CHATTR: u64 = - CA_FORMAT_WITH_FLAG_APPEND| - CA_FORMAT_WITH_FLAG_NOATIME| - CA_FORMAT_WITH_FLAG_COMPR| - CA_FORMAT_WITH_FLAG_NOCOW| - CA_FORMAT_WITH_FLAG_NODUMP| - CA_FORMAT_WITH_FLAG_DIRSYNC| - CA_FORMAT_WITH_FLAG_IMMUTABLE| - CA_FORMAT_WITH_FLAG_SYNC| - CA_FORMAT_WITH_FLAG_NOCOMP| - CA_FORMAT_WITH_FLAG_PROJINHERIT; - -/// All FAT file attributes -pub const CA_FORMAT_WITH_FAT_ATTRS: u64 = - CA_FORMAT_WITH_FLAG_HIDDEN| - CA_FORMAT_WITH_FLAG_SYSTEM| - CA_FORMAT_WITH_FLAG_ARCHIVE; - -/// All bits that may also be exposed via fuse -pub const CA_FORMAT_WITH_FUSE: u64 = - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_FAT_ATTRS| - CA_FORMAT_WITH_CHATTR| - CA_FORMAT_WITH_XATTRS; - -/// Default feature flags for encoder/decoder -pub const CA_FORMAT_DEFAULT: u64 = - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_FLAG_HIDDEN| - CA_FORMAT_WITH_FLAG_SYSTEM| - CA_FORMAT_WITH_FLAG_ARCHIVE| - CA_FORMAT_WITH_FLAG_APPEND| - CA_FORMAT_WITH_FLAG_NOATIME| - CA_FORMAT_WITH_FLAG_COMPR| - CA_FORMAT_WITH_FLAG_NOCOW| - //CA_FORMAT_WITH_FLAG_NODUMP| - CA_FORMAT_WITH_FLAG_DIRSYNC| - CA_FORMAT_WITH_FLAG_IMMUTABLE| - CA_FORMAT_WITH_FLAG_SYNC| - CA_FORMAT_WITH_FLAG_NOCOMP| - CA_FORMAT_WITH_FLAG_PROJINHERIT| - CA_FORMAT_WITH_SUBVOLUME| - CA_FORMAT_WITH_SUBVOLUME_RO| - CA_FORMAT_WITH_XATTRS| - CA_FORMAT_WITH_ACL| - CA_FORMAT_WITH_SELINUX| - CA_FORMAT_WITH_FCAPS| - CA_FORMAT_WITH_QUOTA_PROJID| - CA_FORMAT_EXCLUDE_NODUMP| - CA_FORMAT_EXCLUDE_FILE| - CA_FORMAT_SHA512_256; - -/// Return the supported *pxar* feature flags based on the magic number of the filesystem. -pub fn feature_flags_from_magic(magic: i64) -> u64 { - use crate::tools::fs::magic::*; - - match magic { - MSDOS_SUPER_MAGIC => { - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_FAT_ATTRS - }, - EXT4_SUPER_MAGIC => { - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_FLAG_APPEND| - CA_FORMAT_WITH_FLAG_NOATIME| - CA_FORMAT_WITH_FLAG_NODUMP| - CA_FORMAT_WITH_FLAG_DIRSYNC| - CA_FORMAT_WITH_FLAG_IMMUTABLE| - CA_FORMAT_WITH_FLAG_SYNC| - CA_FORMAT_WITH_XATTRS| - CA_FORMAT_WITH_ACL| - CA_FORMAT_WITH_SELINUX| - CA_FORMAT_WITH_FCAPS| - CA_FORMAT_WITH_QUOTA_PROJID - }, - XFS_SUPER_MAGIC => { - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_FLAG_APPEND| - CA_FORMAT_WITH_FLAG_NOATIME| - CA_FORMAT_WITH_FLAG_NODUMP| - CA_FORMAT_WITH_FLAG_IMMUTABLE| - CA_FORMAT_WITH_FLAG_SYNC| - CA_FORMAT_WITH_XATTRS| - CA_FORMAT_WITH_ACL| - CA_FORMAT_WITH_SELINUX| - CA_FORMAT_WITH_FCAPS| - CA_FORMAT_WITH_QUOTA_PROJID - }, - ZFS_SUPER_MAGIC => { - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_FLAG_APPEND| - CA_FORMAT_WITH_FLAG_NOATIME| - CA_FORMAT_WITH_FLAG_NODUMP| - CA_FORMAT_WITH_FLAG_DIRSYNC| - CA_FORMAT_WITH_FLAG_IMMUTABLE| - CA_FORMAT_WITH_FLAG_SYNC| - CA_FORMAT_WITH_XATTRS| - CA_FORMAT_WITH_ACL| - CA_FORMAT_WITH_SELINUX| - CA_FORMAT_WITH_FCAPS| - CA_FORMAT_WITH_QUOTA_PROJID - }, - BTRFS_SUPER_MAGIC => { - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_FLAG_APPEND| - CA_FORMAT_WITH_FLAG_NOATIME| - CA_FORMAT_WITH_FLAG_COMPR| - CA_FORMAT_WITH_FLAG_NOCOW| - CA_FORMAT_WITH_FLAG_NODUMP| - CA_FORMAT_WITH_FLAG_DIRSYNC| - CA_FORMAT_WITH_FLAG_IMMUTABLE| - CA_FORMAT_WITH_FLAG_SYNC| - CA_FORMAT_WITH_FLAG_NOCOMP| - CA_FORMAT_WITH_XATTRS| - CA_FORMAT_WITH_ACL| - CA_FORMAT_WITH_SELINUX| - CA_FORMAT_WITH_SUBVOLUME| - CA_FORMAT_WITH_SUBVOLUME_RO| - CA_FORMAT_WITH_FCAPS - }, - TMPFS_MAGIC => { - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS| - CA_FORMAT_WITH_ACL| - CA_FORMAT_WITH_SELINUX - }, - FUSE_SUPER_MAGIC => { - // FUSE mounts are special as the supported feature set is not clear - // a priori. - CA_FORMAT_WITH_FUSE - }, - _ => { - CA_FORMAT_WITH_SEC_TIME| - CA_FORMAT_WITH_USEC_TIME| - CA_FORMAT_WITH_NSEC_TIME| - CA_FORMAT_WITH_2SEC_TIME| - CA_FORMAT_WITH_READ_ONLY| - CA_FORMAT_WITH_PERMISSIONS| - CA_FORMAT_WITH_SYMLINKS| - CA_FORMAT_WITH_DEVICE_NODES| - CA_FORMAT_WITH_FIFOS| - CA_FORMAT_WITH_SOCKETS - }, - } -} diff --git a/src/pxar/sequential_decoder.rs b/src/pxar/sequential_decoder.rs index cadafd70..b2c42064 100644 --- a/src/pxar/sequential_decoder.rs +++ b/src/pxar/sequential_decoder.rs @@ -5,6 +5,7 @@ use failure::*; use endian_trait::Endian; +use super::flags; use super::format_definition::*; use super::exclude_pattern::*; use super::dir_buffer::*; @@ -186,63 +187,63 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F loop { match head.htype { CA_FORMAT_XATTR => { - if self.has_features(CA_FORMAT_WITH_XATTRS) { + if self.has_features(flags::WITH_XATTRS) { attr.xattrs.push(self.read_xattr(size)?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_FCAPS => { - if self.has_features(CA_FORMAT_WITH_FCAPS) { + if self.has_features(flags::WITH_FCAPS) { attr.fcaps = Some(self.read_fcaps(size)?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_ACL_USER => { - if self.has_features(CA_FORMAT_WITH_ACL) { + if self.has_features(flags::WITH_ACL) { attr.acl_user.push(self.read_item::()?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_ACL_GROUP => { - if self.has_features(CA_FORMAT_WITH_ACL) { + if self.has_features(flags::WITH_ACL) { attr.acl_group.push(self.read_item::()?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_ACL_GROUP_OBJ => { - if self.has_features(CA_FORMAT_WITH_ACL) { + if self.has_features(flags::WITH_ACL) { attr.acl_group_obj = Some(self.read_item::()?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_ACL_DEFAULT => { - if self.has_features(CA_FORMAT_WITH_ACL) { + if self.has_features(flags::WITH_ACL) { attr.acl_default = Some(self.read_item::()?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_ACL_DEFAULT_USER => { - if self.has_features(CA_FORMAT_WITH_ACL) { + if self.has_features(flags::WITH_ACL) { attr.acl_default_user.push(self.read_item::()?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_ACL_DEFAULT_GROUP => { - if self.has_features(CA_FORMAT_WITH_ACL) { + if self.has_features(flags::WITH_ACL) { attr.acl_default_group.push(self.read_item::()?); } else { self.skip_bytes(size)?; } }, CA_FORMAT_QUOTA_PROJID => { - if self.has_features(CA_FORMAT_WITH_QUOTA_PROJID) { + if self.has_features(flags::WITH_QUOTA_PROJID) { attr.quota_projid = Some(self.read_item::()?); } else { self.skip_bytes(size)?; @@ -508,7 +509,7 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F entry: &CaFormatEntry, filename: &OsStr ) -> Result<(), Error> { - if !self.has_features(CA_FORMAT_WITH_SOCKETS) { + if !self.has_features(flags::WITH_SOCKETS) { return Ok(()); } if let Some(fd) = parent_fd { @@ -527,7 +528,7 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F entry: &CaFormatEntry, filename: &OsStr ) -> Result<(), Error> { - if !self.has_features(CA_FORMAT_WITH_FIFOS) { + if !self.has_features(flags::WITH_FIFOS) { return Ok(()); } if let Some(fd) = parent_fd { @@ -551,7 +552,7 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F bail!("got unknown header type inside device entry {:016x}", head.htype); } let device: CaFormatDevice = self.read_item()?; - if !self.has_features(CA_FORMAT_WITH_DEVICE_NODES) { + if !self.has_features(flags::WITH_DEVICE_NODES) { return Ok(()); } if let Some(fd) = parent_fd { @@ -932,55 +933,55 @@ impl <'a, R: Read, F: Fn(&Path) -> Result<(), Error>> SequentialDecoder<'a, R, F match header.htype { CA_FORMAT_XATTR => { let xattr = self.read_xattr((header.size - HEADER_SIZE) as usize)?; - if verbose && self.has_features(CA_FORMAT_WITH_XATTRS) { + if verbose && self.has_features(flags::WITH_XATTRS) { println!("XAttr: {:?}", xattr); } }, CA_FORMAT_FCAPS => { let fcaps = self.read_fcaps((header.size - HEADER_SIZE) as usize)?; - if verbose && self.has_features(CA_FORMAT_WITH_FCAPS) { + if verbose && self.has_features(flags::WITH_FCAPS) { println!("FCaps: {:?}", fcaps); } }, CA_FORMAT_ACL_USER => { let user = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_ACL) { + if verbose && self.has_features(flags::WITH_ACL) { println!("ACLUser: {:?}", user); } }, CA_FORMAT_ACL_GROUP => { let group = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_ACL) { + if verbose && self.has_features(flags::WITH_ACL) { println!("ACLGroup: {:?}", group); } }, CA_FORMAT_ACL_GROUP_OBJ => { let group_obj = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_ACL) { + if verbose && self.has_features(flags::WITH_ACL) { println!("ACLGroupObj: {:?}", group_obj); } }, CA_FORMAT_ACL_DEFAULT => { let default = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_ACL) { + if verbose && self.has_features(flags::WITH_ACL) { println!("ACLDefault: {:?}", default); } }, CA_FORMAT_ACL_DEFAULT_USER => { let default_user = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_ACL) { + if verbose && self.has_features(flags::WITH_ACL) { println!("ACLDefaultUser: {:?}", default_user); } }, CA_FORMAT_ACL_DEFAULT_GROUP => { let default_group = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_ACL) { + if verbose && self.has_features(flags::WITH_ACL) { println!("ACLDefaultGroup: {:?}", default_group); } }, CA_FORMAT_QUOTA_PROJID => { let quota_projid = self.read_item::()?; - if verbose && self.has_features(CA_FORMAT_WITH_QUOTA_PROJID) { + if verbose && self.has_features(flags::WITH_QUOTA_PROJID) { println!("Quota project id: {:?}", quota_projid); } }, diff --git a/tests/catar.rs b/tests/catar.rs index cfb822a4..02c2d1f7 100644 --- a/tests/catar.rs +++ b/tests/catar.rs @@ -26,7 +26,7 @@ fn run_test(dir_name: &str) -> Result<(), Error> { let path = std::path::PathBuf::from(dir_name); - Encoder::encode(path, &mut dir, &mut writer, None, false, false, CA_FORMAT_DEFAULT)?; + Encoder::encode(path, &mut dir, &mut writer, None, false, false, flags::DEFAULT)?; Command::new("cmp") .arg("--verbose")