use std::fs;
use std::path::Path;
use super::error::{EvaluationError, EvaluationResult};
#[cfg(unix)]
pub const PRIVATE_DIR_MODE: u32 = 0o700;
#[cfg(unix)]
pub const PRIVATE_FILE_MODE: u32 = 0o600;
pub fn create_private_dir_all(path: &Path) -> EvaluationResult<()> {
if path.is_dir() {
#[cfg(unix)]
enforce_dir_mode(path)?;
return Ok(());
}
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() && !parent.is_dir() {
create_private_dir_all(parent)?;
}
}
let mut builder = fs::DirBuilder::new();
#[cfg(unix)]
{
use std::os::unix::fs::DirBuilderExt;
builder.mode(PRIVATE_DIR_MODE);
}
match builder.create(path) {
Ok(()) => Ok(()),
Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists && path.is_dir() => {
#[cfg(unix)]
enforce_dir_mode(path)?;
Ok(())
}
Err(source) => Err(EvaluationError::Directory { source }),
}
}
#[cfg(unix)]
fn enforce_dir_mode(path: &Path) -> EvaluationResult<()> {
use std::os::unix::fs::PermissionsExt;
let metadata = fs::metadata(path).map_err(|source| EvaluationError::Directory { source })?;
if metadata.permissions().mode() & 0o777 == PRIVATE_DIR_MODE {
return Ok(());
}
fs::set_permissions(path, fs::Permissions::from_mode(PRIVATE_DIR_MODE))
.map_err(|source| EvaluationError::Directory { source })
}
pub fn open_private_append(path: &Path) -> EvaluationResult<fs::File> {
let mut options = fs::OpenOptions::new();
options.append(true).create(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.mode(PRIVATE_FILE_MODE);
}
options
.open(path)
.map_err(|source| EvaluationError::Append { source })
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(unix)]
#[test]
fn nested_directories_are_created_privately() {
use std::os::unix::fs::PermissionsExt;
let base = tempfile::tempdir().expect("temp base");
let nested = base
.path()
.join("evaluations")
.join("parallel_dependency")
.join("proj-1234");
create_private_dir_all(&nested).expect("nested creation must succeed");
let mut checked = 0;
let mut current = nested.as_path();
while current != base.path() {
let mode = fs::metadata(current)
.expect("metadata")
.permissions()
.mode()
& 0o777;
assert_eq!(mode, PRIVATE_DIR_MODE, "{} is {mode:o}", current.display());
checked += 1;
current = current.parent().expect("parent");
}
assert_eq!(checked, 3, "every created ancestor must be checked");
}
#[cfg(unix)]
#[test]
fn an_existing_loose_directory_is_tightened() {
use std::os::unix::fs::PermissionsExt;
let base = tempfile::tempdir().expect("temp base");
let loose = base.path().join("evaluations");
fs::create_dir(&loose).expect("create");
fs::set_permissions(&loose, fs::Permissions::from_mode(0o777)).expect("loosen");
create_private_dir_all(&loose).expect("must tighten rather than fail");
assert_eq!(
fs::metadata(&loose).expect("metadata").permissions().mode() & 0o777,
PRIVATE_DIR_MODE
);
}
#[test]
fn creating_an_existing_directory_twice_is_idempotent() {
let base = tempfile::tempdir().expect("temp base");
let path = base.path().join("evaluations").join("nested");
create_private_dir_all(&path).expect("first");
create_private_dir_all(&path).expect("second");
assert!(path.is_dir());
}
#[test]
fn a_directory_under_a_file_is_a_typed_error_not_a_panic() {
let base = tempfile::tempdir().expect("temp base");
let blocker = base.path().join("evaluations");
fs::write(&blocker, b"not a directory").expect("write");
let error = create_private_dir_all(&blocker.join("parallel_dependency"))
.expect_err("a file cannot become a parent directory");
assert!(
matches!(error, EvaluationError::Directory { .. }),
"{error:?}"
);
}
#[cfg(unix)]
#[test]
fn append_files_are_created_privately_and_never_truncated() {
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
let base = tempfile::tempdir().expect("temp base");
let path = base.path().join("2026-09-18.jsonl");
let mut first = open_private_append(&path).expect("create");
first.write_all(b"one\n").expect("write");
drop(first);
let mut second = open_private_append(&path).expect("reopen");
second.write_all(b"two\n").expect("write");
drop(second);
assert_eq!(fs::read_to_string(&path).expect("read"), "one\ntwo\n");
assert_eq!(
fs::metadata(&path).expect("metadata").permissions().mode() & 0o777,
PRIVATE_FILE_MODE
);
}
}