use std::io;
#[cfg(unix)]
use std::os::fd::BorrowedFd;
use crate::os::CheckLibcResult;
pub use libc::{F_GETFD, F_GETFL, F_SETFD, F_SETFL, FD_CLOEXEC};
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "redox"
))]
pub use libc::{F_LOCK, F_TEST, F_TLOCK, F_ULOCK};
#[cfg(not(target_os = "wasi"))]
pub use libc::{F_DUPFD, F_DUPFD_CLOEXEC, F_GETLK, F_SETLK, F_SETLKW};
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
pub use libc::{F_GETOWN, F_RDLCK, F_SETOWN, F_UNLCK, F_WRLCK, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN};
#[cfg(target_vendor = "apple")]
pub use libc::{F_FULLFSYNC, F_NOCACHE};
#[cfg(target_os = "freebsd")]
pub use libc::{F_DUP2FD, F_DUP2FD_CLOEXEC};
#[cfg(any(target_os = "android", target_os = "linux", target_vendor = "apple"))]
pub use libc::{F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW};
#[cfg(not(target_os = "wasi"))]
pub const FASYNC: libc::c_int = libc::O_ASYNC;
#[cfg(target_vendor = "apple")]
pub use libc::F_RDAHEAD;
#[cfg(target_vendor = "apple")]
mod darwin_fcntl {
pub const F_SETNOSIGPIPE: libc::c_int = 73;
pub const F_GETNOSIGPIPE: libc::c_int = 74;
pub const F_SETLEASE: libc::c_int = 106;
pub const F_GETLEASE: libc::c_int = 107;
}
#[cfg(target_vendor = "apple")]
pub use darwin_fcntl::{F_GETLEASE, F_GETNOSIGPIPE, F_SETLEASE, F_SETNOSIGPIPE};
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
pub use libc::{
F_ADD_SEALS, F_GET_SEALS, F_GETLEASE, F_GETPIPE_SZ, F_NOTIFY, F_SEAL_GROW, F_SEAL_SEAL,
F_SEAL_SHRINK, F_SEAL_WRITE, F_SETLEASE, F_SETPIPE_SZ,
};
#[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_vendor = "apple"))]
pub use libc::F_GETPATH;
pub fn normalize_ioctl_request(request: i64) -> libc::c_ulong {
(request as u32) as libc::c_ulong
}
pub fn fcntl_int(fd: i32, cmd: i32, arg: i32) -> io::Result<i32> {
unsafe { libc::fcntl(fd, cmd, arg) }.check_libc_neg()
}
pub fn validate_fd(fd: i32) -> io::Result<()> {
fcntl_int(fd, libc::F_GETFD, 0).map(|_| ())
}
#[cfg(unix)]
pub fn get_inheritable(fd: BorrowedFd<'_>) -> io::Result<bool> {
use nix::fcntl as nix_fcntl;
let flags = nix_fcntl::FdFlag::from_bits_truncate(
nix_fcntl::fcntl(fd, nix_fcntl::FcntlArg::F_GETFD).map_err(io::Error::from)?,
);
Ok(!flags.contains(nix_fcntl::FdFlag::FD_CLOEXEC))
}
#[cfg(unix)]
pub fn get_blocking(fd: BorrowedFd<'_>) -> io::Result<bool> {
use nix::fcntl as nix_fcntl;
let flags = nix_fcntl::OFlag::from_bits_truncate(
nix_fcntl::fcntl(fd, nix_fcntl::FcntlArg::F_GETFL).map_err(io::Error::from)?,
);
Ok(!flags.contains(nix_fcntl::OFlag::O_NONBLOCK))
}
#[cfg(unix)]
pub fn set_blocking(fd: BorrowedFd<'_>, blocking: bool) -> io::Result<()> {
use nix::fcntl as nix_fcntl;
let flags = nix_fcntl::OFlag::from_bits_truncate(
nix_fcntl::fcntl(fd, nix_fcntl::FcntlArg::F_GETFL).map_err(io::Error::from)?,
);
let mut new_flags = flags;
new_flags.set(nix_fcntl::OFlag::O_NONBLOCK, !blocking);
if flags != new_flags {
nix_fcntl::fcntl(fd, nix_fcntl::FcntlArg::F_SETFL(new_flags)).map_err(io::Error::from)?;
}
Ok(())
}
pub fn fcntl_with_bytes(fd: i32, cmd: i32, arg: &mut [u8]) -> io::Result<i32> {
unsafe { libc::fcntl(fd, cmd, arg.as_mut_ptr()) }.check_libc_neg()
}
pub unsafe fn ioctl_ptr(
fd: i32,
request: libc::c_ulong,
arg: *mut libc::c_void,
) -> io::Result<i32> {
unsafe { libc::ioctl(fd, request as _, arg) }.check_libc_neg()
}
pub fn ioctl_int(fd: i32, request: libc::c_ulong, arg: i32) -> io::Result<i32> {
unsafe { libc::ioctl(fd, request as _, arg) }.check_libc_neg()
}
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
pub fn flock(fd: i32, operation: i32) -> io::Result<i32> {
unsafe { libc::flock(fd, operation) }.check_libc_neg()
}
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
pub enum LockfError {
InvalidCmd,
Overflow(String),
Io(io::Error),
}
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
pub fn lockf(fd: i32, cmd: i32, len: i64, start: i64, whence: i32) -> Result<i32, LockfError> {
fn convert_field<T, U>(value: T) -> Result<U, LockfError>
where
T: TryInto<U>,
T::Error: core::fmt::Display,
{
value
.try_into()
.map_err(|err| LockfError::Overflow(err.to_string()))
}
let l_type = if cmd == libc::LOCK_UN {
libc::F_UNLCK
} else if (cmd & libc::LOCK_SH) != 0 {
libc::F_RDLCK
} else if (cmd & libc::LOCK_EX) != 0 {
libc::F_WRLCK
} else {
return Err(LockfError::InvalidCmd);
};
let lock = libc::flock {
l_type: convert_field(l_type)?,
l_whence: convert_field(whence)?,
l_start: convert_field(start)?,
l_len: convert_field(len)?,
..unsafe { core::mem::zeroed() }
};
unsafe {
libc::fcntl(
fd,
if (cmd & libc::LOCK_NB) != 0 {
libc::F_SETLK
} else {
libc::F_SETLKW
},
&lock,
)
}
.check_libc_neg()
.map_err(LockfError::Io)
}