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)",
|
"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]]
|
||||||
|
|
|
@ -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 = "*"
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,10 +134,10 @@ 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> {
|
||||||
let _lock = try!(self.lock(false));
|
let _lock = try!(self.lock(false));
|
||||||
|
|
Loading…
Reference in New Issue