]> git.proxmox.com Git - proxmox-backup.git/blob - src/pxar/dir_stack.rs
34d52bdf6c4cfe6ff8d694763e9e11579c5f7445
[proxmox-backup.git] / src / pxar / dir_stack.rs
1 use std::ffi::{OsStr, OsString};
2 use std::os::unix::io::{AsRawFd, RawFd};
3 use std::path::PathBuf;
4
5 use failure::{format_err, Error};
6 use nix::errno::Errno;
7 use nix::fcntl::OFlag;
8 use nix::sys::stat::Mode;
9 use nix::NixPath;
10
11 use super::format_definition::{PxarAttributes, PxarEntry};
12
13 pub struct PxarDir {
14 pub filename: OsString,
15 pub entry: PxarEntry,
16 pub attr: PxarAttributes,
17 pub dir: Option<nix::dir::Dir>,
18 }
19
20 pub struct PxarDirStack {
21 root: RawFd,
22 data: Vec<PxarDir>,
23 }
24
25 impl PxarDir {
26 pub fn new(filename: &OsStr, entry: PxarEntry, attr: PxarAttributes) -> Self {
27 Self {
28 filename: filename.to_os_string(),
29 entry,
30 attr,
31 dir: None,
32 }
33 }
34
35 fn create_dir(&self, parent: RawFd, create_new: bool) -> Result<nix::dir::Dir, nix::Error> {
36 let res = self
37 .filename
38 .with_nix_path(|cstr| unsafe { libc::mkdirat(parent, cstr.as_ptr(), libc::S_IRWXU) })?;
39
40 match Errno::result(res) {
41 Ok(_) => {}
42 Err(err) => {
43 if err == nix::Error::Sys(nix::errno::Errno::EEXIST) {
44 if create_new {
45 return Err(err);
46 }
47 } else {
48 return Err(err);
49 }
50 }
51 }
52
53 let dir = nix::dir::Dir::openat(
54 parent,
55 self.filename.as_os_str(),
56 OFlag::O_DIRECTORY,
57 Mode::empty(),
58 )?;
59
60 Ok(dir)
61 }
62 }
63
64 impl PxarDirStack {
65 pub fn new(parent: RawFd) -> Self {
66 Self {
67 root: parent,
68 data: Vec::new(),
69 }
70 }
71
72 pub fn push(&mut self, dir: PxarDir) {
73 self.data.push(dir);
74 }
75
76 pub fn pop(&mut self) -> Option<PxarDir> {
77 self.data.pop()
78 }
79
80 pub fn as_path_buf(&self) -> PathBuf {
81 let path: PathBuf = self.data.iter().map(|d| d.filename.clone()).collect();
82 path
83 }
84
85 pub fn last(&self) -> Option<&PxarDir> {
86 self.data.last()
87 }
88
89 pub fn last_mut(&mut self) -> Option<&mut PxarDir> {
90 self.data.last_mut()
91 }
92
93 pub fn last_dir_fd(&self) -> Option<RawFd> {
94 let last_dir = self.data.last()?;
95 match &last_dir.dir {
96 Some(d) => Some(d.as_raw_fd()),
97 None => None,
98 }
99 }
100
101 pub fn create_all_dirs(&mut self, create_new: bool) -> Result<RawFd, Error> {
102 let mut current_fd = self.root;
103 for d in &mut self.data {
104 match &d.dir {
105 Some(dir) => current_fd = dir.as_raw_fd(),
106 None => {
107 let dir = d
108 .create_dir(current_fd, create_new)
109 .map_err(|err| format_err!("create dir failed - {}", err))?;
110 current_fd = dir.as_raw_fd();
111 d.dir = Some(dir);
112 }
113 }
114 }
115
116 Ok(current_fd)
117 }
118 }