Files
photocraft/docs/windows-save-durability.md
T
denstu473 851ca348a7 fix(format): persist Windows save publication before acknowledgement
Flush NTFS directory publication after replacing a saved file. Report a
failed barrier as uncertain durability instead of successful Save. Flush
directory-bundle objects before the manifest, including on same-writer
retries, and stop before garbage collection when publication fails.

Add regression tests for failed barriers, retained old objects, cached
object retries, and directory handles. Keep existing Windows metadata
preservation and the separate Unix flush-error policy.

Validation: 130 format tests, 657 I/O corpus tests, clippy, layers, wasm,
12 acknowledged-save power cuts, six publication/cleanup cuts, and 1,368
native fault cases with exact archive comparisons. Existing preview-only
failure ordering remains tracked by #7548/#7549.

Fixes #7858.
2026-10-20 21:24:23 +02:00

4.5 KiB

Windows native-save durability

An acknowledged overwrite must reopen as the complete new document after a Windows/NTFS power loss. Issue #7858 demonstrated that flushing a temporary file before replacement did not establish this guarantee: a fresh Windows boot recovered the previous ZIP or directory bundle after Save returned success.

Publication barrier

The shared atomic writer still writes and flushes a sibling temporary file, preserves the destination's metadata, and replaces the destination. It now flushes the parent directory on Windows before acknowledging success. RealFs::sync_dir opens a directory using FILE_FLAG_BACKUP_SEMANTICS and FILE_ADD_FILE, then calls File::sync_all, which reaches FlushFileBuffers. This uses ordinary directory permissions and does not open or flush a volume or require administrative privileges. No unsupported REPLACEFILE_WRITE_THROUGH flag is used.

Windows references:

A publication-flush error occurs after replacement. It preserves the underlying error kind and says that the new data was written but may not survive a crash. It does not claim the old file is unchanged, attempt an unsafe rollback, or return success. Existing callers then retain the document's dirty state and recovery data.

Directory bundles and retries

Every published bundle file receives a Windows directory flush. Before replacing the manifest, the writer also flushes tiles/ and blobs/, including when it reuses cached objects. A previous attempt can leave valid objects in place after a failed publication flush; validating their bytes alone does not establish their durability. These barriers make a retry using the same writer safe without recompressing every unchanged object.

The manifest's publication barrier completes before obsolete objects are collected. An error stops the save before that cleanup, preserving the objects referenced by the old manifest. Garbage collection remains best effort after a successful commit.

The private save_dir_with seam exercises this complete ordering with injected tile, blob and manifest publication failures. The tests check the reported error, loaded document, preservation of old objects, barriers on reused objects, and successful retry.

Verification

Run the format tests and repository checks:

cargo test -p photocraft-format
cargo clippy -p photocraft-format --all-targets -- -D warnings
cargo xtask layers
cargo xtask wasm
cargo xtask test-corpus -p io

Unit tests cannot prove power-loss durability. The VM test uses a disposable NTFS disk and synthetic old/new documents at 8-, 16- and 32-bit depth, in ZIP and directory form. Flush the old baseline during setup, call the production save API, wait for its successful response, then abruptly power off the guest. Preserve and hash the crashed disk before recovery. Boot Windows fresh against those exact bytes and compare the complete loaded document and every expected bundle entry with the new revision. Do not restore a RAM snapshot for recovery. Repeat each combination and retain failing unchanged-build controls.

Keep volume flushes and clean unmounts in setup or diagnostic controls only; they are not part of the production save implementation. Archive comparisons must account for the build's generator-version stamp while still comparing all document payloads exactly.

This change addresses Windows/NTFS publication. The existing Unix flush-error policy is handled separately by #5420. Preview replacement/deletion ordering on failed directory saves remains tracked by #7548 and #7549. VM tests do not establish physical-controller or firmware-cache behavior, or guarantees on other filesystems.