This commit is contained in:
Dennis Schwerdel 2017-04-04 13:59:57 +02:00
parent 15a01dfbac
commit 1212d08917
7 changed files with 46 additions and 20 deletions

1
Cargo.lock generated
View File

@ -27,6 +27,7 @@ dependencies = [
"squash-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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]] [[package]]

View File

@ -1,7 +1,7 @@
[package] [package]
name = "zvault" name = "zvault"
version = "0.1.0" version = "0.1.0"
authors = ["Dennis Schwerdel <schwerdel@informatik.uni-kl.de>"] authors = ["Dennis Schwerdel <schwerdel@googlemail.com>"]
description = "Deduplicating backup tool" description = "Deduplicating backup tool"
[dependencies] [dependencies]
@ -27,6 +27,7 @@ fuse = "0.3"
lazy_static = "0.2" lazy_static = "0.2"
rand = "0.3" rand = "0.3"
tar = "0.4" tar = "0.4"
xattr = "0.1"
time = "*" time = "*"
libc = "*" libc = "*"

View File

@ -99,8 +99,6 @@ Recommended: Brotli/2-7
### Core functionality ### Core functionality
- Recompress & combine bundles - Recompress & combine bundles
- File attributes
- xattrs https://crates.io/crates/xattr
### CLI functionality ### CLI functionality
- list --tree - list --tree

View File

@ -30,8 +30,7 @@ impl ErrorCode {
pub fn code(&self) -> i32 { pub fn code(&self) -> i32 {
match *self { match *self {
// Crazy stuff // Crazy stuff
ErrorCode::InitializeLogger => -1, ErrorCode::InitializeLogger | ErrorCode::InvalidExcludes => -1,
ErrorCode::InvalidExcludes => -1,
// Arguments // Arguments
ErrorCode::InvalidArgs => 1, ErrorCode::InvalidArgs => 1,
ErrorCode::UnsafeArgs => 2, ErrorCode::UnsafeArgs => 2,

View File

@ -1,4 +1,5 @@
#![recursion_limit="128"] #![recursion_limit="128"]
#![allow(unknown_lints, float_cmp)]
extern crate serde; extern crate serde;
extern crate rmp_serde; extern crate rmp_serde;
#[macro_use] extern crate serde_utils; #[macro_use] extern crate serde_utils;
@ -21,6 +22,7 @@ extern crate regex;
extern crate fuse; extern crate fuse;
extern crate rand; extern crate rand;
extern crate time; extern crate time;
extern crate xattr;
extern crate libc; extern crate libc;
extern crate tar; extern crate tar;

View File

@ -1,6 +1,7 @@
use ::prelude::*; use ::prelude::*;
use filetime::{self, FileTime}; use filetime::{self, FileTime};
use xattr;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -23,6 +24,11 @@ quick_error!{
description("Failed to obtain metadata for file") description("Failed to obtain metadata for file")
display("Inode error: failed to obtain metadata for file {:?}\n\tcaused by: {}", path, err) 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) { ReadLinkTarget(err: io::Error, path: PathBuf) {
cause(err) cause(err)
description("Failed to obtain link target for file") description("Failed to obtain link target for file")
@ -48,6 +54,11 @@ quick_error!{
description("Failed to set file ownership") description("Failed to set file ownership")
display("Inode error: failed to set file ownership on {:?}\n\tcaused by: {}", path, err) 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) { Integrity(reason: &'static str) {
description("Integrity error") description("Integrity error")
display("Inode error: inode integrity error: {}", reason) display("Inode error: inode integrity error: {}", reason)
@ -117,7 +128,8 @@ pub struct Inode {
pub children: Option<BTreeMap<String, ChunkList>>, pub children: Option<BTreeMap<String, ChunkList>>,
pub cum_size: u64, pub cum_size: u64,
pub cum_dirs: usize, pub cum_dirs: usize,
pub cum_files: usize pub cum_files: usize,
pub xattrs: BTreeMap<String, msgpack::Bytes>
} }
impl Default for Inode { impl Default for Inode {
fn default() -> Self { fn default() -> Self {
@ -134,7 +146,8 @@ impl Default for Inode {
children: None, children: None,
cum_size: 0, cum_size: 0,
cum_dirs: 0, cum_dirs: 0,
cum_files: 0 cum_files: 0,
xattrs: BTreeMap::new()
} }
} }
} }
@ -145,15 +158,14 @@ serde_impl!(Inode(u8?) {
mode: u32 => 3, mode: u32 => 3,
user: u32 => 4, user: u32 => 4,
group: u32 => 5, group: u32 => 5,
//__old_access_time: i64 => 6,
timestamp: i64 => 7, timestamp: i64 => 7,
//__old_create_time: i64 => 8,
symlink_target: Option<String> => 9, symlink_target: Option<String> => 9,
data: Option<FileData> => 10, data: Option<FileData> => 10,
children: Option<BTreeMap<String, ChunkList>> => 11, children: Option<BTreeMap<String, ChunkList>> => 11,
cum_size: u64 => 12, cum_size: u64 => 12,
cum_dirs: usize => 13, cum_dirs: usize => 13,
cum_files: usize => 14 cum_files: usize => 14,
xattrs: BTreeMap<String, msgpack::Bytes> => 15
}); });
@ -183,6 +195,14 @@ impl Inode {
inode.user = meta.st_uid(); inode.user = meta.st_uid();
inode.group = meta.st_gid(); inode.group = meta.st_gid();
inode.timestamp = meta.st_mtime(); 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) 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( try!(fs::set_permissions(
&full_path, &full_path,
Permissions::from_mode(self.mode) Permissions::from_mode(self.mode)
).map_err(|e| InodeError::SetPermissions(e, full_path.clone(), 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()))); try!(chown(&full_path, self.user, self.group).map_err(|e| InodeError::SetOwnership(e, full_path.clone())));
Ok(file) Ok(file)
} }

View File

@ -113,15 +113,11 @@ impl Repository {
roots.push((inode, chunks)); roots.push((inode, chunks));
} }
} }
let mut root_inode;
let chunks;
if roots.len() == 1 { if roots.len() == 1 {
let r = roots.pop().unwrap(); Ok(roots.pop().unwrap())
root_inode = r.0;
chunks = r.1;
} else { } else {
warn!("Tar file contains multiple roots, adding dummy folder"); warn!("Tar file contains multiple roots, adding dummy folder");
root_inode = Inode { let mut root_inode = Inode {
file_type: FileType::Directory, file_type: FileType::Directory,
mode: 0o755, mode: 0o755,
name: "archive".to_string(), name: "archive".to_string(),
@ -138,9 +134,9 @@ impl Repository {
root_inode.cum_dirs += inode.cum_dirs; root_inode.cum_dirs += inode.cum_dirs;
} }
root_inode.children = Some(children); 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<P: AsRef<Path>>(&mut self, tarfile: P) -> Result<Backup, RepositoryError> { pub fn import_tarfile<P: AsRef<Path>>(&mut self, tarfile: P) -> Result<Backup, RepositoryError> {