1
2
3
4
5 package cache
6
7 import (
8 "bytes"
9 "crypto/sha256"
10 "fmt"
11 "hash"
12 "io"
13 "os"
14 "runtime"
15 "strings"
16 "sync"
17 )
18
19 var debugHash = false
20
21
22 const HashSize = 32
23
24
25
26 type Hash struct {
27 h hash.Hash
28 name string
29 buf *bytes.Buffer
30 }
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 var hashSalt = []byte(stripExperiment(runtime.Version()))
47
48
49
50 func stripExperiment(version string) string {
51 if i := strings.Index(version, " X:"); i >= 0 {
52 return version[:i]
53 }
54 if i := strings.Index(version, "-X:"); i >= 0 {
55 return version[:i]
56 }
57 return version
58 }
59
60
61
62 func Subkey(parent ActionID, desc string) ActionID {
63 h := sha256.New()
64 h.Write([]byte("subkey:"))
65 h.Write(parent[:])
66 h.Write([]byte(desc))
67 var out ActionID
68 h.Sum(out[:0])
69 if debugHash {
70 fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out)
71 }
72 if verify {
73 hashDebug.Lock()
74 hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc)
75 hashDebug.Unlock()
76 }
77 return out
78 }
79
80
81
82 func NewHash(name string) *Hash {
83 h := &Hash{h: sha256.New(), name: name}
84 if debugHash {
85 fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name)
86 }
87 h.Write(hashSalt)
88 if verify {
89 h.buf = new(bytes.Buffer)
90 }
91 return h
92 }
93
94
95 func (h *Hash) Write(b []byte) (int, error) {
96 if debugHash {
97 fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b)
98 }
99 if h.buf != nil {
100 h.buf.Write(b)
101 }
102 return h.h.Write(b)
103 }
104
105
106 func (h *Hash) Sum() [HashSize]byte {
107 var out [HashSize]byte
108 h.h.Sum(out[:0])
109 if debugHash {
110 fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out)
111 }
112 if h.buf != nil {
113 hashDebug.Lock()
114 if hashDebug.m == nil {
115 hashDebug.m = make(map[[HashSize]byte]string)
116 }
117 hashDebug.m[out] = h.buf.String()
118 hashDebug.Unlock()
119 }
120 return out
121 }
122
123
124
125
126
127 var hashDebug struct {
128 sync.Mutex
129 m map[[HashSize]byte]string
130 }
131
132
133 func reverseHash(id [HashSize]byte) string {
134 hashDebug.Lock()
135 s := hashDebug.m[id]
136 hashDebug.Unlock()
137 return s
138 }
139
140 var hashFileCache struct {
141 sync.Mutex
142 m map[string][HashSize]byte
143 }
144
145
146
147
148
149
150
151 func FileHash(file string) ([HashSize]byte, error) {
152 hashFileCache.Lock()
153 out, ok := hashFileCache.m[file]
154 hashFileCache.Unlock()
155
156 if ok {
157 return out, nil
158 }
159
160 h := sha256.New()
161 f, err := os.Open(file)
162 if err != nil {
163 if debugHash {
164 fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
165 }
166 return [HashSize]byte{}, err
167 }
168 _, err = io.Copy(h, f)
169 f.Close()
170 if err != nil {
171 if debugHash {
172 fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
173 }
174 return [HashSize]byte{}, err
175 }
176 h.Sum(out[:0])
177 if debugHash {
178 fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out)
179 }
180
181 SetFileHash(file, out)
182 return out, nil
183 }
184
185
186 func SetFileHash(file string, sum [HashSize]byte) {
187 hashFileCache.Lock()
188 if hashFileCache.m == nil {
189 hashFileCache.m = make(map[string][HashSize]byte)
190 }
191 hashFileCache.m[file] = sum
192 hashFileCache.Unlock()
193 }
194
View as plain text