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:
parent
27e6e180b6
commit
6a584cfd76
|
@ -65,4 +65,7 @@ pub use decoder::*;
|
|||
mod exclude_pattern;
|
||||
pub use exclude_pattern::*;
|
||||
|
||||
mod dir_buffer;
|
||||
pub use dir_buffer::*;
|
||||
|
||||
mod helper;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue