1pub use libc::{dev_t, mode_t};
2#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
3pub use libc::c_uint;
4#[cfg(any(
5 target_os = "netbsd",
6 target_os = "freebsd",
7 target_os = "dragonfly"
8))]
9pub use libc::c_ulong;
10pub use libc::stat as FileStat;
11
12use crate::{Result, NixPath, errno::Errno};
13#[cfg(not(target_os = "redox"))]
14use crate::fcntl::{AtFlags, at_rawfd};
15use std::mem;
16use std::os::unix::io::RawFd;
17use crate::sys::time::{TimeSpec, TimeVal};
18
19libc_bitflags!(
20 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
33libc_bitflags! {
34 pub struct Mode: mode_t {
36 S_IRWXU;
37 S_IRUSR;
38 S_IWUSR;
39 S_IXUSR;
40 S_IRWXG;
41 S_IRGRP;
42 S_IWGRP;
43 S_IXGRP;
44 S_IRWXO;
45 S_IROTH;
46 S_IWOTH;
47 S_IXOTH;
48 S_ISUID as mode_t;
49 S_ISGID as mode_t;
50 S_ISVTX as mode_t;
51 }
52}
53
54#[cfg(any(target_os = "macos", target_os = "ios", target_os="openbsd"))]
55pub type type_of_file_flag = c_uint;
56#[cfg(any(
57 target_os = "netbsd",
58 target_os = "freebsd",
59 target_os = "dragonfly"
60))]
61pub type type_of_file_flag = c_ulong;
62
63#[cfg(any(
64 target_os = "openbsd",
65 target_os = "netbsd",
66 target_os = "freebsd",
67 target_os = "dragonfly",
68 target_os = "macos",
69 target_os = "ios"
70))]
71libc_bitflags! {
72 #[cfg_attr(docsrs, doc(cfg(all())))]
74 pub struct FileFlag: type_of_file_flag {
75 SF_APPEND;
77 SF_ARCHIVED;
79 #[cfg(any(target_os = "dragonfly"))]
80 SF_CACHE;
81 SF_IMMUTABLE;
83 #[cfg(any(target_os = "netbsd"))]
85 SF_LOG;
86 #[cfg(any(target_os = "dragonfly"))]
88 SF_NOHISTORY;
89 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
91 SF_NOUNLINK;
92 SF_SETTABLE;
94 #[cfg(any(target_os = "netbsd"))]
96 SF_SNAPINVAL;
97 #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
99 SF_SNAPSHOT;
100 #[cfg(any(target_os = "dragonfly"))]
101 SF_XLINK;
102 UF_APPEND;
104 #[cfg(any(target_os = "freebsd"))]
106 UF_ARCHIVE;
107 #[cfg(any(target_os = "dragonfly"))]
108 UF_CACHE;
109 #[cfg(any(target_os = "macos", target_os = "ios"))]
111 UF_COMPRESSED;
112 #[cfg(any(
115 target_os = "freebsd",
116 target_os = "macos",
117 target_os = "ios",
118 ))]
119 UF_HIDDEN;
120 UF_IMMUTABLE;
122 UF_NODUMP;
124 #[cfg(any(target_os = "dragonfly"))]
125 UF_NOHISTORY;
126 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
128 UF_NOUNLINK;
129 #[cfg(any(target_os = "freebsd"))]
132 UF_OFFLINE;
133 UF_OPAQUE;
135 #[cfg(any(target_os = "freebsd"))]
137 UF_READONLY;
138 #[cfg(any(target_os = "freebsd"))]
140 UF_REPARSE;
141 UF_SETTABLE;
143 #[cfg(any(target_os = "freebsd"))]
145 UF_SPARSE;
146 #[cfg(any(target_os = "freebsd"))]
149 UF_SYSTEM;
150 #[cfg(any(target_os = "macos", target_os = "ios"))]
152 UF_TRACKED;
153 #[cfg(any(target_os = "dragonfly"))]
154 UF_XLINK;
155 }
156}
157
158pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
160 let res = path.with_nix_path(|cstr| unsafe {
161 libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
162 })?;
163
164 Errno::result(res).map(drop)
165}
166
167#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))]
169#[cfg_attr(docsrs, doc(cfg(all())))]
170pub fn mknodat<P: ?Sized + NixPath>(
171 dirfd: RawFd,
172 path: &P,
173 kind: SFlag,
174 perm: Mode,
175 dev: dev_t,
176) -> Result<()> {
177 let res = path.with_nix_path(|cstr| unsafe {
178 libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
179 })?;
180
181 Errno::result(res).map(drop)
182}
183
184#[cfg(target_os = "linux")]
185#[cfg_attr(docsrs, doc(cfg(all())))]
186pub const fn major(dev: dev_t) -> u64 {
187 ((dev >> 32) & 0xffff_f000) |
188 ((dev >> 8) & 0x0000_0fff)
189}
190
191#[cfg(target_os = "linux")]
192#[cfg_attr(docsrs, doc(cfg(all())))]
193pub const fn minor(dev: dev_t) -> u64 {
194 ((dev >> 12) & 0xffff_ff00) |
195 ((dev ) & 0x0000_00ff)
196}
197
198#[cfg(target_os = "linux")]
199#[cfg_attr(docsrs, doc(cfg(all())))]
200pub const fn makedev(major: u64, minor: u64) -> dev_t {
201 ((major & 0xffff_f000) << 32) |
202 ((major & 0x0000_0fff) << 8) |
203 ((minor & 0xffff_ff00) << 12) |
204 (minor & 0x0000_00ff)
205}
206
207pub fn umask(mode: Mode) -> Mode {
208 let prev = unsafe { libc::umask(mode.bits() as mode_t) };
209 Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
210}
211
212pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
213 let mut dst = mem::MaybeUninit::uninit();
214 let res = path.with_nix_path(|cstr| {
215 unsafe {
216 libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
217 }
218 })?;
219
220 Errno::result(res)?;
221
222 Ok(unsafe{dst.assume_init()})
223}
224
225pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
226 let mut dst = mem::MaybeUninit::uninit();
227 let res = path.with_nix_path(|cstr| {
228 unsafe {
229 libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
230 }
231 })?;
232
233 Errno::result(res)?;
234
235 Ok(unsafe{dst.assume_init()})
236}
237
238pub fn fstat(fd: RawFd) -> Result<FileStat> {
239 let mut dst = mem::MaybeUninit::uninit();
240 let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
241
242 Errno::result(res)?;
243
244 Ok(unsafe{dst.assume_init()})
245}
246
247#[cfg(not(target_os = "redox"))]
248#[cfg_attr(docsrs, doc(cfg(all())))]
249pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
250 let mut dst = mem::MaybeUninit::uninit();
251 let res = pathname.with_nix_path(|cstr| {
252 unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
253 })?;
254
255 Errno::result(res)?;
256
257 Ok(unsafe{dst.assume_init()})
258}
259
260pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
266 let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
267
268 Errno::result(res).map(drop)
269}
270
271#[derive(Clone, Copy, Debug)]
273pub enum FchmodatFlags {
274 FollowSymlink,
275 NoFollowSymlink,
276}
277
278#[cfg(not(target_os = "redox"))]
295#[cfg_attr(docsrs, doc(cfg(all())))]
296pub fn fchmodat<P: ?Sized + NixPath>(
297 dirfd: Option<RawFd>,
298 path: &P,
299 mode: Mode,
300 flag: FchmodatFlags,
301) -> Result<()> {
302 let atflag =
303 match flag {
304 FchmodatFlags::FollowSymlink => AtFlags::empty(),
305 FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
306 };
307 let res = path.with_nix_path(|cstr| unsafe {
308 libc::fchmodat(
309 at_rawfd(dirfd),
310 cstr.as_ptr(),
311 mode.bits() as mode_t,
312 atflag.bits() as libc::c_int,
313 )
314 })?;
315
316 Errno::result(res).map(drop)
317}
318
319pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
330 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
331 let res = path.with_nix_path(|cstr| unsafe {
332 libc::utimes(cstr.as_ptr(), ×[0])
333 })?;
334
335 Errno::result(res).map(drop)
336}
337
338#[cfg(any(target_os = "linux",
349 target_os = "haiku",
350 target_os = "ios",
351 target_os = "macos",
352 target_os = "freebsd",
353 target_os = "netbsd"))]
354#[cfg_attr(docsrs, doc(cfg(all())))]
355pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
356 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
357 let res = path.with_nix_path(|cstr| unsafe {
358 libc::lutimes(cstr.as_ptr(), ×[0])
359 })?;
360
361 Errno::result(res).map(drop)
362}
363
364#[inline]
370pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
371 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
372 let res = unsafe { libc::futimens(fd, ×[0]) };
373
374 Errno::result(res).map(drop)
375}
376
377#[derive(Clone, Copy, Debug)]
380pub enum UtimensatFlags {
381 FollowSymlink,
382 NoFollowSymlink,
383}
384
385#[cfg(not(target_os = "redox"))]
402#[cfg_attr(docsrs, doc(cfg(all())))]
403pub fn utimensat<P: ?Sized + NixPath>(
404 dirfd: Option<RawFd>,
405 path: &P,
406 atime: &TimeSpec,
407 mtime: &TimeSpec,
408 flag: UtimensatFlags
409) -> Result<()> {
410 let atflag =
411 match flag {
412 UtimensatFlags::FollowSymlink => AtFlags::empty(),
413 UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
414 };
415 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
416 let res = path.with_nix_path(|cstr| unsafe {
417 libc::utimensat(
418 at_rawfd(dirfd),
419 cstr.as_ptr(),
420 ×[0],
421 atflag.bits() as libc::c_int,
422 )
423 })?;
424
425 Errno::result(res).map(drop)
426}
427
428#[cfg(not(target_os = "redox"))]
429#[cfg_attr(docsrs, doc(cfg(all())))]
430pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
431 let res = path.with_nix_path(|cstr| {
432 unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
433 })?;
434
435 Errno::result(res).map(drop)
436}