• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
mknod<P: ?Sized + NixPath>( path: &P, kind: SFlag, perm: Mode, dev: dev_t, ) -> Result<()>173 pub fn mknod<P: ?Sized + NixPath>(
174     path: &P,
175     kind: SFlag,
176     perm: Mode,
177     dev: dev_t,
178 ) -> Result<()> {
179     let res = path.with_nix_path(|cstr| unsafe {
180         libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
181     })?;
182 
183     Errno::result(res).map(drop)
184 }
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())))]
mknodat<P: ?Sized + NixPath>( dirfd: RawFd, path: &P, kind: SFlag, perm: Mode, dev: dev_t, ) -> Result<()>194 pub fn mknodat<P: ?Sized + NixPath>(
195     dirfd: RawFd,
196     path: &P,
197     kind: SFlag,
198     perm: Mode,
199     dev: dev_t,
200 ) -> Result<()> {
201     let res = path.with_nix_path(|cstr| unsafe {
202         libc::mknodat(
203             dirfd,
204             cstr.as_ptr(),
205             kind.bits | perm.bits() as mode_t,
206             dev,
207         )
208     })?;
209 
210     Errno::result(res).map(drop)
211 }
212 
213 #[cfg(target_os = "linux")]
214 #[cfg_attr(docsrs, doc(cfg(all())))]
major(dev: dev_t) -> u64215 pub const fn major(dev: dev_t) -> u64 {
216     ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)
217 }
218 
219 #[cfg(target_os = "linux")]
220 #[cfg_attr(docsrs, doc(cfg(all())))]
minor(dev: dev_t) -> u64221 pub const fn minor(dev: dev_t) -> u64 {
222     ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff)
223 }
224 
225 #[cfg(target_os = "linux")]
226 #[cfg_attr(docsrs, doc(cfg(all())))]
makedev(major: u64, minor: u64) -> dev_t227 pub const fn makedev(major: u64, minor: u64) -> dev_t {
228     ((major & 0xffff_f000) << 32)
229         | ((major & 0x0000_0fff) << 8)
230         | ((minor & 0xffff_ff00) << 12)
231         | (minor & 0x0000_00ff)
232 }
233 
umask(mode: Mode) -> Mode234 pub fn umask(mode: Mode) -> Mode {
235     let prev = unsafe { libc::umask(mode.bits() as mode_t) };
236     Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
237 }
238 
stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat>239 pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
240     let mut dst = mem::MaybeUninit::uninit();
241     let res = path.with_nix_path(|cstr| unsafe {
242         libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
243     })?;
244 
245     Errno::result(res)?;
246 
247     Ok(unsafe { dst.assume_init() })
248 }
249 
lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat>250 pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
251     let mut dst = mem::MaybeUninit::uninit();
252     let res = path.with_nix_path(|cstr| unsafe {
253         libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
254     })?;
255 
256     Errno::result(res)?;
257 
258     Ok(unsafe { dst.assume_init() })
259 }
260 
fstat(fd: RawFd) -> Result<FileStat>261 pub fn fstat(fd: RawFd) -> Result<FileStat> {
262     let mut dst = mem::MaybeUninit::uninit();
263     let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
264 
265     Errno::result(res)?;
266 
267     Ok(unsafe { dst.assume_init() })
268 }
269 
270 #[cfg(not(target_os = "redox"))]
271 #[cfg_attr(docsrs, doc(cfg(all())))]
fstatat<P: ?Sized + NixPath>( dirfd: RawFd, pathname: &P, f: AtFlags, ) -> Result<FileStat>272 pub fn fstatat<P: ?Sized + NixPath>(
273     dirfd: RawFd,
274     pathname: &P,
275     f: AtFlags,
276 ) -> Result<FileStat> {
277     let mut dst = mem::MaybeUninit::uninit();
278     let res = pathname.with_nix_path(|cstr| unsafe {
279         libc::fstatat(
280             dirfd,
281             cstr.as_ptr(),
282             dst.as_mut_ptr(),
283             f.bits() as libc::c_int,
284         )
285     })?;
286 
287     Errno::result(res)?;
288 
289     Ok(unsafe { dst.assume_init() })
290 }
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).
fchmod(fd: RawFd, mode: Mode) -> Result<()>297 pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
298     let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
299 
300     Errno::result(res).map(drop)
301 }
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())))]
fchmodat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, mode: Mode, flag: FchmodatFlags, ) -> Result<()>328 pub fn fchmodat<P: ?Sized + NixPath>(
329     dirfd: Option<RawFd>,
330     path: &P,
331     mode: Mode,
332     flag: FchmodatFlags,
333 ) -> Result<()> {
334     let atflag = match flag {
335         FchmodatFlags::FollowSymlink => AtFlags::empty(),
336         FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
337     };
338     let res = path.with_nix_path(|cstr| unsafe {
339         libc::fchmodat(
340             at_rawfd(dirfd),
341             cstr.as_ptr(),
342             mode.bits() as mode_t,
343             atflag.bits() as libc::c_int,
344         )
345     })?;
346 
347     Errno::result(res).map(drop)
348 }
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).
utimes<P: ?Sized + NixPath>( path: &P, atime: &TimeVal, mtime: &TimeVal, ) -> Result<()>360 pub fn utimes<P: ?Sized + NixPath>(
361     path: &P,
362     atime: &TimeVal,
363     mtime: &TimeVal,
364 ) -> Result<()> {
365     let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
366     let res = path.with_nix_path(|cstr| unsafe {
367         libc::utimes(cstr.as_ptr(), &times[0])
368     })?;
369 
370     Errno::result(res).map(drop)
371 }
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())))]
lutimes<P: ?Sized + NixPath>( path: &P, atime: &TimeVal, mtime: &TimeVal, ) -> Result<()>392 pub fn lutimes<P: ?Sized + NixPath>(
393     path: &P,
394     atime: &TimeVal,
395     mtime: &TimeVal,
396 ) -> Result<()> {
397     let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
398     let res = path.with_nix_path(|cstr| unsafe {
399         libc::lutimes(cstr.as_ptr(), &times[0])
400     })?;
401 
402     Errno::result(res).map(drop)
403 }
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]
futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()>411 pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
412     let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
413     let res = unsafe { libc::futimens(fd, &times[0]) };
414 
415     Errno::result(res).map(drop)
416 }
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())))]
utimensat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, atime: &TimeSpec, mtime: &TimeSpec, flag: UtimensatFlags, ) -> Result<()>444 pub fn utimensat<P: ?Sized + NixPath>(
445     dirfd: Option<RawFd>,
446     path: &P,
447     atime: &TimeSpec,
448     mtime: &TimeSpec,
449     flag: UtimensatFlags,
450 ) -> Result<()> {
451     let atflag = match flag {
452         UtimensatFlags::FollowSymlink => AtFlags::empty(),
453         UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
454     };
455     let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
456     let res = path.with_nix_path(|cstr| unsafe {
457         libc::utimensat(
458             at_rawfd(dirfd),
459             cstr.as_ptr(),
460             &times[0],
461             atflag.bits() as libc::c_int,
462         )
463     })?;
464 
465     Errno::result(res).map(drop)
466 }
467 
468 #[cfg(not(target_os = "redox"))]
469 #[cfg_attr(docsrs, doc(cfg(all())))]
mkdirat<P: ?Sized + NixPath>( fd: RawFd, path: &P, mode: Mode, ) -> Result<()>470 pub fn mkdirat<P: ?Sized + NixPath>(
471     fd: RawFd,
472     path: &P,
473     mode: Mode,
474 ) -> Result<()> {
475     let res = path.with_nix_path(|cstr| unsafe {
476         libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t)
477     })?;
478 
479     Errno::result(res).map(drop)
480 }
481