#[path = "native.rs"]
mod native;
use crate::files::{MacFiles, mutation::supervision, policy, protocol, store::Store};
use cueward_core::files::mutation::MutationStatus;
use cueward_core::files::trash::execution::TrashRequest;
pub use cueward_core::files::trash::execution::TrashRequest as Request;
use cueward_core::files::trash::execution::{self, TrashPlatform};
pub use cueward_core::files::trash::execution::{TrashReceipt, TrashStage};
use cueward_core::files::*;
use serde::{Deserialize, Serialize};
use std::path::Path;
const STORE: Store = Store("files");
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TrashWorkerRequest {
pub operation_id: String,
}
pub fn run(
executable: &Path,
request: &TrashRequest,
timeout: u64,
) -> Result<TrashReceipt, FileError> {
protocol::payload(request, timeout)?;
execution::validate_request(request)?;
let prepared = STORE.create(|id, path| TrashReceipt::new(id, path, request.clone()))?;
supervision::announce(&prepared.operation_id, "trash receipt")?;
let result = supervision::run(
executable,
"files-trash-worker",
&TrashWorkerRequest {
operation_id: prepared.operation_id.clone(),
},
timeout,
)
.and_then(|receipt| {
protocol::verify_receipt(
&prepared,
receipt,
&read_receipt(&prepared.operation_id)?,
"trash worker response differs from prepared/stored evidence",
)
});
match result {
Ok(receipt) => Ok(receipt),
Err(mut error) => {
error.message.push_str("; inspect the receipt, private backup and Trash entry; never automatically retry or delete");
let mut receipt = read_receipt(&prepared.operation_id).unwrap_or(prepared);
execution::record_error(&mut receipt, error);
receipt.status = MutationStatus::Uncertain;
save(&receipt)?;
Ok(receipt)
}
}
}
pub fn read_receipt(id: &str) -> Result<TrashReceipt, FileError> {
let receipt: TrashReceipt = STORE.load(id)?;
if receipt.operation != "trash"
|| receipt.operation_id != id
|| STORE.directory(id)?.join("receipt.json").to_str() != Some(&receipt.receipt_path)
{
return Err(FileError::new(
FileErrorCode::InvalidOptions,
"trash receipt schema/identity/path mismatch",
));
}
Ok(receipt)
}
pub fn read_supervised_request() -> Result<TrashWorkerRequest, FileError> {
supervision::read_request()
}
pub fn execute_worker(input: &TrashWorkerRequest) -> Result<TrashReceipt, FileError> {
execute_prepared(&MacFiles, input)
}
fn execute_prepared(
platform: &impl TrashPlatform,
input: &TrashWorkerRequest,
) -> Result<TrashReceipt, FileError> {
STORE.claim(&input.operation_id)?;
let mut receipt = read_receipt(&input.operation_id)?;
receipt.validate_fresh()?;
let result = policy::NoMaterialization::enter()
.and_then(|_policy| execution::execute(platform, &mut receipt, &mut save));
if let Err(error) = result {
execution::record_error(&mut receipt, error);
}
save(&receipt)?;
Ok(receipt)
}
fn save(receipt: &TrashReceipt) -> Result<(), FileError> {
STORE.save(&receipt.operation_id, &receipt.receipt_path, receipt)
}
#[cfg(test)]
#[path = "tests.rs"]
pub(super) mod tests;
#[cfg(test)]
#[path = "safety_tests.rs"]
mod safety_tests;
#[cfg(test)]
#[path = "lifetime_tests.rs"]
mod lifetime_tests;