pxar: add PxarDir and PxarDirBuf to buffer directory metadata

In order to restore only directories when some of their content fully matched
a match pattern on partial restores, these directories and their metadata are
pushed onto this buffer and only restored successivley on demand.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
Christian Ebner 2019-08-01 16:23:46 +02:00 committed by Dietmar Maurer
parent 27e6e180b6
commit 6a584cfd76
2 changed files with 115 additions and 0 deletions

View File

@ -65,4 +65,7 @@ pub use decoder::*;
mod exclude_pattern;
pub use exclude_pattern::*;
mod dir_buffer;
pub use dir_buffer::*;
mod helper;

112
src/pxar/dir_buffer.rs Normal file
View File

@ -0,0 +1,112 @@
use std::ffi::{OsStr, OsString};
use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf;
use super::format_definition::*;
use failure::*;
use nix::fcntl::OFlag;
use nix::errno::Errno;
use nix::sys::stat::Mode;
use nix::NixPath;
pub struct PxarDir {
pub filename: OsString,
pub entry: CaFormatEntry,
pub attr: PxarAttributes,
pub dir: Option<nix::dir::Dir>,
}
pub struct PxarDirBuf {
root: RawFd,
data: Vec<PxarDir>,
}
impl PxarDir {
pub fn new(filename: &OsStr, entry: CaFormatEntry, attr: PxarAttributes) -> Self {
Self {
filename: filename.to_os_string(),
entry,
attr,
dir: None,
}
}
fn create_dir(&self, parent: RawFd, create_new: bool) -> Result<nix::dir::Dir, nix::Error> {
let res = self.filename.with_nix_path(|cstr| unsafe {
libc::mkdirat(parent, cstr.as_ptr(), libc::S_IRWXU)
})?;
match Errno::result(res) {
Ok(_) => {},
Err(err) => {
if err == nix::Error::Sys(nix::errno::Errno::EEXIST) {
if create_new {
return Err(err);
}
} else {
return Err(err);
}
}
}
let dir = nix::dir::Dir::openat(parent, self.filename.as_os_str(), OFlag::O_DIRECTORY, Mode::empty())?;
Ok(dir)
}
}
impl PxarDirBuf {
pub fn new(parent: RawFd) -> Self {
Self {
root: parent,
data: Vec::new(),
}
}
pub fn push(&mut self, dir: PxarDir) {
self.data.push(dir);
}
pub fn pop(&mut self) -> Option<PxarDir> {
self.data.pop()
}
pub fn as_path_buf(&self) -> PathBuf {
let path: PathBuf = self.data.iter().map(|d| d.filename.clone()).collect();
path
}
pub fn last(&self) -> Option<&PxarDir> {
self.data.last()
}
pub fn last_mut(&mut self) -> Option<&mut PxarDir> {
self.data.last_mut()
}
pub fn last_dir_fd(&self) -> Option<RawFd> {
let last_dir = self.data.last()?;
match &last_dir.dir {
Some(d) => Some(d.as_raw_fd()),
None => None,
}
}
pub fn create_all_dirs(&mut self, create_new: bool) -> Result<RawFd, Error> {
let mut current_fd = self.root;
for d in &mut self.data {
match &d.dir {
Some(dir) => current_fd = dir.as_raw_fd(),
None => {
let dir = d.create_dir(current_fd, create_new)
.map_err(|err| format_err!("create dir failed - {}", err))?;
current_fd = dir.as_raw_fd();
d.dir = Some(dir);
},
}
}
Ok(current_fd)
}
}