use super::compute_oflags;
#[cfg(any(target_os = "android", target_os = "linux"))]
use crate::fs::ensure_cloexec;
use crate::fs::{stat_unchecked, OpenOptions, OpenUncheckedError};
use posish::fs::{openat, Mode};
use std::{fs, path::Path};
pub(crate) fn open_unchecked(
start: &fs::File,
path: &Path,
options: &OpenOptions,
) -> Result<fs::File, OpenUncheckedError> {
let oflags = compute_oflags(options).map_err(OpenUncheckedError::Other)?;
#[allow(clippy::useless_conversion)]
let mode = Mode::from_bits_truncate(options.ext.mode as _);
let err = match openat(start, path, oflags, mode) {
Ok(file) => {
#[cfg(any(target_os = "android", target_os = "linux"))]
ensure_cloexec(&file).map_err(OpenUncheckedError::Other)?;
return Ok(file);
}
Err(err) => err,
};
match err.raw_os_error() {
#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd")))]
Some(libc::ELOOP) => Err(OpenUncheckedError::Symlink(err, ())),
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
Some(libc::EMLINK) => Err(OpenUncheckedError::Symlink(err, ())),
#[cfg(any(target_os = "netbsd"))]
Some(libc::EFTYPE) => Err(OpenUncheckedError::Symlink(err, ())),
Some(libc::ENOENT) => Err(OpenUncheckedError::NotFound(err)),
Some(libc::ENOTDIR) => {
if options.dir_required
&& stat_unchecked(start, path, options.follow)
.map(|m| m.file_type().is_symlink())
.unwrap_or(false)
{
Err(OpenUncheckedError::Symlink(err, ()))
} else {
Err(OpenUncheckedError::NotFound(err))
}
}
_ => Err(OpenUncheckedError::Other(err)),
}
}