1b8a62b91Sopenharmony_ci//! libc syscalls supporting `rustix::fs`.
2b8a62b91Sopenharmony_ci
3b8a62b91Sopenharmony_ciuse super::super::c;
4b8a62b91Sopenharmony_ciuse super::super::conv::{
5b8a62b91Sopenharmony_ci    borrowed_fd, c_str, ret, ret_c_int, ret_off_t, ret_owned_fd, ret_ssize_t,
6b8a62b91Sopenharmony_ci};
7b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
8b8a62b91Sopenharmony_ciuse super::super::conv::{syscall_ret, syscall_ret_owned_fd, syscall_ret_ssize_t};
9b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
10b8a62b91Sopenharmony_ciuse super::super::offset::libc_fallocate;
11b8a62b91Sopenharmony_ci#[cfg(not(any(
12b8a62b91Sopenharmony_ci    target_os = "dragonfly",
13b8a62b91Sopenharmony_ci    target_os = "haiku",
14b8a62b91Sopenharmony_ci    target_os = "illumos",
15b8a62b91Sopenharmony_ci    target_os = "ios",
16b8a62b91Sopenharmony_ci    target_os = "macos",
17b8a62b91Sopenharmony_ci    target_os = "netbsd",
18b8a62b91Sopenharmony_ci    target_os = "openbsd",
19b8a62b91Sopenharmony_ci    target_os = "redox",
20b8a62b91Sopenharmony_ci    target_os = "solaris",
21b8a62b91Sopenharmony_ci)))]
22b8a62b91Sopenharmony_ciuse super::super::offset::libc_posix_fadvise;
23b8a62b91Sopenharmony_ci#[cfg(not(any(
24b8a62b91Sopenharmony_ci    target_os = "aix",
25b8a62b91Sopenharmony_ci    target_os = "android",
26b8a62b91Sopenharmony_ci    target_os = "dragonfly",
27b8a62b91Sopenharmony_ci    target_os = "fuchsia",
28b8a62b91Sopenharmony_ci    target_os = "illumos",
29b8a62b91Sopenharmony_ci    target_os = "ios",
30b8a62b91Sopenharmony_ci    target_os = "linux",
31b8a62b91Sopenharmony_ci    target_os = "macos",
32b8a62b91Sopenharmony_ci    target_os = "netbsd",
33b8a62b91Sopenharmony_ci    target_os = "openbsd",
34b8a62b91Sopenharmony_ci    target_os = "redox",
35b8a62b91Sopenharmony_ci    target_os = "solaris",
36b8a62b91Sopenharmony_ci)))]
37b8a62b91Sopenharmony_ciuse super::super::offset::libc_posix_fallocate;
38b8a62b91Sopenharmony_ciuse super::super::offset::{libc_fstat, libc_fstatat, libc_ftruncate, libc_lseek, libc_off_t};
39b8a62b91Sopenharmony_ci#[cfg(not(any(
40b8a62b91Sopenharmony_ci    target_os = "haiku",
41b8a62b91Sopenharmony_ci    target_os = "illumos",
42b8a62b91Sopenharmony_ci    target_os = "netbsd",
43b8a62b91Sopenharmony_ci    target_os = "redox",
44b8a62b91Sopenharmony_ci    target_os = "solaris",
45b8a62b91Sopenharmony_ci    target_os = "wasi",
46b8a62b91Sopenharmony_ci)))]
47b8a62b91Sopenharmony_ciuse super::super::offset::{libc_fstatfs, libc_statfs};
48b8a62b91Sopenharmony_ci#[cfg(not(any(
49b8a62b91Sopenharmony_ci    target_os = "haiku",
50b8a62b91Sopenharmony_ci    target_os = "illumos",
51b8a62b91Sopenharmony_ci    target_os = "redox",
52b8a62b91Sopenharmony_ci    target_os = "solaris",
53b8a62b91Sopenharmony_ci    target_os = "wasi",
54b8a62b91Sopenharmony_ci)))]
55b8a62b91Sopenharmony_ciuse super::super::offset::{libc_fstatvfs, libc_statvfs};
56b8a62b91Sopenharmony_ci#[cfg(all(
57b8a62b91Sopenharmony_ci    any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
58b8a62b91Sopenharmony_ci    target_env = "gnu",
59b8a62b91Sopenharmony_ci))]
60b8a62b91Sopenharmony_ciuse super::super::time::types::LibcTimespec;
61b8a62b91Sopenharmony_ciuse crate::fd::{BorrowedFd, OwnedFd};
62b8a62b91Sopenharmony_ciuse crate::ffi::CStr;
63b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
64b8a62b91Sopenharmony_ciuse crate::ffi::CString;
65b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
66b8a62b91Sopenharmony_ciuse crate::fs::Access;
67b8a62b91Sopenharmony_ci#[cfg(not(any(
68b8a62b91Sopenharmony_ci    target_os = "dragonfly",
69b8a62b91Sopenharmony_ci    target_os = "haiku",
70b8a62b91Sopenharmony_ci    target_os = "illumos",
71b8a62b91Sopenharmony_ci    target_os = "ios",
72b8a62b91Sopenharmony_ci    target_os = "macos",
73b8a62b91Sopenharmony_ci    target_os = "netbsd",
74b8a62b91Sopenharmony_ci    target_os = "openbsd",
75b8a62b91Sopenharmony_ci    target_os = "redox",
76b8a62b91Sopenharmony_ci    target_os = "solaris",
77b8a62b91Sopenharmony_ci)))]
78b8a62b91Sopenharmony_ciuse crate::fs::Advice;
79b8a62b91Sopenharmony_ci#[cfg(not(any(
80b8a62b91Sopenharmony_ci    target_os = "aix",
81b8a62b91Sopenharmony_ci    target_os = "dragonfly",
82b8a62b91Sopenharmony_ci    target_os = "illumos",
83b8a62b91Sopenharmony_ci    target_os = "netbsd",
84b8a62b91Sopenharmony_ci    target_os = "openbsd",
85b8a62b91Sopenharmony_ci    target_os = "redox",
86b8a62b91Sopenharmony_ci    target_os = "solaris",
87b8a62b91Sopenharmony_ci)))]
88b8a62b91Sopenharmony_ciuse crate::fs::FallocateFlags;
89b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "solaris", target_os = "wasi")))]
90b8a62b91Sopenharmony_ciuse crate::fs::FlockOperation;
91b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
92b8a62b91Sopenharmony_ciuse crate::fs::MemfdFlags;
93b8a62b91Sopenharmony_ci#[cfg(any(
94b8a62b91Sopenharmony_ci    target_os = "android",
95b8a62b91Sopenharmony_ci    target_os = "freebsd",
96b8a62b91Sopenharmony_ci    target_os = "fuchsia",
97b8a62b91Sopenharmony_ci    target_os = "linux",
98b8a62b91Sopenharmony_ci))]
99b8a62b91Sopenharmony_ciuse crate::fs::SealFlags;
100b8a62b91Sopenharmony_ci#[cfg(not(any(
101b8a62b91Sopenharmony_ci    target_os = "haiku",
102b8a62b91Sopenharmony_ci    target_os = "illumos",
103b8a62b91Sopenharmony_ci    target_os = "netbsd",
104b8a62b91Sopenharmony_ci    target_os = "redox",
105b8a62b91Sopenharmony_ci    target_os = "solaris",
106b8a62b91Sopenharmony_ci    target_os = "wasi",
107b8a62b91Sopenharmony_ci)))]
108b8a62b91Sopenharmony_ciuse crate::fs::StatFs;
109b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
110b8a62b91Sopenharmony_ciuse crate::fs::{cwd, RenameFlags, ResolveFlags, Statx, StatxFlags};
111b8a62b91Sopenharmony_ci#[cfg(not(any(
112b8a62b91Sopenharmony_ci    target_os = "ios",
113b8a62b91Sopenharmony_ci    target_os = "macos",
114b8a62b91Sopenharmony_ci    target_os = "redox",
115b8a62b91Sopenharmony_ci    target_os = "wasi",
116b8a62b91Sopenharmony_ci)))]
117b8a62b91Sopenharmony_ciuse crate::fs::{Dev, FileType};
118b8a62b91Sopenharmony_ciuse crate::fs::{Mode, OFlags, Stat, Timestamps};
119b8a62b91Sopenharmony_ci#[cfg(not(any(
120b8a62b91Sopenharmony_ci    target_os = "haiku",
121b8a62b91Sopenharmony_ci    target_os = "illumos",
122b8a62b91Sopenharmony_ci    target_os = "redox",
123b8a62b91Sopenharmony_ci    target_os = "solaris",
124b8a62b91Sopenharmony_ci    target_os = "wasi",
125b8a62b91Sopenharmony_ci)))]
126b8a62b91Sopenharmony_ciuse crate::fs::{StatVfs, StatVfsMountFlags};
127b8a62b91Sopenharmony_ciuse crate::io::{self, SeekFrom};
128b8a62b91Sopenharmony_ci#[cfg(not(target_os = "wasi"))]
129b8a62b91Sopenharmony_ciuse crate::process::{Gid, Uid};
130b8a62b91Sopenharmony_ci#[cfg(not(all(
131b8a62b91Sopenharmony_ci    any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
132b8a62b91Sopenharmony_ci    target_env = "gnu",
133b8a62b91Sopenharmony_ci)))]
134b8a62b91Sopenharmony_ciuse crate::utils::as_ptr;
135b8a62b91Sopenharmony_ciuse core::convert::TryInto;
136b8a62b91Sopenharmony_ci#[cfg(any(
137b8a62b91Sopenharmony_ci    target_os = "android",
138b8a62b91Sopenharmony_ci    target_os = "ios",
139b8a62b91Sopenharmony_ci    target_os = "linux",
140b8a62b91Sopenharmony_ci    target_os = "macos",
141b8a62b91Sopenharmony_ci))]
142b8a62b91Sopenharmony_ciuse core::mem::size_of;
143b8a62b91Sopenharmony_ciuse core::mem::MaybeUninit;
144b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
145b8a62b91Sopenharmony_ciuse core::ptr::null;
146b8a62b91Sopenharmony_ci#[cfg(any(
147b8a62b91Sopenharmony_ci    target_os = "android",
148b8a62b91Sopenharmony_ci    target_os = "ios",
149b8a62b91Sopenharmony_ci    target_os = "linux",
150b8a62b91Sopenharmony_ci    target_os = "macos",
151b8a62b91Sopenharmony_ci))]
152b8a62b91Sopenharmony_ciuse core::ptr::null_mut;
153b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
154b8a62b91Sopenharmony_ciuse {
155b8a62b91Sopenharmony_ci    super::super::conv::nonnegative_ret,
156b8a62b91Sopenharmony_ci    crate::fs::{copyfile_state_t, CloneFlags, CopyfileFlags},
157b8a62b91Sopenharmony_ci};
158b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
159b8a62b91Sopenharmony_ciuse {super::super::offset::libc_openat, crate::fs::AtFlags};
160b8a62b91Sopenharmony_ci
161b8a62b91Sopenharmony_ci#[cfg(all(
162b8a62b91Sopenharmony_ci    any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
163b8a62b91Sopenharmony_ci    target_env = "gnu",
164b8a62b91Sopenharmony_ci))]
165b8a62b91Sopenharmony_ciweak!(fn __utimensat64(c::c_int, *const c::c_char, *const LibcTimespec, c::c_int) -> c::c_int);
166b8a62b91Sopenharmony_ci#[cfg(all(
167b8a62b91Sopenharmony_ci    any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
168b8a62b91Sopenharmony_ci    target_env = "gnu",
169b8a62b91Sopenharmony_ci))]
170b8a62b91Sopenharmony_ciweak!(fn __futimens64(c::c_int, *const LibcTimespec) -> c::c_int);
171b8a62b91Sopenharmony_ci
172b8a62b91Sopenharmony_ci/// Use a direct syscall (via libc) for `openat`.
173b8a62b91Sopenharmony_ci///
174b8a62b91Sopenharmony_ci/// This is only currently necessary as a workaround for old glibc; see below.
175b8a62b91Sopenharmony_ci#[cfg(all(unix, target_env = "gnu"))]
176b8a62b91Sopenharmony_cifn openat_via_syscall(
177b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
178b8a62b91Sopenharmony_ci    path: &CStr,
179b8a62b91Sopenharmony_ci    oflags: OFlags,
180b8a62b91Sopenharmony_ci    mode: Mode,
181b8a62b91Sopenharmony_ci) -> io::Result<OwnedFd> {
182b8a62b91Sopenharmony_ci    unsafe {
183b8a62b91Sopenharmony_ci        let dirfd = borrowed_fd(dirfd);
184b8a62b91Sopenharmony_ci        let path = c_str(path);
185b8a62b91Sopenharmony_ci        let oflags = oflags.bits();
186b8a62b91Sopenharmony_ci        let mode = c::c_uint::from(mode.bits());
187b8a62b91Sopenharmony_ci        ret_owned_fd(c::syscall(
188b8a62b91Sopenharmony_ci            c::SYS_openat,
189b8a62b91Sopenharmony_ci            c::c_long::from(dirfd),
190b8a62b91Sopenharmony_ci            path,
191b8a62b91Sopenharmony_ci            c::c_long::from(oflags),
192b8a62b91Sopenharmony_ci            mode as c::c_long,
193b8a62b91Sopenharmony_ci        ) as c::c_int)
194b8a62b91Sopenharmony_ci    }
195b8a62b91Sopenharmony_ci}
196b8a62b91Sopenharmony_ci
197b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
198b8a62b91Sopenharmony_cipub(crate) fn openat(
199b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
200b8a62b91Sopenharmony_ci    path: &CStr,
201b8a62b91Sopenharmony_ci    oflags: OFlags,
202b8a62b91Sopenharmony_ci    mode: Mode,
203b8a62b91Sopenharmony_ci) -> io::Result<OwnedFd> {
204b8a62b91Sopenharmony_ci    // Work around <https://sourceware.org/bugzilla/show_bug.cgi?id=17523>.
205b8a62b91Sopenharmony_ci    // Basically old glibc versions don't handle O_TMPFILE correctly.
206b8a62b91Sopenharmony_ci    #[cfg(all(unix, target_env = "gnu"))]
207b8a62b91Sopenharmony_ci    if oflags.contains(OFlags::TMPFILE) && crate::backend::if_glibc_is_less_than_2_25() {
208b8a62b91Sopenharmony_ci        return openat_via_syscall(dirfd, path, oflags, mode);
209b8a62b91Sopenharmony_ci    }
210b8a62b91Sopenharmony_ci    unsafe {
211b8a62b91Sopenharmony_ci        // Pass `mode` as a `c_uint` even if `mode_t` is narrower, since
212b8a62b91Sopenharmony_ci        // `libc_openat` is declared as a variadic function and narrower
213b8a62b91Sopenharmony_ci        // arguments are promoted.
214b8a62b91Sopenharmony_ci        ret_owned_fd(libc_openat(
215b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
216b8a62b91Sopenharmony_ci            c_str(path),
217b8a62b91Sopenharmony_ci            oflags.bits(),
218b8a62b91Sopenharmony_ci            c::c_uint::from(mode.bits()),
219b8a62b91Sopenharmony_ci        ))
220b8a62b91Sopenharmony_ci    }
221b8a62b91Sopenharmony_ci}
222b8a62b91Sopenharmony_ci
223b8a62b91Sopenharmony_ci#[cfg(not(any(
224b8a62b91Sopenharmony_ci    target_os = "haiku",
225b8a62b91Sopenharmony_ci    target_os = "illumos",
226b8a62b91Sopenharmony_ci    target_os = "netbsd",
227b8a62b91Sopenharmony_ci    target_os = "redox",
228b8a62b91Sopenharmony_ci    target_os = "solaris",
229b8a62b91Sopenharmony_ci    target_os = "wasi",
230b8a62b91Sopenharmony_ci)))]
231b8a62b91Sopenharmony_ci#[inline]
232b8a62b91Sopenharmony_cipub(crate) fn statfs(filename: &CStr) -> io::Result<StatFs> {
233b8a62b91Sopenharmony_ci    unsafe {
234b8a62b91Sopenharmony_ci        let mut result = MaybeUninit::<StatFs>::uninit();
235b8a62b91Sopenharmony_ci        ret(libc_statfs(c_str(filename), result.as_mut_ptr()))?;
236b8a62b91Sopenharmony_ci        Ok(result.assume_init())
237b8a62b91Sopenharmony_ci    }
238b8a62b91Sopenharmony_ci}
239b8a62b91Sopenharmony_ci
240b8a62b91Sopenharmony_ci#[cfg(not(any(
241b8a62b91Sopenharmony_ci    target_os = "haiku",
242b8a62b91Sopenharmony_ci    target_os = "illumos",
243b8a62b91Sopenharmony_ci    target_os = "redox",
244b8a62b91Sopenharmony_ci    target_os = "solaris",
245b8a62b91Sopenharmony_ci    target_os = "wasi",
246b8a62b91Sopenharmony_ci)))]
247b8a62b91Sopenharmony_ci#[inline]
248b8a62b91Sopenharmony_cipub(crate) fn statvfs(filename: &CStr) -> io::Result<StatVfs> {
249b8a62b91Sopenharmony_ci    unsafe {
250b8a62b91Sopenharmony_ci        let mut result = MaybeUninit::<libc_statvfs>::uninit();
251b8a62b91Sopenharmony_ci        ret(libc_statvfs(c_str(filename), result.as_mut_ptr()))?;
252b8a62b91Sopenharmony_ci        Ok(libc_statvfs_to_statvfs(result.assume_init()))
253b8a62b91Sopenharmony_ci    }
254b8a62b91Sopenharmony_ci}
255b8a62b91Sopenharmony_ci
256b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
257b8a62b91Sopenharmony_ci#[inline]
258b8a62b91Sopenharmony_cipub(crate) fn readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
259b8a62b91Sopenharmony_ci    unsafe {
260b8a62b91Sopenharmony_ci        ret_ssize_t(c::readlinkat(
261b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
262b8a62b91Sopenharmony_ci            c_str(path),
263b8a62b91Sopenharmony_ci            buf.as_mut_ptr().cast::<c::c_char>(),
264b8a62b91Sopenharmony_ci            buf.len(),
265b8a62b91Sopenharmony_ci        ))
266b8a62b91Sopenharmony_ci        .map(|nread| nread as usize)
267b8a62b91Sopenharmony_ci    }
268b8a62b91Sopenharmony_ci}
269b8a62b91Sopenharmony_ci
270b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
271b8a62b91Sopenharmony_cipub(crate) fn mkdirat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
272b8a62b91Sopenharmony_ci    unsafe {
273b8a62b91Sopenharmony_ci        ret(c::mkdirat(
274b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
275b8a62b91Sopenharmony_ci            c_str(path),
276b8a62b91Sopenharmony_ci            mode.bits() as c::mode_t,
277b8a62b91Sopenharmony_ci        ))
278b8a62b91Sopenharmony_ci    }
279b8a62b91Sopenharmony_ci}
280b8a62b91Sopenharmony_ci
281b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
282b8a62b91Sopenharmony_cipub(crate) fn getdents_uninit(
283b8a62b91Sopenharmony_ci    fd: BorrowedFd<'_>,
284b8a62b91Sopenharmony_ci    buf: &mut [MaybeUninit<u8>],
285b8a62b91Sopenharmony_ci) -> io::Result<usize> {
286b8a62b91Sopenharmony_ci    unsafe {
287b8a62b91Sopenharmony_ci        syscall_ret_ssize_t(c::syscall(
288b8a62b91Sopenharmony_ci            c::SYS_getdents64,
289b8a62b91Sopenharmony_ci            fd,
290b8a62b91Sopenharmony_ci            buf.as_mut_ptr().cast::<c::c_char>(),
291b8a62b91Sopenharmony_ci            buf.len(),
292b8a62b91Sopenharmony_ci        ))
293b8a62b91Sopenharmony_ci    }
294b8a62b91Sopenharmony_ci    .map(|nread| nread as usize)
295b8a62b91Sopenharmony_ci}
296b8a62b91Sopenharmony_ci
297b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
298b8a62b91Sopenharmony_cipub(crate) fn linkat(
299b8a62b91Sopenharmony_ci    old_dirfd: BorrowedFd<'_>,
300b8a62b91Sopenharmony_ci    old_path: &CStr,
301b8a62b91Sopenharmony_ci    new_dirfd: BorrowedFd<'_>,
302b8a62b91Sopenharmony_ci    new_path: &CStr,
303b8a62b91Sopenharmony_ci    flags: AtFlags,
304b8a62b91Sopenharmony_ci) -> io::Result<()> {
305b8a62b91Sopenharmony_ci    unsafe {
306b8a62b91Sopenharmony_ci        ret(c::linkat(
307b8a62b91Sopenharmony_ci            borrowed_fd(old_dirfd),
308b8a62b91Sopenharmony_ci            c_str(old_path),
309b8a62b91Sopenharmony_ci            borrowed_fd(new_dirfd),
310b8a62b91Sopenharmony_ci            c_str(new_path),
311b8a62b91Sopenharmony_ci            flags.bits(),
312b8a62b91Sopenharmony_ci        ))
313b8a62b91Sopenharmony_ci    }
314b8a62b91Sopenharmony_ci}
315b8a62b91Sopenharmony_ci
316b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
317b8a62b91Sopenharmony_cipub(crate) fn unlinkat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<()> {
318b8a62b91Sopenharmony_ci    unsafe { ret(c::unlinkat(borrowed_fd(dirfd), c_str(path), flags.bits())) }
319b8a62b91Sopenharmony_ci}
320b8a62b91Sopenharmony_ci
321b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
322b8a62b91Sopenharmony_cipub(crate) fn renameat(
323b8a62b91Sopenharmony_ci    old_dirfd: BorrowedFd<'_>,
324b8a62b91Sopenharmony_ci    old_path: &CStr,
325b8a62b91Sopenharmony_ci    new_dirfd: BorrowedFd<'_>,
326b8a62b91Sopenharmony_ci    new_path: &CStr,
327b8a62b91Sopenharmony_ci) -> io::Result<()> {
328b8a62b91Sopenharmony_ci    unsafe {
329b8a62b91Sopenharmony_ci        ret(c::renameat(
330b8a62b91Sopenharmony_ci            borrowed_fd(old_dirfd),
331b8a62b91Sopenharmony_ci            c_str(old_path),
332b8a62b91Sopenharmony_ci            borrowed_fd(new_dirfd),
333b8a62b91Sopenharmony_ci            c_str(new_path),
334b8a62b91Sopenharmony_ci        ))
335b8a62b91Sopenharmony_ci    }
336b8a62b91Sopenharmony_ci}
337b8a62b91Sopenharmony_ci
338b8a62b91Sopenharmony_ci#[cfg(all(target_os = "linux", target_env = "gnu"))]
339b8a62b91Sopenharmony_cipub(crate) fn renameat2(
340b8a62b91Sopenharmony_ci    old_dirfd: BorrowedFd<'_>,
341b8a62b91Sopenharmony_ci    old_path: &CStr,
342b8a62b91Sopenharmony_ci    new_dirfd: BorrowedFd<'_>,
343b8a62b91Sopenharmony_ci    new_path: &CStr,
344b8a62b91Sopenharmony_ci    flags: RenameFlags,
345b8a62b91Sopenharmony_ci) -> io::Result<()> {
346b8a62b91Sopenharmony_ci    // `getrandom` wasn't supported in glibc until 2.28.
347b8a62b91Sopenharmony_ci    weak_or_syscall! {
348b8a62b91Sopenharmony_ci        fn renameat2(
349b8a62b91Sopenharmony_ci            olddirfd: c::c_int,
350b8a62b91Sopenharmony_ci            oldpath: *const c::c_char,
351b8a62b91Sopenharmony_ci            newdirfd: c::c_int,
352b8a62b91Sopenharmony_ci            newpath: *const c::c_char,
353b8a62b91Sopenharmony_ci            flags: c::c_uint
354b8a62b91Sopenharmony_ci        ) via SYS_renameat2 -> c::c_int
355b8a62b91Sopenharmony_ci    }
356b8a62b91Sopenharmony_ci
357b8a62b91Sopenharmony_ci    unsafe {
358b8a62b91Sopenharmony_ci        ret(renameat2(
359b8a62b91Sopenharmony_ci            borrowed_fd(old_dirfd),
360b8a62b91Sopenharmony_ci            c_str(old_path),
361b8a62b91Sopenharmony_ci            borrowed_fd(new_dirfd),
362b8a62b91Sopenharmony_ci            c_str(new_path),
363b8a62b91Sopenharmony_ci            flags.bits(),
364b8a62b91Sopenharmony_ci        ))
365b8a62b91Sopenharmony_ci    }
366b8a62b91Sopenharmony_ci}
367b8a62b91Sopenharmony_ci
368b8a62b91Sopenharmony_ci/// At present, `libc` only has `renameat2` defined for glibc. On other
369b8a62b91Sopenharmony_ci/// ABIs, `RenameFlags` has no flags defined, and we use plain `renameat`.
370b8a62b91Sopenharmony_ci#[cfg(any(
371b8a62b91Sopenharmony_ci    target_os = "android",
372b8a62b91Sopenharmony_ci    all(target_os = "linux", not(target_env = "gnu")),
373b8a62b91Sopenharmony_ci))]
374b8a62b91Sopenharmony_ci#[inline]
375b8a62b91Sopenharmony_cipub(crate) fn renameat2(
376b8a62b91Sopenharmony_ci    old_dirfd: BorrowedFd<'_>,
377b8a62b91Sopenharmony_ci    old_path: &CStr,
378b8a62b91Sopenharmony_ci    new_dirfd: BorrowedFd<'_>,
379b8a62b91Sopenharmony_ci    new_path: &CStr,
380b8a62b91Sopenharmony_ci    flags: RenameFlags,
381b8a62b91Sopenharmony_ci) -> io::Result<()> {
382b8a62b91Sopenharmony_ci    assert!(flags.is_empty());
383b8a62b91Sopenharmony_ci    renameat(old_dirfd, old_path, new_dirfd, new_path)
384b8a62b91Sopenharmony_ci}
385b8a62b91Sopenharmony_ci
386b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
387b8a62b91Sopenharmony_cipub(crate) fn symlinkat(
388b8a62b91Sopenharmony_ci    old_path: &CStr,
389b8a62b91Sopenharmony_ci    new_dirfd: BorrowedFd<'_>,
390b8a62b91Sopenharmony_ci    new_path: &CStr,
391b8a62b91Sopenharmony_ci) -> io::Result<()> {
392b8a62b91Sopenharmony_ci    unsafe {
393b8a62b91Sopenharmony_ci        ret(c::symlinkat(
394b8a62b91Sopenharmony_ci            c_str(old_path),
395b8a62b91Sopenharmony_ci            borrowed_fd(new_dirfd),
396b8a62b91Sopenharmony_ci            c_str(new_path),
397b8a62b91Sopenharmony_ci        ))
398b8a62b91Sopenharmony_ci    }
399b8a62b91Sopenharmony_ci}
400b8a62b91Sopenharmony_ci
401b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
402b8a62b91Sopenharmony_cipub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
403b8a62b91Sopenharmony_ci    // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
404b8a62b91Sopenharmony_ci    // `statx`.
405b8a62b91Sopenharmony_ci    #[cfg(all(
406b8a62b91Sopenharmony_ci        any(target_os = "android", target_os = "linux"),
407b8a62b91Sopenharmony_ci        any(target_pointer_width = "32", target_arch = "mips64"),
408b8a62b91Sopenharmony_ci    ))]
409b8a62b91Sopenharmony_ci    {
410b8a62b91Sopenharmony_ci        match statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
411b8a62b91Sopenharmony_ci            Ok(x) => statx_to_stat(x),
412b8a62b91Sopenharmony_ci            Err(io::Errno::NOSYS) => statat_old(dirfd, path, flags),
413b8a62b91Sopenharmony_ci            Err(err) => Err(err),
414b8a62b91Sopenharmony_ci        }
415b8a62b91Sopenharmony_ci    }
416b8a62b91Sopenharmony_ci
417b8a62b91Sopenharmony_ci    // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and
418b8a62b91Sopenharmony_ci    // there's nothing practical we can do.
419b8a62b91Sopenharmony_ci    #[cfg(not(all(
420b8a62b91Sopenharmony_ci        any(target_os = "android", target_os = "linux"),
421b8a62b91Sopenharmony_ci        any(target_pointer_width = "32", target_arch = "mips64"),
422b8a62b91Sopenharmony_ci    )))]
423b8a62b91Sopenharmony_ci    unsafe {
424b8a62b91Sopenharmony_ci        let mut stat = MaybeUninit::<Stat>::uninit();
425b8a62b91Sopenharmony_ci        ret(libc_fstatat(
426b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
427b8a62b91Sopenharmony_ci            c_str(path),
428b8a62b91Sopenharmony_ci            stat.as_mut_ptr(),
429b8a62b91Sopenharmony_ci            flags.bits(),
430b8a62b91Sopenharmony_ci        ))?;
431b8a62b91Sopenharmony_ci        Ok(stat.assume_init())
432b8a62b91Sopenharmony_ci    }
433b8a62b91Sopenharmony_ci}
434b8a62b91Sopenharmony_ci
435b8a62b91Sopenharmony_ci#[cfg(all(
436b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
437b8a62b91Sopenharmony_ci    any(target_pointer_width = "32", target_arch = "mips64"),
438b8a62b91Sopenharmony_ci))]
439b8a62b91Sopenharmony_cifn statat_old(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
440b8a62b91Sopenharmony_ci    unsafe {
441b8a62b91Sopenharmony_ci        let mut result = MaybeUninit::<c::stat64>::uninit();
442b8a62b91Sopenharmony_ci        ret(libc_fstatat(
443b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
444b8a62b91Sopenharmony_ci            c_str(path),
445b8a62b91Sopenharmony_ci            result.as_mut_ptr(),
446b8a62b91Sopenharmony_ci            flags.bits(),
447b8a62b91Sopenharmony_ci        ))?;
448b8a62b91Sopenharmony_ci        stat64_to_stat(result.assume_init())
449b8a62b91Sopenharmony_ci    }
450b8a62b91Sopenharmony_ci}
451b8a62b91Sopenharmony_ci
452b8a62b91Sopenharmony_ci#[cfg(not(any(
453b8a62b91Sopenharmony_ci    target_os = "emscripten",
454b8a62b91Sopenharmony_ci    target_os = "illumos",
455b8a62b91Sopenharmony_ci    target_os = "redox",
456b8a62b91Sopenharmony_ci    target_os = "solaris",
457b8a62b91Sopenharmony_ci)))]
458b8a62b91Sopenharmony_cipub(crate) fn accessat(
459b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
460b8a62b91Sopenharmony_ci    path: &CStr,
461b8a62b91Sopenharmony_ci    access: Access,
462b8a62b91Sopenharmony_ci    flags: AtFlags,
463b8a62b91Sopenharmony_ci) -> io::Result<()> {
464b8a62b91Sopenharmony_ci    unsafe {
465b8a62b91Sopenharmony_ci        ret(c::faccessat(
466b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
467b8a62b91Sopenharmony_ci            c_str(path),
468b8a62b91Sopenharmony_ci            access.bits(),
469b8a62b91Sopenharmony_ci            flags.bits(),
470b8a62b91Sopenharmony_ci        ))
471b8a62b91Sopenharmony_ci    }
472b8a62b91Sopenharmony_ci}
473b8a62b91Sopenharmony_ci
474b8a62b91Sopenharmony_ci#[cfg(target_os = "emscripten")]
475b8a62b91Sopenharmony_cipub(crate) fn accessat(
476b8a62b91Sopenharmony_ci    _dirfd: BorrowedFd<'_>,
477b8a62b91Sopenharmony_ci    _path: &CStr,
478b8a62b91Sopenharmony_ci    _access: Access,
479b8a62b91Sopenharmony_ci    _flags: AtFlags,
480b8a62b91Sopenharmony_ci) -> io::Result<()> {
481b8a62b91Sopenharmony_ci    Ok(())
482b8a62b91Sopenharmony_ci}
483b8a62b91Sopenharmony_ci
484b8a62b91Sopenharmony_ci#[cfg(not(target_os = "redox"))]
485b8a62b91Sopenharmony_cipub(crate) fn utimensat(
486b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
487b8a62b91Sopenharmony_ci    path: &CStr,
488b8a62b91Sopenharmony_ci    times: &Timestamps,
489b8a62b91Sopenharmony_ci    flags: AtFlags,
490b8a62b91Sopenharmony_ci) -> io::Result<()> {
491b8a62b91Sopenharmony_ci    // 32-bit gnu version: libc has `utimensat` but it is not y2038 safe by
492b8a62b91Sopenharmony_ci    // default.
493b8a62b91Sopenharmony_ci    #[cfg(all(
494b8a62b91Sopenharmony_ci        any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
495b8a62b91Sopenharmony_ci        target_env = "gnu",
496b8a62b91Sopenharmony_ci    ))]
497b8a62b91Sopenharmony_ci    unsafe {
498b8a62b91Sopenharmony_ci        if let Some(libc_utimensat) = __utimensat64.get() {
499b8a62b91Sopenharmony_ci            let libc_times: [LibcTimespec; 2] = [
500b8a62b91Sopenharmony_ci                times.last_access.clone().into(),
501b8a62b91Sopenharmony_ci                times.last_modification.clone().into(),
502b8a62b91Sopenharmony_ci            ];
503b8a62b91Sopenharmony_ci
504b8a62b91Sopenharmony_ci            ret(libc_utimensat(
505b8a62b91Sopenharmony_ci                borrowed_fd(dirfd),
506b8a62b91Sopenharmony_ci                c_str(path),
507b8a62b91Sopenharmony_ci                libc_times.as_ptr(),
508b8a62b91Sopenharmony_ci                flags.bits(),
509b8a62b91Sopenharmony_ci            ))
510b8a62b91Sopenharmony_ci        } else {
511b8a62b91Sopenharmony_ci            utimensat_old(dirfd, path, times, flags)
512b8a62b91Sopenharmony_ci        }
513b8a62b91Sopenharmony_ci    }
514b8a62b91Sopenharmony_ci
515b8a62b91Sopenharmony_ci    // Main version: libc is y2038 safe and has `utimensat`. Or, the platform
516b8a62b91Sopenharmony_ci    // is not y2038 safe and there's nothing practical we can do.
517b8a62b91Sopenharmony_ci    #[cfg(not(any(
518b8a62b91Sopenharmony_ci        target_os = "ios",
519b8a62b91Sopenharmony_ci        target_os = "macos",
520b8a62b91Sopenharmony_ci        all(
521b8a62b91Sopenharmony_ci            any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
522b8a62b91Sopenharmony_ci            target_env = "gnu",
523b8a62b91Sopenharmony_ci        )
524b8a62b91Sopenharmony_ci    )))]
525b8a62b91Sopenharmony_ci    unsafe {
526b8a62b91Sopenharmony_ci        // Assert that `Timestamps` has the expected layout.
527b8a62b91Sopenharmony_ci        let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone());
528b8a62b91Sopenharmony_ci
529b8a62b91Sopenharmony_ci        ret(c::utimensat(
530b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
531b8a62b91Sopenharmony_ci            c_str(path),
532b8a62b91Sopenharmony_ci            as_ptr(times).cast(),
533b8a62b91Sopenharmony_ci            flags.bits(),
534b8a62b91Sopenharmony_ci        ))
535b8a62b91Sopenharmony_ci    }
536b8a62b91Sopenharmony_ci
537b8a62b91Sopenharmony_ci    // `utimensat` was introduced in macOS 10.13.
538b8a62b91Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os = "macos"))]
539b8a62b91Sopenharmony_ci    unsafe {
540b8a62b91Sopenharmony_ci        // ABI details
541b8a62b91Sopenharmony_ci        weak! {
542b8a62b91Sopenharmony_ci            fn utimensat(
543b8a62b91Sopenharmony_ci                c::c_int,
544b8a62b91Sopenharmony_ci                *const c::c_char,
545b8a62b91Sopenharmony_ci                *const c::timespec,
546b8a62b91Sopenharmony_ci                c::c_int
547b8a62b91Sopenharmony_ci            ) -> c::c_int
548b8a62b91Sopenharmony_ci        }
549b8a62b91Sopenharmony_ci        extern "C" {
550b8a62b91Sopenharmony_ci            fn setattrlist(
551b8a62b91Sopenharmony_ci                path: *const c::c_char,
552b8a62b91Sopenharmony_ci                attr_list: *const Attrlist,
553b8a62b91Sopenharmony_ci                attr_buf: *const c::c_void,
554b8a62b91Sopenharmony_ci                attr_buf_size: c::size_t,
555b8a62b91Sopenharmony_ci                options: c::c_ulong,
556b8a62b91Sopenharmony_ci            ) -> c::c_int;
557b8a62b91Sopenharmony_ci        }
558b8a62b91Sopenharmony_ci        const FSOPT_NOFOLLOW: c::c_ulong = 0x0000_0001;
559b8a62b91Sopenharmony_ci
560b8a62b91Sopenharmony_ci        // If we have `utimensat`, use it.
561b8a62b91Sopenharmony_ci        if let Some(have_utimensat) = utimensat.get() {
562b8a62b91Sopenharmony_ci            // Assert that `Timestamps` has the expected layout.
563b8a62b91Sopenharmony_ci            let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone());
564b8a62b91Sopenharmony_ci
565b8a62b91Sopenharmony_ci            return ret(have_utimensat(
566b8a62b91Sopenharmony_ci                borrowed_fd(dirfd),
567b8a62b91Sopenharmony_ci                c_str(path),
568b8a62b91Sopenharmony_ci                as_ptr(times).cast(),
569b8a62b91Sopenharmony_ci                flags.bits(),
570b8a62b91Sopenharmony_ci            ));
571b8a62b91Sopenharmony_ci        }
572b8a62b91Sopenharmony_ci
573b8a62b91Sopenharmony_ci        // `setattrlistat` was introduced in 10.13 along with `utimensat`, so if
574b8a62b91Sopenharmony_ci        // we don't have `utimensat`, we don't have `setattrlistat` either.
575b8a62b91Sopenharmony_ci        // Emulate it using `fork`, and `fchdir` and [`setattrlist`].
576b8a62b91Sopenharmony_ci        //
577b8a62b91Sopenharmony_ci        // [`setattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setattrlist.2.html
578b8a62b91Sopenharmony_ci        match c::fork() {
579b8a62b91Sopenharmony_ci            -1 => Err(io::Errno::IO),
580b8a62b91Sopenharmony_ci            0 => {
581b8a62b91Sopenharmony_ci                if c::fchdir(borrowed_fd(dirfd)) != 0 {
582b8a62b91Sopenharmony_ci                    let code = match libc_errno::errno().0 {
583b8a62b91Sopenharmony_ci                        c::EACCES => 2,
584b8a62b91Sopenharmony_ci                        c::ENOTDIR => 3,
585b8a62b91Sopenharmony_ci                        _ => 1,
586b8a62b91Sopenharmony_ci                    };
587b8a62b91Sopenharmony_ci                    c::_exit(code);
588b8a62b91Sopenharmony_ci                }
589b8a62b91Sopenharmony_ci
590b8a62b91Sopenharmony_ci                let mut flags_arg = 0;
591b8a62b91Sopenharmony_ci                if flags.contains(AtFlags::SYMLINK_NOFOLLOW) {
592b8a62b91Sopenharmony_ci                    flags_arg |= FSOPT_NOFOLLOW;
593b8a62b91Sopenharmony_ci                }
594b8a62b91Sopenharmony_ci
595b8a62b91Sopenharmony_ci                let (attrbuf_size, times, attrs) = times_to_attrlist(times);
596b8a62b91Sopenharmony_ci
597b8a62b91Sopenharmony_ci                if setattrlist(
598b8a62b91Sopenharmony_ci                    c_str(path),
599b8a62b91Sopenharmony_ci                    &attrs,
600b8a62b91Sopenharmony_ci                    as_ptr(&times).cast(),
601b8a62b91Sopenharmony_ci                    attrbuf_size,
602b8a62b91Sopenharmony_ci                    flags_arg,
603b8a62b91Sopenharmony_ci                ) != 0
604b8a62b91Sopenharmony_ci                {
605b8a62b91Sopenharmony_ci                    // Translate expected errno codes into ad-hoc integer
606b8a62b91Sopenharmony_ci                    // values suitable for exit statuses.
607b8a62b91Sopenharmony_ci                    let code = match libc_errno::errno().0 {
608b8a62b91Sopenharmony_ci                        c::EACCES => 2,
609b8a62b91Sopenharmony_ci                        c::ENOTDIR => 3,
610b8a62b91Sopenharmony_ci                        c::EPERM => 4,
611b8a62b91Sopenharmony_ci                        c::EROFS => 5,
612b8a62b91Sopenharmony_ci                        c::ELOOP => 6,
613b8a62b91Sopenharmony_ci                        c::ENOENT => 7,
614b8a62b91Sopenharmony_ci                        c::ENAMETOOLONG => 8,
615b8a62b91Sopenharmony_ci                        c::EINVAL => 9,
616b8a62b91Sopenharmony_ci                        c::ESRCH => 10,
617b8a62b91Sopenharmony_ci                        c::ENOTSUP => 11,
618b8a62b91Sopenharmony_ci                        _ => 1,
619b8a62b91Sopenharmony_ci                    };
620b8a62b91Sopenharmony_ci                    c::_exit(code);
621b8a62b91Sopenharmony_ci                }
622b8a62b91Sopenharmony_ci
623b8a62b91Sopenharmony_ci                c::_exit(0);
624b8a62b91Sopenharmony_ci            }
625b8a62b91Sopenharmony_ci            child_pid => {
626b8a62b91Sopenharmony_ci                let mut wstatus = 0;
627b8a62b91Sopenharmony_ci                let _ = ret_c_int(c::waitpid(child_pid, &mut wstatus, 0))?;
628b8a62b91Sopenharmony_ci                if c::WIFEXITED(wstatus) {
629b8a62b91Sopenharmony_ci                    // Translate our ad-hoc exit statuses back to errno codes.
630b8a62b91Sopenharmony_ci                    match c::WEXITSTATUS(wstatus) {
631b8a62b91Sopenharmony_ci                        0 => Ok(()),
632b8a62b91Sopenharmony_ci                        2 => Err(io::Errno::ACCESS),
633b8a62b91Sopenharmony_ci                        3 => Err(io::Errno::NOTDIR),
634b8a62b91Sopenharmony_ci                        4 => Err(io::Errno::PERM),
635b8a62b91Sopenharmony_ci                        5 => Err(io::Errno::ROFS),
636b8a62b91Sopenharmony_ci                        6 => Err(io::Errno::LOOP),
637b8a62b91Sopenharmony_ci                        7 => Err(io::Errno::NOENT),
638b8a62b91Sopenharmony_ci                        8 => Err(io::Errno::NAMETOOLONG),
639b8a62b91Sopenharmony_ci                        9 => Err(io::Errno::INVAL),
640b8a62b91Sopenharmony_ci                        10 => Err(io::Errno::SRCH),
641b8a62b91Sopenharmony_ci                        11 => Err(io::Errno::NOTSUP),
642b8a62b91Sopenharmony_ci                        _ => Err(io::Errno::IO),
643b8a62b91Sopenharmony_ci                    }
644b8a62b91Sopenharmony_ci                } else {
645b8a62b91Sopenharmony_ci                    Err(io::Errno::IO)
646b8a62b91Sopenharmony_ci                }
647b8a62b91Sopenharmony_ci            }
648b8a62b91Sopenharmony_ci        }
649b8a62b91Sopenharmony_ci    }
650b8a62b91Sopenharmony_ci}
651b8a62b91Sopenharmony_ci
652b8a62b91Sopenharmony_ci#[cfg(all(
653b8a62b91Sopenharmony_ci    any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
654b8a62b91Sopenharmony_ci    target_env = "gnu",
655b8a62b91Sopenharmony_ci))]
656b8a62b91Sopenharmony_ciunsafe fn utimensat_old(
657b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
658b8a62b91Sopenharmony_ci    path: &CStr,
659b8a62b91Sopenharmony_ci    times: &Timestamps,
660b8a62b91Sopenharmony_ci    flags: AtFlags,
661b8a62b91Sopenharmony_ci) -> io::Result<()> {
662b8a62b91Sopenharmony_ci    let old_times = [
663b8a62b91Sopenharmony_ci        c::timespec {
664b8a62b91Sopenharmony_ci            tv_sec: times
665b8a62b91Sopenharmony_ci                .last_access
666b8a62b91Sopenharmony_ci                .tv_sec
667b8a62b91Sopenharmony_ci                .try_into()
668b8a62b91Sopenharmony_ci                .map_err(|_| io::Errno::OVERFLOW)?,
669b8a62b91Sopenharmony_ci            tv_nsec: times.last_access.tv_nsec,
670b8a62b91Sopenharmony_ci        },
671b8a62b91Sopenharmony_ci        c::timespec {
672b8a62b91Sopenharmony_ci            tv_sec: times
673b8a62b91Sopenharmony_ci                .last_modification
674b8a62b91Sopenharmony_ci                .tv_sec
675b8a62b91Sopenharmony_ci                .try_into()
676b8a62b91Sopenharmony_ci                .map_err(|_| io::Errno::OVERFLOW)?,
677b8a62b91Sopenharmony_ci            tv_nsec: times.last_modification.tv_nsec,
678b8a62b91Sopenharmony_ci        },
679b8a62b91Sopenharmony_ci    ];
680b8a62b91Sopenharmony_ci    ret(c::utimensat(
681b8a62b91Sopenharmony_ci        borrowed_fd(dirfd),
682b8a62b91Sopenharmony_ci        c_str(path),
683b8a62b91Sopenharmony_ci        old_times.as_ptr(),
684b8a62b91Sopenharmony_ci        flags.bits(),
685b8a62b91Sopenharmony_ci    ))
686b8a62b91Sopenharmony_ci}
687b8a62b91Sopenharmony_ci
688b8a62b91Sopenharmony_ci#[cfg(not(any(
689b8a62b91Sopenharmony_ci    target_os = "android",
690b8a62b91Sopenharmony_ci    target_os = "linux",
691b8a62b91Sopenharmony_ci    target_os = "redox",
692b8a62b91Sopenharmony_ci    target_os = "wasi",
693b8a62b91Sopenharmony_ci)))]
694b8a62b91Sopenharmony_cipub(crate) fn chmodat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
695b8a62b91Sopenharmony_ci    unsafe { ret(c::fchmodat(borrowed_fd(dirfd), c_str(path), mode.bits(), 0)) }
696b8a62b91Sopenharmony_ci}
697b8a62b91Sopenharmony_ci
698b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
699b8a62b91Sopenharmony_cipub(crate) fn chmodat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
700b8a62b91Sopenharmony_ci    // Linux's `fchmodat` does not have a flags argument.
701b8a62b91Sopenharmony_ci    unsafe {
702b8a62b91Sopenharmony_ci        // Pass `mode` as a `c_uint` even if `mode_t` is narrower, since
703b8a62b91Sopenharmony_ci        // `libc_openat` is declared as a variadic function and narrower
704b8a62b91Sopenharmony_ci        // arguments are promoted.
705b8a62b91Sopenharmony_ci        syscall_ret(c::syscall(
706b8a62b91Sopenharmony_ci            c::SYS_fchmodat,
707b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
708b8a62b91Sopenharmony_ci            c_str(path),
709b8a62b91Sopenharmony_ci            c::c_uint::from(mode.bits()),
710b8a62b91Sopenharmony_ci        ))
711b8a62b91Sopenharmony_ci    }
712b8a62b91Sopenharmony_ci}
713b8a62b91Sopenharmony_ci
714b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
715b8a62b91Sopenharmony_cipub(crate) fn fclonefileat(
716b8a62b91Sopenharmony_ci    srcfd: BorrowedFd<'_>,
717b8a62b91Sopenharmony_ci    dst_dirfd: BorrowedFd<'_>,
718b8a62b91Sopenharmony_ci    dst: &CStr,
719b8a62b91Sopenharmony_ci    flags: CloneFlags,
720b8a62b91Sopenharmony_ci) -> io::Result<()> {
721b8a62b91Sopenharmony_ci    syscall! {
722b8a62b91Sopenharmony_ci        fn fclonefileat(
723b8a62b91Sopenharmony_ci            srcfd: BorrowedFd<'_>,
724b8a62b91Sopenharmony_ci            dst_dirfd: BorrowedFd<'_>,
725b8a62b91Sopenharmony_ci            dst: *const c::c_char,
726b8a62b91Sopenharmony_ci            flags: c::c_int
727b8a62b91Sopenharmony_ci        ) via SYS_fclonefileat -> c::c_int
728b8a62b91Sopenharmony_ci    }
729b8a62b91Sopenharmony_ci
730b8a62b91Sopenharmony_ci    unsafe { ret(fclonefileat(srcfd, dst_dirfd, c_str(dst), flags.bits())) }
731b8a62b91Sopenharmony_ci}
732b8a62b91Sopenharmony_ci
733b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
734b8a62b91Sopenharmony_cipub(crate) fn chownat(
735b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
736b8a62b91Sopenharmony_ci    path: &CStr,
737b8a62b91Sopenharmony_ci    owner: Option<Uid>,
738b8a62b91Sopenharmony_ci    group: Option<Gid>,
739b8a62b91Sopenharmony_ci    flags: AtFlags,
740b8a62b91Sopenharmony_ci) -> io::Result<()> {
741b8a62b91Sopenharmony_ci    unsafe {
742b8a62b91Sopenharmony_ci        let (ow, gr) = crate::process::translate_fchown_args(owner, group);
743b8a62b91Sopenharmony_ci        ret(c::fchownat(
744b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
745b8a62b91Sopenharmony_ci            c_str(path),
746b8a62b91Sopenharmony_ci            ow,
747b8a62b91Sopenharmony_ci            gr,
748b8a62b91Sopenharmony_ci            flags.bits(),
749b8a62b91Sopenharmony_ci        ))
750b8a62b91Sopenharmony_ci    }
751b8a62b91Sopenharmony_ci}
752b8a62b91Sopenharmony_ci
753b8a62b91Sopenharmony_ci#[cfg(not(any(
754b8a62b91Sopenharmony_ci    target_os = "ios",
755b8a62b91Sopenharmony_ci    target_os = "macos",
756b8a62b91Sopenharmony_ci    target_os = "redox",
757b8a62b91Sopenharmony_ci    target_os = "wasi",
758b8a62b91Sopenharmony_ci)))]
759b8a62b91Sopenharmony_cipub(crate) fn mknodat(
760b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
761b8a62b91Sopenharmony_ci    path: &CStr,
762b8a62b91Sopenharmony_ci    file_type: FileType,
763b8a62b91Sopenharmony_ci    mode: Mode,
764b8a62b91Sopenharmony_ci    dev: Dev,
765b8a62b91Sopenharmony_ci) -> io::Result<()> {
766b8a62b91Sopenharmony_ci    unsafe {
767b8a62b91Sopenharmony_ci        ret(c::mknodat(
768b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
769b8a62b91Sopenharmony_ci            c_str(path),
770b8a62b91Sopenharmony_ci            (mode.bits() | file_type.as_raw_mode()) as c::mode_t,
771b8a62b91Sopenharmony_ci            dev.try_into().map_err(|_e| io::Errno::PERM)?,
772b8a62b91Sopenharmony_ci        ))
773b8a62b91Sopenharmony_ci    }
774b8a62b91Sopenharmony_ci}
775b8a62b91Sopenharmony_ci
776b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
777b8a62b91Sopenharmony_cipub(crate) fn copy_file_range(
778b8a62b91Sopenharmony_ci    fd_in: BorrowedFd<'_>,
779b8a62b91Sopenharmony_ci    off_in: Option<&mut u64>,
780b8a62b91Sopenharmony_ci    fd_out: BorrowedFd<'_>,
781b8a62b91Sopenharmony_ci    off_out: Option<&mut u64>,
782b8a62b91Sopenharmony_ci    len: u64,
783b8a62b91Sopenharmony_ci) -> io::Result<u64> {
784b8a62b91Sopenharmony_ci    assert_eq!(size_of::<c::loff_t>(), size_of::<u64>());
785b8a62b91Sopenharmony_ci
786b8a62b91Sopenharmony_ci    let mut off_in_val: c::loff_t = 0;
787b8a62b91Sopenharmony_ci    let mut off_out_val: c::loff_t = 0;
788b8a62b91Sopenharmony_ci    // Silently cast; we'll get `EINVAL` if the value is negative.
789b8a62b91Sopenharmony_ci    let off_in_ptr = if let Some(off_in) = &off_in {
790b8a62b91Sopenharmony_ci        off_in_val = (**off_in) as i64;
791b8a62b91Sopenharmony_ci        &mut off_in_val
792b8a62b91Sopenharmony_ci    } else {
793b8a62b91Sopenharmony_ci        null_mut()
794b8a62b91Sopenharmony_ci    };
795b8a62b91Sopenharmony_ci    let off_out_ptr = if let Some(off_out) = &off_out {
796b8a62b91Sopenharmony_ci        off_out_val = (**off_out) as i64;
797b8a62b91Sopenharmony_ci        &mut off_out_val
798b8a62b91Sopenharmony_ci    } else {
799b8a62b91Sopenharmony_ci        null_mut()
800b8a62b91Sopenharmony_ci    };
801b8a62b91Sopenharmony_ci    let len: usize = len.try_into().unwrap_or(usize::MAX);
802b8a62b91Sopenharmony_ci    let copied = unsafe {
803b8a62b91Sopenharmony_ci        syscall_ret_ssize_t(c::syscall(
804b8a62b91Sopenharmony_ci            c::SYS_copy_file_range,
805b8a62b91Sopenharmony_ci            borrowed_fd(fd_in),
806b8a62b91Sopenharmony_ci            off_in_ptr,
807b8a62b91Sopenharmony_ci            borrowed_fd(fd_out),
808b8a62b91Sopenharmony_ci            off_out_ptr,
809b8a62b91Sopenharmony_ci            len,
810b8a62b91Sopenharmony_ci            0, // no flags are defined yet
811b8a62b91Sopenharmony_ci        ))?
812b8a62b91Sopenharmony_ci    };
813b8a62b91Sopenharmony_ci    if let Some(off_in) = off_in {
814b8a62b91Sopenharmony_ci        *off_in = off_in_val as u64;
815b8a62b91Sopenharmony_ci    }
816b8a62b91Sopenharmony_ci    if let Some(off_out) = off_out {
817b8a62b91Sopenharmony_ci        *off_out = off_out_val as u64;
818b8a62b91Sopenharmony_ci    }
819b8a62b91Sopenharmony_ci    Ok(copied as u64)
820b8a62b91Sopenharmony_ci}
821b8a62b91Sopenharmony_ci
822b8a62b91Sopenharmony_ci#[cfg(not(any(
823b8a62b91Sopenharmony_ci    target_os = "dragonfly",
824b8a62b91Sopenharmony_ci    target_os = "haiku",
825b8a62b91Sopenharmony_ci    target_os = "illumos",
826b8a62b91Sopenharmony_ci    target_os = "ios",
827b8a62b91Sopenharmony_ci    target_os = "macos",
828b8a62b91Sopenharmony_ci    target_os = "netbsd",
829b8a62b91Sopenharmony_ci    target_os = "openbsd",
830b8a62b91Sopenharmony_ci    target_os = "redox",
831b8a62b91Sopenharmony_ci    target_os = "solaris",
832b8a62b91Sopenharmony_ci)))]
833b8a62b91Sopenharmony_cipub(crate) fn fadvise(fd: BorrowedFd<'_>, offset: u64, len: u64, advice: Advice) -> io::Result<()> {
834b8a62b91Sopenharmony_ci    let offset = offset as i64;
835b8a62b91Sopenharmony_ci    let len = len as i64;
836b8a62b91Sopenharmony_ci
837b8a62b91Sopenharmony_ci    // FreeBSD returns `EINVAL` on invalid offsets; emulate the POSIX behavior.
838b8a62b91Sopenharmony_ci    #[cfg(target_os = "freebsd")]
839b8a62b91Sopenharmony_ci    let offset = if (offset as i64) < 0 {
840b8a62b91Sopenharmony_ci        i64::MAX
841b8a62b91Sopenharmony_ci    } else {
842b8a62b91Sopenharmony_ci        offset
843b8a62b91Sopenharmony_ci    };
844b8a62b91Sopenharmony_ci
845b8a62b91Sopenharmony_ci    // FreeBSD returns `EINVAL` on overflow; emulate the POSIX behavior.
846b8a62b91Sopenharmony_ci    #[cfg(target_os = "freebsd")]
847b8a62b91Sopenharmony_ci    let len = if len > 0 && offset.checked_add(len).is_none() {
848b8a62b91Sopenharmony_ci        i64::MAX - offset
849b8a62b91Sopenharmony_ci    } else {
850b8a62b91Sopenharmony_ci        len
851b8a62b91Sopenharmony_ci    };
852b8a62b91Sopenharmony_ci
853b8a62b91Sopenharmony_ci    let err = unsafe { libc_posix_fadvise(borrowed_fd(fd), offset, len, advice as c::c_int) };
854b8a62b91Sopenharmony_ci
855b8a62b91Sopenharmony_ci    // `posix_fadvise` returns its error status rather than using `errno`.
856b8a62b91Sopenharmony_ci    if err == 0 {
857b8a62b91Sopenharmony_ci        Ok(())
858b8a62b91Sopenharmony_ci    } else {
859b8a62b91Sopenharmony_ci        Err(io::Errno(err))
860b8a62b91Sopenharmony_ci    }
861b8a62b91Sopenharmony_ci}
862b8a62b91Sopenharmony_ci
863b8a62b91Sopenharmony_cipub(crate) fn fcntl_getfl(fd: BorrowedFd<'_>) -> io::Result<OFlags> {
864b8a62b91Sopenharmony_ci    unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFL)).map(OFlags::from_bits_truncate) }
865b8a62b91Sopenharmony_ci}
866b8a62b91Sopenharmony_ci
867b8a62b91Sopenharmony_cipub(crate) fn fcntl_setfl(fd: BorrowedFd<'_>, flags: OFlags) -> io::Result<()> {
868b8a62b91Sopenharmony_ci    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFL, flags.bits())) }
869b8a62b91Sopenharmony_ci}
870b8a62b91Sopenharmony_ci
871b8a62b91Sopenharmony_ci#[cfg(any(
872b8a62b91Sopenharmony_ci    target_os = "android",
873b8a62b91Sopenharmony_ci    target_os = "freebsd",
874b8a62b91Sopenharmony_ci    target_os = "fuchsia",
875b8a62b91Sopenharmony_ci    target_os = "linux",
876b8a62b91Sopenharmony_ci))]
877b8a62b91Sopenharmony_cipub(crate) fn fcntl_get_seals(fd: BorrowedFd<'_>) -> io::Result<SealFlags> {
878b8a62b91Sopenharmony_ci    unsafe {
879b8a62b91Sopenharmony_ci        ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GET_SEALS))
880b8a62b91Sopenharmony_ci            .map(|flags| SealFlags::from_bits_unchecked(flags))
881b8a62b91Sopenharmony_ci    }
882b8a62b91Sopenharmony_ci}
883b8a62b91Sopenharmony_ci
884b8a62b91Sopenharmony_ci#[cfg(any(
885b8a62b91Sopenharmony_ci    target_os = "android",
886b8a62b91Sopenharmony_ci    target_os = "freebsd",
887b8a62b91Sopenharmony_ci    target_os = "fuchsia",
888b8a62b91Sopenharmony_ci    target_os = "linux",
889b8a62b91Sopenharmony_ci))]
890b8a62b91Sopenharmony_cipub(crate) fn fcntl_add_seals(fd: BorrowedFd<'_>, seals: SealFlags) -> io::Result<()> {
891b8a62b91Sopenharmony_ci    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_ADD_SEALS, seals.bits())) }
892b8a62b91Sopenharmony_ci}
893b8a62b91Sopenharmony_ci
894b8a62b91Sopenharmony_cipub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> {
895b8a62b91Sopenharmony_ci    let (whence, offset): (c::c_int, libc_off_t) = match pos {
896b8a62b91Sopenharmony_ci        SeekFrom::Start(pos) => {
897b8a62b91Sopenharmony_ci            let pos: u64 = pos;
898b8a62b91Sopenharmony_ci            // Silently cast; we'll get `EINVAL` if the value is negative.
899b8a62b91Sopenharmony_ci            (c::SEEK_SET, pos as i64)
900b8a62b91Sopenharmony_ci        }
901b8a62b91Sopenharmony_ci        SeekFrom::End(offset) => (c::SEEK_END, offset),
902b8a62b91Sopenharmony_ci        SeekFrom::Current(offset) => (c::SEEK_CUR, offset),
903b8a62b91Sopenharmony_ci    };
904b8a62b91Sopenharmony_ci    let offset = unsafe { ret_off_t(libc_lseek(borrowed_fd(fd), offset, whence))? };
905b8a62b91Sopenharmony_ci    Ok(offset as u64)
906b8a62b91Sopenharmony_ci}
907b8a62b91Sopenharmony_ci
908b8a62b91Sopenharmony_cipub(crate) fn tell(fd: BorrowedFd<'_>) -> io::Result<u64> {
909b8a62b91Sopenharmony_ci    let offset = unsafe { ret_off_t(libc_lseek(borrowed_fd(fd), 0, c::SEEK_CUR))? };
910b8a62b91Sopenharmony_ci    Ok(offset as u64)
911b8a62b91Sopenharmony_ci}
912b8a62b91Sopenharmony_ci
913b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "wasi")))]
914b8a62b91Sopenharmony_cipub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> {
915b8a62b91Sopenharmony_ci    unsafe { ret(c::fchmod(borrowed_fd(fd), mode.bits())) }
916b8a62b91Sopenharmony_ci}
917b8a62b91Sopenharmony_ci
918b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
919b8a62b91Sopenharmony_cipub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> {
920b8a62b91Sopenharmony_ci    // Use `c::syscall` rather than `c::fchmod` because some libc
921b8a62b91Sopenharmony_ci    // implementations, such as musl, add extra logic to `fchmod` to emulate
922b8a62b91Sopenharmony_ci    // support for `O_PATH`, which uses `/proc` outside our control and
923b8a62b91Sopenharmony_ci    // interferes with our own use of `O_PATH`.
924b8a62b91Sopenharmony_ci    unsafe {
925b8a62b91Sopenharmony_ci        syscall_ret(c::syscall(
926b8a62b91Sopenharmony_ci            c::SYS_fchmod,
927b8a62b91Sopenharmony_ci            borrowed_fd(fd),
928b8a62b91Sopenharmony_ci            c::c_uint::from(mode.bits()),
929b8a62b91Sopenharmony_ci        ))
930b8a62b91Sopenharmony_ci    }
931b8a62b91Sopenharmony_ci}
932b8a62b91Sopenharmony_ci
933b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
934b8a62b91Sopenharmony_cipub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
935b8a62b91Sopenharmony_ci    // Use `c::syscall` rather than `c::fchown` because some libc
936b8a62b91Sopenharmony_ci    // implementations, such as musl, add extra logic to `fchown` to emulate
937b8a62b91Sopenharmony_ci    // support for `O_PATH`, which uses `/proc` outside our control and
938b8a62b91Sopenharmony_ci    // interferes with our own use of `O_PATH`.
939b8a62b91Sopenharmony_ci    unsafe {
940b8a62b91Sopenharmony_ci        let (ow, gr) = crate::process::translate_fchown_args(owner, group);
941b8a62b91Sopenharmony_ci        syscall_ret(c::syscall(c::SYS_fchown, borrowed_fd(fd), ow, gr))
942b8a62b91Sopenharmony_ci    }
943b8a62b91Sopenharmony_ci}
944b8a62b91Sopenharmony_ci
945b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "wasi")))]
946b8a62b91Sopenharmony_cipub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option<Uid>, group: Option<Gid>) -> io::Result<()> {
947b8a62b91Sopenharmony_ci    unsafe {
948b8a62b91Sopenharmony_ci        let (ow, gr) = crate::process::translate_fchown_args(owner, group);
949b8a62b91Sopenharmony_ci        ret(c::fchown(borrowed_fd(fd), ow, gr))
950b8a62b91Sopenharmony_ci    }
951b8a62b91Sopenharmony_ci}
952b8a62b91Sopenharmony_ci
953b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "solaris", target_os = "wasi")))]
954b8a62b91Sopenharmony_cipub(crate) fn flock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::Result<()> {
955b8a62b91Sopenharmony_ci    unsafe { ret(c::flock(borrowed_fd(fd), operation as c::c_int)) }
956b8a62b91Sopenharmony_ci}
957b8a62b91Sopenharmony_ci
958b8a62b91Sopenharmony_cipub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
959b8a62b91Sopenharmony_ci    // 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
960b8a62b91Sopenharmony_ci    // `statx`.
961b8a62b91Sopenharmony_ci    #[cfg(all(
962b8a62b91Sopenharmony_ci        any(target_os = "android", target_os = "linux"),
963b8a62b91Sopenharmony_ci        any(target_pointer_width = "32", target_arch = "mips64"),
964b8a62b91Sopenharmony_ci    ))]
965b8a62b91Sopenharmony_ci    {
966b8a62b91Sopenharmony_ci        match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
967b8a62b91Sopenharmony_ci            Ok(x) => statx_to_stat(x),
968b8a62b91Sopenharmony_ci            Err(io::Errno::NOSYS) => fstat_old(fd),
969b8a62b91Sopenharmony_ci            Err(err) => Err(err),
970b8a62b91Sopenharmony_ci        }
971b8a62b91Sopenharmony_ci    }
972b8a62b91Sopenharmony_ci
973b8a62b91Sopenharmony_ci    // Main version: libc is y2038 safe. Or, the platform is not y2038 safe and
974b8a62b91Sopenharmony_ci    // there's nothing practical we can do.
975b8a62b91Sopenharmony_ci    #[cfg(not(all(
976b8a62b91Sopenharmony_ci        any(target_os = "android", target_os = "linux"),
977b8a62b91Sopenharmony_ci        any(target_pointer_width = "32", target_arch = "mips64"),
978b8a62b91Sopenharmony_ci    )))]
979b8a62b91Sopenharmony_ci    unsafe {
980b8a62b91Sopenharmony_ci        let mut stat = MaybeUninit::<Stat>::uninit();
981b8a62b91Sopenharmony_ci        ret(libc_fstat(borrowed_fd(fd), stat.as_mut_ptr()))?;
982b8a62b91Sopenharmony_ci        Ok(stat.assume_init())
983b8a62b91Sopenharmony_ci    }
984b8a62b91Sopenharmony_ci}
985b8a62b91Sopenharmony_ci
986b8a62b91Sopenharmony_ci#[cfg(all(
987b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
988b8a62b91Sopenharmony_ci    any(target_pointer_width = "32", target_arch = "mips64"),
989b8a62b91Sopenharmony_ci))]
990b8a62b91Sopenharmony_cifn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> {
991b8a62b91Sopenharmony_ci    unsafe {
992b8a62b91Sopenharmony_ci        let mut result = MaybeUninit::<c::stat64>::uninit();
993b8a62b91Sopenharmony_ci        ret(libc_fstat(borrowed_fd(fd), result.as_mut_ptr()))?;
994b8a62b91Sopenharmony_ci        stat64_to_stat(result.assume_init())
995b8a62b91Sopenharmony_ci    }
996b8a62b91Sopenharmony_ci}
997b8a62b91Sopenharmony_ci
998b8a62b91Sopenharmony_ci#[cfg(not(any(
999b8a62b91Sopenharmony_ci    target_os = "haiku",
1000b8a62b91Sopenharmony_ci    target_os = "illumos",
1001b8a62b91Sopenharmony_ci    target_os = "netbsd",
1002b8a62b91Sopenharmony_ci    target_os = "redox",
1003b8a62b91Sopenharmony_ci    target_os = "solaris",
1004b8a62b91Sopenharmony_ci    target_os = "wasi",
1005b8a62b91Sopenharmony_ci)))]
1006b8a62b91Sopenharmony_cipub(crate) fn fstatfs(fd: BorrowedFd<'_>) -> io::Result<StatFs> {
1007b8a62b91Sopenharmony_ci    let mut statfs = MaybeUninit::<StatFs>::uninit();
1008b8a62b91Sopenharmony_ci    unsafe {
1009b8a62b91Sopenharmony_ci        ret(libc_fstatfs(borrowed_fd(fd), statfs.as_mut_ptr()))?;
1010b8a62b91Sopenharmony_ci        Ok(statfs.assume_init())
1011b8a62b91Sopenharmony_ci    }
1012b8a62b91Sopenharmony_ci}
1013b8a62b91Sopenharmony_ci
1014b8a62b91Sopenharmony_ci#[cfg(not(any(
1015b8a62b91Sopenharmony_ci    target_os = "haiku",
1016b8a62b91Sopenharmony_ci    target_os = "illumos",
1017b8a62b91Sopenharmony_ci    target_os = "redox",
1018b8a62b91Sopenharmony_ci    target_os = "solaris",
1019b8a62b91Sopenharmony_ci    target_os = "wasi",
1020b8a62b91Sopenharmony_ci)))]
1021b8a62b91Sopenharmony_cipub(crate) fn fstatvfs(fd: BorrowedFd<'_>) -> io::Result<StatVfs> {
1022b8a62b91Sopenharmony_ci    let mut statvfs = MaybeUninit::<libc_statvfs>::uninit();
1023b8a62b91Sopenharmony_ci    unsafe {
1024b8a62b91Sopenharmony_ci        ret(libc_fstatvfs(borrowed_fd(fd), statvfs.as_mut_ptr()))?;
1025b8a62b91Sopenharmony_ci        Ok(libc_statvfs_to_statvfs(statvfs.assume_init()))
1026b8a62b91Sopenharmony_ci    }
1027b8a62b91Sopenharmony_ci}
1028b8a62b91Sopenharmony_ci
1029b8a62b91Sopenharmony_ci#[cfg(not(any(
1030b8a62b91Sopenharmony_ci    target_os = "haiku",
1031b8a62b91Sopenharmony_ci    target_os = "illumos",
1032b8a62b91Sopenharmony_ci    target_os = "redox",
1033b8a62b91Sopenharmony_ci    target_os = "solaris",
1034b8a62b91Sopenharmony_ci    target_os = "wasi"
1035b8a62b91Sopenharmony_ci)))]
1036b8a62b91Sopenharmony_cifn libc_statvfs_to_statvfs(from: libc_statvfs) -> StatVfs {
1037b8a62b91Sopenharmony_ci    StatVfs {
1038b8a62b91Sopenharmony_ci        f_bsize: from.f_bsize as u64,
1039b8a62b91Sopenharmony_ci        f_frsize: from.f_frsize as u64,
1040b8a62b91Sopenharmony_ci        f_blocks: from.f_blocks as u64,
1041b8a62b91Sopenharmony_ci        f_bfree: from.f_bfree as u64,
1042b8a62b91Sopenharmony_ci        f_bavail: from.f_bavail as u64,
1043b8a62b91Sopenharmony_ci        f_files: from.f_files as u64,
1044b8a62b91Sopenharmony_ci        f_ffree: from.f_ffree as u64,
1045b8a62b91Sopenharmony_ci        f_favail: from.f_ffree as u64,
1046b8a62b91Sopenharmony_ci        f_fsid: from.f_fsid as u64,
1047b8a62b91Sopenharmony_ci        f_flag: unsafe { StatVfsMountFlags::from_bits_unchecked(from.f_flag as u64) },
1048b8a62b91Sopenharmony_ci        f_namemax: from.f_namemax as u64,
1049b8a62b91Sopenharmony_ci    }
1050b8a62b91Sopenharmony_ci}
1051b8a62b91Sopenharmony_ci
1052b8a62b91Sopenharmony_cipub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
1053b8a62b91Sopenharmony_ci    // 32-bit gnu version: libc has `futimens` but it is not y2038 safe by default.
1054b8a62b91Sopenharmony_ci    #[cfg(all(
1055b8a62b91Sopenharmony_ci        any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
1056b8a62b91Sopenharmony_ci        target_env = "gnu",
1057b8a62b91Sopenharmony_ci    ))]
1058b8a62b91Sopenharmony_ci    unsafe {
1059b8a62b91Sopenharmony_ci        if let Some(libc_futimens) = __futimens64.get() {
1060b8a62b91Sopenharmony_ci            let libc_times: [LibcTimespec; 2] = [
1061b8a62b91Sopenharmony_ci                times.last_access.clone().into(),
1062b8a62b91Sopenharmony_ci                times.last_modification.clone().into(),
1063b8a62b91Sopenharmony_ci            ];
1064b8a62b91Sopenharmony_ci
1065b8a62b91Sopenharmony_ci            ret(libc_futimens(borrowed_fd(fd), libc_times.as_ptr()))
1066b8a62b91Sopenharmony_ci        } else {
1067b8a62b91Sopenharmony_ci            futimens_old(fd, times)
1068b8a62b91Sopenharmony_ci        }
1069b8a62b91Sopenharmony_ci    }
1070b8a62b91Sopenharmony_ci
1071b8a62b91Sopenharmony_ci    // Main version: libc is y2038 safe and has `futimens`. Or, the platform
1072b8a62b91Sopenharmony_ci    // is not y2038 safe and there's nothing practical we can do.
1073b8a62b91Sopenharmony_ci    #[cfg(not(any(
1074b8a62b91Sopenharmony_ci        target_os = "ios",
1075b8a62b91Sopenharmony_ci        target_os = "macos",
1076b8a62b91Sopenharmony_ci        all(
1077b8a62b91Sopenharmony_ci            any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
1078b8a62b91Sopenharmony_ci            target_env = "gnu",
1079b8a62b91Sopenharmony_ci        )
1080b8a62b91Sopenharmony_ci    )))]
1081b8a62b91Sopenharmony_ci    unsafe {
1082b8a62b91Sopenharmony_ci        // Assert that `Timestamps` has the expected layout.
1083b8a62b91Sopenharmony_ci        let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone());
1084b8a62b91Sopenharmony_ci
1085b8a62b91Sopenharmony_ci        ret(c::futimens(borrowed_fd(fd), as_ptr(times).cast()))
1086b8a62b91Sopenharmony_ci    }
1087b8a62b91Sopenharmony_ci
1088b8a62b91Sopenharmony_ci    // `futimens` was introduced in macOS 10.13.
1089b8a62b91Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os = "macos"))]
1090b8a62b91Sopenharmony_ci    unsafe {
1091b8a62b91Sopenharmony_ci        // ABI details.
1092b8a62b91Sopenharmony_ci        weak! {
1093b8a62b91Sopenharmony_ci            fn futimens(c::c_int, *const c::timespec) -> c::c_int
1094b8a62b91Sopenharmony_ci        }
1095b8a62b91Sopenharmony_ci        extern "C" {
1096b8a62b91Sopenharmony_ci            fn fsetattrlist(
1097b8a62b91Sopenharmony_ci                fd: c::c_int,
1098b8a62b91Sopenharmony_ci                attr_list: *const Attrlist,
1099b8a62b91Sopenharmony_ci                attr_buf: *const c::c_void,
1100b8a62b91Sopenharmony_ci                attr_buf_size: c::size_t,
1101b8a62b91Sopenharmony_ci                options: c::c_ulong,
1102b8a62b91Sopenharmony_ci            ) -> c::c_int;
1103b8a62b91Sopenharmony_ci        }
1104b8a62b91Sopenharmony_ci
1105b8a62b91Sopenharmony_ci        // If we have `futimens`, use it.
1106b8a62b91Sopenharmony_ci        if let Some(have_futimens) = futimens.get() {
1107b8a62b91Sopenharmony_ci            // Assert that `Timestamps` has the expected layout.
1108b8a62b91Sopenharmony_ci            let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone());
1109b8a62b91Sopenharmony_ci
1110b8a62b91Sopenharmony_ci            return ret(have_futimens(borrowed_fd(fd), as_ptr(times).cast()));
1111b8a62b91Sopenharmony_ci        }
1112b8a62b91Sopenharmony_ci
1113b8a62b91Sopenharmony_ci        // Otherwise use `fsetattrlist`.
1114b8a62b91Sopenharmony_ci        let (attrbuf_size, times, attrs) = times_to_attrlist(times);
1115b8a62b91Sopenharmony_ci
1116b8a62b91Sopenharmony_ci        ret(fsetattrlist(
1117b8a62b91Sopenharmony_ci            borrowed_fd(fd),
1118b8a62b91Sopenharmony_ci            &attrs,
1119b8a62b91Sopenharmony_ci            as_ptr(&times).cast(),
1120b8a62b91Sopenharmony_ci            attrbuf_size,
1121b8a62b91Sopenharmony_ci            0,
1122b8a62b91Sopenharmony_ci        ))
1123b8a62b91Sopenharmony_ci    }
1124b8a62b91Sopenharmony_ci}
1125b8a62b91Sopenharmony_ci
1126b8a62b91Sopenharmony_ci#[cfg(all(
1127b8a62b91Sopenharmony_ci    any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
1128b8a62b91Sopenharmony_ci    target_env = "gnu",
1129b8a62b91Sopenharmony_ci))]
1130b8a62b91Sopenharmony_ciunsafe fn futimens_old(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
1131b8a62b91Sopenharmony_ci    let old_times = [
1132b8a62b91Sopenharmony_ci        c::timespec {
1133b8a62b91Sopenharmony_ci            tv_sec: times
1134b8a62b91Sopenharmony_ci                .last_access
1135b8a62b91Sopenharmony_ci                .tv_sec
1136b8a62b91Sopenharmony_ci                .try_into()
1137b8a62b91Sopenharmony_ci                .map_err(|_| io::Errno::OVERFLOW)?,
1138b8a62b91Sopenharmony_ci            tv_nsec: times.last_access.tv_nsec,
1139b8a62b91Sopenharmony_ci        },
1140b8a62b91Sopenharmony_ci        c::timespec {
1141b8a62b91Sopenharmony_ci            tv_sec: times
1142b8a62b91Sopenharmony_ci                .last_modification
1143b8a62b91Sopenharmony_ci                .tv_sec
1144b8a62b91Sopenharmony_ci                .try_into()
1145b8a62b91Sopenharmony_ci                .map_err(|_| io::Errno::OVERFLOW)?,
1146b8a62b91Sopenharmony_ci            tv_nsec: times.last_modification.tv_nsec,
1147b8a62b91Sopenharmony_ci        },
1148b8a62b91Sopenharmony_ci    ];
1149b8a62b91Sopenharmony_ci
1150b8a62b91Sopenharmony_ci    ret(c::futimens(borrowed_fd(fd), old_times.as_ptr()))
1151b8a62b91Sopenharmony_ci}
1152b8a62b91Sopenharmony_ci
1153b8a62b91Sopenharmony_ci#[cfg(not(any(
1154b8a62b91Sopenharmony_ci    target_os = "aix",
1155b8a62b91Sopenharmony_ci    target_os = "dragonfly",
1156b8a62b91Sopenharmony_ci    target_os = "illumos",
1157b8a62b91Sopenharmony_ci    target_os = "ios",
1158b8a62b91Sopenharmony_ci    target_os = "macos",
1159b8a62b91Sopenharmony_ci    target_os = "netbsd",
1160b8a62b91Sopenharmony_ci    target_os = "openbsd",
1161b8a62b91Sopenharmony_ci    target_os = "redox",
1162b8a62b91Sopenharmony_ci    target_os = "solaris",
1163b8a62b91Sopenharmony_ci)))]
1164b8a62b91Sopenharmony_cipub(crate) fn fallocate(
1165b8a62b91Sopenharmony_ci    fd: BorrowedFd<'_>,
1166b8a62b91Sopenharmony_ci    mode: FallocateFlags,
1167b8a62b91Sopenharmony_ci    offset: u64,
1168b8a62b91Sopenharmony_ci    len: u64,
1169b8a62b91Sopenharmony_ci) -> io::Result<()> {
1170b8a62b91Sopenharmony_ci    // Silently cast; we'll get `EINVAL` if the value is negative.
1171b8a62b91Sopenharmony_ci    let offset = offset as i64;
1172b8a62b91Sopenharmony_ci    let len = len as i64;
1173b8a62b91Sopenharmony_ci
1174b8a62b91Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1175b8a62b91Sopenharmony_ci    unsafe {
1176b8a62b91Sopenharmony_ci        ret(libc_fallocate(borrowed_fd(fd), mode.bits(), offset, len))
1177b8a62b91Sopenharmony_ci    }
1178b8a62b91Sopenharmony_ci
1179b8a62b91Sopenharmony_ci    #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
1180b8a62b91Sopenharmony_ci    {
1181b8a62b91Sopenharmony_ci        assert!(mode.is_empty());
1182b8a62b91Sopenharmony_ci        let err = unsafe { libc_posix_fallocate(borrowed_fd(fd), offset, len) };
1183b8a62b91Sopenharmony_ci
1184b8a62b91Sopenharmony_ci        // `posix_fallocate` returns its error status rather than using `errno`.
1185b8a62b91Sopenharmony_ci        if err == 0 {
1186b8a62b91Sopenharmony_ci            Ok(())
1187b8a62b91Sopenharmony_ci        } else {
1188b8a62b91Sopenharmony_ci            Err(io::Errno(err))
1189b8a62b91Sopenharmony_ci        }
1190b8a62b91Sopenharmony_ci    }
1191b8a62b91Sopenharmony_ci}
1192b8a62b91Sopenharmony_ci
1193b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1194b8a62b91Sopenharmony_cipub(crate) fn fallocate(
1195b8a62b91Sopenharmony_ci    fd: BorrowedFd<'_>,
1196b8a62b91Sopenharmony_ci    mode: FallocateFlags,
1197b8a62b91Sopenharmony_ci    offset: u64,
1198b8a62b91Sopenharmony_ci    len: u64,
1199b8a62b91Sopenharmony_ci) -> io::Result<()> {
1200b8a62b91Sopenharmony_ci    let offset: i64 = offset.try_into().map_err(|_e| io::Errno::INVAL)?;
1201b8a62b91Sopenharmony_ci    let len = len as i64;
1202b8a62b91Sopenharmony_ci
1203b8a62b91Sopenharmony_ci    assert!(mode.is_empty());
1204b8a62b91Sopenharmony_ci
1205b8a62b91Sopenharmony_ci    let new_len = offset.checked_add(len).ok_or(io::Errno::FBIG)?;
1206b8a62b91Sopenharmony_ci    let mut store = c::fstore_t {
1207b8a62b91Sopenharmony_ci        fst_flags: c::F_ALLOCATECONTIG,
1208b8a62b91Sopenharmony_ci        fst_posmode: c::F_PEOFPOSMODE,
1209b8a62b91Sopenharmony_ci        fst_offset: 0,
1210b8a62b91Sopenharmony_ci        fst_length: new_len,
1211b8a62b91Sopenharmony_ci        fst_bytesalloc: 0,
1212b8a62b91Sopenharmony_ci    };
1213b8a62b91Sopenharmony_ci    unsafe {
1214b8a62b91Sopenharmony_ci        if c::fcntl(borrowed_fd(fd), c::F_PREALLOCATE, &store) == -1 {
1215b8a62b91Sopenharmony_ci            store.fst_flags = c::F_ALLOCATEALL;
1216b8a62b91Sopenharmony_ci            let _ = ret_c_int(c::fcntl(borrowed_fd(fd), c::F_PREALLOCATE, &store))?;
1217b8a62b91Sopenharmony_ci        }
1218b8a62b91Sopenharmony_ci        ret(c::ftruncate(borrowed_fd(fd), new_len))
1219b8a62b91Sopenharmony_ci    }
1220b8a62b91Sopenharmony_ci}
1221b8a62b91Sopenharmony_ci
1222b8a62b91Sopenharmony_cipub(crate) fn fsync(fd: BorrowedFd<'_>) -> io::Result<()> {
1223b8a62b91Sopenharmony_ci    unsafe { ret(c::fsync(borrowed_fd(fd))) }
1224b8a62b91Sopenharmony_ci}
1225b8a62b91Sopenharmony_ci
1226b8a62b91Sopenharmony_ci#[cfg(not(any(
1227b8a62b91Sopenharmony_ci    target_os = "dragonfly",
1228b8a62b91Sopenharmony_ci    target_os = "haiku",
1229b8a62b91Sopenharmony_ci    target_os = "ios",
1230b8a62b91Sopenharmony_ci    target_os = "macos",
1231b8a62b91Sopenharmony_ci    target_os = "redox",
1232b8a62b91Sopenharmony_ci)))]
1233b8a62b91Sopenharmony_cipub(crate) fn fdatasync(fd: BorrowedFd<'_>) -> io::Result<()> {
1234b8a62b91Sopenharmony_ci    unsafe { ret(c::fdatasync(borrowed_fd(fd))) }
1235b8a62b91Sopenharmony_ci}
1236b8a62b91Sopenharmony_ci
1237b8a62b91Sopenharmony_cipub(crate) fn ftruncate(fd: BorrowedFd<'_>, length: u64) -> io::Result<()> {
1238b8a62b91Sopenharmony_ci    let length = length.try_into().map_err(|_overflow_err| io::Errno::FBIG)?;
1239b8a62b91Sopenharmony_ci    unsafe { ret(libc_ftruncate(borrowed_fd(fd), length)) }
1240b8a62b91Sopenharmony_ci}
1241b8a62b91Sopenharmony_ci
1242b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
1243b8a62b91Sopenharmony_cipub(crate) fn memfd_create(path: &CStr, flags: MemfdFlags) -> io::Result<OwnedFd> {
1244b8a62b91Sopenharmony_ci    #[cfg(target_os = "freebsd")]
1245b8a62b91Sopenharmony_ci    weakcall! {
1246b8a62b91Sopenharmony_ci        fn memfd_create(
1247b8a62b91Sopenharmony_ci            name: *const c::c_char,
1248b8a62b91Sopenharmony_ci            flags: c::c_uint
1249b8a62b91Sopenharmony_ci        ) -> c::c_int
1250b8a62b91Sopenharmony_ci    }
1251b8a62b91Sopenharmony_ci
1252b8a62b91Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1253b8a62b91Sopenharmony_ci    weak_or_syscall! {
1254b8a62b91Sopenharmony_ci        fn memfd_create(
1255b8a62b91Sopenharmony_ci            name: *const c::c_char,
1256b8a62b91Sopenharmony_ci            flags: c::c_uint
1257b8a62b91Sopenharmony_ci        ) via SYS_memfd_create -> c::c_int
1258b8a62b91Sopenharmony_ci    }
1259b8a62b91Sopenharmony_ci
1260b8a62b91Sopenharmony_ci    unsafe { ret_owned_fd(memfd_create(c_str(path), flags.bits())) }
1261b8a62b91Sopenharmony_ci}
1262b8a62b91Sopenharmony_ci
1263b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1264b8a62b91Sopenharmony_cipub(crate) fn openat2(
1265b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
1266b8a62b91Sopenharmony_ci    path: &CStr,
1267b8a62b91Sopenharmony_ci    oflags: OFlags,
1268b8a62b91Sopenharmony_ci    mode: Mode,
1269b8a62b91Sopenharmony_ci    resolve: ResolveFlags,
1270b8a62b91Sopenharmony_ci) -> io::Result<OwnedFd> {
1271b8a62b91Sopenharmony_ci    let oflags: i32 = oflags.bits();
1272b8a62b91Sopenharmony_ci    let open_how = OpenHow {
1273b8a62b91Sopenharmony_ci        oflag: u64::from(oflags as u32),
1274b8a62b91Sopenharmony_ci        mode: u64::from(mode.bits()),
1275b8a62b91Sopenharmony_ci        resolve: resolve.bits(),
1276b8a62b91Sopenharmony_ci    };
1277b8a62b91Sopenharmony_ci
1278b8a62b91Sopenharmony_ci    unsafe {
1279b8a62b91Sopenharmony_ci        syscall_ret_owned_fd(c::syscall(
1280b8a62b91Sopenharmony_ci            SYS_OPENAT2,
1281b8a62b91Sopenharmony_ci            borrowed_fd(dirfd),
1282b8a62b91Sopenharmony_ci            c_str(path),
1283b8a62b91Sopenharmony_ci            &open_how,
1284b8a62b91Sopenharmony_ci            SIZEOF_OPEN_HOW,
1285b8a62b91Sopenharmony_ci        ))
1286b8a62b91Sopenharmony_ci    }
1287b8a62b91Sopenharmony_ci}
1288b8a62b91Sopenharmony_ci#[cfg(all(
1289b8a62b91Sopenharmony_ci    target_pointer_width = "32",
1290b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
1291b8a62b91Sopenharmony_ci))]
1292b8a62b91Sopenharmony_ciconst SYS_OPENAT2: i32 = 437;
1293b8a62b91Sopenharmony_ci#[cfg(all(
1294b8a62b91Sopenharmony_ci    target_pointer_width = "64",
1295b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
1296b8a62b91Sopenharmony_ci))]
1297b8a62b91Sopenharmony_ciconst SYS_OPENAT2: i64 = 437;
1298b8a62b91Sopenharmony_ci
1299b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1300b8a62b91Sopenharmony_ci#[repr(C)]
1301b8a62b91Sopenharmony_ci#[derive(Debug)]
1302b8a62b91Sopenharmony_cistruct OpenHow {
1303b8a62b91Sopenharmony_ci    oflag: u64,
1304b8a62b91Sopenharmony_ci    mode: u64,
1305b8a62b91Sopenharmony_ci    resolve: u64,
1306b8a62b91Sopenharmony_ci}
1307b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1308b8a62b91Sopenharmony_ciconst SIZEOF_OPEN_HOW: usize = size_of::<OpenHow>();
1309b8a62b91Sopenharmony_ci
1310b8a62b91Sopenharmony_ci#[cfg(target_os = "linux")]
1311b8a62b91Sopenharmony_cipub(crate) fn sendfile(
1312b8a62b91Sopenharmony_ci    out_fd: BorrowedFd<'_>,
1313b8a62b91Sopenharmony_ci    in_fd: BorrowedFd<'_>,
1314b8a62b91Sopenharmony_ci    offset: Option<&mut u64>,
1315b8a62b91Sopenharmony_ci    count: usize,
1316b8a62b91Sopenharmony_ci) -> io::Result<usize> {
1317b8a62b91Sopenharmony_ci    unsafe {
1318b8a62b91Sopenharmony_ci        let nsent = ret_ssize_t(c::sendfile64(
1319b8a62b91Sopenharmony_ci            borrowed_fd(out_fd),
1320b8a62b91Sopenharmony_ci            borrowed_fd(in_fd),
1321b8a62b91Sopenharmony_ci            offset.map_or(null_mut(), crate::utils::as_mut_ptr).cast(),
1322b8a62b91Sopenharmony_ci            count,
1323b8a62b91Sopenharmony_ci        ))?;
1324b8a62b91Sopenharmony_ci        Ok(nsent as usize)
1325b8a62b91Sopenharmony_ci    }
1326b8a62b91Sopenharmony_ci}
1327b8a62b91Sopenharmony_ci
1328b8a62b91Sopenharmony_ci/// Convert from a Linux `statx` value to rustix's `Stat`.
1329b8a62b91Sopenharmony_ci#[cfg(all(
1330b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
1331b8a62b91Sopenharmony_ci    target_pointer_width = "32",
1332b8a62b91Sopenharmony_ci))]
1333b8a62b91Sopenharmony_cifn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> {
1334b8a62b91Sopenharmony_ci    Ok(Stat {
1335b8a62b91Sopenharmony_ci        st_dev: crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor).into(),
1336b8a62b91Sopenharmony_ci        st_mode: x.stx_mode.into(),
1337b8a62b91Sopenharmony_ci        st_nlink: x.stx_nlink.into(),
1338b8a62b91Sopenharmony_ci        st_uid: x.stx_uid.into(),
1339b8a62b91Sopenharmony_ci        st_gid: x.stx_gid.into(),
1340b8a62b91Sopenharmony_ci        st_rdev: crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor).into(),
1341b8a62b91Sopenharmony_ci        st_size: x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1342b8a62b91Sopenharmony_ci        st_blksize: x.stx_blksize.into(),
1343b8a62b91Sopenharmony_ci        st_blocks: x.stx_blocks.into(),
1344b8a62b91Sopenharmony_ci        st_atime: x
1345b8a62b91Sopenharmony_ci            .stx_atime
1346b8a62b91Sopenharmony_ci            .tv_sec
1347b8a62b91Sopenharmony_ci            .try_into()
1348b8a62b91Sopenharmony_ci            .map_err(|_| io::Errno::OVERFLOW)?,
1349b8a62b91Sopenharmony_ci        st_atime_nsec: x.stx_atime.tv_nsec as _,
1350b8a62b91Sopenharmony_ci        st_mtime: x
1351b8a62b91Sopenharmony_ci            .stx_mtime
1352b8a62b91Sopenharmony_ci            .tv_sec
1353b8a62b91Sopenharmony_ci            .try_into()
1354b8a62b91Sopenharmony_ci            .map_err(|_| io::Errno::OVERFLOW)?,
1355b8a62b91Sopenharmony_ci        st_mtime_nsec: x.stx_mtime.tv_nsec as _,
1356b8a62b91Sopenharmony_ci        st_ctime: x
1357b8a62b91Sopenharmony_ci            .stx_ctime
1358b8a62b91Sopenharmony_ci            .tv_sec
1359b8a62b91Sopenharmony_ci            .try_into()
1360b8a62b91Sopenharmony_ci            .map_err(|_| io::Errno::OVERFLOW)?,
1361b8a62b91Sopenharmony_ci        st_ctime_nsec: x.stx_ctime.tv_nsec as _,
1362b8a62b91Sopenharmony_ci        st_ino: x.stx_ino.into(),
1363b8a62b91Sopenharmony_ci    })
1364b8a62b91Sopenharmony_ci}
1365b8a62b91Sopenharmony_ci
1366b8a62b91Sopenharmony_ci/// Convert from a Linux `statx` value to rustix's `Stat`.
1367b8a62b91Sopenharmony_ci///
1368b8a62b91Sopenharmony_ci/// mips64' `struct stat64` in libc has private fields, and `stx_blocks`
1369b8a62b91Sopenharmony_ci#[cfg(all(
1370b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
1371b8a62b91Sopenharmony_ci    target_arch = "mips64",
1372b8a62b91Sopenharmony_ci))]
1373b8a62b91Sopenharmony_cifn statx_to_stat(x: crate::fs::Statx) -> io::Result<Stat> {
1374b8a62b91Sopenharmony_ci    let mut result: Stat = unsafe { core::mem::zeroed() };
1375b8a62b91Sopenharmony_ci
1376b8a62b91Sopenharmony_ci    result.st_dev = crate::fs::makedev(x.stx_dev_major, x.stx_dev_minor);
1377b8a62b91Sopenharmony_ci    result.st_mode = x.stx_mode.into();
1378b8a62b91Sopenharmony_ci    result.st_nlink = x.stx_nlink.into();
1379b8a62b91Sopenharmony_ci    result.st_uid = x.stx_uid.into();
1380b8a62b91Sopenharmony_ci    result.st_gid = x.stx_gid.into();
1381b8a62b91Sopenharmony_ci    result.st_rdev = crate::fs::makedev(x.stx_rdev_major, x.stx_rdev_minor);
1382b8a62b91Sopenharmony_ci    result.st_size = x.stx_size.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1383b8a62b91Sopenharmony_ci    result.st_blksize = x.stx_blksize.into();
1384b8a62b91Sopenharmony_ci    result.st_blocks = x.stx_blocks.try_into().map_err(|_e| io::Errno::OVERFLOW)?;
1385b8a62b91Sopenharmony_ci    result.st_atime = x
1386b8a62b91Sopenharmony_ci        .stx_atime
1387b8a62b91Sopenharmony_ci        .tv_sec
1388b8a62b91Sopenharmony_ci        .try_into()
1389b8a62b91Sopenharmony_ci        .map_err(|_| io::Errno::OVERFLOW)?;
1390b8a62b91Sopenharmony_ci    result.st_atime_nsec = x.stx_atime.tv_nsec as _;
1391b8a62b91Sopenharmony_ci    result.st_mtime = x
1392b8a62b91Sopenharmony_ci        .stx_mtime
1393b8a62b91Sopenharmony_ci        .tv_sec
1394b8a62b91Sopenharmony_ci        .try_into()
1395b8a62b91Sopenharmony_ci        .map_err(|_| io::Errno::OVERFLOW)?;
1396b8a62b91Sopenharmony_ci    result.st_mtime_nsec = x.stx_mtime.tv_nsec as _;
1397b8a62b91Sopenharmony_ci    result.st_ctime = x
1398b8a62b91Sopenharmony_ci        .stx_ctime
1399b8a62b91Sopenharmony_ci        .tv_sec
1400b8a62b91Sopenharmony_ci        .try_into()
1401b8a62b91Sopenharmony_ci        .map_err(|_| io::Errno::OVERFLOW)?;
1402b8a62b91Sopenharmony_ci    result.st_ctime_nsec = x.stx_ctime.tv_nsec as _;
1403b8a62b91Sopenharmony_ci    result.st_ino = x.stx_ino.into();
1404b8a62b91Sopenharmony_ci
1405b8a62b91Sopenharmony_ci    Ok(result)
1406b8a62b91Sopenharmony_ci}
1407b8a62b91Sopenharmony_ci
1408b8a62b91Sopenharmony_ci/// Convert from a Linux `stat64` value to rustix's `Stat`.
1409b8a62b91Sopenharmony_ci#[cfg(all(
1410b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
1411b8a62b91Sopenharmony_ci    target_pointer_width = "32",
1412b8a62b91Sopenharmony_ci))]
1413b8a62b91Sopenharmony_cifn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> {
1414b8a62b91Sopenharmony_ci    Ok(Stat {
1415b8a62b91Sopenharmony_ci        st_dev: s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1416b8a62b91Sopenharmony_ci        st_mode: s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1417b8a62b91Sopenharmony_ci        st_nlink: s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1418b8a62b91Sopenharmony_ci        st_uid: s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1419b8a62b91Sopenharmony_ci        st_gid: s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1420b8a62b91Sopenharmony_ci        st_rdev: s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1421b8a62b91Sopenharmony_ci        st_size: s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1422b8a62b91Sopenharmony_ci        st_blksize: s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1423b8a62b91Sopenharmony_ci        st_blocks: s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1424b8a62b91Sopenharmony_ci        st_atime: s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1425b8a62b91Sopenharmony_ci        st_atime_nsec: s64
1426b8a62b91Sopenharmony_ci            .st_atime_nsec
1427b8a62b91Sopenharmony_ci            .try_into()
1428b8a62b91Sopenharmony_ci            .map_err(|_| io::Errno::OVERFLOW)?,
1429b8a62b91Sopenharmony_ci        st_mtime: s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1430b8a62b91Sopenharmony_ci        st_mtime_nsec: s64
1431b8a62b91Sopenharmony_ci            .st_mtime_nsec
1432b8a62b91Sopenharmony_ci            .try_into()
1433b8a62b91Sopenharmony_ci            .map_err(|_| io::Errno::OVERFLOW)?,
1434b8a62b91Sopenharmony_ci        st_ctime: s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1435b8a62b91Sopenharmony_ci        st_ctime_nsec: s64
1436b8a62b91Sopenharmony_ci            .st_ctime_nsec
1437b8a62b91Sopenharmony_ci            .try_into()
1438b8a62b91Sopenharmony_ci            .map_err(|_| io::Errno::OVERFLOW)?,
1439b8a62b91Sopenharmony_ci        st_ino: s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?,
1440b8a62b91Sopenharmony_ci    })
1441b8a62b91Sopenharmony_ci}
1442b8a62b91Sopenharmony_ci
1443b8a62b91Sopenharmony_ci/// Convert from a Linux `stat64` value to rustix's `Stat`.
1444b8a62b91Sopenharmony_ci///
1445b8a62b91Sopenharmony_ci/// mips64' `struct stat64` in libc has private fields, and `st_blocks` has
1446b8a62b91Sopenharmony_ci/// type `i64`.
1447b8a62b91Sopenharmony_ci#[cfg(all(
1448b8a62b91Sopenharmony_ci    any(target_os = "android", target_os = "linux"),
1449b8a62b91Sopenharmony_ci    target_arch = "mips64",
1450b8a62b91Sopenharmony_ci))]
1451b8a62b91Sopenharmony_cifn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> {
1452b8a62b91Sopenharmony_ci    let mut result: Stat = unsafe { core::mem::zeroed() };
1453b8a62b91Sopenharmony_ci
1454b8a62b91Sopenharmony_ci    result.st_dev = s64.st_dev.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1455b8a62b91Sopenharmony_ci    result.st_mode = s64.st_mode.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1456b8a62b91Sopenharmony_ci    result.st_nlink = s64.st_nlink.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1457b8a62b91Sopenharmony_ci    result.st_uid = s64.st_uid.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1458b8a62b91Sopenharmony_ci    result.st_gid = s64.st_gid.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1459b8a62b91Sopenharmony_ci    result.st_rdev = s64.st_rdev.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1460b8a62b91Sopenharmony_ci    result.st_size = s64.st_size.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1461b8a62b91Sopenharmony_ci    result.st_blksize = s64.st_blksize.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1462b8a62b91Sopenharmony_ci    result.st_blocks = s64.st_blocks.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1463b8a62b91Sopenharmony_ci    result.st_atime = s64.st_atime.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1464b8a62b91Sopenharmony_ci    result.st_atime_nsec = s64
1465b8a62b91Sopenharmony_ci        .st_atime_nsec
1466b8a62b91Sopenharmony_ci        .try_into()
1467b8a62b91Sopenharmony_ci        .map_err(|_| io::Errno::OVERFLOW)?;
1468b8a62b91Sopenharmony_ci    result.st_mtime = s64.st_mtime.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1469b8a62b91Sopenharmony_ci    result.st_mtime_nsec = s64
1470b8a62b91Sopenharmony_ci        .st_mtime_nsec
1471b8a62b91Sopenharmony_ci        .try_into()
1472b8a62b91Sopenharmony_ci        .map_err(|_| io::Errno::OVERFLOW)?;
1473b8a62b91Sopenharmony_ci    result.st_ctime = s64.st_ctime.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1474b8a62b91Sopenharmony_ci    result.st_ctime_nsec = s64
1475b8a62b91Sopenharmony_ci        .st_ctime_nsec
1476b8a62b91Sopenharmony_ci        .try_into()
1477b8a62b91Sopenharmony_ci        .map_err(|_| io::Errno::OVERFLOW)?;
1478b8a62b91Sopenharmony_ci    result.st_ino = s64.st_ino.try_into().map_err(|_| io::Errno::OVERFLOW)?;
1479b8a62b91Sopenharmony_ci
1480b8a62b91Sopenharmony_ci    Ok(result)
1481b8a62b91Sopenharmony_ci}
1482b8a62b91Sopenharmony_ci
1483b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1484b8a62b91Sopenharmony_ci#[allow(non_upper_case_globals)]
1485b8a62b91Sopenharmony_cimod sys {
1486b8a62b91Sopenharmony_ci    use super::{c, BorrowedFd, Statx};
1487b8a62b91Sopenharmony_ci
1488b8a62b91Sopenharmony_ci    #[cfg(all(target_os = "android", target_arch = "arm"))]
1489b8a62b91Sopenharmony_ci    const SYS_statx: c::c_long = 397;
1490b8a62b91Sopenharmony_ci    #[cfg(all(target_os = "android", target_arch = "x86"))]
1491b8a62b91Sopenharmony_ci    const SYS_statx: c::c_long = 383;
1492b8a62b91Sopenharmony_ci    #[cfg(all(target_os = "android", target_arch = "aarch64"))]
1493b8a62b91Sopenharmony_ci    const SYS_statx: c::c_long = 291;
1494b8a62b91Sopenharmony_ci    #[cfg(all(target_os = "android", target_arch = "x86_64"))]
1495b8a62b91Sopenharmony_ci    const SYS_statx: c::c_long = 332;
1496b8a62b91Sopenharmony_ci
1497b8a62b91Sopenharmony_ci    weak_or_syscall! {
1498b8a62b91Sopenharmony_ci        pub(super) fn statx(
1499b8a62b91Sopenharmony_ci            pirfd: BorrowedFd<'_>,
1500b8a62b91Sopenharmony_ci            path: *const c::c_char,
1501b8a62b91Sopenharmony_ci            flags: c::c_int,
1502b8a62b91Sopenharmony_ci            mask: c::c_uint,
1503b8a62b91Sopenharmony_ci            buf: *mut Statx
1504b8a62b91Sopenharmony_ci        ) via SYS_statx -> c::c_int
1505b8a62b91Sopenharmony_ci    }
1506b8a62b91Sopenharmony_ci}
1507b8a62b91Sopenharmony_ci
1508b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1509b8a62b91Sopenharmony_ci#[allow(non_upper_case_globals)]
1510b8a62b91Sopenharmony_cipub(crate) fn statx(
1511b8a62b91Sopenharmony_ci    dirfd: BorrowedFd<'_>,
1512b8a62b91Sopenharmony_ci    path: &CStr,
1513b8a62b91Sopenharmony_ci    flags: AtFlags,
1514b8a62b91Sopenharmony_ci    mask: StatxFlags,
1515b8a62b91Sopenharmony_ci) -> io::Result<Statx> {
1516b8a62b91Sopenharmony_ci    // If a future Linux kernel adds more fields to `struct statx` and users
1517b8a62b91Sopenharmony_ci    // passing flags unknown to rustix in `StatxFlags`, we could end up
1518b8a62b91Sopenharmony_ci    // writing outside of the buffer. To prevent this possibility, we mask off
1519b8a62b91Sopenharmony_ci    // any flags that we don't know about.
1520b8a62b91Sopenharmony_ci    //
1521b8a62b91Sopenharmony_ci    // This includes `STATX__RESERVED`, which has a value that we know, but
1522b8a62b91Sopenharmony_ci    // which could take on arbitrary new meaning in the future. Linux currently
1523b8a62b91Sopenharmony_ci    // rejects this flag with `EINVAL`, so we do the same.
1524b8a62b91Sopenharmony_ci    //
1525b8a62b91Sopenharmony_ci    // This doesn't rely on `STATX_ALL` because [it's deprecated] and already
1526b8a62b91Sopenharmony_ci    // doesn't represent all the known flags.
1527b8a62b91Sopenharmony_ci    //
1528b8a62b91Sopenharmony_ci    // [it's deprecated]: https://patchwork.kernel.org/project/linux-fsdevel/patch/20200505095915.11275-7-mszeredi@redhat.com/
1529b8a62b91Sopenharmony_ci    #[cfg(not(any(target_os = "android", target_env = "musl")))]
1530b8a62b91Sopenharmony_ci    const STATX__RESERVED: u32 = libc::STATX__RESERVED as u32;
1531b8a62b91Sopenharmony_ci    #[cfg(any(target_os = "android", target_env = "musl"))]
1532b8a62b91Sopenharmony_ci    const STATX__RESERVED: u32 = linux_raw_sys::general::STATX__RESERVED;
1533b8a62b91Sopenharmony_ci    if (mask.bits() & STATX__RESERVED) == STATX__RESERVED {
1534b8a62b91Sopenharmony_ci        return Err(io::Errno::INVAL);
1535b8a62b91Sopenharmony_ci    }
1536b8a62b91Sopenharmony_ci    let mask = mask & StatxFlags::all();
1537b8a62b91Sopenharmony_ci
1538b8a62b91Sopenharmony_ci    let mut statx_buf = MaybeUninit::<Statx>::uninit();
1539b8a62b91Sopenharmony_ci    unsafe {
1540b8a62b91Sopenharmony_ci        ret(sys::statx(
1541b8a62b91Sopenharmony_ci            dirfd,
1542b8a62b91Sopenharmony_ci            c_str(path),
1543b8a62b91Sopenharmony_ci            flags.bits(),
1544b8a62b91Sopenharmony_ci            mask.bits(),
1545b8a62b91Sopenharmony_ci            statx_buf.as_mut_ptr(),
1546b8a62b91Sopenharmony_ci        ))?;
1547b8a62b91Sopenharmony_ci        Ok(statx_buf.assume_init())
1548b8a62b91Sopenharmony_ci    }
1549b8a62b91Sopenharmony_ci}
1550b8a62b91Sopenharmony_ci
1551b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1552b8a62b91Sopenharmony_ci#[inline]
1553b8a62b91Sopenharmony_cipub(crate) fn is_statx_available() -> bool {
1554b8a62b91Sopenharmony_ci    unsafe {
1555b8a62b91Sopenharmony_ci        // Call `statx` with null pointers so that if it fails for any reason
1556b8a62b91Sopenharmony_ci        // other than `EFAULT`, we know it's not supported.
1557b8a62b91Sopenharmony_ci        matches!(
1558b8a62b91Sopenharmony_ci            ret(sys::statx(cwd(), null(), 0, 0, null_mut())),
1559b8a62b91Sopenharmony_ci            Err(io::Errno::FAULT)
1560b8a62b91Sopenharmony_ci        )
1561b8a62b91Sopenharmony_ci    }
1562b8a62b91Sopenharmony_ci}
1563b8a62b91Sopenharmony_ci
1564b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1565b8a62b91Sopenharmony_cipub(crate) unsafe fn fcopyfile(
1566b8a62b91Sopenharmony_ci    from: BorrowedFd<'_>,
1567b8a62b91Sopenharmony_ci    to: BorrowedFd<'_>,
1568b8a62b91Sopenharmony_ci    state: copyfile_state_t,
1569b8a62b91Sopenharmony_ci    flags: CopyfileFlags,
1570b8a62b91Sopenharmony_ci) -> io::Result<()> {
1571b8a62b91Sopenharmony_ci    extern "C" {
1572b8a62b91Sopenharmony_ci        fn fcopyfile(
1573b8a62b91Sopenharmony_ci            from: c::c_int,
1574b8a62b91Sopenharmony_ci            to: c::c_int,
1575b8a62b91Sopenharmony_ci            state: copyfile_state_t,
1576b8a62b91Sopenharmony_ci            flags: c::c_uint,
1577b8a62b91Sopenharmony_ci        ) -> c::c_int;
1578b8a62b91Sopenharmony_ci    }
1579b8a62b91Sopenharmony_ci
1580b8a62b91Sopenharmony_ci    nonnegative_ret(fcopyfile(
1581b8a62b91Sopenharmony_ci        borrowed_fd(from),
1582b8a62b91Sopenharmony_ci        borrowed_fd(to),
1583b8a62b91Sopenharmony_ci        state,
1584b8a62b91Sopenharmony_ci        flags.bits(),
1585b8a62b91Sopenharmony_ci    ))
1586b8a62b91Sopenharmony_ci}
1587b8a62b91Sopenharmony_ci
1588b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1589b8a62b91Sopenharmony_cipub(crate) fn copyfile_state_alloc() -> io::Result<copyfile_state_t> {
1590b8a62b91Sopenharmony_ci    extern "C" {
1591b8a62b91Sopenharmony_ci        fn copyfile_state_alloc() -> copyfile_state_t;
1592b8a62b91Sopenharmony_ci    }
1593b8a62b91Sopenharmony_ci
1594b8a62b91Sopenharmony_ci    let result = unsafe { copyfile_state_alloc() };
1595b8a62b91Sopenharmony_ci    if result.0.is_null() {
1596b8a62b91Sopenharmony_ci        Err(io::Errno::last_os_error())
1597b8a62b91Sopenharmony_ci    } else {
1598b8a62b91Sopenharmony_ci        Ok(result)
1599b8a62b91Sopenharmony_ci    }
1600b8a62b91Sopenharmony_ci}
1601b8a62b91Sopenharmony_ci
1602b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1603b8a62b91Sopenharmony_cipub(crate) unsafe fn copyfile_state_free(state: copyfile_state_t) -> io::Result<()> {
1604b8a62b91Sopenharmony_ci    extern "C" {
1605b8a62b91Sopenharmony_ci        fn copyfile_state_free(state: copyfile_state_t) -> c::c_int;
1606b8a62b91Sopenharmony_ci    }
1607b8a62b91Sopenharmony_ci
1608b8a62b91Sopenharmony_ci    nonnegative_ret(copyfile_state_free(state))
1609b8a62b91Sopenharmony_ci}
1610b8a62b91Sopenharmony_ci
1611b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1612b8a62b91Sopenharmony_ciconst COPYFILE_STATE_COPIED: u32 = 8;
1613b8a62b91Sopenharmony_ci
1614b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1615b8a62b91Sopenharmony_cipub(crate) unsafe fn copyfile_state_get_copied(state: copyfile_state_t) -> io::Result<u64> {
1616b8a62b91Sopenharmony_ci    let mut copied = MaybeUninit::<u64>::uninit();
1617b8a62b91Sopenharmony_ci    copyfile_state_get(state, COPYFILE_STATE_COPIED, copied.as_mut_ptr().cast())?;
1618b8a62b91Sopenharmony_ci    Ok(copied.assume_init())
1619b8a62b91Sopenharmony_ci}
1620b8a62b91Sopenharmony_ci
1621b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1622b8a62b91Sopenharmony_cipub(crate) unsafe fn copyfile_state_get(
1623b8a62b91Sopenharmony_ci    state: copyfile_state_t,
1624b8a62b91Sopenharmony_ci    flag: u32,
1625b8a62b91Sopenharmony_ci    dst: *mut c::c_void,
1626b8a62b91Sopenharmony_ci) -> io::Result<()> {
1627b8a62b91Sopenharmony_ci    extern "C" {
1628b8a62b91Sopenharmony_ci        fn copyfile_state_get(state: copyfile_state_t, flag: u32, dst: *mut c::c_void) -> c::c_int;
1629b8a62b91Sopenharmony_ci    }
1630b8a62b91Sopenharmony_ci
1631b8a62b91Sopenharmony_ci    nonnegative_ret(copyfile_state_get(state, flag, dst))
1632b8a62b91Sopenharmony_ci}
1633b8a62b91Sopenharmony_ci
1634b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1635b8a62b91Sopenharmony_cipub(crate) fn getpath(fd: BorrowedFd<'_>) -> io::Result<CString> {
1636b8a62b91Sopenharmony_ci    // The use of PATH_MAX is generally not encouraged, but it
1637b8a62b91Sopenharmony_ci    // is inevitable in this case because macOS defines `fcntl` with
1638b8a62b91Sopenharmony_ci    // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
1639b8a62b91Sopenharmony_ci    // alternatives. If a better method is invented, it should be used
1640b8a62b91Sopenharmony_ci    // instead.
1641b8a62b91Sopenharmony_ci    let mut buf = alloc::vec![0; c::PATH_MAX as usize];
1642b8a62b91Sopenharmony_ci
1643b8a62b91Sopenharmony_ci    // From the [macOS `fcntl` man page]:
1644b8a62b91Sopenharmony_ci    // `F_GETPATH` - Get the path of the file descriptor `Fildes`. The argument
1645b8a62b91Sopenharmony_ci    //               must be a buffer of size `MAXPATHLEN` or greater.
1646b8a62b91Sopenharmony_ci    //
1647b8a62b91Sopenharmony_ci    // [macOS `fcntl` man page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
1648b8a62b91Sopenharmony_ci    unsafe {
1649b8a62b91Sopenharmony_ci        ret(c::fcntl(borrowed_fd(fd), c::F_GETPATH, buf.as_mut_ptr()))?;
1650b8a62b91Sopenharmony_ci    }
1651b8a62b91Sopenharmony_ci
1652b8a62b91Sopenharmony_ci    let l = buf.iter().position(|&c| c == 0).unwrap();
1653b8a62b91Sopenharmony_ci    buf.truncate(l);
1654b8a62b91Sopenharmony_ci
1655b8a62b91Sopenharmony_ci    // TODO: On Rust 1.56, we can use `shrink_to` here.
1656b8a62b91Sopenharmony_ci    //buf.shrink_to(l + 1);
1657b8a62b91Sopenharmony_ci    buf.shrink_to_fit();
1658b8a62b91Sopenharmony_ci
1659b8a62b91Sopenharmony_ci    Ok(CString::new(buf).unwrap())
1660b8a62b91Sopenharmony_ci}
1661b8a62b91Sopenharmony_ci
1662b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1663b8a62b91Sopenharmony_cipub(crate) fn fcntl_rdadvise(fd: BorrowedFd<'_>, offset: u64, len: u64) -> io::Result<()> {
1664b8a62b91Sopenharmony_ci    // From the [macOS `fcntl` man page]:
1665b8a62b91Sopenharmony_ci    // `F_RDADVISE` - Issue an advisory read async with no copy to user.
1666b8a62b91Sopenharmony_ci    //
1667b8a62b91Sopenharmony_ci    // The `F_RDADVISE` command operates on the following structure which holds
1668b8a62b91Sopenharmony_ci    // information passed from the user to the system:
1669b8a62b91Sopenharmony_ci    //
1670b8a62b91Sopenharmony_ci    // ```c
1671b8a62b91Sopenharmony_ci    // struct radvisory {
1672b8a62b91Sopenharmony_ci    //      off_t   ra_offset;  /* offset into the file */
1673b8a62b91Sopenharmony_ci    //      int     ra_count;   /* size of the read     */
1674b8a62b91Sopenharmony_ci    // };
1675b8a62b91Sopenharmony_ci    // ```
1676b8a62b91Sopenharmony_ci    //
1677b8a62b91Sopenharmony_ci    // [macOS `fcntl` man page]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html
1678b8a62b91Sopenharmony_ci    let ra_offset = match offset.try_into() {
1679b8a62b91Sopenharmony_ci        Ok(len) => len,
1680b8a62b91Sopenharmony_ci        // If this conversion fails, the user is providing an offset outside
1681b8a62b91Sopenharmony_ci        // any possible file extent, so just ignore it.
1682b8a62b91Sopenharmony_ci        Err(_) => return Ok(()),
1683b8a62b91Sopenharmony_ci    };
1684b8a62b91Sopenharmony_ci    let ra_count = match len.try_into() {
1685b8a62b91Sopenharmony_ci        Ok(len) => len,
1686b8a62b91Sopenharmony_ci        // If this conversion fails, the user is providing a dubiously large
1687b8a62b91Sopenharmony_ci        // hint which is unlikely to improve performance.
1688b8a62b91Sopenharmony_ci        Err(_) => return Ok(()),
1689b8a62b91Sopenharmony_ci    };
1690b8a62b91Sopenharmony_ci    unsafe {
1691b8a62b91Sopenharmony_ci        let radvisory = c::radvisory {
1692b8a62b91Sopenharmony_ci            ra_offset,
1693b8a62b91Sopenharmony_ci            ra_count,
1694b8a62b91Sopenharmony_ci        };
1695b8a62b91Sopenharmony_ci        ret(c::fcntl(borrowed_fd(fd), c::F_RDADVISE, &radvisory))
1696b8a62b91Sopenharmony_ci    }
1697b8a62b91Sopenharmony_ci}
1698b8a62b91Sopenharmony_ci
1699b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1700b8a62b91Sopenharmony_cipub(crate) fn fcntl_fullfsync(fd: BorrowedFd<'_>) -> io::Result<()> {
1701b8a62b91Sopenharmony_ci    unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_FULLFSYNC)) }
1702b8a62b91Sopenharmony_ci}
1703b8a62b91Sopenharmony_ci
1704b8a62b91Sopenharmony_ci/// Convert `times` from a `futimens`/`utimensat` argument into `setattrlist`
1705b8a62b91Sopenharmony_ci/// arguments.
1706b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1707b8a62b91Sopenharmony_cifn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrlist) {
1708b8a62b91Sopenharmony_ci    // ABI details.
1709b8a62b91Sopenharmony_ci    const ATTR_CMN_MODTIME: u32 = 0x0000_0400;
1710b8a62b91Sopenharmony_ci    const ATTR_CMN_ACCTIME: u32 = 0x0000_1000;
1711b8a62b91Sopenharmony_ci    const ATTR_BIT_MAP_COUNT: u16 = 5;
1712b8a62b91Sopenharmony_ci
1713b8a62b91Sopenharmony_ci    let mut times = times.clone();
1714b8a62b91Sopenharmony_ci
1715b8a62b91Sopenharmony_ci    // If we have any `UTIME_NOW` elements, replace them with the current time.
1716b8a62b91Sopenharmony_ci    if times.last_access.tv_nsec == c::UTIME_NOW || times.last_modification.tv_nsec == c::UTIME_NOW
1717b8a62b91Sopenharmony_ci    {
1718b8a62b91Sopenharmony_ci        let now = {
1719b8a62b91Sopenharmony_ci            let mut tv = c::timeval {
1720b8a62b91Sopenharmony_ci                tv_sec: 0,
1721b8a62b91Sopenharmony_ci                tv_usec: 0,
1722b8a62b91Sopenharmony_ci            };
1723b8a62b91Sopenharmony_ci            unsafe {
1724b8a62b91Sopenharmony_ci                let r = c::gettimeofday(&mut tv, null_mut());
1725b8a62b91Sopenharmony_ci                assert_eq!(r, 0);
1726b8a62b91Sopenharmony_ci            }
1727b8a62b91Sopenharmony_ci            c::timespec {
1728b8a62b91Sopenharmony_ci                tv_sec: tv.tv_sec,
1729b8a62b91Sopenharmony_ci                tv_nsec: (tv.tv_usec * 1000) as _,
1730b8a62b91Sopenharmony_ci            }
1731b8a62b91Sopenharmony_ci        };
1732b8a62b91Sopenharmony_ci        if times.last_access.tv_nsec == c::UTIME_NOW {
1733b8a62b91Sopenharmony_ci            times.last_access = now;
1734b8a62b91Sopenharmony_ci        }
1735b8a62b91Sopenharmony_ci        if times.last_modification.tv_nsec == c::UTIME_NOW {
1736b8a62b91Sopenharmony_ci            times.last_modification = now;
1737b8a62b91Sopenharmony_ci        }
1738b8a62b91Sopenharmony_ci    }
1739b8a62b91Sopenharmony_ci
1740b8a62b91Sopenharmony_ci    // Pack the return values following the rules for [`getattrlist`].
1741b8a62b91Sopenharmony_ci    //
1742b8a62b91Sopenharmony_ci    // [`getattrlist`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getattrlist.2.html
1743b8a62b91Sopenharmony_ci    let mut times_size = 0;
1744b8a62b91Sopenharmony_ci    let mut attrs = Attrlist {
1745b8a62b91Sopenharmony_ci        bitmapcount: ATTR_BIT_MAP_COUNT,
1746b8a62b91Sopenharmony_ci        reserved: 0,
1747b8a62b91Sopenharmony_ci        commonattr: 0,
1748b8a62b91Sopenharmony_ci        volattr: 0,
1749b8a62b91Sopenharmony_ci        dirattr: 0,
1750b8a62b91Sopenharmony_ci        fileattr: 0,
1751b8a62b91Sopenharmony_ci        forkattr: 0,
1752b8a62b91Sopenharmony_ci    };
1753b8a62b91Sopenharmony_ci    let mut return_times = [c::timespec {
1754b8a62b91Sopenharmony_ci        tv_sec: 0,
1755b8a62b91Sopenharmony_ci        tv_nsec: 0,
1756b8a62b91Sopenharmony_ci    }; 2];
1757b8a62b91Sopenharmony_ci    let mut times_index = 0;
1758b8a62b91Sopenharmony_ci    if times.last_modification.tv_nsec != c::UTIME_OMIT {
1759b8a62b91Sopenharmony_ci        attrs.commonattr |= ATTR_CMN_MODTIME;
1760b8a62b91Sopenharmony_ci        return_times[times_index] = times.last_modification;
1761b8a62b91Sopenharmony_ci        times_index += 1;
1762b8a62b91Sopenharmony_ci        times_size += size_of::<c::timespec>();
1763b8a62b91Sopenharmony_ci    }
1764b8a62b91Sopenharmony_ci    if times.last_access.tv_nsec != c::UTIME_OMIT {
1765b8a62b91Sopenharmony_ci        attrs.commonattr |= ATTR_CMN_ACCTIME;
1766b8a62b91Sopenharmony_ci        return_times[times_index] = times.last_access;
1767b8a62b91Sopenharmony_ci        times_size += size_of::<c::timespec>();
1768b8a62b91Sopenharmony_ci    }
1769b8a62b91Sopenharmony_ci
1770b8a62b91Sopenharmony_ci    (times_size, return_times, attrs)
1771b8a62b91Sopenharmony_ci}
1772b8a62b91Sopenharmony_ci
1773b8a62b91Sopenharmony_ci/// Support type for `Attrlist`.
1774b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1775b8a62b91Sopenharmony_citype Attrgroup = u32;
1776b8a62b91Sopenharmony_ci
1777b8a62b91Sopenharmony_ci/// Attribute list for use with `setattrlist`.
1778b8a62b91Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
1779b8a62b91Sopenharmony_ci#[repr(C)]
1780b8a62b91Sopenharmony_cistruct Attrlist {
1781b8a62b91Sopenharmony_ci    bitmapcount: u16,
1782b8a62b91Sopenharmony_ci    reserved: u16,
1783b8a62b91Sopenharmony_ci    commonattr: Attrgroup,
1784b8a62b91Sopenharmony_ci    volattr: Attrgroup,
1785b8a62b91Sopenharmony_ci    dirattr: Attrgroup,
1786b8a62b91Sopenharmony_ci    fileattr: Attrgroup,
1787b8a62b91Sopenharmony_ci    forkattr: Attrgroup,
1788b8a62b91Sopenharmony_ci}
1789b8a62b91Sopenharmony_ci
1790b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
1791b8a62b91Sopenharmony_cipub(crate) fn mount(
1792b8a62b91Sopenharmony_ci    source: Option<&CStr>,
1793b8a62b91Sopenharmony_ci    target: &CStr,
1794b8a62b91Sopenharmony_ci    file_system_type: Option<&CStr>,
1795b8a62b91Sopenharmony_ci    flags: super::types::MountFlagsArg,
1796b8a62b91Sopenharmony_ci    data: Option<&CStr>,
1797b8a62b91Sopenharmony_ci) -> io::Result<()> {
1798b8a62b91Sopenharmony_ci    unsafe {
1799b8a62b91Sopenharmony_ci        ret(c::mount(
1800b8a62b91Sopenharmony_ci            source.map_or_else(null, CStr::as_ptr),
1801b8a62b91Sopenharmony_ci            target.as_ptr(),
1802b8a62b91Sopenharmony_ci            file_system_type.map_or_else(null, CStr::as_ptr),
1803b8a62b91Sopenharmony_ci            flags.0,
1804b8a62b91Sopenharmony_ci            data.map_or_else(null, CStr::as_ptr).cast(),
1805b8a62b91Sopenharmony_ci        ))
1806b8a62b91Sopenharmony_ci    }
1807b8a62b91Sopenharmony_ci}
1808