mirror of https://github.com/dswd/zvault
xattrs
This commit is contained in:
parent
15a01dfbac
commit
1212d08917
|
@ -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]]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "zvault"
|
||||
version = "0.1.0"
|
||||
authors = ["Dennis Schwerdel <schwerdel@informatik.uni-kl.de>"]
|
||||
authors = ["Dennis Schwerdel <schwerdel@googlemail.com>"]
|
||||
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 = "*"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<BTreeMap<String, ChunkList>>,
|
||||
pub cum_size: u64,
|
||||
pub cum_dirs: usize,
|
||||
pub cum_files: usize
|
||||
pub cum_files: usize,
|
||||
pub xattrs: BTreeMap<String, msgpack::Bytes>
|
||||
}
|
||||
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<String> => 9,
|
||||
data: Option<FileData> => 10,
|
||||
children: Option<BTreeMap<String, ChunkList>> => 11,
|
||||
cum_size: u64 => 12,
|
||||
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.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)
|
||||
}
|
||||
|
|
|
@ -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<P: AsRef<Path>>(&mut self, tarfile: P) -> Result<Backup, RepositoryError> {
|
||||
|
|
Loading…
Reference in New Issue