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(×).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(×).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