Files
go-sip/internal/store/private_data.go
T

66 lines
1.5 KiB
Go

package store
import (
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
)
func persistPrivateData(dir, name string, data []byte) error {
if err := os.MkdirAll(dir, 0700); err != nil {
return err
}
info, err := os.Lstat(dir)
if err != nil || !info.IsDir() || info.Mode().Perm() != 0700 {
return errors.New("private data directory must have mode 0700")
}
target := filepath.Join(dir, name)
if info, err := os.Lstat(target); err == nil {
if !info.Mode().IsRegular() || info.Mode().Perm() != 0600 {
return errors.New("existing private data must be a regular 0600 file")
}
existing, err := os.ReadFile(target)
if err != nil {
return err
}
if !bytes.Equal(existing, data) {
return errors.New("private original data conflicts with existing file")
}
f, err := os.Open(target)
if err != nil {
return err
}
if err := errors.Join(f.Sync(), f.Close()); err != nil {
return err
}
return syncPrivateDirectory(dir)
} else if !errors.Is(err, os.ErrNotExist) {
return err
}
f, err := os.CreateTemp(dir, ".pending-")
if err != nil {
return err
}
temp := f.Name()
defer os.Remove(temp)
_, writeErr := f.Write(data)
syncErr := f.Sync()
closeErr := f.Close()
if err := errors.Join(writeErr, syncErr, closeErr); err != nil {
return fmt.Errorf("persist private original bytes: %w", err)
}
if err := os.Rename(temp, target); err != nil {
return err
}
return syncPrivateDirectory(dir)
}
func syncPrivateDirectory(dir string) error {
f, err := os.Open(dir)
if err != nil {
return err
}
return errors.Join(f.Sync(), f.Close())
}