1 use std
::ffi
::OsString
;
2 use std
::os
::unix
::io
::{AsRawFd, RawFd}
;
3 use std
::path
::{Path, PathBuf}
;
5 use anyhow
::{bail, format_err, Error}
;
8 use nix
::sys
::stat
::{mkdirat, Mode}
;
10 use proxmox
::sys
::error
::SysError
;
11 use proxmox
::tools
::fd
::BorrowedFd
;
14 use crate::pxar
::tools
::{assert_single_path_component, perms_from_metadata}
;
23 pub fn new(file_name
: OsString
, metadata
: Metadata
) -> Self {
31 pub fn with_dir(dir
: Dir
, metadata
: Metadata
) -> Self {
33 file_name
: OsString
::from("."),
42 allow_existing_dirs
: bool
,
43 ) -> Result
<BorrowedFd
, Error
> {
46 self.file_name
.as_os_str(),
47 perms_from_metadata(&self.metadata
)?
,
51 if !(allow_existing_dirs
&& err
.already_exists()) {
52 return Err(err
.into());
60 fn open_dir(&mut self, parent
: RawFd
) -> Result
<BorrowedFd
, Error
> {
61 let dir
= Dir
::openat(
63 self.file_name
.as_os_str(),
68 let fd
= BorrowedFd
::new(&dir
);
74 pub fn try_as_borrowed_fd(&self) -> Option
<BorrowedFd
> {
75 self.dir
.as_ref().map(BorrowedFd
::new
)
78 pub fn metadata(&self) -> &Metadata
{
83 pub struct PxarDirStack
{
90 pub fn new(root
: Dir
, metadata
: Metadata
) -> Self {
92 dirs
: vec
![PxarDir
::with_dir(root
, metadata
)],
93 path
: PathBuf
::from("/"),
94 created
: 1, // the root directory exists
98 pub fn is_empty(&self) -> bool
{
102 pub fn push(&mut self, file_name
: OsString
, metadata
: Metadata
) -> Result
<(), Error
> {
103 assert_single_path_component(&file_name
)?
;
104 self.path
.push(&file_name
);
105 self.dirs
.push(PxarDir
::new(file_name
, metadata
));
109 pub fn pop(&mut self) -> Result
<Option
<PxarDir
>, Error
> {
110 let out
= self.dirs
.pop();
111 if !self.path
.pop() {
112 if self.path
.as_os_str() == "/" {
113 // we just finished the root directory, make sure this can only happen once:
114 self.path
= PathBuf
::new();
116 bail
!("lost track of path");
119 self.created
= self.created
.min(self.dirs
.len());
123 pub fn last_dir_fd(&mut self, allow_existing_dirs
: bool
) -> Result
<BorrowedFd
, Error
> {
124 // should not be possible given the way we use it:
125 assert
!(!self.dirs
.is_empty(), "PxarDirStack underrun");
127 let dirs_len
= self.dirs
.len();
128 let mut fd
= self.dirs
[self.created
- 1]
129 .try_as_borrowed_fd()
130 .ok_or_else(|| format_err
!("lost track of directory file descriptors"))?
133 while self.created
< dirs_len
{
134 fd
= self.dirs
[self.created
]
135 .create_dir(fd
, allow_existing_dirs
)?
140 self.dirs
[self.created
- 1]
141 .try_as_borrowed_fd()
142 .ok_or_else(|| format_err
!("lost track of directory file descriptors"))
145 pub fn create_last_dir(&mut self, allow_existing_dirs
: bool
) -> Result
<(), Error
> {
146 let _
: BorrowedFd
= self.last_dir_fd(allow_existing_dirs
)?
;
150 pub fn root_dir_fd(&self) -> Result
<BorrowedFd
, Error
> {
151 // should not be possible given the way we use it:
152 assert
!(!self.dirs
.is_empty(), "PxarDirStack underrun");
155 .try_as_borrowed_fd()
156 .ok_or_else(|| format_err
!("lost track of directory file descriptors"))
159 pub fn path(&self) -> &Path
{