Atomic write.

The reason it is safe to point this tool at four thousand photographs and walk away.

// definition

An atomic write completes entirely or not at all, with no observable intermediate state. ScrubPony achieves it the standard POSIX way: build the new file in a temporary beside the destination, fsync it, then rename it over the top.

What it is

Writing directly over a file is not atomic. If the process dies partway, the file on disk is a mixture of old and new bytes — and for a JPEG that usually means a file that opens, looks fine at the top, and is corrupt further down.

rename within a filesystem is atomic: the directory entry points at the old inode or the new one, never at something in between. Doing the write elsewhere first and then renaming turns a long, interruptible operation into an instantaneous one.

Why it matters

A partially scrubbed file is worse than no file, because it looks finished. If a scrub is interrupted halfway through a library, you want to know exactly which files were done — not to discover months later that one of them is subtly broken.

The fsync before the rename matters too: without it, a crash can leave the rename durable but the contents not.

// in ScrubPony Every write in ScrubPony goes through this path, including -i. tests/run_interrupt.sh asserts it by SIGKILLing a 24 MB in-place scrub thirty times at varying moments and checking that nothing but the two legal states ever appears — and that no stray temporary is left behind. Permissions and ownership are carried onto the replacement, and a file that would not change is not touched at all, decided by comparing the bytes rather than counting segments.

Related terms

Common questions.

Does this protect my data from disk failure?

No. It guarantees no observer sees a half-written file. It does not guarantee the pre-scrub bytes are unrecoverable from the medium afterwards, and on a copy-on-write filesystem or an SSD with wear levelling they may well persist.

What happens if the input turns out to be malformed halfway through?

Nothing is written at all. The temporary is discarded and the original is untouched.

Why does -i break hard links?

Because the rename installs a new inode. Other links to the old inode keep the unscrubbed content, and extended attributes — Finder tags, Spotlight comments, quarantine flags — go with the old inode too.

Get ScrubPony

Strips identifying metadata out of JPEGs without touching a pixel. C99, no dependencies beyond libc, macOS and Linux, MIT-licensed.