Coverage Report

Created: 2025-09-04 06:37

/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.27.1/src/sys/stat.rs
Line
Count
Source (jump to first uncovered line)
1
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
2
pub use libc::c_uint;
3
#[cfg(any(
4
    target_os = "netbsd",
5
    target_os = "freebsd",
6
    target_os = "dragonfly"
7
))]
8
pub use libc::c_ulong;
9
pub use libc::stat as FileStat;
10
pub use libc::{dev_t, mode_t};
11
12
#[cfg(not(target_os = "redox"))]
13
use crate::fcntl::{at_rawfd, AtFlags};
14
use crate::sys::time::{TimeSpec, TimeVal};
15
use crate::{errno::Errno, NixPath, Result};
16
use std::mem;
17
use std::os::unix::io::RawFd;
18
19
libc_bitflags!(
20
    /// "File type" flags for `mknod` and related functions.
21
    pub struct SFlag: mode_t {
22
        S_IFIFO;
23
        S_IFCHR;
24
        S_IFDIR;
25
        S_IFBLK;
26
        S_IFREG;
27
        S_IFLNK;
28
        S_IFSOCK;
29
        S_IFMT;
30
    }
31
);
32
33
libc_bitflags! {
34
    /// "File mode / permissions" flags.
35
    pub struct Mode: mode_t {
36
        /// Read, write and execute for owner.
37
        S_IRWXU;
38
        /// Read for owner.
39
        S_IRUSR;
40
        /// Write for owner.
41
        S_IWUSR;
42
        /// Execute for owner.
43
        S_IXUSR;
44
        /// Read write and execute for group.
45
        S_IRWXG;
46
        /// Read fr group.
47
        S_IRGRP;
48
        /// Write for group.
49
        S_IWGRP;
50
        /// Execute for group.
51
        S_IXGRP;
52
        /// Read, write and execute for other.
53
        S_IRWXO;
54
        /// Read for other.
55
        S_IROTH;
56
        /// Write for other.
57
        S_IWOTH;
58
        /// Execute for other.
59
        S_IXOTH;
60
        /// Set user id on execution.
61
        S_ISUID as mode_t;
62
        /// Set group id on execution.
63
        S_ISGID as mode_t;
64
        S_ISVTX as mode_t;
65
    }
66
}
67
68
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
69
pub type type_of_file_flag = c_uint;
70
#[cfg(any(
71
    target_os = "netbsd",
72
    target_os = "freebsd",
73
    target_os = "dragonfly"
74
))]
75
pub type type_of_file_flag = c_ulong;
76
77
#[cfg(any(
78
    target_os = "openbsd",
79
    target_os = "netbsd",
80
    target_os = "freebsd",
81
    target_os = "dragonfly",
82
    target_os = "macos",
83
    target_os = "ios"
84
))]
85
libc_bitflags! {
86
    /// File flags.
87
    #[cfg_attr(docsrs, doc(cfg(all())))]
88
    pub struct FileFlag: type_of_file_flag {
89
        /// The file may only be appended to.
90
        SF_APPEND;
91
        /// The file has been archived.
92
        SF_ARCHIVED;
93
        #[cfg(any(target_os = "dragonfly"))]
94
        SF_CACHE;
95
        /// The file may not be changed.
96
        SF_IMMUTABLE;
97
        /// Indicates a WAPBL journal file.
98
        #[cfg(any(target_os = "netbsd"))]
99
        SF_LOG;
100
        /// Do not retain history for file
101
        #[cfg(any(target_os = "dragonfly"))]
102
        SF_NOHISTORY;
103
        /// The file may not be renamed or deleted.
104
        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
105
        SF_NOUNLINK;
106
        /// Mask of superuser changeable flags
107
        SF_SETTABLE;
108
        /// Snapshot is invalid.
109
        #[cfg(any(target_os = "netbsd"))]
110
        SF_SNAPINVAL;
111
        /// The file is a snapshot file.
112
        #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
113
        SF_SNAPSHOT;
114
        #[cfg(any(target_os = "dragonfly"))]
115
        SF_XLINK;
116
        /// The file may only be appended to.
117
        UF_APPEND;
118
        /// The file needs to be archived.
119
        #[cfg(any(target_os = "freebsd"))]
120
        UF_ARCHIVE;
121
        #[cfg(any(target_os = "dragonfly"))]
122
        UF_CACHE;
123
        /// File is compressed at the file system level.
124
        #[cfg(any(target_os = "macos", target_os = "ios"))]
125
        UF_COMPRESSED;
126
        /// The file may be hidden from directory listings at the application's
127
        /// discretion.
128
        #[cfg(any(
129
            target_os = "freebsd",
130
            target_os = "macos",
131
            target_os = "ios",
132
        ))]
133
        UF_HIDDEN;
134
        /// The file may not be changed.
135
        UF_IMMUTABLE;
136
        /// Do not dump the file.
137
        UF_NODUMP;
138
        #[cfg(any(target_os = "dragonfly"))]
139
        UF_NOHISTORY;
140
        /// The file may not be renamed or deleted.
141
        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
142
        UF_NOUNLINK;
143
        /// The file is offline, or has the Windows and CIFS
144
        /// `FILE_ATTRIBUTE_OFFLINE` attribute.
145
        #[cfg(any(target_os = "freebsd"))]
146
        UF_OFFLINE;
147
        /// The directory is opaque when viewed through a union stack.
148
        UF_OPAQUE;
149
        /// The file is read only, and may not be written or appended.
150
        #[cfg(any(target_os = "freebsd"))]
151
        UF_READONLY;
152
        /// The file contains a Windows reparse point.
153
        #[cfg(any(target_os = "freebsd"))]
154
        UF_REPARSE;
155
        /// Mask of owner changeable flags.
156
        UF_SETTABLE;
157
        /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute.
158
        #[cfg(any(target_os = "freebsd"))]
159
        UF_SPARSE;
160
        /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM`
161
        /// attribute.
162
        #[cfg(any(target_os = "freebsd"))]
163
        UF_SYSTEM;
164
        /// File renames and deletes are tracked.
165
        #[cfg(any(target_os = "macos", target_os = "ios"))]
166
        UF_TRACKED;
167
        #[cfg(any(target_os = "dragonfly"))]
168
        UF_XLINK;
169
    }
170
}
171
172
/// Create a special or ordinary file, by pathname.
173
0
pub fn mknod<P: ?Sized + NixPath>(
174
0
    path: &P,
175
0
    kind: SFlag,
176
0
    perm: Mode,
177
0
    dev: dev_t,
178
0
) -> Result<()> {
179
0
    let res = path.with_nix_path(|cstr| unsafe {
180
0
        libc::mknod(cstr.as_ptr(), kind.bits() | perm.bits() as mode_t, dev)
181
0
    })?;
182
183
0
    Errno::result(res).map(drop)
184
0
}
185
186
/// Create a special or ordinary file, relative to a given directory.
187
#[cfg(not(any(
188
    target_os = "ios",
189
    target_os = "macos",
190
    target_os = "redox",
191
    target_os = "haiku"
192
)))]
193
#[cfg_attr(docsrs, doc(cfg(all())))]
194
0
pub fn mknodat<P: ?Sized + NixPath>(
195
0
    dirfd: RawFd,
196
0
    path: &P,
197
0
    kind: SFlag,
198
0
    perm: Mode,
199
0
    dev: dev_t,
200
0
) -> Result<()> {
201
0
    let res = path.with_nix_path(|cstr| unsafe {
202
0
        libc::mknodat(
203
0
            dirfd,
204
0
            cstr.as_ptr(),
205
0
            kind.bits() | perm.bits() as mode_t,
206
0
            dev,
207
0
        )
208
0
    })?;
209
210
0
    Errno::result(res).map(drop)
211
0
}
212
213
#[cfg(target_os = "linux")]
214
#[cfg_attr(docsrs, doc(cfg(all())))]
215
0
pub const fn major(dev: dev_t) -> u64 {
216
0
    ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)
217
0
}
218
219
#[cfg(target_os = "linux")]
220
#[cfg_attr(docsrs, doc(cfg(all())))]
221
0
pub const fn minor(dev: dev_t) -> u64 {
222
0
    ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff)
223
0
}
224
225
#[cfg(target_os = "linux")]
226
#[cfg_attr(docsrs, doc(cfg(all())))]
227
0
pub const fn makedev(major: u64, minor: u64) -> dev_t {
228
0
    ((major & 0xffff_f000) << 32)
229
0
        | ((major & 0x0000_0fff) << 8)
230
0
        | ((minor & 0xffff_ff00) << 12)
231
0
        | (minor & 0x0000_00ff)
232
0
}
233
234
0
pub fn umask(mode: Mode) -> Mode {
235
0
    let prev = unsafe { libc::umask(mode.bits() as mode_t) };
236
0
    Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
237
0
}
238
239
0
pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
240
0
    let mut dst = mem::MaybeUninit::uninit();
241
0
    let res = path.with_nix_path(|cstr| unsafe {
242
0
        libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
243
0
    })?;
244
245
0
    Errno::result(res)?;
246
247
0
    Ok(unsafe { dst.assume_init() })
248
0
}
249
250
0
pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
251
0
    let mut dst = mem::MaybeUninit::uninit();
252
0
    let res = path.with_nix_path(|cstr| unsafe {
253
0
        libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
254
0
    })?;
255
256
0
    Errno::result(res)?;
257
258
0
    Ok(unsafe { dst.assume_init() })
259
0
}
260
261
0
pub fn fstat(fd: RawFd) -> Result<FileStat> {
262
0
    let mut dst = mem::MaybeUninit::uninit();
263
0
    let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
264
0
265
0
    Errno::result(res)?;
266
267
0
    Ok(unsafe { dst.assume_init() })
268
0
}
269
270
#[cfg(not(target_os = "redox"))]
271
#[cfg_attr(docsrs, doc(cfg(all())))]
272
0
pub fn fstatat<P: ?Sized + NixPath>(
273
0
    dirfd: RawFd,
274
0
    pathname: &P,
275
0
    f: AtFlags,
276
0
) -> Result<FileStat> {
277
0
    let mut dst = mem::MaybeUninit::uninit();
278
0
    let res = pathname.with_nix_path(|cstr| unsafe {
279
0
        libc::fstatat(
280
0
            dirfd,
281
0
            cstr.as_ptr(),
282
0
            dst.as_mut_ptr(),
283
0
            f.bits() as libc::c_int,
284
0
        )
285
0
    })?;
286
287
0
    Errno::result(res)?;
288
289
0
    Ok(unsafe { dst.assume_init() })
290
0
}
291
292
/// Change the file permission bits of the file specified by a file descriptor.
293
///
294
/// # References
295
///
296
/// [fchmod(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html).
297
0
pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
298
0
    let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
299
0
300
0
    Errno::result(res).map(drop)
301
0
}
302
303
/// Flags for `fchmodat` function.
304
#[derive(Clone, Copy, Debug)]
305
pub enum FchmodatFlags {
306
    FollowSymlink,
307
    NoFollowSymlink,
308
}
309
310
/// Change the file permission bits.
311
///
312
/// The file to be changed is determined relative to the directory associated
313
/// with the file descriptor `dirfd` or the current working directory
314
/// if `dirfd` is `None`.
315
///
316
/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
317
/// then the mode of the symbolic link is changed.
318
///
319
/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
320
/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
321
/// in the `nix` crate.
322
///
323
/// # References
324
///
325
/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
326
#[cfg(not(target_os = "redox"))]
327
#[cfg_attr(docsrs, doc(cfg(all())))]
328
0
pub fn fchmodat<P: ?Sized + NixPath>(
329
0
    dirfd: Option<RawFd>,
330
0
    path: &P,
331
0
    mode: Mode,
332
0
    flag: FchmodatFlags,
333
0
) -> Result<()> {
334
0
    let atflag = match flag {
335
0
        FchmodatFlags::FollowSymlink => AtFlags::empty(),
336
0
        FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
337
    };
338
0
    let res = path.with_nix_path(|cstr| unsafe {
339
0
        libc::fchmodat(
340
0
            at_rawfd(dirfd),
341
0
            cstr.as_ptr(),
342
0
            mode.bits() as mode_t,
343
0
            atflag.bits() as libc::c_int,
344
0
        )
345
0
    })?;
346
347
0
    Errno::result(res).map(drop)
348
0
}
349
350
/// Change the access and modification times of a file.
351
///
352
/// `utimes(path, times)` is identical to
353
/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former
354
/// is a deprecated API so prefer using the latter if the platforms you care
355
/// about support it.
356
///
357
/// # References
358
///
359
/// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html).
360
0
pub fn utimes<P: ?Sized + NixPath>(
361
0
    path: &P,
362
0
    atime: &TimeVal,
363
0
    mtime: &TimeVal,
364
0
) -> Result<()> {
365
0
    let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
366
0
    let res = path.with_nix_path(|cstr| unsafe {
367
0
        libc::utimes(cstr.as_ptr(), &times[0])
368
0
    })?;
369
370
0
    Errno::result(res).map(drop)
371
0
}
372
373
/// Change the access and modification times of a file without following symlinks.
374
///
375
/// `lutimes(path, times)` is identical to
376
/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
377
/// is a deprecated API so prefer using the latter if the platforms you care
378
/// about support it.
379
///
380
/// # References
381
///
382
/// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
383
#[cfg(any(
384
    target_os = "linux",
385
    target_os = "haiku",
386
    target_os = "ios",
387
    target_os = "macos",
388
    target_os = "freebsd",
389
    target_os = "netbsd"
390
))]
391
#[cfg_attr(docsrs, doc(cfg(all())))]
392
0
pub fn lutimes<P: ?Sized + NixPath>(
393
0
    path: &P,
394
0
    atime: &TimeVal,
395
0
    mtime: &TimeVal,
396
0
) -> Result<()> {
397
0
    let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
398
0
    let res = path.with_nix_path(|cstr| unsafe {
399
0
        libc::lutimes(cstr.as_ptr(), &times[0])
400
0
    })?;
401
402
0
    Errno::result(res).map(drop)
403
0
}
404
405
/// Change the access and modification times of the file specified by a file descriptor.
406
///
407
/// # References
408
///
409
/// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
410
#[inline]
411
0
pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
412
0
    let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
413
0
    let res = unsafe { libc::futimens(fd, &times[0]) };
414
0
415
0
    Errno::result(res).map(drop)
416
0
}
417
418
/// Flags for `utimensat` function.
419
// TODO: replace with fcntl::AtFlags
420
#[derive(Clone, Copy, Debug)]
421
pub enum UtimensatFlags {
422
    FollowSymlink,
423
    NoFollowSymlink,
424
}
425
426
/// Change the access and modification times of a file.
427
///
428
/// The file to be changed is determined relative to the directory associated
429
/// with the file descriptor `dirfd` or the current working directory
430
/// if `dirfd` is `None`.
431
///
432
/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link,
433
/// then the mode of the symbolic link is changed.
434
///
435
/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to
436
/// `utimes(path, times)`. The latter is a deprecated API so prefer using the
437
/// former if the platforms you care about support it.
438
///
439
/// # References
440
///
441
/// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
442
#[cfg(not(target_os = "redox"))]
443
#[cfg_attr(docsrs, doc(cfg(all())))]
444
0
pub fn utimensat<P: ?Sized + NixPath>(
445
0
    dirfd: Option<RawFd>,
446
0
    path: &P,
447
0
    atime: &TimeSpec,
448
0
    mtime: &TimeSpec,
449
0
    flag: UtimensatFlags,
450
0
) -> Result<()> {
451
0
    let atflag = match flag {
452
0
        UtimensatFlags::FollowSymlink => AtFlags::empty(),
453
0
        UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
454
    };
455
0
    let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
456
0
    let res = path.with_nix_path(|cstr| unsafe {
457
0
        libc::utimensat(
458
0
            at_rawfd(dirfd),
459
0
            cstr.as_ptr(),
460
0
            &times[0],
461
0
            atflag.bits() as libc::c_int,
462
0
        )
463
0
    })?;
464
465
0
    Errno::result(res).map(drop)
466
0
}
467
468
#[cfg(not(target_os = "redox"))]
469
#[cfg_attr(docsrs, doc(cfg(all())))]
470
0
pub fn mkdirat<P: ?Sized + NixPath>(
471
0
    fd: RawFd,
472
0
    path: &P,
473
0
    mode: Mode,
474
0
) -> Result<()> {
475
0
    let res = path.with_nix_path(|cstr| unsafe {
476
0
        libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t)
477
0
    })?;
478
479
0
    Errno::result(res).map(drop)
480
0
}