Files
go-sip/internal/agent/file_state.go
T

66 lines
1.3 KiB
Go

package agent
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
)
func writeJSONAtomic(path string, value any) error {
data, err := json.MarshalIndent(value, "", " ")
if err != nil {
return err
}
file, err := os.CreateTemp(filepath.Dir(path), ".state-*.tmp")
if err != nil {
return err
}
tmp := file.Name()
defer os.Remove(tmp)
if _, err := file.Write(append(data, '\n')); err != nil {
_ = file.Close()
return err
}
if err := file.Sync(); err != nil {
_ = file.Close()
_ = os.Remove(tmp)
return err
}
if err := file.Close(); err != nil {
_ = os.Remove(tmp)
return err
}
if err := os.Rename(tmp, path); err != nil {
_ = os.Remove(tmp)
return err
}
return syncDirectory(filepath.Dir(path))
}
func syncDirectory(path string) error {
dir, err := os.Open(path)
if err != nil {
return err
}
syncErr := dir.Sync()
return firstError(syncErr, dir.Close())
}
func validateName(name string) error {
if name == "" || name == "." || name == ".." || strings.ContainsAny(name, `/\\`) || strings.Contains(name, "..") || strings.TrimSpace(name) != name {
return fmt.Errorf("unsafe file name %q", name)
}
return nil
}
func firstError(errs ...error) error {
for _, err := range errs {
if err != nil {
return err
}
}
return nil
}