Skip to main content

write_atomic

Function write_atomic 

Source
pub fn write_atomic(path: &Path, bytes: &[u8], mode: u32) -> Result<()>
Expand description

Writes bytes to path atomically, at mode.

Two properties fs::write does not have. Atomic: the content lands via a temporary file and a rename, so a crash part-way through leaves the previous version intact rather than a truncated one. That matters for the local CA’s revocation ledger, which is the authoritative input to CRL generation — a half-written ledger read at the next startup is a set of revocations silently forgotten. Owner-controlled: the mode is passed to open rather than applied afterwards, the same reasoning as write_private_key, so the file is never briefly world-readable.

The temporary file sits beside the target, since rename is only atomic within a filesystem.

The scratch name belongs to one writer and one target. It used to be path.with_extension("tmp"), shared two ways, and both hurt:

  • Across targets, the local CA writes ca.crl and ca.json back to back and both mapped to ca.tmp, so a startup rebuilding the CRL while a revocation persisted the ledger could rename one file’s bytes over the other’s name. The observed symptom was a sidecar full of CRL PEM, which the next startup refuses to parse — every revocation this CA had ever recorded, unreadable, because two writes shared a scratch name. Appending the suffix rather than substituting the extension separates those.
  • Across writers, two processes truncating and filling one temp file interleave, and then each renames the mixture into place: atomic, and atomically wrong. The pid separates those.

The cost is that a crash leaves litter rather than a file the next run reuses, which is the right way round — a leftover temporary is inert, and the alternative was a shared mutable one.