Skip to content

Release Notes v0.12.0

Released: 2026-10-31

Highlights

Replace a file atomically on every platform in one call. fs.WriteFileAtomic writes a temporary file beside the target, flushes it, sets the mode, renames it into place and flushes the directory, so a reader, or a crash, sees the whole old file or the whole new one, never a partial write. The platform differences are handled inside: callers need no runtime.GOOS check and no special case for mode bits on Windows.

New Features

fs.WriteFileAtomic and fs.WriteFileAtomicPrivate

if err := fs.WriteFileAtomic(path, data, 0); err != nil { // DefaultFilePerm (0644)
    return err
}
if err := fs.WriteFileAtomicPrivate(statePath, state); err != nil { // 0600
    return err
}

The sequence:

  1. Create a temporary file in the target's directory, so the rename stays on one file system.
  2. Write the data and flush the file.
  3. Set the mode: perm, or DefaultFilePerm when perm is 0.
  4. Rename the temporary file over the target.
  5. Flush the directory with SyncDir, so the rename survives a crash.

Where the platform does not enforce mode bits (PermissionsEnforced is false, as on Windows), a failure to set the mode is ignored, since the mode could not have been relied on. On Windows the rename fails if another process holds the target open. On any error the temporary file is removed and the target is unchanged.

WriteFileAtomic does not serialize writers: when two processes replace the same file, the last rename wins. Hold fs.Lock around it when that matters.

Documentation

  • The fs guide explains WriteFileAtomic and when to hold Lock around it.
  • The getting-started example now uses WriteFileAtomicPrivate in place of the hand-written temporary-file sequence.
  • The README and the getting-started table list the new functions.

Installation

go get github.com/grokify/oscompat@v0.12.0

Compatibility

Additive only. An API comparison against v0.11.0 reports two compatible changes, the new functions, and no incompatible changes. The module still has no dependencies outside the standard library.