use super::NamedWriteError;
use std::{convert::Infallible, ffi::OsStr, fs::File, io, os::fd::BorrowedFd};
pub fn create_retained_at(
parent: BorrowedFd<'_>,
name: &OsStr,
permissions: u32,
) -> io::Result<File> {
#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
{
use rustix::fs::{OFlags, fsync, openat};
super::supported::validate_file_name(name)?;
let permissions = super::supported::native_permissions(permissions)?;
let file = File::from(openat(
parent,
name,
OFlags::WRONLY | OFlags::CREATE | OFlags::EXCL | OFlags::NOFOLLOW | OFlags::CLOEXEC,
permissions,
)?);
fsync(parent)?;
Ok(file)
}
#[cfg(not(any(target_os = "linux", target_os = "android", target_vendor = "apple")))]
{
let _ = (parent, name, permissions);
Err(io::Error::from(io::ErrorKind::Unsupported))
}
}
pub fn publish_retained_at(
parent: BorrowedFd<'_>,
stage: &OsStr,
target: &OsStr,
file: File,
) -> Result<(), NamedWriteError<Infallible>> {
#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
{
use super::supported::{publish_create_new, validate_file_name, verify_staging};
validate_file_name(stage).map_err(NamedWriteError::before)?;
validate_file_name(target).map_err(NamedWriteError::before)?;
verify_staging(&parent, None, stage, &file).map_err(NamedWriteError::before)?;
file.sync_all().map_err(NamedWriteError::before)?;
publish_create_new(&parent, stage, target, &file)?;
drop(file);
rustix::fs::fsync(parent).map_err(|source| NamedWriteError::AfterPublication {
source: source.into(),
})
}
#[cfg(not(any(target_os = "linux", target_os = "android", target_vendor = "apple")))]
{
let _ = (parent, stage, target, file);
Err(NamedWriteError::before(io::Error::from(
io::ErrorKind::Unsupported,
)))
}
}
#[cfg(all(
test,
any(target_os = "linux", target_os = "android", target_vendor = "apple")
))]
mod tests;