Skip root folder on restore & fixed exporting files with long names as tar files

This commit is contained in:
Dennis Schwerdel 2017-05-11 10:47:21 +02:00
parent 30bc7d80c5
commit 2a1dc52c56
3 changed files with 87 additions and 47 deletions

View File

@ -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)

View File

@ -145,7 +145,9 @@ 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 inode.file_type != FileType::Directory || !is_root {
if let Some(name) = backup.user_names.get(&inode.user) { if let Some(name) = backup.user_names.get(&inode.user) {
if let Some(user) = cache.get_user_by_name(name) { if let Some(user) = cache.get_user_by_name(name) {
inode.user = user.uid(); inode.user = user.uid();
@ -157,13 +159,15 @@ impl Repository {
} }
} }
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(())
} }

View File

@ -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,17 +285,26 @@ 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> {
let path = if skip_root { path.to_path_buf() } else { path.join(&inode.name) };
if inode.file_type != FileType::Directory || !skip_root {
if !inode.xattrs.is_empty() { if !inode.xattrs.is_empty() {
try!(self.export_xattrs(&inode, tarfile)); try!(self.export_xattrs(&inode, tarfile));
} }
let mut header = tar::Header::new_gnu(); let mut header = tar::Header::new_gnu();
header.set_size(inode.size); header.set_size(inode.size);
let path = path.join(inode.name); if path.as_os_str().as_bytes().len() >= MAX_NAME_LEN {
try!(tarfile.append_long_name(&path));
} else {
try!(header.set_path(&path)); try!(header.set_path(&path));
}
if let Some(target) = inode.symlink_target { if let Some(target) = inode.symlink_target {
if target.len() >= MAX_LINK_LEN {
try!(tarfile.append_long_link(Path::new(&target)));
} else {
try!(header.set_link_name(target)); try!(header.set_link_name(target));
} }
}
header.set_mode(inode.mode); header.set_mode(inode.mode);
header.set_uid(inode.user); header.set_uid(inode.user);
if let Some(name) = backup.user_names.get(&inode.user) { if let Some(name) = backup.user_names.get(&inode.user) {
@ -297,10 +330,11 @@ impl Repository {
try!(tarfile.append(&header, self.get_reader(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(())