This repository has been archived on 2025-08-23. You can view files and clone it, but cannot push or open issues or pull requests.
Files
GreenCoast/internal/storage/fsstore.go
Dani e2651456da Fixed up the .gitignore
More push to move towards a deployment stage
2025-08-21 20:57:23 -04:00

96 lines
1.8 KiB
Go

package storage
import (
"crypto/sha256"
"encoding/hex"
"errors"
"io"
"os"
"path/filepath"
)
type FSStore struct {
root string
maxObjectB int64
}
func NewFSStore(root string, maxKB int) (*FSStore, error) {
if root == "" {
root = "./data/objects"
}
if err := os.MkdirAll(root, 0o755); err != nil {
return nil, err
}
return &FSStore{root: root, maxObjectB: int64(maxKB) * 1024}, nil
}
func (s *FSStore) Put(r io.Reader) (string, int64, error) {
h := sha256.New()
tmp := filepath.Join(s.root, ".tmp")
_ = os.MkdirAll(tmp, 0o755)
f, err := os.CreateTemp(tmp, "obj-*")
if err != nil {
return "", 0, err
}
defer f.Close()
var n int64
buf := make([]byte, 32*1024)
for {
m, er := r.Read(buf)
if m > 0 {
n += int64(m)
if s.maxObjectB > 0 && n > s.maxObjectB {
return "", 0, errors.New("object too large")
}
_, _ = h.Write(buf[:m])
if _, werr := f.Write(buf[:m]); werr != nil {
return "", 0, werr
}
}
if er == io.EOF {
break
}
if er != nil {
return "", 0, er
}
}
sum := hex.EncodeToString(h.Sum(nil))
dst := filepath.Join(s.root, sum[:2], sum[2:4], sum)
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
return "", 0, err
}
if err := os.Rename(f.Name(), dst); err != nil {
return "", 0, err
}
return sum, n, nil
}
func (s *FSStore) pathFor(hash string) string {
return filepath.Join(s.root, hash[:2], hash[2:4], hash)
}
func (s *FSStore) Get(hash string) (string, error) {
if len(hash) < 4 {
return "", os.ErrNotExist
}
p := s.pathFor(hash)
if _, err := os.Stat(p); err != nil {
return "", err
}
return p, nil
}
func (s *FSStore) Delete(hash string) error {
if len(hash) < 4 {
return os.ErrNotExist
}
p := s.pathFor(hash)
if err := os.Remove(p); err != nil {
return err
}
_ = os.Remove(filepath.Dir(p))
_ = os.Remove(filepath.Dir(filepath.Dir(p)))
return nil
}