2022-03-01 18:20:54 +01:00

119 lines
2.4 KiB
Go

package store
import (
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"os"
"path/filepath"
)
type Store struct {
Path string
}
func (s *Store) Dir(path, sum string) string {
return filepath.Join(s.Path, path, sum[0:1], sum[1:2])
}
func (s *Store) MkDirs(dirs []string) error {
for _, dir := range dirs {
if err := os.MkdirAll(filepath.Join(s.Path, dir), 0755); err != nil {
return err
}
}
return nil
}
func (s *Store) FileExists(filename string) bool {
fs, err := os.Stat(filename)
if errors.Is(err, os.ErrNotExist) {
return false
}
return !fs.IsDir()
}
func (s *Store) SaveTemp(path string, sumb string, b []byte) error {
sum := sha1.New()
sum.Write(b)
sumString := hex.EncodeToString(sum.Sum(nil))
if sumb != sumString {
return errors.New("wrong checksum")
}
dir := s.Dir(path, sumString)
filename := filepath.Join(dir, sumString)
if s.FileExists(filename) {
return nil
}
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
fs, err := os.Create(filename)
if err != nil {
return err
}
defer fs.Close()
_, err = fs.Write(b)
return err
}
func (s *Store) CombineTemp(path string, sumb []string) (string, uint64, error) {
tmpdir := filepath.Join("tmp", path)
sum := sha1.New()
size := uint64(0)
for _, sb := range sumb {
dir := s.Dir(tmpdir, sb)
filename := filepath.Join(dir, sb)
if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
return "", 0, fmt.Errorf("%s: chunk %s doesn't exists", path, sb)
}
b, err := os.ReadFile(filename)
if err != nil {
return "", 0, err
}
sum.Write(b)
size += uint64(len(b))
}
return hex.EncodeToString(sum.Sum(nil)), size, nil
}
func (s *Store) CommitTemp(path string, sumb []string) error {
tmpdir := filepath.Join("tmp", path)
originaldir := s.Dir("original", path)
originalname := filepath.Join(originaldir, path)
if s.FileExists(originalname) {
return fmt.Errorf("original file already exists")
}
os.MkdirAll(originaldir, 0755)
fs, err := os.Create(originalname)
if err != nil {
return err
}
defer fs.Close()
for _, sb := range sumb {
dir := s.Dir(tmpdir, sb)
filename := filepath.Join(dir, sb)
if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("%s: chunk %s doesn't exists", path, sb)
}
b, err := os.ReadFile(filename)
if err != nil {
return err
}
if _, err := fs.Write(b); err != nil {
return err
}
}
return nil
}