test / test (push) Has been cancelled
Implement phase 1 and 2 review actions (DMARC UI CSS fixes, bounded DMARC ingest stdin, rate-limit eviction hardening, settings/user handler cleanup, shared atomic/supervisor helpers) and phase 3 documentation/changelog updates including roadmap and accepted-risk notes. Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.1 KiB
Go
46 lines
1.1 KiB
Go
package atomicfile
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// Write writes data to path via a temp file in the same directory followed by
|
|
// a rename, so readers only ever see the complete old or new file.
|
|
func Write(path string, data []byte, perm os.FileMode) error {
|
|
dir := filepath.Dir(path)
|
|
tmp, err := os.CreateTemp(dir, ".tmp-*")
|
|
if err != nil {
|
|
return fmt.Errorf("create temp in %s: %w", dir, err)
|
|
}
|
|
tmpName := tmp.Name()
|
|
cleanup := true
|
|
defer func() {
|
|
if cleanup {
|
|
_ = os.Remove(tmpName)
|
|
}
|
|
}()
|
|
|
|
if _, err := tmp.Write(data); err != nil {
|
|
tmp.Close()
|
|
return fmt.Errorf("write temp %s: %w", tmpName, err)
|
|
}
|
|
if err := tmp.Chmod(perm); err != nil {
|
|
tmp.Close()
|
|
return fmt.Errorf("chmod temp %s: %w", tmpName, err)
|
|
}
|
|
if err := tmp.Sync(); err != nil {
|
|
tmp.Close()
|
|
return fmt.Errorf("sync temp %s: %w", tmpName, err)
|
|
}
|
|
if err := tmp.Close(); err != nil {
|
|
return fmt.Errorf("close temp %s: %w", tmpName, err)
|
|
}
|
|
if err := os.Rename(tmpName, path); err != nil {
|
|
return fmt.Errorf("rename %s -> %s: %w", tmpName, path, err)
|
|
}
|
|
cleanup = false
|
|
return nil
|
|
}
|