]> git.proxmox.com Git - proxmox-backup.git/blame - src/pxar/dir_stack.rs
switch to external pxar and fuse crates
[proxmox-backup.git] / src / pxar / dir_stack.rs
CommitLineData
c443f58b 1use std::ffi::OsString;
6a584cfd
CE
2use std::os::unix::io::{AsRawFd, RawFd};
3use std::path::PathBuf;
4
c443f58b
WB
5use anyhow::{bail, format_err, Error};
6use nix::dir::Dir;
dac88033 7use nix::fcntl::OFlag;
c443f58b 8use nix::sys::stat::{mkdirat, Mode};
6a584cfd 9
c443f58b
WB
10use proxmox::sys::error::SysError;
11use pxar::Metadata;
dac88033 12
c443f58b 13use crate::pxar::tools::{assert_relative_path, perms_from_metadata};
6a584cfd 14
c443f58b
WB
15pub struct PxarDir {
16 file_name: OsString,
17 metadata: Metadata,
18 dir: Option<Dir>,
6a584cfd
CE
19}
20
21impl PxarDir {
c443f58b 22 pub fn new(file_name: OsString, metadata: Metadata) -> Self {
6a584cfd 23 Self {
c443f58b
WB
24 file_name,
25 metadata,
6a584cfd
CE
26 dir: None,
27 }
28 }
29
c443f58b
WB
30 pub fn with_dir(dir: Dir, metadata: Metadata) -> Self {
31 Self {
32 file_name: OsString::from("."),
33 metadata,
34 dir: Some(dir),
35 }
36 }
6a584cfd 37
c443f58b
WB
38 fn create_dir(&mut self, parent: RawFd, allow_existing_dirs: bool) -> Result<RawFd, Error> {
39 match mkdirat(
40 parent,
41 self.file_name.as_os_str(),
42 perms_from_metadata(&self.metadata)?,
43 ) {
44 Ok(()) => (),
6a584cfd 45 Err(err) => {
c443f58b
WB
46 if !(allow_existing_dirs && err.already_exists()) {
47 return Err(err.into());
6a584cfd
CE
48 }
49 }
50 }
51
c443f58b
WB
52 self.open_dir(parent)
53 }
54
55 fn open_dir(&mut self, parent: RawFd) -> Result<RawFd, Error> {
56 let dir = Dir::openat(
dac88033 57 parent,
c443f58b 58 self.file_name.as_os_str(),
dac88033
CE
59 OFlag::O_DIRECTORY,
60 Mode::empty(),
61 )?;
6a584cfd 62
c443f58b
WB
63 let fd = dir.as_raw_fd();
64 self.dir = Some(dir);
65
66 Ok(fd)
6a584cfd 67 }
c443f58b
WB
68
69 pub fn try_as_raw_fd(&self) -> Option<RawFd> {
70 self.dir.as_ref().map(AsRawFd::as_raw_fd)
71 }
72
73 pub fn metadata(&self) -> &Metadata {
74 &self.metadata
75 }
76}
77
78pub struct PxarDirStack {
79 dirs: Vec<PxarDir>,
80 path: PathBuf,
81 created: usize,
6a584cfd
CE
82}
83
fe076c82 84impl PxarDirStack {
c443f58b 85 pub fn new(root: Dir, metadata: Metadata) -> Self {
6a584cfd 86 Self {
c443f58b
WB
87 dirs: vec![PxarDir::with_dir(root, metadata)],
88 path: PathBuf::from("/"),
89 created: 1, // the root directory exists
6a584cfd
CE
90 }
91 }
92
c443f58b
WB
93 pub fn is_empty(&self) -> bool {
94 self.dirs.is_empty()
6a584cfd
CE
95 }
96
c443f58b
WB
97 pub fn push(&mut self, file_name: OsString, metadata: Metadata) -> Result<(), Error> {
98 assert_relative_path(&file_name)?;
99 self.path.push(&file_name);
100 self.dirs.push(PxarDir::new(file_name, metadata));
101 Ok(())
6a584cfd
CE
102 }
103
c443f58b
WB
104 pub fn pop(&mut self) -> Result<Option<PxarDir>, Error> {
105 let out = self.dirs.pop();
106 if !self.path.pop() {
107 if self.path.as_os_str() == "/" {
108 // we just finished the root directory, make sure this can only happen once:
109 self.path = PathBuf::new();
110 } else {
111 bail!("lost track of path");
112 }
113 }
114 self.created = self.created.min(self.dirs.len());
115 Ok(out)
6a584cfd
CE
116 }
117
c443f58b
WB
118 pub fn last_dir_fd(&mut self, allow_existing_dirs: bool) -> Result<RawFd, Error> {
119 // should not be possible given the way we use it:
120 assert!(!self.dirs.is_empty(), "PxarDirStack underrun");
6a584cfd 121
c443f58b
WB
122 let mut fd = self.dirs[self.created - 1]
123 .try_as_raw_fd()
124 .ok_or_else(|| format_err!("lost track of directory file descriptors"))?;
125 while self.created < self.dirs.len() {
126 fd = self.dirs[self.created].create_dir(fd, allow_existing_dirs)?;
127 self.created += 1;
6a584cfd 128 }
c443f58b
WB
129
130 Ok(fd)
6a584cfd
CE
131 }
132
c443f58b
WB
133 pub fn root_dir_fd(&self) -> Result<RawFd, Error> {
134 // should not be possible given the way we use it:
135 assert!(!self.dirs.is_empty(), "PxarDirStack underrun");
6a584cfd 136
c443f58b
WB
137 self.dirs[0]
138 .try_as_raw_fd()
139 .ok_or_else(|| format_err!("lost track of directory file descriptors"))
6a584cfd
CE
140 }
141}