1 // Lightweight implementation of io.ReadCloser that checks the contents read
2 // from the underlying io.Reader a against checksum hash. To avoid reading the
3 // entire contents into a buffer up front, the hash is updated with each read,
4 // and the actual checksum is not checked until the underlying reader returns
15 var BadChecksum = errors.New("Reader failed checksum")
17 type HashCheckingReader struct {
18 // The underlying data source
21 // The hashing function to use
24 // The hash value to check against. Must be a hex-encoded lowercase string.
28 // Read from the underlying reader, update the hashing function, and pass the
29 // results through. Will return BadChecksum on the last read instead of EOF if
30 // the checksum doesn't match.
31 func (this HashCheckingReader) Read(p []byte) (n int, err error) {
32 n, err = this.Reader.Read(p)
34 this.Hash.Write(p[:n])
37 sum := this.Hash.Sum(make([]byte, 0, this.Hash.Size()))
38 if fmt.Sprintf("%x", sum) != this.Check {
45 // Write entire contents of this.Reader to 'dest'. Returns BadChecksum if the
46 // data written to 'dest' doesn't match the hash code of this.Check.
47 func (this HashCheckingReader) WriteTo(dest io.Writer) (written int64, err error) {
48 if writeto, ok := this.Reader.(io.WriterTo); ok {
49 written, err = writeto.WriteTo(io.MultiWriter(dest, this.Hash))
51 written, err = io.Copy(io.MultiWriter(dest, this.Hash), this.Reader)
54 sum := this.Hash.Sum(make([]byte, 0, this.Hash.Size()))
56 if fmt.Sprintf("%x", sum) != this.Check {
63 // Close() the underlying Reader if it is castable to io.ReadCloser. This will
64 // drain the underlying reader of any remaining data and check the checksum.
65 func (this HashCheckingReader) Close() (err error) {
66 _, err = io.Copy(this.Hash, this.Reader)
68 if closer, ok := this.Reader.(io.ReadCloser); ok {
72 sum := this.Hash.Sum(make([]byte, 0, this.Hash.Size()))
73 if fmt.Sprintf("%x", sum) != this.Check {