diff --git a/src/repository/tarfile.rs b/src/repository/tarfile.rs index aaf0917..5eb6f00 100644 --- a/src/repository/tarfile.rs +++ b/src/repository/tarfile.rs @@ -4,12 +4,15 @@ use std::collections::{HashMap, HashSet, BTreeMap}; use std::path::{Path, PathBuf}; use std::io::{Read, Cursor}; use std::fs::File; +use std::str; use chrono::prelude::*; use tar; +static PAX_XATTR_PREFIX: &'static str = "SCHILY.xattr."; + fn inode_from_entry(entry: &mut tar::Entry) -> Result { let mut inode = { let path = try!(entry.path()); @@ -36,8 +39,8 @@ fn inode_from_entry(entry: &mut tar::Entry) -> Result) -> Result<(), RepositoryError> { + let mut data = Vec::new(); + for (key, value) in &inode.xattrs { + let mut len_len = 1; + let mut max_len = 10; + let rest_len = 3 + key.len() + value.len() + PAX_XATTR_PREFIX.len(); + while rest_len + len_len >= max_len { + len_len += 1; + max_len *= 10; + } + let len = rest_len + len_len; + let value = str::from_utf8(value).unwrap(); + let line = format!("{} {}{}={}\n", len, PAX_XATTR_PREFIX, key, value); + assert_eq!(line.len(), len); + data.extend_from_slice(line.as_bytes()); + } + let mut header = tar::Header::new_ustar(); + header.set_size(data.len() as u64); + header.set_entry_type(tar::EntryType::XHeader); + header.set_cksum(); + Ok(try!(tarfile.append(&header, Cursor::new(&data)))) + } + fn export_tarfile_recurse(&mut self, backup: &Backup, path: &Path, inode: Inode, tarfile: &mut tar::Builder) -> Result<(), RepositoryError> { + if !inode.xattrs.is_empty() { + try!(self.export_xattrs(&inode, tarfile)); + } let mut header = tar::Header::new_gnu(); header.set_size(inode.size); let path = path.join(inode.name);