-
Notifications
You must be signed in to change notification settings - Fork 4
/
store_file.go
102 lines (79 loc) · 2.17 KB
/
store_file.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package fsdup
import (
"errors"
"fmt"
"io/ioutil"
"os"
"sync"
)
type fileChunkStore struct {
root string
chunkMap *sync.Map
}
func NewFileChunkStore(root string) *fileChunkStore {
return &fileChunkStore{
root: root,
chunkMap: &sync.Map{},
}
}
func (idx *fileChunkStore) Stat(checksum []byte) error {
checksumStr := fmt.Sprintf("%x", checksum)
if _, ok := idx.chunkMap.Load(checksumStr); ok {
return nil
}
dir := fmt.Sprintf("%s/%s/%s", idx.root, checksumStr[0:3], checksumStr[3:6])
file := fmt.Sprintf("%s/%s", dir, checksumStr)
_, err := os.Stat(file)
return err
}
func (idx *fileChunkStore) Write(checksum []byte, buffer []byte) error {
checksumStr := fmt.Sprintf("%x", checksum)
if _, ok := idx.chunkMap.Load(checksumStr); !ok {
dir := fmt.Sprintf("%s/%s/%s", idx.root, checksumStr[0:3], checksumStr[3:6])
file := fmt.Sprintf("%s/%s", dir, checksumStr)
if _, err := os.Stat(file); err != nil {
if err := os.MkdirAll(dir, 0770); err != nil {
return err
}
err = ioutil.WriteFile(file, buffer, 0666)
if err != nil {
return err
}
}
idx.chunkMap.Store(checksumStr, true)
}
return nil
}
func (idx *fileChunkStore) ReadAt(checksum []byte, buffer []byte, offset int64) (int, error) {
checksumStr := fmt.Sprintf("%x", checksum)
dir := fmt.Sprintf("%s/%s/%s", idx.root, checksumStr[0:3], checksumStr[3:6])
file := fmt.Sprintf("%s/%s", dir, checksumStr)
if _, err := os.Stat(file); err != nil {
return 0, err
}
chunk, err := os.OpenFile(file, os.O_RDONLY, 0666)
if err != nil {
return 0, err
}
defer chunk.Close()
read, err := chunk.ReadAt(buffer, offset)
if err != nil {
return 0, err
} else if read != len(buffer) {
return 0, errors.New("cannot read full section")
}
return read, nil
}
func (idx *fileChunkStore) Remove(checksum []byte) error {
checksumStr := fmt.Sprintf("%x", checksum)
dir1 := fmt.Sprintf("%s/%s", idx.root, checksumStr[0:3])
dir2 := fmt.Sprintf("%s/%s/%s", idx.root, checksumStr[0:3], checksumStr[3:6])
file := fmt.Sprintf("%s/%s", dir2, checksumStr)
if err := os.Remove(file); err != nil {
return err
}
os.Remove(dir2)
os.Remove(dir1)
idx.chunkMap.Delete(checksumStr)
return nil
}