std/sys/fs/unix/
dir.rs

1use libc::c_int;
2
3cfg_select! {
4    not(
5        any(
6            all(target_os = "linux", not(target_env = "musl")),
7            target_os = "l4re",
8            target_os = "android",
9            target_os = "hurd",
10        )
11    ) => {
12        use libc::{open as open64, openat as openat64};
13    }
14    _ => {
15        use libc::{open64, openat64};
16    }
17}
18
19use crate::ffi::CStr;
20use crate::os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd};
21#[cfg(target_family = "unix")]
22use crate::os::unix::io::{AsRawFd, FromRawFd};
23#[cfg(target_os = "wasi")]
24use crate::os::wasi::io::{AsRawFd, FromRawFd};
25use crate::path::Path;
26use crate::sys::fd::FileDesc;
27use crate::sys::fs::OpenOptions;
28use crate::sys::fs::unix::{File, debug_path_fd};
29use crate::sys::helpers::run_path_with_cstr;
30use crate::sys::{AsInner, FromInner, IntoInner, cvt_r};
31use crate::{fmt, fs, io};
32
33pub struct Dir(OwnedFd);
34
35impl Dir {
36    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<Self> {
37        run_path_with_cstr(path, &|path| Self::open_with_c(path, opts))
38    }
39
40    pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result<File> {
41        run_path_with_cstr(path.as_ref(), &|path| self.open_file_c(path, &opts))
42    }
43
44    pub fn open_with_c(path: &CStr, opts: &OpenOptions) -> io::Result<Self> {
45        let flags = libc::O_CLOEXEC
46            | libc::O_DIRECTORY
47            | opts.get_access_mode()?
48            | opts.get_creation_mode()?
49            | (opts.custom_flags as c_int & !libc::O_ACCMODE);
50        let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
51        Ok(Self(unsafe { OwnedFd::from_raw_fd(fd) }))
52    }
53
54    fn open_file_c(&self, path: &CStr, opts: &OpenOptions) -> io::Result<File> {
55        let flags = libc::O_CLOEXEC
56            | opts.get_access_mode()?
57            | opts.get_creation_mode()?
58            | (opts.custom_flags as c_int & !libc::O_ACCMODE);
59        let fd = cvt_r(|| unsafe {
60            openat64(self.0.as_raw_fd(), path.as_ptr(), flags, opts.mode as c_int)
61        })?;
62        Ok(File(unsafe { FileDesc::from_raw_fd(fd) }))
63    }
64}
65
66impl fmt::Debug for Dir {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        let fd = self.0.as_raw_fd();
69        let mut b = debug_path_fd(fd, f, "Dir");
70        b.finish()
71    }
72}
73
74#[unstable(feature = "dirfd", issue = "120426")]
75impl AsRawFd for fs::Dir {
76    fn as_raw_fd(&self) -> RawFd {
77        self.as_inner().0.as_raw_fd()
78    }
79}
80
81#[unstable(feature = "dirfd", issue = "120426")]
82impl IntoRawFd for fs::Dir {
83    fn into_raw_fd(self) -> RawFd {
84        self.into_inner().0.into_raw_fd()
85    }
86}
87
88#[unstable(feature = "dirfd", issue = "120426")]
89impl FromRawFd for fs::Dir {
90    unsafe fn from_raw_fd(fd: RawFd) -> Self {
91        Self::from_inner(Dir(unsafe { FromRawFd::from_raw_fd(fd) }))
92    }
93}
94
95#[unstable(feature = "dirfd", issue = "120426")]
96impl AsFd for fs::Dir {
97    fn as_fd(&self) -> BorrowedFd<'_> {
98        self.as_inner().0.as_fd()
99    }
100}
101
102#[unstable(feature = "dirfd", issue = "120426")]
103impl From<fs::Dir> for OwnedFd {
104    fn from(value: fs::Dir) -> Self {
105        value.into_inner().0
106    }
107}
108
109#[unstable(feature = "dirfd", issue = "120426")]
110impl From<OwnedFd> for fs::Dir {
111    fn from(value: OwnedFd) -> Self {
112        Self::from_inner(Dir(value))
113    }
114}