1pub use libc::{dev_t, mode_t};
2pub use libc::stat as FileStat;
3
4use crate::{Result, NixPath, errno::Errno};
5#[cfg(not(target_os = "redox"))]
6use crate::fcntl::{AtFlags, at_rawfd};
7use std::mem;
8use std::os::unix::io::RawFd;
9use crate::sys::time::{TimeSpec, TimeVal};
10
11libc_bitflags!(
12 pub struct SFlag: mode_t {
14 S_IFIFO;
15 S_IFCHR;
16 S_IFDIR;
17 S_IFBLK;
18 S_IFREG;
19 S_IFLNK;
20 S_IFSOCK;
21 S_IFMT;
22 }
23);
24
25libc_bitflags! {
26 pub struct Mode: mode_t {
28 S_IRWXU;
29 S_IRUSR;
30 S_IWUSR;
31 S_IXUSR;
32 S_IRWXG;
33 S_IRGRP;
34 S_IWGRP;
35 S_IXGRP;
36 S_IRWXO;
37 S_IROTH;
38 S_IWOTH;
39 S_IXOTH;
40 S_ISUID as mode_t;
41 S_ISGID as mode_t;
42 S_ISVTX as mode_t;
43 }
44}
45
46pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
48 let res = path.with_nix_path(|cstr| unsafe {
49 libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
50 })?;
51
52 Errno::result(res).map(drop)
53}
54
55#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
57pub fn mknodat<P: ?Sized + NixPath>(
58 dirfd: RawFd,
59 path: &P,
60 kind: SFlag,
61 perm: Mode,
62 dev: dev_t,
63) -> Result<()> {
64 let res = path.with_nix_path(|cstr| unsafe {
65 libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
66 })?;
67
68 Errno::result(res).map(drop)
69}
70
71#[cfg(target_os = "linux")]
72pub const fn major(dev: dev_t) -> u64 {
73 ((dev >> 32) & 0xffff_f000) |
74 ((dev >> 8) & 0x0000_0fff)
75}
76
77#[cfg(target_os = "linux")]
78pub const fn minor(dev: dev_t) -> u64 {
79 ((dev >> 12) & 0xffff_ff00) |
80 ((dev ) & 0x0000_00ff)
81}
82
83#[cfg(target_os = "linux")]
84pub const fn makedev(major: u64, minor: u64) -> dev_t {
85 ((major & 0xffff_f000) << 32) |
86 ((major & 0x0000_0fff) << 8) |
87 ((minor & 0xffff_ff00) << 12) |
88 (minor & 0x0000_00ff)
89}
90
91pub fn umask(mode: Mode) -> Mode {
92 let prev = unsafe { libc::umask(mode.bits() as mode_t) };
93 Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
94}
95
96pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
97 let mut dst = mem::MaybeUninit::uninit();
98 let res = path.with_nix_path(|cstr| {
99 unsafe {
100 libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
101 }
102 })?;
103
104 Errno::result(res)?;
105
106 Ok(unsafe{dst.assume_init()})
107}
108
109pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
110 let mut dst = mem::MaybeUninit::uninit();
111 let res = path.with_nix_path(|cstr| {
112 unsafe {
113 libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
114 }
115 })?;
116
117 Errno::result(res)?;
118
119 Ok(unsafe{dst.assume_init()})
120}
121
122pub fn fstat(fd: RawFd) -> Result<FileStat> {
123 let mut dst = mem::MaybeUninit::uninit();
124 let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
125
126 Errno::result(res)?;
127
128 Ok(unsafe{dst.assume_init()})
129}
130
131#[cfg(not(target_os = "redox"))]
132pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
133 let mut dst = mem::MaybeUninit::uninit();
134 let res = pathname.with_nix_path(|cstr| {
135 unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
136 })?;
137
138 Errno::result(res)?;
139
140 Ok(unsafe{dst.assume_init()})
141}
142
143pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
149 let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
150
151 Errno::result(res).map(drop)
152}
153
154#[derive(Clone, Copy, Debug)]
156pub enum FchmodatFlags {
157 FollowSymlink,
158 NoFollowSymlink,
159}
160
161#[cfg(not(target_os = "redox"))]
178pub fn fchmodat<P: ?Sized + NixPath>(
179 dirfd: Option<RawFd>,
180 path: &P,
181 mode: Mode,
182 flag: FchmodatFlags,
183) -> Result<()> {
184 let atflag =
185 match flag {
186 FchmodatFlags::FollowSymlink => AtFlags::empty(),
187 FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
188 };
189 let res = path.with_nix_path(|cstr| unsafe {
190 libc::fchmodat(
191 at_rawfd(dirfd),
192 cstr.as_ptr(),
193 mode.bits() as mode_t,
194 atflag.bits() as libc::c_int,
195 )
196 })?;
197
198 Errno::result(res).map(drop)
199}
200
201pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
212 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
213 let res = path.with_nix_path(|cstr| unsafe {
214 libc::utimes(cstr.as_ptr(), ×[0])
215 })?;
216
217 Errno::result(res).map(drop)
218}
219
220#[cfg(any(target_os = "linux",
231 target_os = "haiku",
232 target_os = "ios",
233 target_os = "macos",
234 target_os = "freebsd",
235 target_os = "netbsd"))]
236pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
237 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
238 let res = path.with_nix_path(|cstr| unsafe {
239 libc::lutimes(cstr.as_ptr(), ×[0])
240 })?;
241
242 Errno::result(res).map(drop)
243}
244
245#[inline]
251pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
252 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
253 let res = unsafe { libc::futimens(fd, ×[0]) };
254
255 Errno::result(res).map(drop)
256}
257
258#[derive(Clone, Copy, Debug)]
261pub enum UtimensatFlags {
262 FollowSymlink,
263 NoFollowSymlink,
264}
265
266#[cfg(not(target_os = "redox"))]
283pub fn utimensat<P: ?Sized + NixPath>(
284 dirfd: Option<RawFd>,
285 path: &P,
286 atime: &TimeSpec,
287 mtime: &TimeSpec,
288 flag: UtimensatFlags
289) -> Result<()> {
290 let atflag =
291 match flag {
292 UtimensatFlags::FollowSymlink => AtFlags::empty(),
293 UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
294 };
295 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
296 let res = path.with_nix_path(|cstr| unsafe {
297 libc::utimensat(
298 at_rawfd(dirfd),
299 cstr.as_ptr(),
300 ×[0],
301 atflag.bits() as libc::c_int,
302 )
303 })?;
304
305 Errno::result(res).map(drop)
306}
307
308#[cfg(not(target_os = "redox"))]
309pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
310 let res = path.with_nix_path(|cstr| {
311 unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
312 })?;
313
314 Errno::result(res).map(drop)
315}