Skip to main content

rustix/backend/libc/fs/
types.rs

1use crate::backend::c;
2#[cfg(not(target_os = "horizon"))]
3use crate::ffi;
4use bitflags::bitflags;
5
6#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
7bitflags! {
8    /// `*_OK` constants for use with [`accessat`].
9    ///
10    /// [`accessat`]: fn.accessat.html
11    #[repr(transparent)]
12    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
13    pub struct Access: ffi::c_int {
14        /// `R_OK`
15        const READ_OK = c::R_OK;
16
17        /// `W_OK`
18        const WRITE_OK = c::W_OK;
19
20        /// `X_OK`
21        const EXEC_OK = c::X_OK;
22
23        /// `F_OK`
24        const EXISTS = c::F_OK;
25
26        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
27        const _ = !0;
28    }
29}
30
31#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "redox")))]
32bitflags! {
33    /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at`
34    /// functions.
35    ///
36    /// [`openat`]: crate::fs::openat
37    /// [`statat`]: crate::fs::statat
38    #[repr(transparent)]
39    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
40    pub struct AtFlags: u32 {
41        /// `AT_SYMLINK_NOFOLLOW`
42        const SYMLINK_NOFOLLOW = bitcast!(c::AT_SYMLINK_NOFOLLOW);
43
44        /// `AT_EACCESS`
45        #[cfg(not(target_os = "android"))]
46        const EACCESS = bitcast!(c::AT_EACCESS);
47
48        /// `AT_REMOVEDIR`
49        const REMOVEDIR = bitcast!(c::AT_REMOVEDIR);
50
51        /// `AT_SYMLINK_FOLLOW`
52        const SYMLINK_FOLLOW = bitcast!(c::AT_SYMLINK_FOLLOW);
53
54        /// `AT_NO_AUTOMOUNT`
55        #[cfg(any(linux_like, target_os = "fuchsia"))]
56        const NO_AUTOMOUNT = bitcast!(c::AT_NO_AUTOMOUNT);
57
58        /// `AT_EMPTY_PATH`
59        #[cfg(any(
60            linux_kernel,
61            target_os = "freebsd",
62            target_os = "fuchsia",
63        ))]
64        const EMPTY_PATH = bitcast!(c::AT_EMPTY_PATH);
65
66        /// `AT_RESOLVE_BENEATH`
67        #[cfg(target_os = "freebsd")]
68        const RESOLVE_BENEATH = bitcast!(c::AT_RESOLVE_BENEATH);
69
70        /// `AT_STATX_SYNC_AS_STAT`
71        #[cfg(all(target_os = "linux", target_env = "gnu"))]
72        const STATX_SYNC_AS_STAT = bitcast!(c::AT_STATX_SYNC_AS_STAT);
73
74        /// `AT_STATX_FORCE_SYNC`
75        #[cfg(all(target_os = "linux", target_env = "gnu"))]
76        const STATX_FORCE_SYNC = bitcast!(c::AT_STATX_FORCE_SYNC);
77
78        /// `AT_STATX_DONT_SYNC`
79        #[cfg(all(target_os = "linux", target_env = "gnu"))]
80        const STATX_DONT_SYNC = bitcast!(c::AT_STATX_DONT_SYNC);
81
82        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
83        const _ = !0;
84    }
85}
86
87#[cfg(target_os = "horizon")]
88bitflags! {
89    /// `AT_*` constants for use with [`openat`], [`statat`], and other `*at`
90    /// functions.
91    ///
92    /// [`openat`]: crate::fs::openat
93    /// [`statat`]: crate::fs::statat
94    #[repr(transparent)]
95    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
96    pub struct AtFlags: u32 {
97        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
98        const _ = !0;
99    }
100}
101
102#[cfg(not(target_os = "horizon"))]
103bitflags! {
104    /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`].
105    ///
106    /// [`openat`]: crate::fs::openat
107    /// [`chmodat`]: crate::fs::chmodat
108    /// [`fchmod`]: crate::fs::fchmod
109    #[repr(transparent)]
110    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
111    pub struct Mode: RawMode {
112        /// `S_IRWXU`
113        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
114        const RWXU = c::S_IRWXU as RawMode;
115
116        /// `S_IRUSR`
117        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
118        const RUSR = c::S_IRUSR as RawMode;
119
120        /// `S_IWUSR`
121        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
122        const WUSR = c::S_IWUSR as RawMode;
123
124        /// `S_IXUSR`
125        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
126        const XUSR = c::S_IXUSR as RawMode;
127
128        /// `S_IRWXG`
129        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
130        const RWXG = c::S_IRWXG as RawMode;
131
132        /// `S_IRGRP`
133        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
134        const RGRP = c::S_IRGRP as RawMode;
135
136        /// `S_IWGRP`
137        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
138        const WGRP = c::S_IWGRP as RawMode;
139
140        /// `S_IXGRP`
141        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
142        const XGRP = c::S_IXGRP as RawMode;
143
144        /// `S_IRWXO`
145        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
146        const RWXO = c::S_IRWXO as RawMode;
147
148        /// `S_IROTH`
149        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
150        const ROTH = c::S_IROTH as RawMode;
151
152        /// `S_IWOTH`
153        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
154        const WOTH = c::S_IWOTH as RawMode;
155
156        /// `S_IXOTH`
157        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
158        const XOTH = c::S_IXOTH as RawMode;
159
160        /// `S_ISUID`
161        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
162        const SUID = c::S_ISUID as RawMode;
163
164        /// `S_ISGID`
165        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
166        const SGID = c::S_ISGID as RawMode;
167
168        /// `S_ISVTX`
169        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
170        const SVTX = c::S_ISVTX as RawMode;
171
172        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
173        const _ = !0;
174    }
175}
176
177#[cfg(target_os = "horizon")]
178bitflags! {
179    /// `S_I*` constants for use with [`openat`], [`chmodat`], and [`fchmod`].
180    ///
181    /// [`openat`]: crate::fs::openat
182    /// [`chmodat`]: crate::fs::chmodat
183    /// [`fchmod`]: crate::fs::fchmod
184    #[repr(transparent)]
185    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
186    pub struct Mode: RawMode {
187        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
188        const _ = !0;
189    }
190}
191
192#[cfg(not(target_os = "espidf"))]
193impl Mode {
194    /// Construct a `Mode` from the mode bits of the `st_mode` field of a
195    /// `Mode`.
196    #[inline]
197    pub const fn from_raw_mode(st_mode: RawMode) -> Self {
198        Self::from_bits_truncate(st_mode & !c::S_IFMT as RawMode)
199    }
200
201    /// Construct an `st_mode` value from a `Mode`.
202    #[inline]
203    pub const fn as_raw_mode(self) -> RawMode {
204        self.bits()
205    }
206}
207
208#[cfg(not(target_os = "espidf"))]
209impl From<RawMode> for Mode {
210    /// Support conversions from raw mode values to `Mode`.
211    ///
212    /// ```
213    /// use rustix::fs::{Mode, RawMode};
214    /// assert_eq!(Mode::from(0o700), Mode::RWXU);
215    /// ```
216    #[inline]
217    fn from(st_mode: RawMode) -> Self {
218        Self::from_raw_mode(st_mode)
219    }
220}
221
222#[cfg(not(target_os = "espidf"))]
223impl From<Mode> for RawMode {
224    /// Support conversions from `Mode` to raw mode values.
225    ///
226    /// ```
227    /// use rustix::fs::{Mode, RawMode};
228    /// assert_eq!(RawMode::from(Mode::RWXU), 0o700);
229    /// ```
230    #[inline]
231    fn from(mode: Mode) -> Self {
232        mode.as_raw_mode()
233    }
234}
235
236bitflags! {
237    /// `O_*` constants for use with [`openat`].
238    ///
239    /// [`openat`]: crate::fs::openat
240    #[repr(transparent)]
241    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
242    pub struct OFlags: u32 {
243        /// `O_ACCMODE`
244        const ACCMODE = bitcast!(c::O_ACCMODE);
245
246        /// Similar to `ACCMODE`, but just includes the read/write flags, and
247        /// no other flags.
248        ///
249        /// On some platforms, `PATH` may be included in `ACCMODE`, when
250        /// sometimes we really just want the read/write bits. Caution is
251        /// indicated, as the presence of `PATH` may mean that the read/write
252        /// bits don't have their usual meaning.
253        const RWMODE = bitcast!(c::O_RDONLY | c::O_WRONLY | c::O_RDWR);
254
255        /// `O_APPEND`
256        const APPEND = bitcast!(c::O_APPEND);
257
258        /// `O_CREAT`
259        #[doc(alias = "CREAT")]
260        const CREATE = bitcast!(c::O_CREAT);
261
262        /// `O_DIRECTORY`
263        #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
264        const DIRECTORY = bitcast!(c::O_DIRECTORY);
265
266        /// `O_DSYNC`
267        #[cfg(not(any(target_os = "dragonfly", target_os = "espidf", target_os = "horizon", target_os = "l4re", target_os = "redox", target_os = "vita")))]
268        const DSYNC = bitcast!(c::O_DSYNC);
269
270        /// `O_EXCL`
271        const EXCL = bitcast!(c::O_EXCL);
272
273        /// `O_FSYNC`
274        #[cfg(any(
275            bsd,
276            all(target_os = "linux", not(target_env = "musl")),
277        ))]
278        const FSYNC = bitcast!(c::O_FSYNC);
279
280        /// `O_NOFOLLOW`
281        #[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
282        const NOFOLLOW = bitcast!(c::O_NOFOLLOW);
283
284        /// `O_NONBLOCK`
285        const NONBLOCK = bitcast!(c::O_NONBLOCK);
286
287        /// `O_RDONLY`
288        const RDONLY = bitcast!(c::O_RDONLY);
289
290        /// `O_WRONLY`
291        const WRONLY = bitcast!(c::O_WRONLY);
292
293        /// `O_RDWR`
294        ///
295        /// This is not equal to `RDONLY | WRONLY`. It's a distinct flag.
296        const RDWR = bitcast!(c::O_RDWR);
297
298        /// `O_NOCTTY`
299        #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "l4re", target_os = "redox", target_os = "vita")))]
300        const NOCTTY = bitcast!(c::O_NOCTTY);
301
302        /// `O_RSYNC`
303        #[cfg(any(
304            linux_kernel,
305            netbsdlike,
306            solarish,
307            target_os = "emscripten",
308            target_os = "wasi",
309        ))]
310        const RSYNC = bitcast!(c::O_RSYNC);
311
312        /// `O_SYNC`
313        #[cfg(not(any(target_os = "l4re", target_os = "redox")))]
314        const SYNC = bitcast!(c::O_SYNC);
315
316        /// `O_TRUNC`
317        const TRUNC = bitcast!(c::O_TRUNC);
318
319        /// `O_PATH`
320        #[cfg(any(
321            linux_kernel,
322            target_os = "emscripten",
323            target_os = "freebsd",
324            target_os = "fuchsia",
325            target_os = "redox",
326        ))]
327        const PATH = bitcast!(c::O_PATH);
328
329        /// `O_CLOEXEC`
330        const CLOEXEC = bitcast!(c::O_CLOEXEC);
331
332        /// `O_TMPFILE`
333        #[cfg(any(
334            linux_kernel,
335            target_os = "emscripten",
336            target_os = "fuchsia",
337        ))]
338        const TMPFILE = bitcast!(c::O_TMPFILE);
339
340        /// `O_NOATIME`
341        #[cfg(any(
342            linux_kernel,
343            target_os = "fuchsia",
344        ))]
345        const NOATIME = bitcast!(c::O_NOATIME);
346
347        /// `O_DIRECT`
348        #[cfg(any(
349            linux_kernel,
350            target_os = "emscripten",
351            target_os = "freebsd",
352            target_os = "fuchsia",
353            target_os = "netbsd",
354        ))]
355        const DIRECT = bitcast!(c::O_DIRECT);
356
357        /// `O_RESOLVE_BENEATH`
358        #[cfg(target_os = "freebsd")]
359        const RESOLVE_BENEATH = bitcast!(c::O_RESOLVE_BENEATH);
360
361        /// `O_EMPTY_PATH`
362        #[cfg(target_os = "freebsd")]
363        const EMPTY_PATH = bitcast!(c::O_EMPTY_PATH);
364
365        /// `O_SYMLINK`
366        #[cfg(any(apple, target_os = "redox"))]
367        const SYMLINK = bitcast!(c::O_SYMLINK);
368
369        /// `O_NOFOLLOW_ANY`
370        #[cfg(apple)]
371        const NOFOLLOW_ANY = bitcast!(c::O_NOFOLLOW_ANY);
372
373        /// `O_LARGEFILE`
374        ///
375        /// Rustix and/or libc will automatically set this flag when
376        /// appropriate in the [`rustix::fs::open`] family of functions, so
377        /// typical users do not need to care about it. It may be reported in
378        /// the return of `fcntl_getfl`, though.
379        #[cfg(any(linux_kernel, solarish))]
380        const LARGEFILE = bitcast!(c::O_LARGEFILE);
381
382        /// `O_ASYNC`, `FASYNC`
383        ///
384        /// This flag can't be used with the [`rustix::fs::open`] family of
385        /// functions, use [`rustix::fs::fcntl_setfl`] instead.
386        #[cfg(not(any(
387            target_os = "aix",
388            target_os = "cygwin",
389            target_os = "espidf",
390            target_os = "haiku",
391            target_os = "horizon",
392            target_os = "wasi",
393            target_os = "vita",
394            solarish
395        )))]
396        const ASYNC = bitcast!(c::O_ASYNC);
397
398        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
399        const _ = !0;
400    }
401}
402
403#[cfg(apple)]
404bitflags! {
405    /// `CLONE_*` constants for use with [`fclonefileat`].
406    ///
407    /// [`fclonefileat`]: crate::fs::fclonefileat
408    #[repr(transparent)]
409    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
410    pub struct CloneFlags: u32 {
411        /// `CLONE_NOFOLLOW`
412        const NOFOLLOW = 1;
413
414        /// `CLONE_NOOWNERCOPY`
415        const NOOWNERCOPY = 2;
416
417        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
418        const _ = !0;
419    }
420}
421
422#[cfg(apple)]
423mod copyfile {
424    pub(super) const ACL: u32 = 1 << 0;
425    pub(super) const STAT: u32 = 1 << 1;
426    pub(super) const XATTR: u32 = 1 << 2;
427    pub(super) const DATA: u32 = 1 << 3;
428    pub(super) const SECURITY: u32 = STAT | ACL;
429    pub(super) const METADATA: u32 = SECURITY | XATTR;
430    pub(super) const ALL: u32 = METADATA | DATA;
431}
432
433#[cfg(apple)]
434bitflags! {
435    /// `COPYFILE_*` constants for use with [`fcopyfile`].
436    ///
437    /// [`fcopyfile`]: crate::fs::fcopyfile
438    #[repr(transparent)]
439    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
440    pub struct CopyfileFlags: ffi::c_uint {
441        /// `COPYFILE_ACL`
442        const ACL = copyfile::ACL;
443
444        /// `COPYFILE_STAT`
445        const STAT = copyfile::STAT;
446
447        /// `COPYFILE_XATTR`
448        const XATTR = copyfile::XATTR;
449
450        /// `COPYFILE_DATA`
451        const DATA = copyfile::DATA;
452
453        /// `COPYFILE_SECURITY`
454        const SECURITY = copyfile::SECURITY;
455
456        /// `COPYFILE_METADATA`
457        const METADATA = copyfile::METADATA;
458
459        /// `COPYFILE_ALL`
460        const ALL = copyfile::ALL;
461
462        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
463        const _ = !0;
464    }
465}
466
467#[cfg(linux_kernel)]
468bitflags! {
469    /// `RESOLVE_*` constants for use with [`openat2`].
470    ///
471    /// [`openat2`]: crate::fs::openat2
472    #[repr(transparent)]
473    #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
474    pub struct ResolveFlags: u64 {
475        /// `RESOLVE_NO_XDEV`
476        const NO_XDEV = 0x01;
477
478        /// `RESOLVE_NO_MAGICLINKS`
479        const NO_MAGICLINKS = 0x02;
480
481        /// `RESOLVE_NO_SYMLINKS`
482        const NO_SYMLINKS = 0x04;
483
484        /// `RESOLVE_BENEATH`
485        const BENEATH = 0x08;
486
487        /// `RESOLVE_IN_ROOT`
488        const IN_ROOT = 0x10;
489
490        /// `RESOLVE_CACHED` (since Linux 5.12)
491        const CACHED = 0x20;
492
493        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
494        const _ = !0;
495    }
496}
497
498#[cfg(linux_kernel)]
499bitflags! {
500    /// `RENAME_*` constants for use with [`renameat_with`].
501    ///
502    /// [`renameat_with`]: crate::fs::renameat_with
503    #[repr(transparent)]
504    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
505    pub struct RenameFlags: ffi::c_uint {
506        /// `RENAME_EXCHANGE`
507        const EXCHANGE = bitcast!(c::RENAME_EXCHANGE);
508
509        /// `RENAME_NOREPLACE`
510        const NOREPLACE = bitcast!(c::RENAME_NOREPLACE);
511
512        /// `RENAME_WHITEOUT`
513        const WHITEOUT = bitcast!(c::RENAME_WHITEOUT);
514
515        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
516        const _ = !0;
517    }
518}
519
520#[cfg(target_os = "redox")]
521bitflags! {
522    /// `RENAME_*` constants for use with [`renameat_with`].
523    ///
524    /// [`renameat_with`]: crate::fs::renameat_with
525    #[repr(transparent)]
526    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
527    pub struct RenameFlags: ffi::c_uint {
528        /// `RENAME_NOREPLACE`
529        const NOREPLACE = bitcast!(c::RENAME_NOREPLACE);
530
531        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
532        const _ = !0;
533    }
534}
535
536#[cfg(apple)]
537bitflags! {
538    /// `RENAME_*` constants for use with [`renameat_with`].
539    ///
540    /// [`renameat_with`]: crate::fs::renameat_with
541    #[repr(transparent)]
542    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
543    pub struct RenameFlags: ffi::c_uint {
544        /// `RENAME_SWAP`
545        const EXCHANGE = bitcast!(c::RENAME_SWAP);
546
547        /// `RENAME_EXCL`
548        const NOREPLACE = bitcast!(c::RENAME_EXCL);
549
550        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
551        const _ = !0;
552    }
553}
554
555/// `S_IF*` constants for use with [`mknodat`] and [`Stat`]'s `st_mode` field.
556///
557/// [`mknodat`]: crate::fs::mknodat
558/// [`Stat`]: crate::fs::Stat
559#[derive(Clone, Copy, Debug, PartialEq, Eq)]
560pub enum FileType {
561    /// `S_IFREG`
562    RegularFile = c::S_IFREG as isize,
563
564    /// `S_IFDIR`
565    Directory = c::S_IFDIR as isize,
566
567    /// `S_IFLNK`
568    Symlink = c::S_IFLNK as isize,
569
570    /// `S_IFIFO`
571    #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`.
572    #[doc(alias = "IFO")]
573    Fifo = c::S_IFIFO as isize,
574
575    /// `S_IFSOCK`
576    #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`.
577    Socket = c::S_IFSOCK as isize,
578
579    /// `S_IFCHR`
580    CharacterDevice = c::S_IFCHR as isize,
581
582    /// `S_IFBLK`
583    BlockDevice = c::S_IFBLK as isize,
584
585    /// An unknown filesystem object.
586    Unknown,
587}
588
589impl FileType {
590    /// Construct a `FileType` from the `S_IFMT` bits of the `st_mode` field of
591    /// a `Stat`.
592    #[inline]
593    pub const fn from_raw_mode(st_mode: RawMode) -> Self {
594        match (st_mode as c::mode_t) & c::S_IFMT {
595            c::S_IFREG => Self::RegularFile,
596            c::S_IFDIR => Self::Directory,
597            c::S_IFLNK => Self::Symlink,
598            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`.
599            c::S_IFIFO => Self::Fifo,
600            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`.
601            c::S_IFSOCK => Self::Socket,
602            c::S_IFCHR => Self::CharacterDevice,
603            c::S_IFBLK => Self::BlockDevice,
604            _ => Self::Unknown,
605        }
606    }
607
608    /// Construct an `st_mode` value from a `FileType`.
609    #[inline]
610    pub const fn as_raw_mode(self) -> RawMode {
611        match self {
612            Self::RegularFile => c::S_IFREG as RawMode,
613            Self::Directory => c::S_IFDIR as RawMode,
614            Self::Symlink => c::S_IFLNK as RawMode,
615            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFIFO`.
616            Self::Fifo => c::S_IFIFO as RawMode,
617            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `S_IFSOCK`.
618            Self::Socket => c::S_IFSOCK as RawMode,
619            Self::CharacterDevice => c::S_IFCHR as RawMode,
620            Self::BlockDevice => c::S_IFBLK as RawMode,
621            Self::Unknown => c::S_IFMT as RawMode,
622        }
623    }
624
625    /// Construct a `FileType` from the `d_type` field of a `c::dirent`.
626    #[cfg(not(any(
627        solarish,
628        target_os = "aix",
629        target_os = "espidf",
630        target_os = "haiku",
631        target_os = "horizon",
632        target_os = "nto",
633        target_os = "redox",
634        target_os = "vita"
635    )))]
636    #[inline]
637    pub(crate) const fn from_dirent_d_type(d_type: u8) -> Self {
638        match d_type {
639            c::DT_REG => Self::RegularFile,
640            c::DT_DIR => Self::Directory,
641            c::DT_LNK => Self::Symlink,
642            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `DT_SOCK`.
643            c::DT_SOCK => Self::Socket,
644            #[cfg(not(target_os = "wasi"))] // TODO: Use WASI's `DT_FIFO`.
645            c::DT_FIFO => Self::Fifo,
646            c::DT_CHR => Self::CharacterDevice,
647            c::DT_BLK => Self::BlockDevice,
648            // c::DT_UNKNOWN |
649            _ => Self::Unknown,
650        }
651    }
652}
653
654/// `POSIX_FADV_*` constants for use with [`fadvise`].
655///
656/// [`fadvise`]: crate::fs::fadvise
657#[cfg(not(any(
658    apple,
659    netbsdlike,
660    target_os = "dragonfly",
661    target_os = "espidf",
662    target_os = "horizon",
663    target_os = "haiku",
664    target_os = "redox",
665    target_os = "solaris",
666    target_os = "vita",
667)))]
668#[derive(Debug, Copy, Clone, Eq, PartialEq)]
669#[repr(u32)]
670pub enum Advice {
671    /// `POSIX_FADV_NORMAL`
672    Normal = c::POSIX_FADV_NORMAL as c::c_uint,
673
674    /// `POSIX_FADV_SEQUENTIAL`
675    Sequential = c::POSIX_FADV_SEQUENTIAL as c::c_uint,
676
677    /// `POSIX_FADV_RANDOM`
678    Random = c::POSIX_FADV_RANDOM as c::c_uint,
679
680    /// `POSIX_FADV_NOREUSE`
681    NoReuse = c::POSIX_FADV_NOREUSE as c::c_uint,
682
683    /// `POSIX_FADV_WILLNEED`
684    WillNeed = c::POSIX_FADV_WILLNEED as c::c_uint,
685
686    /// `POSIX_FADV_DONTNEED`
687    DontNeed = c::POSIX_FADV_DONTNEED as c::c_uint,
688}
689
690#[cfg(any(linux_kernel, target_os = "freebsd"))]
691bitflags! {
692    /// `MFD_*` constants for use with [`memfd_create`].
693    ///
694    /// [`memfd_create`]: crate::fs::memfd_create
695    #[repr(transparent)]
696    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
697    pub struct MemfdFlags: ffi::c_uint {
698        /// `MFD_CLOEXEC`
699        const CLOEXEC = c::MFD_CLOEXEC;
700
701        /// `MFD_ALLOW_SEALING`
702        const ALLOW_SEALING = c::MFD_ALLOW_SEALING;
703
704        /// `MFD_HUGETLB` (since Linux 4.14)
705        const HUGETLB = c::MFD_HUGETLB;
706
707        /// `MFD_NOEXEC_SEAL` (since Linux 6.3)
708        #[cfg(linux_kernel)]
709        const NOEXEC_SEAL = c::MFD_NOEXEC_SEAL;
710        /// `MFD_EXEC` (since Linux 6.3)
711        #[cfg(linux_kernel)]
712        const EXEC = c::MFD_EXEC;
713
714        /// `MFD_HUGE_64KB`
715        const HUGE_64KB = c::MFD_HUGE_64KB;
716        /// `MFD_HUGE_512JB`
717        const HUGE_512KB = c::MFD_HUGE_512KB;
718        /// `MFD_HUGE_1MB`
719        const HUGE_1MB = c::MFD_HUGE_1MB;
720        /// `MFD_HUGE_2MB`
721        const HUGE_2MB = c::MFD_HUGE_2MB;
722        /// `MFD_HUGE_8MB`
723        const HUGE_8MB = c::MFD_HUGE_8MB;
724        /// `MFD_HUGE_16MB`
725        const HUGE_16MB = c::MFD_HUGE_16MB;
726        /// `MFD_HUGE_32MB`
727        const HUGE_32MB = c::MFD_HUGE_32MB;
728        /// `MFD_HUGE_256MB`
729        const HUGE_256MB = c::MFD_HUGE_256MB;
730        /// `MFD_HUGE_512MB`
731        const HUGE_512MB = c::MFD_HUGE_512MB;
732        /// `MFD_HUGE_1GB`
733        const HUGE_1GB = c::MFD_HUGE_1GB;
734        /// `MFD_HUGE_2GB`
735        const HUGE_2GB = c::MFD_HUGE_2GB;
736        /// `MFD_HUGE_16GB`
737        const HUGE_16GB = c::MFD_HUGE_16GB;
738
739        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
740        const _ = !0;
741    }
742}
743
744#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
745bitflags! {
746    /// `F_SEAL_*` constants for use with [`fcntl_add_seals`] and
747    /// [`fcntl_get_seals`].
748    ///
749    /// [`fcntl_add_seals`]: crate::fs::fcntl_add_seals
750    /// [`fcntl_get_seals`]: crate::fs::fcntl_get_seals
751    #[repr(transparent)]
752    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
753    pub struct SealFlags: u32 {
754        /// `F_SEAL_SEAL`
755        const SEAL = bitcast!(c::F_SEAL_SEAL);
756        /// `F_SEAL_SHRINK`
757        const SHRINK = bitcast!(c::F_SEAL_SHRINK);
758        /// `F_SEAL_GROW`
759        const GROW = bitcast!(c::F_SEAL_GROW);
760        /// `F_SEAL_WRITE`
761        const WRITE = bitcast!(c::F_SEAL_WRITE);
762        /// `F_SEAL_FUTURE_WRITE` (since Linux 5.1)
763        #[cfg(linux_kernel)]
764        const FUTURE_WRITE = bitcast!(c::F_SEAL_FUTURE_WRITE);
765        /// `F_SEAL_EXEC` (since Linux 6.3)
766        #[cfg(linux_kernel)]
767        const EXEC = bitcast!(c::F_SEAL_EXEC);
768
769        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
770        const _ = !0;
771    }
772}
773
774#[cfg(not(any(
775    netbsdlike,
776    target_os = "espidf",
777    target_os = "horizon",
778    target_os = "nto",
779    target_os = "redox",
780    target_os = "vita"
781)))]
782bitflags! {
783    /// `FALLOC_FL_*` constants for use with [`fallocate`].
784    ///
785    /// [`fallocate`]: crate::fs::fallocate
786    #[repr(transparent)]
787    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
788    pub struct FallocateFlags: u32 {
789        /// `FALLOC_FL_KEEP_SIZE`
790        #[cfg(not(any(
791            bsd,
792            solarish,
793            target_os = "aix",
794            target_os = "haiku",
795            target_os = "hurd",
796            target_os = "wasi",
797        )))]
798        const KEEP_SIZE = bitcast!(c::FALLOC_FL_KEEP_SIZE);
799        /// `FALLOC_FL_PUNCH_HOLE`
800        #[cfg(not(any(
801            bsd,
802            solarish,
803            target_os = "aix",
804            target_os = "haiku",
805            target_os = "hurd",
806            target_os = "wasi",
807        )))]
808        const PUNCH_HOLE = bitcast!(c::FALLOC_FL_PUNCH_HOLE);
809        /// `FALLOC_FL_NO_HIDE_STALE`
810        #[cfg(not(any(
811            bsd,
812            solarish,
813            target_os = "aix",
814            target_os = "cygwin",
815            target_os = "emscripten",
816            target_os = "fuchsia",
817            target_os = "haiku",
818            target_os = "hurd",
819            target_os = "l4re",
820            target_os = "linux",
821            target_os = "wasi",
822        )))]
823        const NO_HIDE_STALE = bitcast!(c::FALLOC_FL_NO_HIDE_STALE);
824        /// `FALLOC_FL_COLLAPSE_RANGE`
825        #[cfg(not(any(
826            bsd,
827            solarish,
828            target_os = "aix",
829            target_os = "haiku",
830            target_os = "hurd",
831            target_os = "emscripten",
832            target_os = "wasi",
833        )))]
834        const COLLAPSE_RANGE = bitcast!(c::FALLOC_FL_COLLAPSE_RANGE);
835        /// `FALLOC_FL_ZERO_RANGE`
836        #[cfg(not(any(
837            bsd,
838            solarish,
839            target_os = "aix",
840            target_os = "haiku",
841            target_os = "hurd",
842            target_os = "emscripten",
843            target_os = "wasi",
844        )))]
845        const ZERO_RANGE = bitcast!(c::FALLOC_FL_ZERO_RANGE);
846        /// `FALLOC_FL_INSERT_RANGE`
847        #[cfg(not(any(
848            bsd,
849            solarish,
850            target_os = "aix",
851            target_os = "haiku",
852            target_os = "hurd",
853            target_os = "emscripten",
854            target_os = "wasi",
855        )))]
856        const INSERT_RANGE = bitcast!(c::FALLOC_FL_INSERT_RANGE);
857        /// `FALLOC_FL_UNSHARE_RANGE`
858        #[cfg(not(any(
859            bsd,
860            solarish,
861            target_os = "aix",
862            target_os = "haiku",
863            target_os = "hurd",
864            target_os = "emscripten",
865            target_os = "wasi",
866        )))]
867        const UNSHARE_RANGE = bitcast!(c::FALLOC_FL_UNSHARE_RANGE);
868
869        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
870        const _ = !0;
871    }
872}
873
874#[cfg(not(target_os = "wasi"))]
875bitflags! {
876    /// `ST_*` constants for use with [`StatVfs`].
877    #[repr(transparent)]
878    #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
879    pub struct StatVfsMountFlags: u64 {
880        /// `ST_MANDLOCK`
881        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
882        const MANDLOCK = c::ST_MANDLOCK as u64;
883
884        /// `ST_NOATIME`
885        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
886        const NOATIME = c::ST_NOATIME as u64;
887
888        /// `ST_NODEV`
889        #[cfg(any(
890            linux_kernel,
891            target_os = "aix",
892            target_os = "emscripten",
893            target_os = "fuchsia"
894        ))]
895        const NODEV = c::ST_NODEV as u64;
896
897        /// `ST_NODIRATIME`
898        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
899        const NODIRATIME = c::ST_NODIRATIME as u64;
900
901        /// `ST_NOEXEC`
902        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
903        const NOEXEC = c::ST_NOEXEC as u64;
904
905        /// `ST_NOSUID`
906        #[cfg(not(any(target_os = "espidf", target_os = "haiku", target_os = "horizon", target_os = "redox", target_os = "vita")))]
907        const NOSUID = c::ST_NOSUID as u64;
908
909        /// `ST_RDONLY`
910        #[cfg(not(any(target_os = "espidf", target_os = "haiku", target_os = "horizon", target_os = "redox", target_os = "vita")))]
911        const RDONLY = c::ST_RDONLY as u64;
912
913        /// `ST_RELATIME`
914        #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))]
915        const RELATIME = c::ST_RELATIME as u64;
916
917        /// `ST_SYNCHRONOUS`
918        #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "fuchsia"))]
919        const SYNCHRONOUS = c::ST_SYNCHRONOUS as u64;
920
921        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
922        const _ = !0;
923    }
924}
925
926/// `LOCK_*` constants for use with [`flock`] and [`fcntl_lock`].
927///
928/// [`flock`]: crate::fs::flock
929/// [`fcntl_lock`]: crate::fs::fcntl_lock
930// Solaris doesn't support `flock` and doesn't define `LOCK_SH` etc., but we
931// reuse this `FlockOperation` enum for `fcntl_lock`, so on Solaris we use
932// our own made-up integer values.
933#[cfg(not(any(
934    target_os = "espidf",
935    target_os = "horizon",
936    target_os = "vita",
937    target_os = "wasi"
938)))]
939#[derive(Clone, Copy, Debug, PartialEq, Eq)]
940#[repr(u32)]
941pub enum FlockOperation {
942    /// `LOCK_SH`
943    #[cfg(not(target_os = "solaris"))]
944    LockShared = bitcast!(c::LOCK_SH),
945    /// `LOCK_SH`
946    #[cfg(target_os = "solaris")]
947    LockShared = bitcast!(1),
948    /// `LOCK_EX`
949    #[cfg(not(target_os = "solaris"))]
950    LockExclusive = bitcast!(c::LOCK_EX),
951    /// `LOCK_EX`
952    #[cfg(target_os = "solaris")]
953    LockExclusive = bitcast!(2),
954    /// `LOCK_UN`
955    #[cfg(not(target_os = "solaris"))]
956    Unlock = bitcast!(c::LOCK_UN),
957    /// `LOCK_UN`
958    #[cfg(target_os = "solaris")]
959    Unlock = bitcast!(8),
960    /// `LOCK_SH | LOCK_NB`
961    #[cfg(not(target_os = "solaris"))]
962    NonBlockingLockShared = bitcast!(c::LOCK_SH | c::LOCK_NB),
963    /// `LOCK_SH | LOCK_NB`
964    #[cfg(target_os = "solaris")]
965    NonBlockingLockShared = bitcast!(1 | 4),
966    /// `LOCK_EX | LOCK_NB`
967    #[cfg(not(target_os = "solaris"))]
968    NonBlockingLockExclusive = bitcast!(c::LOCK_EX | c::LOCK_NB),
969    /// `LOCK_EX | LOCK_NB`
970    #[cfg(target_os = "solaris")]
971    NonBlockingLockExclusive = bitcast!(2 | 4),
972    /// `LOCK_UN | LOCK_NB`
973    #[cfg(not(target_os = "solaris"))]
974    NonBlockingUnlock = bitcast!(c::LOCK_UN | c::LOCK_NB),
975    /// `LOCK_UN | LOCK_NB`
976    #[cfg(target_os = "solaris")]
977    NonBlockingUnlock = bitcast!(8 | 4),
978}
979
980/// `struct stat` for use with [`statat`] and [`fstat`].
981///
982/// [`statat`]: crate::fs::statat
983/// [`fstat`]: crate::fs::fstat
984#[cfg(not(any(linux_like, target_os = "hurd", target_os = "netbsd")))]
985pub type Stat = c::stat;
986
987/// `struct stat` for use with [`statat`] and [`fstat`].
988///
989/// [`statat`]: crate::fs::statat
990/// [`fstat`]: crate::fs::fstat
991#[cfg(any(
992    all(linux_kernel, target_pointer_width = "64"),
993    target_os = "hurd",
994    target_os = "emscripten",
995    target_os = "l4re",
996))]
997pub type Stat = c::stat64;
998
999/// `struct stat` for use with [`statat`] and [`fstat`].
1000///
1001/// [`statat`]: crate::fs::statat
1002/// [`fstat`]: crate::fs::fstat
1003// On 32-bit, Linux's `struct stat64` has a 32-bit `st_mtime` and friends, so
1004// we use our own struct, populated from `statx` where possible, to avoid the
1005// y2038 bug.
1006#[cfg(all(linux_kernel, target_pointer_width = "32"))]
1007#[derive(Debug, Copy, Clone)]
1008#[allow(missing_docs)]
1009pub struct Stat {
1010    pub st_dev: u64,
1011    pub st_mode: u32,
1012    pub st_nlink: u64,
1013    pub st_uid: u32,
1014    pub st_gid: u32,
1015    pub st_rdev: u64,
1016    pub st_size: i64,
1017    pub st_blksize: u32,
1018    pub st_blocks: u64,
1019    pub st_atime: i64,
1020    pub st_atime_nsec: u32,
1021    pub st_mtime: i64,
1022    pub st_mtime_nsec: u32,
1023    pub st_ctime: i64,
1024    pub st_ctime_nsec: u32,
1025    pub st_ino: u64,
1026}
1027
1028/// `struct stat` for use with [`statat`] and [`fstat`].
1029///
1030/// [`statat`]: crate::fs::statat
1031/// [`fstat`]: crate::fs::fstat
1032// NetBSD's `st_mtime_nsec` is named `st_mtimensec` so we declare our own
1033// `Stat` so that we can be consistent with other platforms.
1034#[cfg(target_os = "netbsd")]
1035#[derive(Debug, Copy, Clone)]
1036#[allow(missing_docs)]
1037#[repr(C)]
1038pub struct Stat {
1039    pub st_dev: c::dev_t,
1040    pub st_mode: c::mode_t,
1041    pub st_ino: c::ino_t,
1042    pub st_nlink: c::nlink_t,
1043    pub st_uid: c::uid_t,
1044    pub st_gid: c::gid_t,
1045    pub st_rdev: c::dev_t,
1046    pub st_atime: c::time_t,
1047    pub st_atime_nsec: c::c_long,
1048    pub st_mtime: c::time_t,
1049    pub st_mtime_nsec: c::c_long,
1050    pub st_ctime: c::time_t,
1051    pub st_ctime_nsec: c::c_long,
1052    pub st_birthtime: c::time_t,
1053    pub st_birthtime_nsec: c::c_long,
1054    pub st_size: c::off_t,
1055    pub st_blocks: c::blkcnt_t,
1056    pub st_blksize: c::blksize_t,
1057    pub st_flags: u32,
1058    pub st_gen: u32,
1059    pub st_spare: [u32; 2],
1060}
1061
1062/// `struct statfs` for use with [`statfs`] and [`fstatfs`].
1063///
1064/// [`statfs`]: crate::fs::statfs
1065/// [`fstatfs`]: crate::fs::fstatfs
1066#[cfg(not(any(
1067    linux_like,
1068    solarish,
1069    target_os = "espidf",
1070    target_os = "haiku",
1071    target_os = "horizon",
1072    target_os = "netbsd",
1073    target_os = "nto",
1074    target_os = "redox",
1075    target_os = "vita",
1076    target_os = "wasi",
1077)))]
1078#[allow(clippy::module_name_repetitions)]
1079pub type StatFs = c::statfs;
1080
1081/// `struct statfs` for use with [`statfs`] and [`fstatfs`].
1082///
1083/// [`statfs`]: crate::fs::statfs
1084/// [`fstatfs`]: crate::fs::fstatfs
1085#[cfg(linux_like)]
1086pub type StatFs = c::statfs64;
1087
1088/// `fsid_t` for use with [`StatFs`].
1089#[cfg(not(any(
1090    solarish,
1091    target_os = "cygwin",
1092    target_os = "espidf",
1093    target_os = "haiku",
1094    target_os = "horizon",
1095    target_os = "nto",
1096    target_os = "redox",
1097    target_os = "vita",
1098    target_os = "wasi",
1099)))]
1100pub type Fsid = c::fsid_t;
1101
1102/// `struct statvfs` for use with [`statvfs`] and [`fstatvfs`].
1103///
1104/// [`statvfs`]: crate::fs::statvfs
1105/// [`fstatvfs`]: crate::fs::fstatvfs
1106#[cfg(not(target_os = "wasi"))]
1107#[allow(missing_docs)]
1108pub struct StatVfs {
1109    pub f_bsize: u64,
1110    pub f_frsize: u64,
1111    pub f_blocks: u64,
1112    pub f_bfree: u64,
1113    pub f_bavail: u64,
1114    pub f_files: u64,
1115    pub f_ffree: u64,
1116    pub f_favail: u64,
1117    pub f_fsid: u64,
1118    pub f_flag: StatVfsMountFlags,
1119    pub f_namemax: u64,
1120}
1121
1122/// `mode_t`
1123#[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
1124pub type RawMode = c::mode_t;
1125
1126/// `mode_t`
1127#[cfg(all(target_os = "android", target_pointer_width = "32"))]
1128pub type RawMode = ffi::c_uint;
1129
1130/// `dev_t`
1131#[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
1132pub type Dev = c::dev_t;
1133
1134/// `dev_t`
1135#[cfg(all(target_os = "android", target_pointer_width = "32"))]
1136pub type Dev = ffi::c_ulonglong;
1137
1138/// `__fsword_t`
1139#[cfg(all(
1140    target_os = "linux",
1141    not(target_env = "musl"),
1142    not(target_arch = "s390x"),
1143))]
1144pub type FsWord = c::__fsword_t;
1145
1146/// `__fsword_t`
1147#[cfg(all(
1148    any(target_os = "android", all(target_os = "linux", target_env = "musl")),
1149    target_pointer_width = "32",
1150))]
1151pub type FsWord = u32;
1152
1153/// `__fsword_t`
1154#[cfg(all(
1155    any(target_os = "android", all(target_os = "linux", target_env = "musl")),
1156    not(target_arch = "s390x"),
1157    target_pointer_width = "64",
1158))]
1159pub type FsWord = u64;
1160
1161/// `__fsword_t`
1162// s390x uses `u32` for `statfs` entries on glibc, even though `__fsword_t` is
1163// `u64`.
1164#[cfg(all(target_os = "linux", target_arch = "s390x", target_env = "gnu"))]
1165pub type FsWord = u32;
1166
1167/// `__fsword_t`
1168// s390x uses `u64` for `statfs` entries on musl.
1169#[cfg(all(target_os = "linux", target_arch = "s390x", target_env = "musl"))]
1170pub type FsWord = u64;
1171
1172/// `copyfile_state_t`—State for use with [`fcopyfile`].
1173///
1174/// [`fcopyfile`]: crate::fs::fcopyfile
1175#[cfg(apple)]
1176#[allow(non_camel_case_types)]
1177#[repr(transparent)]
1178#[derive(Copy, Clone)]
1179pub struct copyfile_state_t(pub(crate) *mut c::c_void);