119 lines
2.4 KiB
Go
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
|
|
}
|