openat_ct/
builder.rs

1use std::ffi::CStr;
2use std::fs::File;
3use std::io;
4
5use crate::dir::{clone_dirfd_upgrade, to_cstr};
6use crate::{AsPath, Dir};
7
8/// 'Dir::new()' creates a new DirFlags object with default (O_CLOEXEC) flags. One can then
9/// freely add/remove flags to the set. The final open calls will add O_DIRECTORY and O_PATH
10/// as applicable/supported but not verify or remove any defined flags. This allows passing
11/// flags the 'openat' implementation is not even aware about. Thus the open call may fail
12/// with some error when one constructed an invalid flag set.
13#[derive(Copy, Clone)]
14pub struct DirFlags {
15    flags: libc::c_int,
16}
17
18impl DirFlags {
19    #[inline]
20    pub(crate) fn new(flags: libc::c_int) -> DirFlags {
21        DirFlags { flags }
22    }
23
24    /// Sets the given flags
25    #[inline]
26    pub fn with(self, flags: libc::c_int) -> DirFlags {
27        DirFlags {
28            flags: self.flags | flags,
29        }
30    }
31
32    /// Clears the given flags
33    #[inline]
34    pub fn without(self, flags: libc::c_int) -> DirFlags {
35        DirFlags {
36            flags: self.flags & !flags,
37        }
38    }
39
40    /// Queries current flags
41    #[inline]
42    pub fn get_flags(&self) -> libc::c_int {
43        self.flags
44    }
45
46    /// Open a directory descriptor at specified path
47    #[inline]
48    pub fn open<P: AsPath>(&self, path: P) -> io::Result<Dir> {
49        Dir::_open(to_cstr(path)?.as_ref(), self.flags)
50    }
51}
52
53/// 'Dir::with(&self)'/'Dir::with(&self)' creates a new DirMethodsFlags object with default
54/// (O_CLOEXEC|O_NOFOLLOW) flags. One can then freely add/remove flags to the set.
55/// Implements proxies for the Dir:: methods that open contained objects.
56#[derive(Copy, Clone)]
57pub struct DirMethodFlags<'a> {
58    object: &'a Dir,
59    flags: libc::c_int,
60}
61
62impl<'a> DirMethodFlags<'a> {
63    #[inline]
64    pub(crate) fn new(object: &'a Dir, flags: libc::c_int) -> Self {
65        Self { object, flags }
66    }
67
68    /// Sets the given flags
69    #[inline]
70    pub fn with(self, flags: libc::c_int) -> Self {
71        Self {
72            object: self.object,
73            flags: self.flags | flags,
74        }
75    }
76
77    /// Clears the given flags
78    #[inline]
79    pub fn without(self, flags: libc::c_int) -> Self {
80        Self {
81            object: self.object,
82            flags: self.flags & !flags,
83        }
84    }
85
86    /// Open subdirectory
87    #[inline]
88    pub fn sub_dir<P: AsPath>(&self, path: P) -> io::Result<Dir> {
89        self.object._sub_dir(to_cstr(path)?.as_ref(), self.flags)
90    }
91
92    /// Open file for reading in this directory
93    #[inline]
94    pub fn open_file<P: AsPath>(&self, path: P) -> io::Result<File> {
95        self.object
96            ._open_file(to_cstr(path)?.as_ref(), self.flags | libc::O_RDONLY, 0)
97    }
98
99    /// Open file for writing, create if necessary, truncate on open
100    #[inline]
101    pub fn write_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -> io::Result<File> {
102        self.object._open_file(
103            to_cstr(path)?.as_ref(),
104            self.flags | libc::O_CREAT | libc::O_WRONLY | libc::O_TRUNC,
105            mode,
106        )
107    }
108
109    /// Open file for append, create if necessary
110    #[inline]
111    pub fn append_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -> io::Result<File> {
112        self.object._open_file(
113            to_cstr(path)?.as_ref(),
114            self.flags | libc::O_CREAT | libc::O_WRONLY | libc::O_APPEND,
115            mode,
116        )
117    }
118
119    /// Create file for writing (and truncate) in this directory
120    #[deprecated(since = "0.1.7", note = "please use `write_file` instead")]
121    #[inline]
122    pub fn create_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -> io::Result<File> {
123        self.object._open_file(
124            to_cstr(path)?.as_ref(),
125            self.flags | libc::O_CREAT | libc::O_WRONLY | libc::O_TRUNC,
126            mode,
127        )
128    }
129
130    /// Create a tmpfile in this directory which isn't linked to any filename
131    #[cfg(feature = "o_tmpfile")]
132    #[inline]
133    pub fn new_unnamed_file(&self, mode: libc::mode_t) -> io::Result<File> {
134        self.object._open_file(
135            unsafe { CStr::from_bytes_with_nul_unchecked(b".\0") },
136            self.flags | libc::O_TMPFILE | libc::O_WRONLY,
137            mode,
138        )
139    }
140
141    /// Create file if not exists, fail if exists
142    #[inline]
143    pub fn new_file<P: AsPath>(&self, path: P, mode: libc::mode_t) -> io::Result<File> {
144        self.object._open_file(
145            to_cstr(path)?.as_ref(),
146            self.flags | libc::O_CREAT | libc::O_EXCL | libc::O_WRONLY,
147            mode,
148        )
149    }
150
151    /// Creates a new 'Normal' independently owned handle to the underlying directory.
152    pub fn clone_upgrade(&self) -> io::Result<Dir> {
153        Ok(Dir(clone_dirfd_upgrade(self.object.0, self.flags)?))
154    }
155}