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;
|
mod exclude_pattern;
|
||||||
pub use exclude_pattern::*;
|
pub use exclude_pattern::*;
|
||||||
|
|
||||||
|
mod dir_buffer;
|
||||||
|
pub use dir_buffer::*;
|
||||||
|
|
||||||
mod helper;
|
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