1#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
2pub use libc::c_uint;
3#[cfg(any(
4 target_os = "netbsd",
5 target_os = "freebsd",
6 target_os = "dragonfly"
7))]
8pub use libc::c_ulong;
9pub use libc::stat as FileStat;
10pub use libc::{dev_t, mode_t};
11
12#[cfg(not(target_os = "redox"))]
13use crate::fcntl::{at_rawfd, AtFlags};
14use crate::sys::time::{TimeSpec, TimeVal};
15use crate::{errno::Errno, NixPath, Result};
16use std::mem;
17use std::os::unix::io::RawFd;
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;
38 S_IRUSR;
40 S_IWUSR;
42 S_IXUSR;
44 S_IRWXG;
46 S_IRGRP;
48 S_IWGRP;
50 S_IXGRP;
52 S_IRWXO;
54 S_IROTH;
56 S_IWOTH;
58 S_IXOTH;
60 S_ISUID as mode_t;
62 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"))]
69pub type type_of_file_flag = c_uint;
70#[cfg(any(
71 target_os = "netbsd",
72 target_os = "freebsd",
73 target_os = "dragonfly"
74))]
75pub 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))]
85libc_bitflags! {
86 #[cfg_attr(docsrs, doc(cfg(all())))]
88 pub struct FileFlag: type_of_file_flag {
89 SF_APPEND;
91 SF_ARCHIVED;
93 #[cfg(any(target_os = "dragonfly"))]
94 SF_CACHE;
95 SF_IMMUTABLE;
97 #[cfg(any(target_os = "netbsd"))]
99 SF_LOG;
100 #[cfg(any(target_os = "dragonfly"))]
102 SF_NOHISTORY;
103 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
105 SF_NOUNLINK;
106 SF_SETTABLE;
108 #[cfg(any(target_os = "netbsd"))]
110 SF_SNAPINVAL;
111 #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
113 SF_SNAPSHOT;
114 #[cfg(any(target_os = "dragonfly"))]
115 SF_XLINK;
116 UF_APPEND;
118 #[cfg(any(target_os = "freebsd"))]
120 UF_ARCHIVE;
121 #[cfg(any(target_os = "dragonfly"))]
122 UF_CACHE;
123 #[cfg(any(target_os = "macos", target_os = "ios"))]
125 UF_COMPRESSED;
126 #[cfg(any(
129 target_os = "freebsd",
130 target_os = "macos",
131 target_os = "ios",
132 ))]
133 UF_HIDDEN;
134 UF_IMMUTABLE;
136 UF_NODUMP;
138 #[cfg(any(target_os = "dragonfly"))]
139 UF_NOHISTORY;
140 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
142 UF_NOUNLINK;
143 #[cfg(any(target_os = "freebsd"))]
146 UF_OFFLINE;
147 UF_OPAQUE;
149 #[cfg(any(target_os = "freebsd"))]
151 UF_READONLY;
152 #[cfg(any(target_os = "freebsd"))]
154 UF_REPARSE;
155 UF_SETTABLE;
157 #[cfg(any(target_os = "freebsd"))]
159 UF_SPARSE;
160 #[cfg(any(target_os = "freebsd"))]
163 UF_SYSTEM;
164 #[cfg(any(target_os = "macos", target_os = "ios"))]
166 UF_TRACKED;
167 #[cfg(any(target_os = "dragonfly"))]
168 UF_XLINK;
169 }
170}
171
172pub 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#[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())))]
194pub 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())))]
215pub 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())))]
221pub 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())))]
227pub 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
234pub 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
239pub 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
250pub 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
261pub 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())))]
272pub 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
292pub 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#[derive(Clone, Copy, Debug)]
305pub enum FchmodatFlags {
306 FollowSymlink,
307 NoFollowSymlink,
308}
309
310#[cfg(not(target_os = "redox"))]
327#[cfg_attr(docsrs, doc(cfg(all())))]
328pub 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
350pub 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(), ×[0])
368 })?;
369
370 Errno::result(res).map(drop)
371}
372
373#[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())))]
392pub 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(), ×[0])
400 })?;
401
402 Errno::result(res).map(drop)
403}
404
405#[inline]
411pub 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, ×[0]) };
414
415 Errno::result(res).map(drop)
416}
417
418#[derive(Clone, Copy, Debug)]
421pub enum UtimensatFlags {
422 FollowSymlink,
423 NoFollowSymlink,
424}
425
426#[cfg(not(target_os = "redox"))]
443#[cfg_attr(docsrs, doc(cfg(all())))]
444pub 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 ×[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())))]
470pub 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}