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")))]
57#[cfg_attr(docsrs, doc(cfg(all())))]
58pub fn mknodat<P: ?Sized + NixPath>(
59 dirfd: RawFd,
60 path: &P,
61 kind: SFlag,
62 perm: Mode,
63 dev: dev_t,
64) -> Result<()> {
65 let res = path.with_nix_path(|cstr| unsafe {
66 libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
67 })?;
68
69 Errno::result(res).map(drop)
70}
71
72#[cfg(target_os = "linux")]
73#[cfg_attr(docsrs, doc(cfg(all())))]
74pub const fn major(dev: dev_t) -> u64 {
75 ((dev >> 32) & 0xffff_f000) |
76 ((dev >> 8) & 0x0000_0fff)
77}
78
79#[cfg(target_os = "linux")]
80#[cfg_attr(docsrs, doc(cfg(all())))]
81pub const fn minor(dev: dev_t) -> u64 {
82 ((dev >> 12) & 0xffff_ff00) |
83 ((dev ) & 0x0000_00ff)
84}
85
86#[cfg(target_os = "linux")]
87#[cfg_attr(docsrs, doc(cfg(all())))]
88pub const fn makedev(major: u64, minor: u64) -> dev_t {
89 ((major & 0xffff_f000) << 32) |
90 ((major & 0x0000_0fff) << 8) |
91 ((minor & 0xffff_ff00) << 12) |
92 (minor & 0x0000_00ff)
93}
94
95pub fn umask(mode: Mode) -> Mode {
96 let prev = unsafe { libc::umask(mode.bits() as mode_t) };
97 Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
98}
99
100pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
101 let mut dst = mem::MaybeUninit::uninit();
102 let res = path.with_nix_path(|cstr| {
103 unsafe {
104 libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
105 }
106 })?;
107
108 Errno::result(res)?;
109
110 Ok(unsafe{dst.assume_init()})
111}
112
113pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
114 let mut dst = mem::MaybeUninit::uninit();
115 let res = path.with_nix_path(|cstr| {
116 unsafe {
117 libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
118 }
119 })?;
120
121 Errno::result(res)?;
122
123 Ok(unsafe{dst.assume_init()})
124}
125
126pub fn fstat(fd: RawFd) -> Result<FileStat> {
127 let mut dst = mem::MaybeUninit::uninit();
128 let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
129
130 Errno::result(res)?;
131
132 Ok(unsafe{dst.assume_init()})
133}
134
135#[cfg(not(target_os = "redox"))]
136#[cfg_attr(docsrs, doc(cfg(all())))]
137pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
138 let mut dst = mem::MaybeUninit::uninit();
139 let res = pathname.with_nix_path(|cstr| {
140 unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
141 })?;
142
143 Errno::result(res)?;
144
145 Ok(unsafe{dst.assume_init()})
146}
147
148pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
154 let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
155
156 Errno::result(res).map(drop)
157}
158
159#[derive(Clone, Copy, Debug)]
161pub enum FchmodatFlags {
162 FollowSymlink,
163 NoFollowSymlink,
164}
165
166#[cfg(not(target_os = "redox"))]
183#[cfg_attr(docsrs, doc(cfg(all())))]
184pub fn fchmodat<P: ?Sized + NixPath>(
185 dirfd: Option<RawFd>,
186 path: &P,
187 mode: Mode,
188 flag: FchmodatFlags,
189) -> Result<()> {
190 let atflag =
191 match flag {
192 FchmodatFlags::FollowSymlink => AtFlags::empty(),
193 FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
194 };
195 let res = path.with_nix_path(|cstr| unsafe {
196 libc::fchmodat(
197 at_rawfd(dirfd),
198 cstr.as_ptr(),
199 mode.bits() as mode_t,
200 atflag.bits() as libc::c_int,
201 )
202 })?;
203
204 Errno::result(res).map(drop)
205}
206
207pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
218 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
219 let res = path.with_nix_path(|cstr| unsafe {
220 libc::utimes(cstr.as_ptr(), ×[0])
221 })?;
222
223 Errno::result(res).map(drop)
224}
225
226#[cfg(any(target_os = "linux",
237 target_os = "haiku",
238 target_os = "ios",
239 target_os = "macos",
240 target_os = "freebsd",
241 target_os = "netbsd"))]
242#[cfg_attr(docsrs, doc(cfg(all())))]
243pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
244 let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
245 let res = path.with_nix_path(|cstr| unsafe {
246 libc::lutimes(cstr.as_ptr(), ×[0])
247 })?;
248
249 Errno::result(res).map(drop)
250}
251
252#[inline]
258pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
259 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
260 let res = unsafe { libc::futimens(fd, ×[0]) };
261
262 Errno::result(res).map(drop)
263}
264
265#[derive(Clone, Copy, Debug)]
268pub enum UtimensatFlags {
269 FollowSymlink,
270 NoFollowSymlink,
271}
272
273#[cfg(not(target_os = "redox"))]
290#[cfg_attr(docsrs, doc(cfg(all())))]
291pub fn utimensat<P: ?Sized + NixPath>(
292 dirfd: Option<RawFd>,
293 path: &P,
294 atime: &TimeSpec,
295 mtime: &TimeSpec,
296 flag: UtimensatFlags
297) -> Result<()> {
298 let atflag =
299 match flag {
300 UtimensatFlags::FollowSymlink => AtFlags::empty(),
301 UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
302 };
303 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
304 let res = path.with_nix_path(|cstr| unsafe {
305 libc::utimensat(
306 at_rawfd(dirfd),
307 cstr.as_ptr(),
308 ×[0],
309 atflag.bits() as libc::c_int,
310 )
311 })?;
312
313 Errno::result(res).map(drop)
314}
315
316#[cfg(not(target_os = "redox"))]
317#[cfg_attr(docsrs, doc(cfg(all())))]
318pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
319 let res = path.with_nix_path(|cstr| {
320 unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
321 })?;
322
323 Errno::result(res).map(drop)
324}