169. File::create_new — Atomic 'Create Only If It Doesn't Exist'
You want to write a config file, a lockfile, or a “did we run yet” sentinel — but only if it isn’t already there. The if path.exists() { … } else { File::create(path) } pattern looks fine until two processes hit it at the same time. There’s a one-line fix sitting in std::fs.
The naive guard is a textbook TOCTOU race: between the moment you check existence and the moment you call create, another process can slip in and put a file there. You’ll then happily truncate their work.
| |
File::create_new (stable since 1.77) collapses both steps into a single syscall — O_CREAT | O_EXCL on Unix, CREATE_NEW on Windows — so the kernel decides the winner:
| |
If the file already exists, you get back an io::Error with ErrorKind::AlreadyExists and nothing on disk is touched. That’s the whole behaviour — and it’s the same whether one process or fifty are racing for the same path.
| |
For the equivalent guarantee on an existing handle you’d previously reach for OpenOptions::new().write(true).create_new(true).open(path) — that still works, and File::create_new is just the shorthand when you want the default “write, create-new, truncate-off” combo.
Use it for lockfiles, idempotent setup steps, “did we already write the manifest” checks, and anywhere the existence test and the create were a single logical step pretending to be two.