13da5c369Sopenharmony_ciuse crate::errno::Errno; 23da5c369Sopenharmony_ciuse libc::{self, c_char, c_int, c_uint, size_t, ssize_t}; 33da5c369Sopenharmony_ciuse std::ffi::OsString; 43da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 53da5c369Sopenharmony_ciuse std::os::raw; 63da5c369Sopenharmony_ciuse std::os::unix::ffi::OsStringExt; 73da5c369Sopenharmony_ciuse std::os::unix::io::RawFd; 83da5c369Sopenharmony_ci 93da5c369Sopenharmony_ci#[cfg(feature = "fs")] 103da5c369Sopenharmony_ciuse crate::{sys::stat::Mode, NixPath, Result}; 113da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))] 123da5c369Sopenharmony_ciuse std::ptr; // For splice and copy_file_range 133da5c369Sopenharmony_ci 143da5c369Sopenharmony_ci#[cfg(any( 153da5c369Sopenharmony_ci target_os = "linux", 163da5c369Sopenharmony_ci target_os = "android", 173da5c369Sopenharmony_ci target_os = "emscripten", 183da5c369Sopenharmony_ci target_os = "fuchsia", 193da5c369Sopenharmony_ci target_os = "wasi", 203da5c369Sopenharmony_ci target_env = "uclibc", 213da5c369Sopenharmony_ci target_os = "freebsd" 223da5c369Sopenharmony_ci))] 233da5c369Sopenharmony_ci#[cfg(feature = "fs")] 243da5c369Sopenharmony_cipub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice}; 253da5c369Sopenharmony_ci 263da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 273da5c369Sopenharmony_ci#[cfg(any(feature = "fs", feature = "process"))] 283da5c369Sopenharmony_cilibc_bitflags! { 293da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))] 303da5c369Sopenharmony_ci pub struct AtFlags: c_int { 313da5c369Sopenharmony_ci AT_REMOVEDIR; 323da5c369Sopenharmony_ci AT_SYMLINK_FOLLOW; 333da5c369Sopenharmony_ci AT_SYMLINK_NOFOLLOW; 343da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 353da5c369Sopenharmony_ci AT_NO_AUTOMOUNT; 363da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 373da5c369Sopenharmony_ci AT_EMPTY_PATH; 383da5c369Sopenharmony_ci #[cfg(any(target_os = "illumos", target_os = "solaris"))] 393da5c369Sopenharmony_ci AT_EACCESS; 403da5c369Sopenharmony_ci } 413da5c369Sopenharmony_ci} 423da5c369Sopenharmony_ci 433da5c369Sopenharmony_ci#[cfg(any(feature = "fs", feature = "term"))] 443da5c369Sopenharmony_cilibc_bitflags!( 453da5c369Sopenharmony_ci /// Configuration options for opened files. 463da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))] 473da5c369Sopenharmony_ci pub struct OFlag: c_int { 483da5c369Sopenharmony_ci /// Mask for the access mode of the file. 493da5c369Sopenharmony_ci O_ACCMODE; 503da5c369Sopenharmony_ci /// Use alternate I/O semantics. 513da5c369Sopenharmony_ci #[cfg(target_os = "netbsd")] 523da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 533da5c369Sopenharmony_ci O_ALT_IO; 543da5c369Sopenharmony_ci /// Open the file in append-only mode. 553da5c369Sopenharmony_ci O_APPEND; 563da5c369Sopenharmony_ci /// Generate a signal when input or output becomes possible. 573da5c369Sopenharmony_ci #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] 583da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 593da5c369Sopenharmony_ci O_ASYNC; 603da5c369Sopenharmony_ci /// Closes the file descriptor once an `execve` call is made. 613da5c369Sopenharmony_ci /// 623da5c369Sopenharmony_ci /// Also sets the file offset to the beginning of the file. 633da5c369Sopenharmony_ci O_CLOEXEC; 643da5c369Sopenharmony_ci /// Create the file if it does not exist. 653da5c369Sopenharmony_ci O_CREAT; 663da5c369Sopenharmony_ci /// Try to minimize cache effects of the I/O for this file. 673da5c369Sopenharmony_ci #[cfg(any(target_os = "android", 683da5c369Sopenharmony_ci target_os = "dragonfly", 693da5c369Sopenharmony_ci target_os = "freebsd", 703da5c369Sopenharmony_ci target_os = "linux", 713da5c369Sopenharmony_ci target_os = "netbsd"))] 723da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 733da5c369Sopenharmony_ci O_DIRECT; 743da5c369Sopenharmony_ci /// If the specified path isn't a directory, fail. 753da5c369Sopenharmony_ci #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] 763da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 773da5c369Sopenharmony_ci O_DIRECTORY; 783da5c369Sopenharmony_ci /// Implicitly follow each `write()` with an `fdatasync()`. 793da5c369Sopenharmony_ci #[cfg(any(target_os = "android", 803da5c369Sopenharmony_ci target_os = "ios", 813da5c369Sopenharmony_ci target_os = "linux", 823da5c369Sopenharmony_ci target_os = "macos", 833da5c369Sopenharmony_ci target_os = "netbsd", 843da5c369Sopenharmony_ci target_os = "openbsd"))] 853da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 863da5c369Sopenharmony_ci O_DSYNC; 873da5c369Sopenharmony_ci /// Error out if a file was not created. 883da5c369Sopenharmony_ci O_EXCL; 893da5c369Sopenharmony_ci /// Open for execute only. 903da5c369Sopenharmony_ci #[cfg(target_os = "freebsd")] 913da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 923da5c369Sopenharmony_ci O_EXEC; 933da5c369Sopenharmony_ci /// Open with an exclusive file lock. 943da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", 953da5c369Sopenharmony_ci target_os = "freebsd", 963da5c369Sopenharmony_ci target_os = "ios", 973da5c369Sopenharmony_ci target_os = "macos", 983da5c369Sopenharmony_ci target_os = "netbsd", 993da5c369Sopenharmony_ci target_os = "openbsd", 1003da5c369Sopenharmony_ci target_os = "redox"))] 1013da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1023da5c369Sopenharmony_ci O_EXLOCK; 1033da5c369Sopenharmony_ci /// Same as `O_SYNC`. 1043da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", 1053da5c369Sopenharmony_ci target_os = "freebsd", 1063da5c369Sopenharmony_ci target_os = "ios", 1073da5c369Sopenharmony_ci all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos"))), 1083da5c369Sopenharmony_ci target_os = "macos", 1093da5c369Sopenharmony_ci target_os = "netbsd", 1103da5c369Sopenharmony_ci target_os = "openbsd", 1113da5c369Sopenharmony_ci target_os = "redox"))] 1123da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1133da5c369Sopenharmony_ci O_FSYNC; 1143da5c369Sopenharmony_ci /// Allow files whose sizes can't be represented in an `off_t` to be opened. 1153da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 1163da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1173da5c369Sopenharmony_ci O_LARGEFILE; 1183da5c369Sopenharmony_ci /// Do not update the file last access time during `read(2)`s. 1193da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 1203da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1213da5c369Sopenharmony_ci O_NOATIME; 1223da5c369Sopenharmony_ci /// Don't attach the device as the process' controlling terminal. 1233da5c369Sopenharmony_ci #[cfg(not(target_os = "redox"))] 1243da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1253da5c369Sopenharmony_ci O_NOCTTY; 1263da5c369Sopenharmony_ci /// Same as `O_NONBLOCK`. 1273da5c369Sopenharmony_ci #[cfg(not(any(target_os = "redox", target_os = "haiku")))] 1283da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1293da5c369Sopenharmony_ci O_NDELAY; 1303da5c369Sopenharmony_ci /// `open()` will fail if the given path is a symbolic link. 1313da5c369Sopenharmony_ci O_NOFOLLOW; 1323da5c369Sopenharmony_ci /// When possible, open the file in nonblocking mode. 1333da5c369Sopenharmony_ci O_NONBLOCK; 1343da5c369Sopenharmony_ci /// Don't deliver `SIGPIPE`. 1353da5c369Sopenharmony_ci #[cfg(target_os = "netbsd")] 1363da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1373da5c369Sopenharmony_ci O_NOSIGPIPE; 1383da5c369Sopenharmony_ci /// Obtain a file descriptor for low-level access. 1393da5c369Sopenharmony_ci /// 1403da5c369Sopenharmony_ci /// The file itself is not opened and other file operations will fail. 1413da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] 1423da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1433da5c369Sopenharmony_ci O_PATH; 1443da5c369Sopenharmony_ci /// Only allow reading. 1453da5c369Sopenharmony_ci /// 1463da5c369Sopenharmony_ci /// This should not be combined with `O_WRONLY` or `O_RDWR`. 1473da5c369Sopenharmony_ci O_RDONLY; 1483da5c369Sopenharmony_ci /// Allow both reading and writing. 1493da5c369Sopenharmony_ci /// 1503da5c369Sopenharmony_ci /// This should not be combined with `O_WRONLY` or `O_RDONLY`. 1513da5c369Sopenharmony_ci O_RDWR; 1523da5c369Sopenharmony_ci /// Similar to `O_DSYNC` but applies to `read`s instead. 1533da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] 1543da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1553da5c369Sopenharmony_ci O_RSYNC; 1563da5c369Sopenharmony_ci /// Skip search permission checks. 1573da5c369Sopenharmony_ci #[cfg(target_os = "netbsd")] 1583da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1593da5c369Sopenharmony_ci O_SEARCH; 1603da5c369Sopenharmony_ci /// Open with a shared file lock. 1613da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", 1623da5c369Sopenharmony_ci target_os = "freebsd", 1633da5c369Sopenharmony_ci target_os = "ios", 1643da5c369Sopenharmony_ci target_os = "macos", 1653da5c369Sopenharmony_ci target_os = "netbsd", 1663da5c369Sopenharmony_ci target_os = "openbsd", 1673da5c369Sopenharmony_ci target_os = "redox"))] 1683da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1693da5c369Sopenharmony_ci O_SHLOCK; 1703da5c369Sopenharmony_ci /// Implicitly follow each `write()` with an `fsync()`. 1713da5c369Sopenharmony_ci #[cfg(not(target_os = "redox"))] 1723da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1733da5c369Sopenharmony_ci O_SYNC; 1743da5c369Sopenharmony_ci /// Create an unnamed temporary file. 1753da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 1763da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1773da5c369Sopenharmony_ci O_TMPFILE; 1783da5c369Sopenharmony_ci /// Truncate an existing regular file to 0 length if it allows writing. 1793da5c369Sopenharmony_ci O_TRUNC; 1803da5c369Sopenharmony_ci /// Restore default TTY attributes. 1813da5c369Sopenharmony_ci #[cfg(target_os = "freebsd")] 1823da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1833da5c369Sopenharmony_ci O_TTY_INIT; 1843da5c369Sopenharmony_ci /// Only allow writing. 1853da5c369Sopenharmony_ci /// 1863da5c369Sopenharmony_ci /// This should not be combined with `O_RDONLY` or `O_RDWR`. 1873da5c369Sopenharmony_ci O_WRONLY; 1883da5c369Sopenharmony_ci } 1893da5c369Sopenharmony_ci); 1903da5c369Sopenharmony_ci 1913da5c369Sopenharmony_cifeature! { 1923da5c369Sopenharmony_ci#![feature = "fs"] 1933da5c369Sopenharmony_ci 1943da5c369Sopenharmony_ci// The conversion is not identical on all operating systems. 1953da5c369Sopenharmony_ci#[allow(clippy::useless_conversion)] 1963da5c369Sopenharmony_cipub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> { 1973da5c369Sopenharmony_ci let fd = path.with_nix_path(|cstr| { 1983da5c369Sopenharmony_ci unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } 1993da5c369Sopenharmony_ci })?; 2003da5c369Sopenharmony_ci 2013da5c369Sopenharmony_ci Errno::result(fd) 2023da5c369Sopenharmony_ci} 2033da5c369Sopenharmony_ci 2043da5c369Sopenharmony_ci// The conversion is not identical on all operating systems. 2053da5c369Sopenharmony_ci#[allow(clippy::useless_conversion)] 2063da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 2073da5c369Sopenharmony_cipub fn openat<P: ?Sized + NixPath>( 2083da5c369Sopenharmony_ci dirfd: RawFd, 2093da5c369Sopenharmony_ci path: &P, 2103da5c369Sopenharmony_ci oflag: OFlag, 2113da5c369Sopenharmony_ci mode: Mode, 2123da5c369Sopenharmony_ci) -> Result<RawFd> { 2133da5c369Sopenharmony_ci let fd = path.with_nix_path(|cstr| { 2143da5c369Sopenharmony_ci unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } 2153da5c369Sopenharmony_ci })?; 2163da5c369Sopenharmony_ci Errno::result(fd) 2173da5c369Sopenharmony_ci} 2183da5c369Sopenharmony_ci 2193da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 2203da5c369Sopenharmony_cipub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( 2213da5c369Sopenharmony_ci old_dirfd: Option<RawFd>, 2223da5c369Sopenharmony_ci old_path: &P1, 2233da5c369Sopenharmony_ci new_dirfd: Option<RawFd>, 2243da5c369Sopenharmony_ci new_path: &P2, 2253da5c369Sopenharmony_ci) -> Result<()> { 2263da5c369Sopenharmony_ci let res = old_path.with_nix_path(|old_cstr| { 2273da5c369Sopenharmony_ci new_path.with_nix_path(|new_cstr| unsafe { 2283da5c369Sopenharmony_ci libc::renameat( 2293da5c369Sopenharmony_ci at_rawfd(old_dirfd), 2303da5c369Sopenharmony_ci old_cstr.as_ptr(), 2313da5c369Sopenharmony_ci at_rawfd(new_dirfd), 2323da5c369Sopenharmony_ci new_cstr.as_ptr(), 2333da5c369Sopenharmony_ci ) 2343da5c369Sopenharmony_ci }) 2353da5c369Sopenharmony_ci })??; 2363da5c369Sopenharmony_ci Errno::result(res).map(drop) 2373da5c369Sopenharmony_ci} 2383da5c369Sopenharmony_ci} 2393da5c369Sopenharmony_ci 2403da5c369Sopenharmony_ci#[cfg(all(target_os = "linux", target_env = "gnu",))] 2413da5c369Sopenharmony_ci#[cfg(feature = "fs")] 2423da5c369Sopenharmony_cilibc_bitflags! { 2433da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 2443da5c369Sopenharmony_ci pub struct RenameFlags: u32 { 2453da5c369Sopenharmony_ci RENAME_EXCHANGE; 2463da5c369Sopenharmony_ci RENAME_NOREPLACE; 2473da5c369Sopenharmony_ci RENAME_WHITEOUT; 2483da5c369Sopenharmony_ci } 2493da5c369Sopenharmony_ci} 2503da5c369Sopenharmony_ci 2513da5c369Sopenharmony_cifeature! { 2523da5c369Sopenharmony_ci#![feature = "fs"] 2533da5c369Sopenharmony_ci#[cfg(all( 2543da5c369Sopenharmony_ci target_os = "linux", 2553da5c369Sopenharmony_ci target_env = "gnu", 2563da5c369Sopenharmony_ci))] 2573da5c369Sopenharmony_cipub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( 2583da5c369Sopenharmony_ci old_dirfd: Option<RawFd>, 2593da5c369Sopenharmony_ci old_path: &P1, 2603da5c369Sopenharmony_ci new_dirfd: Option<RawFd>, 2613da5c369Sopenharmony_ci new_path: &P2, 2623da5c369Sopenharmony_ci flags: RenameFlags, 2633da5c369Sopenharmony_ci) -> Result<()> { 2643da5c369Sopenharmony_ci let res = old_path.with_nix_path(|old_cstr| { 2653da5c369Sopenharmony_ci new_path.with_nix_path(|new_cstr| unsafe { 2663da5c369Sopenharmony_ci libc::renameat2( 2673da5c369Sopenharmony_ci at_rawfd(old_dirfd), 2683da5c369Sopenharmony_ci old_cstr.as_ptr(), 2693da5c369Sopenharmony_ci at_rawfd(new_dirfd), 2703da5c369Sopenharmony_ci new_cstr.as_ptr(), 2713da5c369Sopenharmony_ci flags.bits(), 2723da5c369Sopenharmony_ci ) 2733da5c369Sopenharmony_ci }) 2743da5c369Sopenharmony_ci })??; 2753da5c369Sopenharmony_ci Errno::result(res).map(drop) 2763da5c369Sopenharmony_ci} 2773da5c369Sopenharmony_ci 2783da5c369Sopenharmony_cifn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> { 2793da5c369Sopenharmony_ci unsafe { v.set_len(len as usize) } 2803da5c369Sopenharmony_ci v.shrink_to_fit(); 2813da5c369Sopenharmony_ci Ok(OsString::from_vec(v.to_vec())) 2823da5c369Sopenharmony_ci} 2833da5c369Sopenharmony_ci 2843da5c369Sopenharmony_cifn readlink_maybe_at<P: ?Sized + NixPath>( 2853da5c369Sopenharmony_ci dirfd: Option<RawFd>, 2863da5c369Sopenharmony_ci path: &P, 2873da5c369Sopenharmony_ci v: &mut Vec<u8>, 2883da5c369Sopenharmony_ci) -> Result<libc::ssize_t> { 2893da5c369Sopenharmony_ci path.with_nix_path(|cstr| unsafe { 2903da5c369Sopenharmony_ci match dirfd { 2913da5c369Sopenharmony_ci #[cfg(target_os = "redox")] 2923da5c369Sopenharmony_ci Some(_) => unreachable!(), 2933da5c369Sopenharmony_ci #[cfg(not(target_os = "redox"))] 2943da5c369Sopenharmony_ci Some(dirfd) => libc::readlinkat( 2953da5c369Sopenharmony_ci dirfd, 2963da5c369Sopenharmony_ci cstr.as_ptr(), 2973da5c369Sopenharmony_ci v.as_mut_ptr() as *mut c_char, 2983da5c369Sopenharmony_ci v.capacity() as size_t, 2993da5c369Sopenharmony_ci ), 3003da5c369Sopenharmony_ci None => libc::readlink( 3013da5c369Sopenharmony_ci cstr.as_ptr(), 3023da5c369Sopenharmony_ci v.as_mut_ptr() as *mut c_char, 3033da5c369Sopenharmony_ci v.capacity() as size_t, 3043da5c369Sopenharmony_ci ), 3053da5c369Sopenharmony_ci } 3063da5c369Sopenharmony_ci }) 3073da5c369Sopenharmony_ci} 3083da5c369Sopenharmony_ci 3093da5c369Sopenharmony_cifn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> { 3103da5c369Sopenharmony_ci let mut v = Vec::with_capacity(libc::PATH_MAX as usize); 3113da5c369Sopenharmony_ci // simple case: result is strictly less than `PATH_MAX` 3123da5c369Sopenharmony_ci let res = readlink_maybe_at(dirfd, path, &mut v)?; 3133da5c369Sopenharmony_ci let len = Errno::result(res)?; 3143da5c369Sopenharmony_ci debug_assert!(len >= 0); 3153da5c369Sopenharmony_ci if (len as usize) < v.capacity() { 3163da5c369Sopenharmony_ci return wrap_readlink_result(v, res); 3173da5c369Sopenharmony_ci } 3183da5c369Sopenharmony_ci // Uh oh, the result is too long... 3193da5c369Sopenharmony_ci // Let's try to ask lstat how many bytes to allocate. 3203da5c369Sopenharmony_ci let reported_size = match dirfd { 3213da5c369Sopenharmony_ci #[cfg(target_os = "redox")] 3223da5c369Sopenharmony_ci Some(_) => unreachable!(), 3233da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 3243da5c369Sopenharmony_ci Some(dirfd) => { 3253da5c369Sopenharmony_ci let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() }; 3263da5c369Sopenharmony_ci super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW) 3273da5c369Sopenharmony_ci }, 3283da5c369Sopenharmony_ci #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))] 3293da5c369Sopenharmony_ci Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW), 3303da5c369Sopenharmony_ci None => super::sys::stat::lstat(path) 3313da5c369Sopenharmony_ci } 3323da5c369Sopenharmony_ci .map(|x| x.st_size) 3333da5c369Sopenharmony_ci .unwrap_or(0); 3343da5c369Sopenharmony_ci let mut try_size = if reported_size > 0 { 3353da5c369Sopenharmony_ci // Note: even if `lstat`'s apparently valid answer turns out to be 3363da5c369Sopenharmony_ci // wrong, we will still read the full symlink no matter what. 3373da5c369Sopenharmony_ci reported_size as usize + 1 3383da5c369Sopenharmony_ci } else { 3393da5c369Sopenharmony_ci // If lstat doesn't cooperate, or reports an error, be a little less 3403da5c369Sopenharmony_ci // precise. 3413da5c369Sopenharmony_ci (libc::PATH_MAX as usize).max(128) << 1 3423da5c369Sopenharmony_ci }; 3433da5c369Sopenharmony_ci loop { 3443da5c369Sopenharmony_ci v.reserve_exact(try_size); 3453da5c369Sopenharmony_ci let res = readlink_maybe_at(dirfd, path, &mut v)?; 3463da5c369Sopenharmony_ci let len = Errno::result(res)?; 3473da5c369Sopenharmony_ci debug_assert!(len >= 0); 3483da5c369Sopenharmony_ci if (len as usize) < v.capacity() { 3493da5c369Sopenharmony_ci break wrap_readlink_result(v, res); 3503da5c369Sopenharmony_ci } else { 3513da5c369Sopenharmony_ci // Ugh! Still not big enough! 3523da5c369Sopenharmony_ci match try_size.checked_shl(1) { 3533da5c369Sopenharmony_ci Some(next_size) => try_size = next_size, 3543da5c369Sopenharmony_ci // It's absurd that this would happen, but handle it sanely 3553da5c369Sopenharmony_ci // anyway. 3563da5c369Sopenharmony_ci None => break Err(Errno::ENAMETOOLONG), 3573da5c369Sopenharmony_ci } 3583da5c369Sopenharmony_ci } 3593da5c369Sopenharmony_ci } 3603da5c369Sopenharmony_ci} 3613da5c369Sopenharmony_ci 3623da5c369Sopenharmony_cipub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> { 3633da5c369Sopenharmony_ci inner_readlink(None, path) 3643da5c369Sopenharmony_ci} 3653da5c369Sopenharmony_ci 3663da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 3673da5c369Sopenharmony_cipub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> { 3683da5c369Sopenharmony_ci inner_readlink(Some(dirfd), path) 3693da5c369Sopenharmony_ci} 3703da5c369Sopenharmony_ci 3713da5c369Sopenharmony_ci/// Computes the raw fd consumed by a function of the form `*at`. 3723da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 3733da5c369Sopenharmony_cipub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int { 3743da5c369Sopenharmony_ci match fd { 3753da5c369Sopenharmony_ci None => libc::AT_FDCWD, 3763da5c369Sopenharmony_ci Some(fd) => fd, 3773da5c369Sopenharmony_ci } 3783da5c369Sopenharmony_ci} 3793da5c369Sopenharmony_ci} 3803da5c369Sopenharmony_ci 3813da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] 3823da5c369Sopenharmony_ci#[cfg(feature = "fs")] 3833da5c369Sopenharmony_cilibc_bitflags!( 3843da5c369Sopenharmony_ci /// Additional flags for file sealing, which allows for limiting operations on a file. 3853da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 3863da5c369Sopenharmony_ci pub struct SealFlag: c_int { 3873da5c369Sopenharmony_ci /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`. 3883da5c369Sopenharmony_ci F_SEAL_SEAL; 3893da5c369Sopenharmony_ci /// The file cannot be reduced in size. 3903da5c369Sopenharmony_ci F_SEAL_SHRINK; 3913da5c369Sopenharmony_ci /// The size of the file cannot be increased. 3923da5c369Sopenharmony_ci F_SEAL_GROW; 3933da5c369Sopenharmony_ci /// The file contents cannot be modified. 3943da5c369Sopenharmony_ci F_SEAL_WRITE; 3953da5c369Sopenharmony_ci } 3963da5c369Sopenharmony_ci); 3973da5c369Sopenharmony_ci 3983da5c369Sopenharmony_ci#[cfg(feature = "fs")] 3993da5c369Sopenharmony_cilibc_bitflags!( 4003da5c369Sopenharmony_ci /// Additional configuration flags for `fcntl`'s `F_SETFD`. 4013da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 4023da5c369Sopenharmony_ci pub struct FdFlag: c_int { 4033da5c369Sopenharmony_ci /// The file descriptor will automatically be closed during a successful `execve(2)`. 4043da5c369Sopenharmony_ci FD_CLOEXEC; 4053da5c369Sopenharmony_ci } 4063da5c369Sopenharmony_ci); 4073da5c369Sopenharmony_ci 4083da5c369Sopenharmony_cifeature! { 4093da5c369Sopenharmony_ci#![feature = "fs"] 4103da5c369Sopenharmony_ci 4113da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 4123da5c369Sopenharmony_ci#[derive(Debug, Eq, Hash, PartialEq)] 4133da5c369Sopenharmony_ci#[non_exhaustive] 4143da5c369Sopenharmony_cipub enum FcntlArg<'a> { 4153da5c369Sopenharmony_ci F_DUPFD(RawFd), 4163da5c369Sopenharmony_ci F_DUPFD_CLOEXEC(RawFd), 4173da5c369Sopenharmony_ci F_GETFD, 4183da5c369Sopenharmony_ci F_SETFD(FdFlag), // FD_FLAGS 4193da5c369Sopenharmony_ci F_GETFL, 4203da5c369Sopenharmony_ci F_SETFL(OFlag), // O_NONBLOCK 4213da5c369Sopenharmony_ci F_SETLK(&'a libc::flock), 4223da5c369Sopenharmony_ci F_SETLKW(&'a libc::flock), 4233da5c369Sopenharmony_ci F_GETLK(&'a mut libc::flock), 4243da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4253da5c369Sopenharmony_ci F_OFD_SETLK(&'a libc::flock), 4263da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4273da5c369Sopenharmony_ci F_OFD_SETLKW(&'a libc::flock), 4283da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4293da5c369Sopenharmony_ci F_OFD_GETLK(&'a mut libc::flock), 4303da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] 4313da5c369Sopenharmony_ci F_ADD_SEALS(SealFlag), 4323da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] 4333da5c369Sopenharmony_ci F_GET_SEALS, 4343da5c369Sopenharmony_ci #[cfg(any(target_os = "macos", target_os = "ios"))] 4353da5c369Sopenharmony_ci F_FULLFSYNC, 4363da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4373da5c369Sopenharmony_ci F_GETPIPE_SZ, 4383da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4393da5c369Sopenharmony_ci F_SETPIPE_SZ(c_int), 4403da5c369Sopenharmony_ci // TODO: Rest of flags 4413da5c369Sopenharmony_ci} 4423da5c369Sopenharmony_ci 4433da5c369Sopenharmony_ci#[cfg(target_os = "redox")] 4443da5c369Sopenharmony_ci#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] 4453da5c369Sopenharmony_ci#[non_exhaustive] 4463da5c369Sopenharmony_cipub enum FcntlArg { 4473da5c369Sopenharmony_ci F_DUPFD(RawFd), 4483da5c369Sopenharmony_ci F_DUPFD_CLOEXEC(RawFd), 4493da5c369Sopenharmony_ci F_GETFD, 4503da5c369Sopenharmony_ci F_SETFD(FdFlag), // FD_FLAGS 4513da5c369Sopenharmony_ci F_GETFL, 4523da5c369Sopenharmony_ci F_SETFL(OFlag), // O_NONBLOCK 4533da5c369Sopenharmony_ci} 4543da5c369Sopenharmony_cipub use self::FcntlArg::*; 4553da5c369Sopenharmony_ci 4563da5c369Sopenharmony_ci// TODO: Figure out how to handle value fcntl returns 4573da5c369Sopenharmony_cipub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> { 4583da5c369Sopenharmony_ci let res = unsafe { 4593da5c369Sopenharmony_ci match arg { 4603da5c369Sopenharmony_ci F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd), 4613da5c369Sopenharmony_ci F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd), 4623da5c369Sopenharmony_ci F_GETFD => libc::fcntl(fd, libc::F_GETFD), 4633da5c369Sopenharmony_ci F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()), 4643da5c369Sopenharmony_ci F_GETFL => libc::fcntl(fd, libc::F_GETFL), 4653da5c369Sopenharmony_ci F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()), 4663da5c369Sopenharmony_ci #[cfg(not(target_os = "redox"))] 4673da5c369Sopenharmony_ci F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock), 4683da5c369Sopenharmony_ci #[cfg(not(target_os = "redox"))] 4693da5c369Sopenharmony_ci F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock), 4703da5c369Sopenharmony_ci #[cfg(not(target_os = "redox"))] 4713da5c369Sopenharmony_ci F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock), 4723da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 4733da5c369Sopenharmony_ci F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock), 4743da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 4753da5c369Sopenharmony_ci F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), 4763da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux"))] 4773da5c369Sopenharmony_ci F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), 4783da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] 4793da5c369Sopenharmony_ci F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()), 4803da5c369Sopenharmony_ci #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] 4813da5c369Sopenharmony_ci F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), 4823da5c369Sopenharmony_ci #[cfg(any(target_os = "macos", target_os = "ios"))] 4833da5c369Sopenharmony_ci F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), 4843da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4853da5c369Sopenharmony_ci F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ), 4863da5c369Sopenharmony_ci #[cfg(any(target_os = "linux", target_os = "android"))] 4873da5c369Sopenharmony_ci F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size), 4883da5c369Sopenharmony_ci } 4893da5c369Sopenharmony_ci }; 4903da5c369Sopenharmony_ci 4913da5c369Sopenharmony_ci Errno::result(res) 4923da5c369Sopenharmony_ci} 4933da5c369Sopenharmony_ci 4943da5c369Sopenharmony_ci// TODO: convert to libc_enum 4953da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 4963da5c369Sopenharmony_ci#[non_exhaustive] 4973da5c369Sopenharmony_cipub enum FlockArg { 4983da5c369Sopenharmony_ci LockShared, 4993da5c369Sopenharmony_ci LockExclusive, 5003da5c369Sopenharmony_ci Unlock, 5013da5c369Sopenharmony_ci LockSharedNonblock, 5023da5c369Sopenharmony_ci LockExclusiveNonblock, 5033da5c369Sopenharmony_ci UnlockNonblock, 5043da5c369Sopenharmony_ci} 5053da5c369Sopenharmony_ci 5063da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] 5073da5c369Sopenharmony_cipub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { 5083da5c369Sopenharmony_ci use self::FlockArg::*; 5093da5c369Sopenharmony_ci 5103da5c369Sopenharmony_ci let res = unsafe { 5113da5c369Sopenharmony_ci match arg { 5123da5c369Sopenharmony_ci LockShared => libc::flock(fd, libc::LOCK_SH), 5133da5c369Sopenharmony_ci LockExclusive => libc::flock(fd, libc::LOCK_EX), 5143da5c369Sopenharmony_ci Unlock => libc::flock(fd, libc::LOCK_UN), 5153da5c369Sopenharmony_ci LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB), 5163da5c369Sopenharmony_ci LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB), 5173da5c369Sopenharmony_ci UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB), 5183da5c369Sopenharmony_ci } 5193da5c369Sopenharmony_ci }; 5203da5c369Sopenharmony_ci 5213da5c369Sopenharmony_ci Errno::result(res).map(drop) 5223da5c369Sopenharmony_ci} 5233da5c369Sopenharmony_ci} 5243da5c369Sopenharmony_ci 5253da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))] 5263da5c369Sopenharmony_ci#[cfg(feature = "zerocopy")] 5273da5c369Sopenharmony_cilibc_bitflags! { 5283da5c369Sopenharmony_ci /// Additional flags to `splice` and friends. 5293da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(feature = "zerocopy")))] 5303da5c369Sopenharmony_ci pub struct SpliceFFlags: c_uint { 5313da5c369Sopenharmony_ci /// Request that pages be moved instead of copied. 5323da5c369Sopenharmony_ci /// 5333da5c369Sopenharmony_ci /// Not applicable to `vmsplice`. 5343da5c369Sopenharmony_ci SPLICE_F_MOVE; 5353da5c369Sopenharmony_ci /// Do not block on I/O. 5363da5c369Sopenharmony_ci SPLICE_F_NONBLOCK; 5373da5c369Sopenharmony_ci /// Hint that more data will be coming in a subsequent splice. 5383da5c369Sopenharmony_ci /// 5393da5c369Sopenharmony_ci /// Not applicable to `vmsplice`. 5403da5c369Sopenharmony_ci SPLICE_F_MORE; 5413da5c369Sopenharmony_ci /// Gift the user pages to the kernel. 5423da5c369Sopenharmony_ci /// 5433da5c369Sopenharmony_ci /// Not applicable to `splice`. 5443da5c369Sopenharmony_ci SPLICE_F_GIFT; 5453da5c369Sopenharmony_ci } 5463da5c369Sopenharmony_ci} 5473da5c369Sopenharmony_ci 5483da5c369Sopenharmony_cifeature! { 5493da5c369Sopenharmony_ci#![feature = "zerocopy"] 5503da5c369Sopenharmony_ci 5513da5c369Sopenharmony_ci/// Copy a range of data from one file to another 5523da5c369Sopenharmony_ci/// 5533da5c369Sopenharmony_ci/// The `copy_file_range` system call performs an in-kernel copy between 5543da5c369Sopenharmony_ci/// file descriptors `fd_in` and `fd_out` without the additional cost of 5553da5c369Sopenharmony_ci/// transferring data from the kernel to user space and then back into the 5563da5c369Sopenharmony_ci/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to 5573da5c369Sopenharmony_ci/// file descriptor `fd_out`, overwriting any data that exists within the 5583da5c369Sopenharmony_ci/// requested range of the target file. 5593da5c369Sopenharmony_ci/// 5603da5c369Sopenharmony_ci/// If the `off_in` and/or `off_out` arguments are used, the values 5613da5c369Sopenharmony_ci/// will be mutated to reflect the new position within the file after 5623da5c369Sopenharmony_ci/// copying. If they are not used, the relevant filedescriptors will be seeked 5633da5c369Sopenharmony_ci/// to the new position. 5643da5c369Sopenharmony_ci/// 5653da5c369Sopenharmony_ci/// On successful completion the number of bytes actually copied will be 5663da5c369Sopenharmony_ci/// returned. 5673da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))] 5683da5c369Sopenharmony_cipub fn copy_file_range( 5693da5c369Sopenharmony_ci fd_in: RawFd, 5703da5c369Sopenharmony_ci off_in: Option<&mut libc::loff_t>, 5713da5c369Sopenharmony_ci fd_out: RawFd, 5723da5c369Sopenharmony_ci off_out: Option<&mut libc::loff_t>, 5733da5c369Sopenharmony_ci len: usize, 5743da5c369Sopenharmony_ci) -> Result<usize> { 5753da5c369Sopenharmony_ci let off_in = off_in 5763da5c369Sopenharmony_ci .map(|offset| offset as *mut libc::loff_t) 5773da5c369Sopenharmony_ci .unwrap_or(ptr::null_mut()); 5783da5c369Sopenharmony_ci let off_out = off_out 5793da5c369Sopenharmony_ci .map(|offset| offset as *mut libc::loff_t) 5803da5c369Sopenharmony_ci .unwrap_or(ptr::null_mut()); 5813da5c369Sopenharmony_ci 5823da5c369Sopenharmony_ci let ret = unsafe { 5833da5c369Sopenharmony_ci libc::syscall( 5843da5c369Sopenharmony_ci libc::SYS_copy_file_range, 5853da5c369Sopenharmony_ci fd_in, 5863da5c369Sopenharmony_ci off_in, 5873da5c369Sopenharmony_ci fd_out, 5883da5c369Sopenharmony_ci off_out, 5893da5c369Sopenharmony_ci len, 5903da5c369Sopenharmony_ci 0, 5913da5c369Sopenharmony_ci ) 5923da5c369Sopenharmony_ci }; 5933da5c369Sopenharmony_ci Errno::result(ret).map(|r| r as usize) 5943da5c369Sopenharmony_ci} 5953da5c369Sopenharmony_ci 5963da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))] 5973da5c369Sopenharmony_cipub fn splice( 5983da5c369Sopenharmony_ci fd_in: RawFd, 5993da5c369Sopenharmony_ci off_in: Option<&mut libc::loff_t>, 6003da5c369Sopenharmony_ci fd_out: RawFd, 6013da5c369Sopenharmony_ci off_out: Option<&mut libc::loff_t>, 6023da5c369Sopenharmony_ci len: usize, 6033da5c369Sopenharmony_ci flags: SpliceFFlags, 6043da5c369Sopenharmony_ci) -> Result<usize> { 6053da5c369Sopenharmony_ci let off_in = off_in 6063da5c369Sopenharmony_ci .map(|offset| offset as *mut libc::loff_t) 6073da5c369Sopenharmony_ci .unwrap_or(ptr::null_mut()); 6083da5c369Sopenharmony_ci let off_out = off_out 6093da5c369Sopenharmony_ci .map(|offset| offset as *mut libc::loff_t) 6103da5c369Sopenharmony_ci .unwrap_or(ptr::null_mut()); 6113da5c369Sopenharmony_ci 6123da5c369Sopenharmony_ci let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) }; 6133da5c369Sopenharmony_ci Errno::result(ret).map(|r| r as usize) 6143da5c369Sopenharmony_ci} 6153da5c369Sopenharmony_ci 6163da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))] 6173da5c369Sopenharmony_cipub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> { 6183da5c369Sopenharmony_ci let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) }; 6193da5c369Sopenharmony_ci Errno::result(ret).map(|r| r as usize) 6203da5c369Sopenharmony_ci} 6213da5c369Sopenharmony_ci 6223da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))] 6233da5c369Sopenharmony_cipub fn vmsplice( 6243da5c369Sopenharmony_ci fd: RawFd, 6253da5c369Sopenharmony_ci iov: &[std::io::IoSlice<'_>], 6263da5c369Sopenharmony_ci flags: SpliceFFlags 6273da5c369Sopenharmony_ci ) -> Result<usize> 6283da5c369Sopenharmony_ci{ 6293da5c369Sopenharmony_ci let ret = unsafe { 6303da5c369Sopenharmony_ci libc::vmsplice( 6313da5c369Sopenharmony_ci fd, 6323da5c369Sopenharmony_ci iov.as_ptr() as *const libc::iovec, 6333da5c369Sopenharmony_ci iov.len(), 6343da5c369Sopenharmony_ci flags.bits(), 6353da5c369Sopenharmony_ci ) 6363da5c369Sopenharmony_ci }; 6373da5c369Sopenharmony_ci Errno::result(ret).map(|r| r as usize) 6383da5c369Sopenharmony_ci} 6393da5c369Sopenharmony_ci} 6403da5c369Sopenharmony_ci 6413da5c369Sopenharmony_ci#[cfg(any(target_os = "linux"))] 6423da5c369Sopenharmony_ci#[cfg(feature = "fs")] 6433da5c369Sopenharmony_cilibc_bitflags!( 6443da5c369Sopenharmony_ci /// Mode argument flags for fallocate determining operation performed on a given range. 6453da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 6463da5c369Sopenharmony_ci pub struct FallocateFlags: c_int { 6473da5c369Sopenharmony_ci /// File size is not changed. 6483da5c369Sopenharmony_ci /// 6493da5c369Sopenharmony_ci /// offset + len can be greater than file size. 6503da5c369Sopenharmony_ci FALLOC_FL_KEEP_SIZE; 6513da5c369Sopenharmony_ci /// Deallocates space by creating a hole. 6523da5c369Sopenharmony_ci /// 6533da5c369Sopenharmony_ci /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes. 6543da5c369Sopenharmony_ci FALLOC_FL_PUNCH_HOLE; 6553da5c369Sopenharmony_ci /// Removes byte range from a file without leaving a hole. 6563da5c369Sopenharmony_ci /// 6573da5c369Sopenharmony_ci /// Byte range to collapse starts at offset and continues for len bytes. 6583da5c369Sopenharmony_ci FALLOC_FL_COLLAPSE_RANGE; 6593da5c369Sopenharmony_ci /// Zeroes space in specified byte range. 6603da5c369Sopenharmony_ci /// 6613da5c369Sopenharmony_ci /// Byte range starts at offset and continues for len bytes. 6623da5c369Sopenharmony_ci FALLOC_FL_ZERO_RANGE; 6633da5c369Sopenharmony_ci /// Increases file space by inserting a hole within the file size. 6643da5c369Sopenharmony_ci /// 6653da5c369Sopenharmony_ci /// Does not overwrite existing data. Hole starts at offset and continues for len bytes. 6663da5c369Sopenharmony_ci FALLOC_FL_INSERT_RANGE; 6673da5c369Sopenharmony_ci /// Shared file data extants are made private to the file. 6683da5c369Sopenharmony_ci /// 6693da5c369Sopenharmony_ci /// Gaurantees that a subsequent write will not fail due to lack of space. 6703da5c369Sopenharmony_ci FALLOC_FL_UNSHARE_RANGE; 6713da5c369Sopenharmony_ci } 6723da5c369Sopenharmony_ci); 6733da5c369Sopenharmony_ci 6743da5c369Sopenharmony_cifeature! { 6753da5c369Sopenharmony_ci#![feature = "fs"] 6763da5c369Sopenharmony_ci 6773da5c369Sopenharmony_ci/// Manipulates file space. 6783da5c369Sopenharmony_ci/// 6793da5c369Sopenharmony_ci/// Allows the caller to directly manipulate the allocated disk space for the 6803da5c369Sopenharmony_ci/// file referred to by fd. 6813da5c369Sopenharmony_ci#[cfg(any(target_os = "linux"))] 6823da5c369Sopenharmony_ci#[cfg(feature = "fs")] 6833da5c369Sopenharmony_cipub fn fallocate( 6843da5c369Sopenharmony_ci fd: RawFd, 6853da5c369Sopenharmony_ci mode: FallocateFlags, 6863da5c369Sopenharmony_ci offset: libc::off_t, 6873da5c369Sopenharmony_ci len: libc::off_t, 6883da5c369Sopenharmony_ci) -> Result<()> { 6893da5c369Sopenharmony_ci let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) }; 6903da5c369Sopenharmony_ci Errno::result(res).map(drop) 6913da5c369Sopenharmony_ci} 6923da5c369Sopenharmony_ci 6933da5c369Sopenharmony_ci/// Argument to [`fspacectl`] describing the range to zero. The first member is 6943da5c369Sopenharmony_ci/// the file offset, and the second is the length of the region. 6953da5c369Sopenharmony_ci#[cfg(any(target_os = "freebsd"))] 6963da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, PartialEq)] 6973da5c369Sopenharmony_cipub struct SpacectlRange(pub libc::off_t, pub libc::off_t); 6983da5c369Sopenharmony_ci 6993da5c369Sopenharmony_ci#[cfg(any(target_os = "freebsd"))] 7003da5c369Sopenharmony_ciimpl SpacectlRange { 7013da5c369Sopenharmony_ci #[inline] 7023da5c369Sopenharmony_ci pub fn is_empty(&self) -> bool { 7033da5c369Sopenharmony_ci self.1 == 0 7043da5c369Sopenharmony_ci } 7053da5c369Sopenharmony_ci 7063da5c369Sopenharmony_ci #[inline] 7073da5c369Sopenharmony_ci pub fn len(&self) -> libc::off_t { 7083da5c369Sopenharmony_ci self.1 7093da5c369Sopenharmony_ci } 7103da5c369Sopenharmony_ci 7113da5c369Sopenharmony_ci #[inline] 7123da5c369Sopenharmony_ci pub fn offset(&self) -> libc::off_t { 7133da5c369Sopenharmony_ci self.0 7143da5c369Sopenharmony_ci } 7153da5c369Sopenharmony_ci} 7163da5c369Sopenharmony_ci 7173da5c369Sopenharmony_ci/// Punch holes in a file. 7183da5c369Sopenharmony_ci/// 7193da5c369Sopenharmony_ci/// `fspacectl` instructs the file system to deallocate a portion of a file. 7203da5c369Sopenharmony_ci/// After a successful operation, this region of the file will return all zeroes 7213da5c369Sopenharmony_ci/// if read. If the file system supports deallocation, then it may free the 7223da5c369Sopenharmony_ci/// underlying storage, too. 7233da5c369Sopenharmony_ci/// 7243da5c369Sopenharmony_ci/// # Arguments 7253da5c369Sopenharmony_ci/// 7263da5c369Sopenharmony_ci/// - `fd` - File to operate on 7273da5c369Sopenharmony_ci/// - `range.0` - File offset at which to begin deallocation 7283da5c369Sopenharmony_ci/// - `range.1` - Length of the region to deallocate 7293da5c369Sopenharmony_ci/// 7303da5c369Sopenharmony_ci/// # Returns 7313da5c369Sopenharmony_ci/// 7323da5c369Sopenharmony_ci/// The operation may deallocate less than the entire requested region. On 7333da5c369Sopenharmony_ci/// success, it returns the region that still remains to be deallocated. The 7343da5c369Sopenharmony_ci/// caller should loop until the returned region is empty. 7353da5c369Sopenharmony_ci/// 7363da5c369Sopenharmony_ci/// # Example 7373da5c369Sopenharmony_ci/// 7383da5c369Sopenharmony_ci#[cfg_attr(fbsd14, doc = " ```")] 7393da5c369Sopenharmony_ci#[cfg_attr(not(fbsd14), doc = " ```no_run")] 7403da5c369Sopenharmony_ci/// # use std::io::Write; 7413da5c369Sopenharmony_ci/// # use std::os::unix::fs::FileExt; 7423da5c369Sopenharmony_ci/// # use std::os::unix::io::AsRawFd; 7433da5c369Sopenharmony_ci/// # use nix::fcntl::*; 7443da5c369Sopenharmony_ci/// # use tempfile::tempfile; 7453da5c369Sopenharmony_ci/// const INITIAL: &[u8] = b"0123456789abcdef"; 7463da5c369Sopenharmony_ci/// let mut f = tempfile().unwrap(); 7473da5c369Sopenharmony_ci/// f.write_all(INITIAL).unwrap(); 7483da5c369Sopenharmony_ci/// let mut range = SpacectlRange(3, 6); 7493da5c369Sopenharmony_ci/// while (!range.is_empty()) { 7503da5c369Sopenharmony_ci/// range = fspacectl(f.as_raw_fd(), range).unwrap(); 7513da5c369Sopenharmony_ci/// } 7523da5c369Sopenharmony_ci/// let mut buf = vec![0; INITIAL.len()]; 7533da5c369Sopenharmony_ci/// f.read_exact_at(&mut buf, 0).unwrap(); 7543da5c369Sopenharmony_ci/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); 7553da5c369Sopenharmony_ci/// ``` 7563da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 7573da5c369Sopenharmony_cipub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> { 7583da5c369Sopenharmony_ci let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1}; 7593da5c369Sopenharmony_ci let res = unsafe { libc::fspacectl( 7603da5c369Sopenharmony_ci fd, 7613da5c369Sopenharmony_ci libc::SPACECTL_DEALLOC, // Only one command is supported ATM 7623da5c369Sopenharmony_ci &rqsr, 7633da5c369Sopenharmony_ci 0, // No flags are currently supported 7643da5c369Sopenharmony_ci &mut rqsr 7653da5c369Sopenharmony_ci )}; 7663da5c369Sopenharmony_ci Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len)) 7673da5c369Sopenharmony_ci} 7683da5c369Sopenharmony_ci 7693da5c369Sopenharmony_ci/// Like [`fspacectl`], but will never return incomplete. 7703da5c369Sopenharmony_ci/// 7713da5c369Sopenharmony_ci/// # Arguments 7723da5c369Sopenharmony_ci/// 7733da5c369Sopenharmony_ci/// - `fd` - File to operate on 7743da5c369Sopenharmony_ci/// - `offset` - File offset at which to begin deallocation 7753da5c369Sopenharmony_ci/// - `len` - Length of the region to deallocate 7763da5c369Sopenharmony_ci/// 7773da5c369Sopenharmony_ci/// # Returns 7783da5c369Sopenharmony_ci/// 7793da5c369Sopenharmony_ci/// Returns `()` on success. On failure, the region may or may not be partially 7803da5c369Sopenharmony_ci/// deallocated. 7813da5c369Sopenharmony_ci/// 7823da5c369Sopenharmony_ci/// # Example 7833da5c369Sopenharmony_ci/// 7843da5c369Sopenharmony_ci#[cfg_attr(fbsd14, doc = " ```")] 7853da5c369Sopenharmony_ci#[cfg_attr(not(fbsd14), doc = " ```no_run")] 7863da5c369Sopenharmony_ci/// # use std::io::Write; 7873da5c369Sopenharmony_ci/// # use std::os::unix::fs::FileExt; 7883da5c369Sopenharmony_ci/// # use std::os::unix::io::AsRawFd; 7893da5c369Sopenharmony_ci/// # use nix::fcntl::*; 7903da5c369Sopenharmony_ci/// # use tempfile::tempfile; 7913da5c369Sopenharmony_ci/// const INITIAL: &[u8] = b"0123456789abcdef"; 7923da5c369Sopenharmony_ci/// let mut f = tempfile().unwrap(); 7933da5c369Sopenharmony_ci/// f.write_all(INITIAL).unwrap(); 7943da5c369Sopenharmony_ci/// fspacectl_all(f.as_raw_fd(), 3, 6).unwrap(); 7953da5c369Sopenharmony_ci/// let mut buf = vec![0; INITIAL.len()]; 7963da5c369Sopenharmony_ci/// f.read_exact_at(&mut buf, 0).unwrap(); 7973da5c369Sopenharmony_ci/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); 7983da5c369Sopenharmony_ci/// ``` 7993da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 8003da5c369Sopenharmony_cipub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) 8013da5c369Sopenharmony_ci -> Result<()> 8023da5c369Sopenharmony_ci{ 8033da5c369Sopenharmony_ci let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len}; 8043da5c369Sopenharmony_ci while rqsr.r_len > 0 { 8053da5c369Sopenharmony_ci let res = unsafe { libc::fspacectl( 8063da5c369Sopenharmony_ci fd, 8073da5c369Sopenharmony_ci libc::SPACECTL_DEALLOC, // Only one command is supported ATM 8083da5c369Sopenharmony_ci &rqsr, 8093da5c369Sopenharmony_ci 0, // No flags are currently supported 8103da5c369Sopenharmony_ci &mut rqsr 8113da5c369Sopenharmony_ci )}; 8123da5c369Sopenharmony_ci Errno::result(res)?; 8133da5c369Sopenharmony_ci } 8143da5c369Sopenharmony_ci Ok(()) 8153da5c369Sopenharmony_ci} 8163da5c369Sopenharmony_ci 8173da5c369Sopenharmony_ci#[cfg(any( 8183da5c369Sopenharmony_ci target_os = "linux", 8193da5c369Sopenharmony_ci target_os = "android", 8203da5c369Sopenharmony_ci target_os = "emscripten", 8213da5c369Sopenharmony_ci target_os = "fuchsia", 8223da5c369Sopenharmony_ci target_os = "wasi", 8233da5c369Sopenharmony_ci target_env = "uclibc", 8243da5c369Sopenharmony_ci target_os = "freebsd" 8253da5c369Sopenharmony_ci))] 8263da5c369Sopenharmony_cimod posix_fadvise { 8273da5c369Sopenharmony_ci use crate::errno::Errno; 8283da5c369Sopenharmony_ci use std::os::unix::io::RawFd; 8293da5c369Sopenharmony_ci use crate::Result; 8303da5c369Sopenharmony_ci 8313da5c369Sopenharmony_ci #[cfg(feature = "fs")] 8323da5c369Sopenharmony_ci libc_enum! { 8333da5c369Sopenharmony_ci #[repr(i32)] 8343da5c369Sopenharmony_ci #[non_exhaustive] 8353da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] 8363da5c369Sopenharmony_ci pub enum PosixFadviseAdvice { 8373da5c369Sopenharmony_ci POSIX_FADV_NORMAL, 8383da5c369Sopenharmony_ci POSIX_FADV_SEQUENTIAL, 8393da5c369Sopenharmony_ci POSIX_FADV_RANDOM, 8403da5c369Sopenharmony_ci POSIX_FADV_NOREUSE, 8413da5c369Sopenharmony_ci POSIX_FADV_WILLNEED, 8423da5c369Sopenharmony_ci POSIX_FADV_DONTNEED, 8433da5c369Sopenharmony_ci } 8443da5c369Sopenharmony_ci } 8453da5c369Sopenharmony_ci 8463da5c369Sopenharmony_ci feature! { 8473da5c369Sopenharmony_ci #![feature = "fs"] 8483da5c369Sopenharmony_ci pub fn posix_fadvise( 8493da5c369Sopenharmony_ci fd: RawFd, 8503da5c369Sopenharmony_ci offset: libc::off_t, 8513da5c369Sopenharmony_ci len: libc::off_t, 8523da5c369Sopenharmony_ci advice: PosixFadviseAdvice, 8533da5c369Sopenharmony_ci ) -> Result<()> { 8543da5c369Sopenharmony_ci let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) }; 8553da5c369Sopenharmony_ci 8563da5c369Sopenharmony_ci if res == 0 { 8573da5c369Sopenharmony_ci Ok(()) 8583da5c369Sopenharmony_ci } else { 8593da5c369Sopenharmony_ci Err(Errno::from_i32(res)) 8603da5c369Sopenharmony_ci } 8613da5c369Sopenharmony_ci } 8623da5c369Sopenharmony_ci } 8633da5c369Sopenharmony_ci} 8643da5c369Sopenharmony_ci 8653da5c369Sopenharmony_ci#[cfg(any( 8663da5c369Sopenharmony_ci target_os = "linux", 8673da5c369Sopenharmony_ci target_os = "android", 8683da5c369Sopenharmony_ci target_os = "dragonfly", 8693da5c369Sopenharmony_ci target_os = "emscripten", 8703da5c369Sopenharmony_ci target_os = "fuchsia", 8713da5c369Sopenharmony_ci target_os = "wasi", 8723da5c369Sopenharmony_ci target_os = "freebsd" 8733da5c369Sopenharmony_ci))] 8743da5c369Sopenharmony_cipub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> { 8753da5c369Sopenharmony_ci let res = unsafe { libc::posix_fallocate(fd, offset, len) }; 8763da5c369Sopenharmony_ci match Errno::result(res) { 8773da5c369Sopenharmony_ci Err(err) => Err(err), 8783da5c369Sopenharmony_ci Ok(0) => Ok(()), 8793da5c369Sopenharmony_ci Ok(errno) => Err(Errno::from_i32(errno)), 8803da5c369Sopenharmony_ci } 8813da5c369Sopenharmony_ci} 8823da5c369Sopenharmony_ci} 883