rustix/backend/libc/fs/
types.rs

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