diff --git a/Cargo.lock b/Cargo.lock index 3976c2b..9b3743d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,6 +27,7 @@ dependencies = [ "squash-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3f8277e..42633f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "zvault" version = "0.1.0" -authors = ["Dennis Schwerdel "] +authors = ["Dennis Schwerdel "] description = "Deduplicating backup tool" [dependencies] @@ -27,6 +27,7 @@ fuse = "0.3" lazy_static = "0.2" rand = "0.3" tar = "0.4" +xattr = "0.1" time = "*" libc = "*" diff --git a/README.md b/README.md index a665e3d..dafca06 100644 --- a/README.md +++ b/README.md @@ -99,8 +99,6 @@ Recommended: Brotli/2-7 ### Core functionality - Recompress & combine bundles -- File attributes - - xattrs https://crates.io/crates/xattr ### CLI functionality - list --tree diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 193dc61..f81bec5 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -30,8 +30,7 @@ impl ErrorCode { pub fn code(&self) -> i32 { match *self { // Crazy stuff - ErrorCode::InitializeLogger => -1, - ErrorCode::InvalidExcludes => -1, + ErrorCode::InitializeLogger | ErrorCode::InvalidExcludes => -1, // Arguments ErrorCode::InvalidArgs => 1, ErrorCode::UnsafeArgs => 2, diff --git a/src/main.rs b/src/main.rs index 69e489e..9e11ddc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![recursion_limit="128"] +#![allow(unknown_lints, float_cmp)] extern crate serde; extern crate rmp_serde; #[macro_use] extern crate serde_utils; @@ -21,6 +22,7 @@ extern crate regex; extern crate fuse; extern crate rand; extern crate time; +extern crate xattr; extern crate libc; extern crate tar; diff --git a/src/repository/metadata.rs b/src/repository/metadata.rs index a08d7ab..572506a 100644 --- a/src/repository/metadata.rs +++ b/src/repository/metadata.rs @@ -1,6 +1,7 @@ use ::prelude::*; use filetime::{self, FileTime}; +use xattr; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; @@ -23,6 +24,11 @@ quick_error!{ description("Failed to obtain metadata for file") display("Inode error: failed to obtain metadata for file {:?}\n\tcaused by: {}", path, err) } + ReadXattr(err: io::Error, path: PathBuf) { + cause(err) + description("Failed to obtain xattr for file") + display("Inode error: failed to obtain xattr for file {:?}\n\tcaused by: {}", path, err) + } ReadLinkTarget(err: io::Error, path: PathBuf) { cause(err) description("Failed to obtain link target for file") @@ -48,6 +54,11 @@ quick_error!{ description("Failed to set file ownership") display("Inode error: failed to set file ownership on {:?}\n\tcaused by: {}", path, err) } + SetXattr(err: io::Error, path: PathBuf) { + cause(err) + description("Failed to set xattr") + display("Inode error: failed to set xattr on {:?}\n\tcaused by: {}", path, err) + } Integrity(reason: &'static str) { description("Integrity error") display("Inode error: inode integrity error: {}", reason) @@ -117,7 +128,8 @@ pub struct Inode { pub children: Option>, pub cum_size: u64, pub cum_dirs: usize, - pub cum_files: usize + pub cum_files: usize, + pub xattrs: BTreeMap } impl Default for Inode { fn default() -> Self { @@ -134,7 +146,8 @@ impl Default for Inode { children: None, cum_size: 0, cum_dirs: 0, - cum_files: 0 + cum_files: 0, + xattrs: BTreeMap::new() } } } @@ -145,15 +158,14 @@ serde_impl!(Inode(u8?) { mode: u32 => 3, user: u32 => 4, group: u32 => 5, - //__old_access_time: i64 => 6, timestamp: i64 => 7, - //__old_create_time: i64 => 8, symlink_target: Option => 9, data: Option => 10, children: Option> => 11, cum_size: u64 => 12, cum_dirs: usize => 13, - cum_files: usize => 14 + cum_files: usize => 14, + xattrs: BTreeMap => 15 }); @@ -183,6 +195,14 @@ impl Inode { inode.user = meta.st_uid(); inode.group = meta.st_gid(); inode.timestamp = meta.st_mtime(); + if xattr::SUPPORTED_PLATFORM { + if let Ok(attrs) = xattr::list(path) { + for name in attrs { + let data = try!(xattr::get(path, &name).map_err(|e| InodeError::ReadXattr(e, path.to_owned()))); + inode.xattrs.insert(name.to_string_lossy().to_string(), data.into()); + } + } + } Ok(inode) } @@ -205,12 +225,21 @@ impl Inode { } } } + let time = FileTime::from_seconds_since_1970(self.timestamp as u64, 0); + try!(filetime::set_file_times(&full_path, time, time).map_err(|e| InodeError::SetTimes(e, full_path.clone()))); + if !self.xattrs.is_empty() { + if xattr::SUPPORTED_PLATFORM { + for (name, data) in &self.xattrs { + try!(xattr::set(&full_path, name, data).map_err(|e| InodeError::SetXattr(e, full_path.clone()))) + } + } else { + warn!("Not setting xattr on {:?}", full_path); + } + } try!(fs::set_permissions( &full_path, Permissions::from_mode(self.mode) ).map_err(|e| InodeError::SetPermissions(e, full_path.clone(), self.mode))); - let time = FileTime::from_seconds_since_1970(self.timestamp as u64, 0); - try!(filetime::set_file_times(&full_path, time, time).map_err(|e| InodeError::SetTimes(e, full_path.clone()))); try!(chown(&full_path, self.user, self.group).map_err(|e| InodeError::SetOwnership(e, full_path.clone()))); Ok(file) } diff --git a/src/repository/tarfile.rs b/src/repository/tarfile.rs index ef9c4d3..72ba6d7 100644 --- a/src/repository/tarfile.rs +++ b/src/repository/tarfile.rs @@ -113,15 +113,11 @@ impl Repository { roots.push((inode, chunks)); } } - let mut root_inode; - let chunks; if roots.len() == 1 { - let r = roots.pop().unwrap(); - root_inode = r.0; - chunks = r.1; + Ok(roots.pop().unwrap()) } else { warn!("Tar file contains multiple roots, adding dummy folder"); - root_inode = Inode { + let mut root_inode = Inode { file_type: FileType::Directory, mode: 0o755, name: "archive".to_string(), @@ -138,9 +134,9 @@ impl Repository { root_inode.cum_dirs += inode.cum_dirs; } root_inode.children = Some(children); - chunks = try!(self.put_inode(&root_inode)); + let chunks = try!(self.put_inode(&root_inode)); + Ok((root_inode, chunks)) } - Ok((root_inode, chunks)) } pub fn import_tarfile>(&mut self, tarfile: P) -> Result {