1#[cfg(any(apple_targets, target_os = "openbsd"))]
2pub use libc::c_uint;
3#[cfg(any(target_os = "netbsd", freebsdlike))]
4pub use libc::c_ulong;
5pub use libc::stat as FileStat;
6pub use libc::{dev_t, mode_t};
7
8#[cfg(not(target_os = "redox"))]
9use crate::fcntl::AtFlags;
10use crate::sys::time::{TimeSpec, TimeVal};
11use crate::{errno::Errno, NixPath, Result};
12use std::mem;
13
14libc_bitflags!(
15 pub struct SFlag: mode_t {
17 S_IFIFO;
18 S_IFCHR;
19 S_IFDIR;
20 S_IFBLK;
21 S_IFREG;
22 S_IFLNK;
23 S_IFSOCK;
24 S_IFMT;
25 }
26);
27
28libc_bitflags! {
29 pub struct Mode: mode_t {
31 S_IRWXU;
33 S_IRUSR;
35 S_IWUSR;
37 S_IXUSR;
39 S_IRWXG;
41 S_IRGRP;
43 S_IWGRP;
45 S_IXGRP;
47 S_IRWXO;
49 S_IROTH;
51 S_IWOTH;
53 S_IXOTH;
55 S_ISUID as mode_t;
57 S_ISGID as mode_t;
59 S_ISVTX as mode_t;
60 }
61}
62
63#[cfg(any(apple_targets, target_os = "openbsd"))]
64pub type type_of_file_flag = c_uint;
65#[cfg(any(freebsdlike, target_os = "netbsd"))]
66pub type type_of_file_flag = c_ulong;
67
68#[cfg(bsd)]
69libc_bitflags! {
70 pub struct FileFlag: type_of_file_flag {
72 SF_APPEND;
74 SF_ARCHIVED;
76 #[cfg(any(target_os = "dragonfly"))]
77 SF_CACHE;
78 SF_IMMUTABLE;
80 #[cfg(any(target_os = "netbsd"))]
82 SF_LOG;
83 #[cfg(any(target_os = "dragonfly"))]
85 SF_NOHISTORY;
86 #[cfg(freebsdlike)]
88 SF_NOUNLINK;
89 SF_SETTABLE;
91 #[cfg(any(target_os = "netbsd"))]
93 SF_SNAPINVAL;
94 #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
96 SF_SNAPSHOT;
97 #[cfg(any(target_os = "dragonfly"))]
98 SF_XLINK;
99 UF_APPEND;
101 #[cfg(any(target_os = "freebsd"))]
103 UF_ARCHIVE;
104 #[cfg(any(target_os = "dragonfly"))]
105 UF_CACHE;
106 #[cfg(apple_targets)]
108 UF_COMPRESSED;
109 #[cfg(any(
112 target_os = "freebsd",
113 apple_targets,
114 ))]
115 UF_HIDDEN;
116 UF_IMMUTABLE;
118 UF_NODUMP;
120 #[cfg(any(target_os = "dragonfly"))]
121 UF_NOHISTORY;
122 #[cfg(freebsdlike)]
124 UF_NOUNLINK;
125 #[cfg(any(target_os = "freebsd"))]
128 UF_OFFLINE;
129 UF_OPAQUE;
131 #[cfg(any(target_os = "freebsd"))]
133 UF_READONLY;
134 #[cfg(any(target_os = "freebsd"))]
136 UF_REPARSE;
137 UF_SETTABLE;
139 #[cfg(any(target_os = "freebsd"))]
141 UF_SPARSE;
142 #[cfg(any(target_os = "freebsd"))]
145 UF_SYSTEM;
146 #[cfg(apple_targets)]
148 UF_TRACKED;
149 #[cfg(any(target_os = "dragonfly"))]
150 UF_XLINK;
151 }
152}
153
154pub fn mknod<P: ?Sized + NixPath>(
156 path: &P,
157 kind: SFlag,
158 perm: Mode,
159 dev: dev_t,
160) -> Result<()> {
161 let res = path.with_nix_path(|cstr| unsafe {
162 libc::mknod(cstr.as_ptr(), kind.bits() | perm.bits() as mode_t, dev)
163 })?;
164
165 Errno::result(res).map(drop)
166}
167
168#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))]
170pub fn mknodat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
171 dirfd: Fd,
172 path: &P,
173 kind: SFlag,
174 perm: Mode,
175 dev: dev_t,
176) -> Result<()> {
177 use std::os::fd::AsRawFd;
178
179 let res = path.with_nix_path(|cstr| unsafe {
180 libc::mknodat(
181 dirfd.as_fd().as_raw_fd(),
182 cstr.as_ptr(),
183 kind.bits() | perm.bits() as mode_t,
184 dev,
185 )
186 })?;
187
188 Errno::result(res).map(drop)
189}
190
191#[cfg(target_os = "linux")]
192pub const fn major(dev: dev_t) -> u64 {
193 ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)
194}
195
196#[cfg(target_os = "linux")]
197pub const fn minor(dev: dev_t) -> u64 {
198 ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff)
199}
200
201#[cfg(target_os = "linux")]
202pub const fn makedev(major: u64, minor: u64) -> dev_t {
203 ((major & 0xffff_f000) << 32)
204 | ((major & 0x0000_0fff) << 8)
205 | ((minor & 0xffff_ff00) << 12)
206 | (minor & 0x0000_00ff)
207}
208
209pub fn umask(mode: Mode) -> Mode {
210 let prev = unsafe { libc::umask(mode.bits() as mode_t) };
211 Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
212}
213
214pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
215 let mut dst = mem::MaybeUninit::uninit();
216 let res = path.with_nix_path(|cstr| unsafe {
217 libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
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| unsafe {
228 libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
229 })?;
230
231 Errno::result(res)?;
232
233 Ok(unsafe { dst.assume_init() })
234}
235
236pub fn fstat<Fd: std::os::fd::AsFd>(fd: Fd) -> Result<FileStat> {
237 use std::os::fd::AsRawFd;
238
239 let mut dst = mem::MaybeUninit::uninit();
240 let res = unsafe { libc::fstat(fd.as_fd().as_raw_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"))]
248pub fn fstatat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
249 dirfd: Fd,
250 pathname: &P,
251 f: AtFlags,
252) -> Result<FileStat> {
253 use std::os::fd::AsRawFd;
254
255 let mut dst = mem::MaybeUninit::uninit();
256 let res = pathname.with_nix_path(|cstr| unsafe {
257 libc::fstatat(
258 dirfd.as_fd().as_raw_fd(),
259 cstr.as_ptr(),
260 dst.as_mut_ptr(),
261 f.bits() as libc::c_int,
262 )
263 })?;
264
265 Errno::result(res)?;
266
267 Ok(unsafe { dst.assume_init() })
268}
269
270pub fn fchmod<Fd: std::os::fd::AsFd>(fd: Fd, mode: Mode) -> Result<()> {
276 use std::os::fd::AsRawFd;
277
278 let res =
279 unsafe { libc::fchmod(fd.as_fd().as_raw_fd(), mode.bits() as mode_t) };
280
281 Errno::result(res).map(drop)
282}
283
284#[derive(Clone, Copy, Debug)]
286pub enum FchmodatFlags {
287 FollowSymlink,
288 NoFollowSymlink,
289}
290
291#[cfg(not(target_os = "redox"))]
308pub fn fchmodat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
309 dirfd: Fd,
310 path: &P,
311 mode: Mode,
312 flag: FchmodatFlags,
313) -> Result<()> {
314 use std::os::fd::AsRawFd;
315
316 let atflag = match flag {
317 FchmodatFlags::FollowSymlink => AtFlags::empty(),
318 FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
319 };
320 let res = path.with_nix_path(|cstr| unsafe {
321 libc::fchmodat(
322 dirfd.as_fd().as_raw_fd(),
323 cstr.as_ptr(),
324 mode.bits() as mode_t,
325 atflag.bits() as libc::c_int,
326 )
327 })?;
328
329 Errno::result(res).map(drop)
330}
331
332pub fn utimes<P: ?Sized + NixPath>(
343 path: &P,
344 atime: &TimeVal,
345 mtime: &TimeVal,
346) -> Result<()> {
347 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
348 let res = path.with_nix_path(|cstr| unsafe {
349 libc::utimes(cstr.as_ptr(), ×[0])
350 })?;
351
352 Errno::result(res).map(drop)
353}
354
355#[cfg(any(
366 target_os = "linux",
367 target_os = "haiku",
368 apple_targets,
369 target_os = "freebsd",
370 target_os = "netbsd"
371))]
372pub fn lutimes<P: ?Sized + NixPath>(
373 path: &P,
374 atime: &TimeVal,
375 mtime: &TimeVal,
376) -> Result<()> {
377 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
378 let res = path.with_nix_path(|cstr| unsafe {
379 libc::lutimes(cstr.as_ptr(), ×[0])
380 })?;
381
382 Errno::result(res).map(drop)
383}
384
385#[inline]
394pub fn futimens<Fd: std::os::fd::AsFd>(
395 fd: Fd,
396 atime: &TimeSpec,
397 mtime: &TimeSpec,
398) -> Result<()> {
399 use std::os::fd::AsRawFd;
400
401 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
402 let res = unsafe { libc::futimens(fd.as_fd().as_raw_fd(), ×[0]) };
403
404 Errno::result(res).map(drop)
405}
406
407#[derive(Clone, Copy, Debug)]
410pub enum UtimensatFlags {
411 FollowSymlink,
412 NoFollowSymlink,
413}
414
415#[cfg(not(target_os = "redox"))]
435pub fn utimensat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
436 dirfd: Fd,
437 path: &P,
438 atime: &TimeSpec,
439 mtime: &TimeSpec,
440 flag: UtimensatFlags,
441) -> Result<()> {
442 use std::os::fd::AsRawFd;
443
444 let atflag = match flag {
445 UtimensatFlags::FollowSymlink => AtFlags::empty(),
446 UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
447 };
448 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
449 let res = path.with_nix_path(|cstr| unsafe {
450 libc::utimensat(
451 dirfd.as_fd().as_raw_fd(),
452 cstr.as_ptr(),
453 ×[0],
454 atflag.bits() as libc::c_int,
455 )
456 })?;
457
458 Errno::result(res).map(drop)
459}
460
461#[cfg(not(target_os = "redox"))]
470pub fn mkdirat<Fd: std::os::fd::AsFd, P: ?Sized + NixPath>(
471 dirfd: Fd,
472 path: &P,
473 mode: Mode,
474) -> Result<()> {
475 use std::os::fd::AsRawFd;
476
477 let res = path.with_nix_path(|cstr| unsafe {
478 libc::mkdirat(
479 dirfd.as_fd().as_raw_fd(),
480 cstr.as_ptr(),
481 mode.bits() as mode_t,
482 )
483 })?;
484
485 Errno::result(res).map(drop)
486}