Files
wehub-resource-sync c4536f7e05
CI / test (push) Failing after 1s
CI / macOS amd64 (push) Has been cancelled
CI / macOS arm64 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:31 +08:00

54 lines
1.2 KiB
Go

package atomicfile
import (
"os"
"path/filepath"
)
// atomicWriteFile replaces path with data via a temp file in the same
// directory: the temp file is chmodded (CreateTemp creates it 0600),
// fsynced so a crash cannot leave a truncated file behind the
// already-journaled rename, renamed over the target, and the parent
// directory is best-effort synced so the rename itself survives a crash.
func Write(path string, data []byte, perm os.FileMode) error {
dir := filepath.Dir(path)
tmp, err := os.CreateTemp(dir, "."+filepath.Base(path)+"-*.tmp")
if err != nil {
return err
}
tmpName := tmp.Name()
defer os.Remove(tmpName)
if err := tmp.Chmod(perm); err != nil {
_ = tmp.Close()
return err
}
if _, err := tmp.Write(data); err != nil {
_ = tmp.Close()
return err
}
if err := tmp.Sync(); err != nil {
_ = tmp.Close()
return err
}
if err := tmp.Close(); err != nil {
return err
}
if err := os.Rename(tmpName, path); err != nil {
return err
}
syncDir(dir)
return nil
}
// syncDir best-effort flushes directory metadata so a rename survives a
// crash. Errors are ignored: not all platforms support syncing directories.
func syncDir(dir string) {
d, err := os.Open(dir)
if err != nil {
return
}
_ = d.Sync()
_ = d.Close()
}