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 return version
55 }
56
57
58
59 func Subkey(parent ActionID, desc string) ActionID {
60 h := sha256.New()
61 h.Write([]byte("subkey:"))
62 h.Write(parent[:])
63 h.Write([]byte(desc))
64 var out ActionID
65 h.Sum(out[:0])
66 if debugHash {
67 fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out)
68 }
69 if verify {
70 hashDebug.Lock()
71 hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc)
72 hashDebug.Unlock()
73 }
74 return out
75 }
76
77
78
79 func NewHash(name string) *Hash {
80 h := &Hash{h: sha256.New(), name: name}
81 if debugHash {
82 fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name)
83 }
84 h.Write(hashSalt)
85 if verify {
86 h.buf = new(bytes.Buffer)
87 }
88 return h
89 }
90
91
92 func (h *Hash) Write(b []byte) (int, error) {
93 if debugHash {
94 fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b)
95 }
96 if h.buf != nil {
97 h.buf.Write(b)
98 }
99 return h.h.Write(b)
100 }
101
102
103 func (h *Hash) Sum() [HashSize]byte {
104 var out [HashSize]byte
105 h.h.Sum(out[:0])
106 if debugHash {
107 fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out)
108 }
109 if h.buf != nil {
110 hashDebug.Lock()
111 if hashDebug.m == nil {
112 hashDebug.m = make(map[[HashSize]byte]string)
113 }
114 hashDebug.m[out] = h.buf.String()
115 hashDebug.Unlock()
116 }
117 return out
118 }
119
120
121
122
123
124 var hashDebug struct {
125 sync.Mutex
126 m map[[HashSize]byte]string
127 }
128
129
130 func reverseHash(id [HashSize]byte) string {
131 hashDebug.Lock()
132 s := hashDebug.m[id]
133 hashDebug.Unlock()
134 return s
135 }
136
137 var hashFileCache struct {
138 sync.Mutex
139 m map[string][HashSize]byte
140 }
141
142
143
144
145
146
147
148 func FileHash(file string) ([HashSize]byte, error) {
149 hashFileCache.Lock()
150 out, ok := hashFileCache.m[file]
151 hashFileCache.Unlock()
152
153 if ok {
154 return out, nil
155 }
156
157 h := sha256.New()
158 f, err := os.Open(file)
159 if err != nil {
160 if debugHash {
161 fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
162 }
163 return [HashSize]byte{}, err
164 }
165 _, err = io.Copy(h, f)
166 f.Close()
167 if err != nil {
168 if debugHash {
169 fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
170 }
171 return [HashSize]byte{}, err
172 }
173 h.Sum(out[:0])
174 if debugHash {
175 fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out)
176 }
177
178 SetFileHash(file, out)
179 return out, nil
180 }
181
182
183 func SetFileHash(file string, sum [HashSize]byte) {
184 hashFileCache.Lock()
185 if hashFileCache.m == nil {
186 hashFileCache.m = make(map[string][HashSize]byte)
187 }
188 hashFileCache.m[file] = sum
189 hashFileCache.Unlock()
190 }
191
View as plain text