use std::path::Path;
use prikk_error::{PrikkError, Result};
mod directory;
#[cfg(any(target_os = "linux", target_os = "macos"))]
mod failpoints;
#[cfg(any(target_os = "linux", target_os = "macos"))]
mod immutable;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(any(
all(test, not(target_os = "windows")),
not(any(target_os = "linux", target_os = "macos", target_os = "windows"))
))]
mod none;
mod read;
mod regular;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
mod windows_authority;
pub(crate) use directory::MutationRoot;
pub(crate) use read::{
EntryKind, RootFileStat, inspect_entry, list_directory, read_file_if_exists,
read_file_required, stat_file_state_if_exists,
};
use crate::fsutil::contract::DurabilityContract;
#[cfg(target_os = "linux")]
pub(crate) use linux::LinuxDurability;
#[cfg(target_os = "macos")]
pub(crate) use macos::MacosDurability;
#[cfg(any(
all(test, not(target_os = "windows")),
not(any(target_os = "linux", target_os = "macos", target_os = "windows"))
))]
pub(crate) use none::NoDurability;
#[cfg(target_os = "windows")]
pub(crate) use windows::WindowsDurability;
#[cfg(all(test, any(target_os = "linux", target_os = "macos")))]
pub(crate) use failpoints::{
Point as TestFailPoint, fail_after as fail_after_for_test, fail_once as fail_once_for_test,
set_directory_create_barrier as set_directory_create_barrier_for_test,
set_immutable_install_barrier as set_immutable_install_barrier_for_test,
};
#[cfg(target_os = "linux")]
const ACTIVE_DURABILITY: LinuxDurability = LinuxDurability;
#[cfg(target_os = "macos")]
const ACTIVE_DURABILITY: MacosDurability = MacosDurability;
#[cfg(target_os = "windows")]
const ACTIVE_DURABILITY: WindowsDurability = WindowsDurability;
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
const ACTIVE_DURABILITY: NoDurability = NoDurability;
pub(crate) fn write_file_atomically(
root: &MutationRoot,
relative: &Path,
bytes: &[u8],
) -> Result<()> {
ACTIVE_DURABILITY.atomic_replace(root, relative, bytes)
}
pub(crate) fn write_worktree_file_atomically(
root: &MutationRoot,
relative: &Path,
bytes: &[u8],
) -> Result<()> {
write_file_atomically(root, relative, bytes)
}
pub(crate) fn append_file_required(
root: &MutationRoot,
relative: &Path,
bytes: &[u8],
) -> Result<()> {
ACTIVE_DURABILITY.durable_append(root, relative, bytes)
}
pub(crate) fn truncate_existing_file_required(
root: &MutationRoot,
relative: &Path,
len: u64,
) -> Result<()> {
ACTIVE_DURABILITY.durable_truncate(root, relative, len)
}
pub(crate) fn set_regular_file_mode_required(
root: &MutationRoot,
relative: &Path,
mode: u32,
) -> Result<()> {
ACTIVE_DURABILITY.set_permission_bits(root, relative, mode)
}
pub(crate) fn truncate_file_empty_required(root: &MutationRoot, relative: &Path) -> Result<()> {
ACTIVE_DURABILITY.durable_truncate_to_empty(root, relative)
}
pub(crate) fn create_new_file_required(
root: &MutationRoot,
relative: &Path,
bytes: &[u8],
) -> std::io::Result<()> {
ACTIVE_DURABILITY.create_exclusive(root, relative, bytes)
}
pub(crate) fn remove_file_required(root: &MutationRoot, relative: &Path) -> Result<()> {
remove_file_if_present_required(root, relative).map(|_| ())
}
pub(crate) fn remove_file_if_present_required(
root: &MutationRoot,
relative: &Path,
) -> Result<bool> {
ACTIVE_DURABILITY.remove_if_present(root, relative)
}
pub(crate) fn remove_file_cleanup_best_effort(root: &MutationRoot, relative: &Path) {
let _ = remove_file_required(root, relative);
}
pub(crate) fn remove_worktree_file_required(root: &MutationRoot, relative: &Path) -> Result<()> {
remove_file_required(root, relative)
}
#[allow(dead_code)]
pub(crate) fn promote_file_required(
root: &MutationRoot,
source: &Path,
destination: &Path,
) -> Result<()> {
ACTIVE_DURABILITY.promote(root, source, destination)
}
#[cfg(all(test, any(target_os = "linux", target_os = "macos")))]
pub(crate) fn publish_immutable_file(
root: &MutationRoot,
relative: &Path,
candidate: &[u8],
validate_existing: impl Fn(&[u8]) -> Result<()>,
) -> Result<()> {
ACTIVE_DURABILITY.publish_immutable(root, relative, candidate, validate_existing)
}
pub(crate) fn ensure_directory_required(root: &MutationRoot, relative: &Path) -> Result<()> {
ACTIVE_DURABILITY.ensure_directory(root, relative)
}
pub(crate) fn sync_directory_required(root: &MutationRoot, relative: &Path) -> Result<()> {
ACTIVE_DURABILITY.durable_directory_entry(root, relative)
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn io_error(error: rustix::io::Errno) -> PrikkError {
PrikkError::from(std::io::Error::from(error))
}
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
fn prikk_to_io(error: PrikkError) -> std::io::Error {
std::io::Error::other(error.to_string())
}
#[cfg(any(
all(test, not(target_os = "windows")),
not(any(target_os = "linux", target_os = "macos", target_os = "windows"))
))]
fn unsupported_mutation<T>() -> Result<T> {
Err(PrikkError::Io(
"repository mutation requires Linux, macOS, or Windows root-scoped filesystem \
capabilities"
.to_string(),
))
}