// Package atomicfile persists bounded service snapshots without exposing a // partially written destination after a process crash. package atomicfile import ( "errors" "fmt" "os" "path/filepath" ) func Write(path string, content []byte, mode os.FileMode) error { if path == "" { return errors.New("atomic file path must not be empty") } path = filepath.Clean(path) if info, err := os.Lstat(path); err == nil { if info.Mode()&os.ModeSymlink != 0 { return errors.New("refusing to replace a symbolic-link store path") } if !info.Mode().IsRegular() { return errors.New("refusing to replace a non-regular store path") } } else if !os.IsNotExist(err) { return fmt.Errorf("inspect store path: %w", err) } directory := filepath.Dir(path) temporary, err := os.CreateTemp(directory, ".tera-store-*") if err != nil { return fmt.Errorf("create temporary store: %w", err) } temporaryPath := temporary.Name() renamed := false defer func() { _ = temporary.Close() if !renamed { _ = os.Remove(temporaryPath) } }() if err := temporary.Chmod(mode.Perm()); err != nil { return fmt.Errorf("protect temporary store: %w", err) } if _, err := temporary.Write(content); err != nil { return fmt.Errorf("write temporary store: %w", err) } if err := temporary.Sync(); err != nil { return fmt.Errorf("sync temporary store: %w", err) } if err := temporary.Close(); err != nil { return fmt.Errorf("close temporary store: %w", err) } if err := os.Rename(temporaryPath, path); err != nil { return fmt.Errorf("replace store: %w", err) } renamed = true if err := syncDirectory(directory); err != nil { return fmt.Errorf("sync store directory: %w", err) } return nil }