-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchecksum_reader.go
More file actions
68 lines (57 loc) · 1.46 KB
/
checksum_reader.go
File metadata and controls
68 lines (57 loc) · 1.46 KB
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
package blobcache
import (
"errors"
"hash"
"io"
"github.com/miretskiy/blobcache/base"
)
type Hasher func() hash.Hash32
// verifyChecksum computes the checksum of data and compares it to expected.
func verifyChecksum(data []byte, hasher Hasher, expected uint32) error {
h := hasher()
_, _ = h.Write(data) // hash.Hash implementations never return an error
computed := h.Sum32()
if computed != expected {
return &base.ChecksumError{
Expected: expected,
Got: computed,
}
}
return nil
}
// checksumVerifyingReader wraps a reader and verifies checksum on final read
type checksumVerifyingReader struct {
r io.Reader
hash hash.Hash32
expected uint32
err error // Cached error from checksum mismatch
}
// newChecksumVerifyingReader creates a reader that verifies checksum on EOF
func newChecksumVerifyingReader(r io.Reader, hasher Hasher, expected uint32) io.Reader {
return &checksumVerifyingReader{
r: r,
hash: hasher(),
expected: expected,
}
}
func (c *checksumVerifyingReader) Read(p []byte) (n int, err error) {
if c.err != nil {
return 0, c.err
}
n, err = c.r.Read(p)
if n > 0 {
// Standard hash.Hash implementations (crc32, etc) never return an error on Write.
_, _ = c.hash.Write(p[:n])
}
if errors.Is(err, io.EOF) {
computed := c.hash.Sum32()
if computed != c.expected {
c.err = &base.ChecksumError{
Expected: c.expected,
Got: computed,
}
return n, c.err
}
}
return n, err
}