mirror of https://github.com/dswd/zvault
Skip root folder on restore & fixed exporting files with long names as tar files
This commit is contained in:
parent
30bc7d80c5
commit
2a1dc52c56
|
@ -4,9 +4,11 @@ This project follows [semantic versioning](http://semver.org).
|
||||||
|
|
||||||
|
|
||||||
### UNRELEASED
|
### UNRELEASED
|
||||||
* [modifed] Changed order of arguments in `addkey` to match src-dst scheme
|
* [modified] Changed order of arguments in `addkey` to match src-dst scheme
|
||||||
|
* [modified] Skip root folder on restore
|
||||||
* [fixed] Fixed `addkey` subcommand
|
* [fixed] Fixed `addkey` subcommand
|
||||||
* [fixed] Fixed reading tar files from stdin
|
* [fixed] Fixed reading tar files from stdin
|
||||||
|
* [fixed] Fixed exporting files with long names as tar files
|
||||||
|
|
||||||
|
|
||||||
### v0.3.1 (2017-05-09)
|
### v0.3.1 (2017-05-09)
|
||||||
|
|
|
@ -145,25 +145,29 @@ impl Repository {
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
queue.push_back((path.as_ref().to_owned(), inode));
|
queue.push_back((path.as_ref().to_owned(), inode));
|
||||||
let cache = users::UsersCache::new();
|
let cache = users::UsersCache::new();
|
||||||
|
let mut is_root = true;
|
||||||
while let Some((path, mut inode)) = queue.pop_front() {
|
while let Some((path, mut inode)) = queue.pop_front() {
|
||||||
if let Some(name) = backup.user_names.get(&inode.user) {
|
if inode.file_type != FileType::Directory || !is_root {
|
||||||
if let Some(user) = cache.get_user_by_name(name) {
|
if let Some(name) = backup.user_names.get(&inode.user) {
|
||||||
inode.user = user.uid();
|
if let Some(user) = cache.get_user_by_name(name) {
|
||||||
|
inode.user = user.uid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if let Some(name) = backup.group_names.get(&inode.group) {
|
||||||
if let Some(name) = backup.group_names.get(&inode.group) {
|
if let Some(group) = cache.get_group_by_name(name) {
|
||||||
if let Some(group) = cache.get_group_by_name(name) {
|
inode.group = group.gid();
|
||||||
inode.group = group.gid();
|
}
|
||||||
}
|
}
|
||||||
|
try!(self.save_inode_at(&inode, &path));
|
||||||
}
|
}
|
||||||
try!(self.save_inode_at(&inode, &path));
|
|
||||||
if inode.file_type == FileType::Directory {
|
if inode.file_type == FileType::Directory {
|
||||||
let path = path.join(inode.name);
|
let path = if is_root { path.to_path_buf() } else { path.join(inode.name) };
|
||||||
for chunks in inode.children.unwrap().values() {
|
for chunks in inode.children.unwrap().values() {
|
||||||
let inode = try!(self.get_inode(chunks));
|
let inode = try!(self.get_inode(chunks));
|
||||||
queue.push_back((path.clone(), inode));
|
queue.push_back((path.clone(), inode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is_root = false;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,15 @@ use std::path::{Path, PathBuf};
|
||||||
use std::io::{self, Read, Write, Cursor};
|
use std::io::{self, Read, Write, Cursor};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
|
||||||
use tar;
|
use tar;
|
||||||
|
|
||||||
|
static MAX_NAME_LEN: usize = 99;
|
||||||
|
static MAX_LINK_LEN: usize = 99;
|
||||||
|
|
||||||
|
|
||||||
struct PaxBuilder(Vec<u8>);
|
struct PaxBuilder(Vec<u8>);
|
||||||
|
|
||||||
|
@ -38,6 +42,8 @@ impl PaxBuilder {
|
||||||
|
|
||||||
trait BuilderExt {
|
trait BuilderExt {
|
||||||
fn append_pax_extensions(&mut self, headers: &PaxBuilder) -> Result<(), io::Error>;
|
fn append_pax_extensions(&mut self, headers: &PaxBuilder) -> Result<(), io::Error>;
|
||||||
|
fn append_long_name(&mut self, path: &Path) -> Result<(), io::Error>;
|
||||||
|
fn append_long_link(&mut self, path: &Path) -> Result<(), io::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Write> BuilderExt for tar::Builder<T> {
|
impl<T: Write> BuilderExt for tar::Builder<T> {
|
||||||
|
@ -48,6 +54,24 @@ impl<T: Write> BuilderExt for tar::Builder<T> {
|
||||||
header.set_cksum();
|
header.set_cksum();
|
||||||
self.append(&header, headers.as_bytes())
|
self.append(&header, headers.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn append_long_name(&mut self, path: &Path) -> Result<(), io::Error> {
|
||||||
|
let mut header = tar::Header::new_gnu();
|
||||||
|
let bytes = path.as_os_str().as_bytes();
|
||||||
|
header.set_size(bytes.len() as u64);
|
||||||
|
header.set_entry_type(tar::EntryType::GNULongName);
|
||||||
|
header.set_cksum();
|
||||||
|
self.append(&header, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_long_link(&mut self, path: &Path) -> Result<(), io::Error> {
|
||||||
|
let mut header = tar::Header::new_gnu();
|
||||||
|
let bytes = path.as_os_str().as_bytes();
|
||||||
|
header.set_size(bytes.len() as u64);
|
||||||
|
header.set_entry_type(tar::EntryType::GNULongLink);
|
||||||
|
header.set_cksum();
|
||||||
|
self.append(&header, bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,46 +285,56 @@ impl Repository {
|
||||||
Ok(try!(tarfile.append_pax_extensions(&pax)))
|
Ok(try!(tarfile.append_pax_extensions(&pax)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_tarfile_recurse<W: Write>(&mut self, backup: &Backup, path: &Path, inode: Inode, tarfile: &mut tar::Builder<W>) -> Result<(), RepositoryError> {
|
fn export_tarfile_recurse<W: Write>(&mut self, backup: &Backup, path: &Path, inode: Inode, tarfile: &mut tar::Builder<W>, skip_root: bool) -> Result<(), RepositoryError> {
|
||||||
if !inode.xattrs.is_empty() {
|
let path = if skip_root { path.to_path_buf() } else { path.join(&inode.name) };
|
||||||
try!(self.export_xattrs(&inode, tarfile));
|
if inode.file_type != FileType::Directory || !skip_root {
|
||||||
}
|
if !inode.xattrs.is_empty() {
|
||||||
let mut header = tar::Header::new_gnu();
|
try!(self.export_xattrs(&inode, tarfile));
|
||||||
header.set_size(inode.size);
|
}
|
||||||
let path = path.join(inode.name);
|
let mut header = tar::Header::new_gnu();
|
||||||
try!(header.set_path(&path));
|
header.set_size(inode.size);
|
||||||
if let Some(target) = inode.symlink_target {
|
if path.as_os_str().as_bytes().len() >= MAX_NAME_LEN {
|
||||||
try!(header.set_link_name(target));
|
try!(tarfile.append_long_name(&path));
|
||||||
}
|
} else {
|
||||||
header.set_mode(inode.mode);
|
try!(header.set_path(&path));
|
||||||
header.set_uid(inode.user);
|
}
|
||||||
if let Some(name) = backup.user_names.get(&inode.user) {
|
if let Some(target) = inode.symlink_target {
|
||||||
header.set_username(name).ok();
|
if target.len() >= MAX_LINK_LEN {
|
||||||
}
|
try!(tarfile.append_long_link(Path::new(&target)));
|
||||||
header.set_gid(inode.group);
|
} else {
|
||||||
if let Some(name) = backup.group_names.get(&inode.group) {
|
try!(header.set_link_name(target));
|
||||||
header.set_groupname(name).ok();
|
}
|
||||||
}
|
}
|
||||||
header.set_mtime(inode.timestamp as u64);
|
header.set_mode(inode.mode);
|
||||||
header.set_entry_type(match inode.file_type {
|
header.set_uid(inode.user);
|
||||||
FileType::File => tar::EntryType::Regular,
|
if let Some(name) = backup.user_names.get(&inode.user) {
|
||||||
FileType::Symlink => tar::EntryType::Symlink,
|
header.set_username(name).ok();
|
||||||
FileType::Directory => tar::EntryType::Directory
|
}
|
||||||
});
|
header.set_gid(inode.group);
|
||||||
header.set_cksum();
|
if let Some(name) = backup.group_names.get(&inode.group) {
|
||||||
match inode.data {
|
header.set_groupname(name).ok();
|
||||||
None => try!(tarfile.append(&header, Cursor::new(&[]))),
|
}
|
||||||
Some(FileData::Inline(data)) => try!(tarfile.append(&header, Cursor::new(data))),
|
header.set_mtime(inode.timestamp as u64);
|
||||||
Some(FileData::ChunkedDirect(chunks)) => try!(tarfile.append(&header, self.get_reader(chunks))),
|
header.set_entry_type(match inode.file_type {
|
||||||
Some(FileData::ChunkedIndirect(chunks)) => {
|
FileType::File => tar::EntryType::Regular,
|
||||||
let chunks = ChunkList::read_from(&try!(self.get_data(&chunks)));
|
FileType::Symlink => tar::EntryType::Symlink,
|
||||||
try!(tarfile.append(&header, self.get_reader(chunks)))
|
FileType::Directory => tar::EntryType::Directory
|
||||||
|
});
|
||||||
|
header.set_cksum();
|
||||||
|
match inode.data {
|
||||||
|
None => try!(tarfile.append(&header, Cursor::new(&[]))),
|
||||||
|
Some(FileData::Inline(data)) => try!(tarfile.append(&header, Cursor::new(data))),
|
||||||
|
Some(FileData::ChunkedDirect(chunks)) => try!(tarfile.append(&header, self.get_reader(chunks))),
|
||||||
|
Some(FileData::ChunkedIndirect(chunks)) => {
|
||||||
|
let chunks = ChunkList::read_from(&try!(self.get_data(&chunks)));
|
||||||
|
try!(tarfile.append(&header, self.get_reader(chunks)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(children) = inode.children {
|
if let Some(children) = inode.children {
|
||||||
for chunks in children.values() {
|
for chunks in children.values() {
|
||||||
let inode = try!(self.get_inode(chunks));
|
let inode = try!(self.get_inode(chunks));
|
||||||
try!(self.export_tarfile_recurse(backup, &path, inode, tarfile));
|
try!(self.export_tarfile_recurse(backup, &path, inode, tarfile, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -310,11 +344,11 @@ impl Repository {
|
||||||
let tarfile = tarfile.as_ref();
|
let tarfile = tarfile.as_ref();
|
||||||
if tarfile == Path::new("-") {
|
if tarfile == Path::new("-") {
|
||||||
let mut tarfile = tar::Builder::new(io::stdout());
|
let mut tarfile = tar::Builder::new(io::stdout());
|
||||||
try!(self.export_tarfile_recurse(backup, Path::new(""), inode, &mut tarfile));
|
try!(self.export_tarfile_recurse(backup, Path::new(""), inode, &mut tarfile, true));
|
||||||
try!(tarfile.finish());
|
try!(tarfile.finish());
|
||||||
} else {
|
} else {
|
||||||
let mut tarfile = tar::Builder::new(try!(File::create(tarfile)));
|
let mut tarfile = tar::Builder::new(try!(File::create(tarfile)));
|
||||||
try!(self.export_tarfile_recurse(backup, Path::new(""), inode, &mut tarfile));
|
try!(self.export_tarfile_recurse(backup, Path::new(""), inode, &mut tarfile, true));
|
||||||
try!(tarfile.finish());
|
try!(tarfile.finish());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue