forked from folbricht/desync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
local.go
69 lines (63 loc) · 1.63 KB
/
local.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package casync
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
)
// LocalStore casync store
type LocalStore struct {
Base string
// When accessing chunks, should mtime be updated? Useful when this is
// a cache. Old chunks can be identified and removed from the store that way
UpdateTimes bool
}
// NewLocalStore creates an instance of a local castore, it only checks presence
// of the store
func NewLocalStore(dir string) (LocalStore, error) {
info, err := os.Stat(dir)
if err != nil {
return LocalStore{}, err
}
if !info.IsDir() {
return LocalStore{}, fmt.Errorf("%s is not a directory", dir)
}
return LocalStore{Base: dir}, nil
}
// GetChunk reads and returns one (compressed!) chunk from the store
func (s LocalStore) GetChunk(id ChunkID) ([]byte, error) {
sID := id.String()
p := filepath.Join(s.Base, sID[0:4], sID) + ".cacnk"
if _, err := os.Stat(p); err != nil {
return nil, ChunkMissing{id}
}
if s.UpdateTimes {
now := time.Now()
if err := os.Chtimes(p, now, now); err != nil {
return nil, err
}
}
return ioutil.ReadFile(p)
}
// StoreChunk adds a new chunk to the store
func (s LocalStore) StoreChunk(id ChunkID, b []byte) error {
sID := id.String()
d := filepath.Join(s.Base, sID[0:4])
if err := os.MkdirAll(d, 0755); err != nil {
return err
}
tmpfile, err := ioutil.TempFile(d, ".tmp-cacnk")
if err != nil {
return err
}
defer os.Remove(tmpfile.Name()) // in case we don't get to the rename, clean up
if _, err := tmpfile.Write(b); err != nil {
return err
}
if err := tmpfile.Close(); err != nil {
return err
}
p := filepath.Join(d, sID) + ".cacnk"
return os.Rename(tmpfile.Name(), p)
}