1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
14 var BadChecksum = errors.New("Reader failed checksum")
16 // HashCheckingReader is an io.ReadCloser that checks the contents
17 // read from the underlying io.Reader against the provided hash.
18 type HashCheckingReader struct {
19 // The underlying data source
22 // The hash function to use
25 // The hash value to check against. Must be a hex-encoded lowercase string.
29 // Reads from the underlying reader, update the hashing function, and
30 // pass the results through. Returns BadChecksum (instead of EOF) on
31 // the last read if the checksum doesn't match.
32 func (this HashCheckingReader) Read(p []byte) (n int, err error) {
33 n, err = this.Reader.Read(p)
35 this.Hash.Write(p[:n])
38 sum := this.Hash.Sum(nil)
39 if fmt.Sprintf("%x", sum) != this.Check {
46 // WriteTo writes the entire contents of this.Reader to dest. Returns
47 // BadChecksum if writing is successful but the checksum doesn't
49 func (this HashCheckingReader) WriteTo(dest io.Writer) (written int64, err error) {
50 if writeto, ok := this.Reader.(io.WriterTo); ok {
51 written, err = writeto.WriteTo(io.MultiWriter(dest, this.Hash))
53 written, err = io.Copy(io.MultiWriter(dest, this.Hash), this.Reader)
60 sum := this.Hash.Sum(nil)
61 if fmt.Sprintf("%x", sum) != this.Check {
62 return written, BadChecksum
68 // Close reads all remaining data from the underlying Reader and
69 // returns BadChecksum if the checksum doesn't match. It also closes
70 // the underlying Reader if it implements io.ReadCloser.
71 func (this HashCheckingReader) Close() (err error) {
72 _, err = io.Copy(this.Hash, this.Reader)
74 if closer, ok := this.Reader.(io.Closer); ok {
75 closeErr := closer.Close()
83 if fmt.Sprintf("%x", this.Hash.Sum(nil)) != this.Check {