From 6a584cfd764864bc81809fe37afa65d63c1e01a9 Mon Sep 17 00:00:00 2001 From: Christian Ebner Date: Thu, 1 Aug 2019 16:23:46 +0200 Subject: [PATCH] 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 --- src/pxar.rs | 3 ++ src/pxar/dir_buffer.rs | 112 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/pxar/dir_buffer.rs diff --git a/src/pxar.rs b/src/pxar.rs index b760a9c7..7123d834 100644 --- a/src/pxar.rs +++ b/src/pxar.rs @@ -65,4 +65,7 @@ pub use decoder::*; mod exclude_pattern; pub use exclude_pattern::*; +mod dir_buffer; +pub use dir_buffer::*; + mod helper; diff --git a/src/pxar/dir_buffer.rs b/src/pxar/dir_buffer.rs new file mode 100644 index 00000000..c6cfde34 --- /dev/null +++ b/src/pxar/dir_buffer.rs @@ -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, +} + +pub struct PxarDirBuf { + root: RawFd, + data: Vec, +} + +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 { + 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 { + 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 { + 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 { + 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) + } +}