github.com/hashicorp/packer@v1.14.3/packer/plugin-getter/checksum.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package plugingetter 5 6 import ( 7 "bytes" 8 "encoding/hex" 9 "fmt" 10 "hash" 11 "io" 12 "os" 13 "strings" 14 ) 15 16 // A ChecksumError is returned when a checksum differs 17 type ChecksumError struct { 18 Hash hash.Hash 19 Actual []byte 20 Expected []byte 21 File string 22 } 23 24 func (cerr *ChecksumError) Error() string { 25 if cerr == nil { 26 return "<nil>" 27 } 28 return fmt.Sprintf( 29 "Checksums (%T) did not match.\nExpected: %s\nGot : %s\n", 30 cerr.Hash, // ex: *sha256.digest 31 hex.EncodeToString(cerr.Expected), 32 hex.EncodeToString(cerr.Actual), 33 ) 34 } 35 36 type Checksum []byte 37 38 func (c Checksum) String() string { return hex.EncodeToString(c) } 39 40 type FileChecksum struct { 41 Filename string 42 Expected Checksum 43 Checksummer 44 } 45 46 type Checksummer struct { 47 // Something like md5 or sha256 48 Type string 49 // Hash function 50 hash.Hash 51 } 52 53 func (c *Checksummer) FileExt() string { 54 return "_" + strings.ToUpper(c.Type) + "SUM" 55 } 56 57 // GetCacheChecksumOfFile will extract the checksum from file `filePath + c.FileExt()`. 58 // It expects the checksum file to only contains the checksum and nothing else. 59 func (c *Checksummer) GetCacheChecksumOfFile(filePath string) ([]byte, error) { 60 checksumFile := filePath + c.FileExt() 61 62 f, err := os.Open(checksumFile) 63 if err != nil { 64 return nil, err 65 } 66 defer f.Close() 67 return c.ParseChecksum(f) 68 } 69 70 // ParseChecksum expects the checksum reader to only contain the checksum and 71 // nothing else. 72 func (c *Checksummer) ParseChecksum(f io.Reader) (Checksum, error) { 73 res := make([]byte, c.Hash.Size()) 74 _, err := hex.NewDecoder(f).Read(res) 75 if err == io.EOF { 76 err = nil 77 } 78 return res, err 79 } 80 81 // ChecksumFile compares the expected checksum to the checksum of the file in 82 // filePath using the hash function. 83 func (c *Checksummer) ChecksumFile(expected []byte, filePath string) error { 84 f, err := os.Open(filePath) 85 if err != nil { 86 return fmt.Errorf("Checksum: failed to open file for checksum: %s", err) 87 } 88 defer f.Close() 89 err = c.Checksum(expected, f) 90 if cerr, ok := err.(*ChecksumError); ok { 91 cerr.File = filePath 92 } 93 return err 94 } 95 96 func (c *Checksummer) Sum(f io.Reader) ([]byte, error) { 97 c.Hash.Reset() 98 if _, err := io.Copy(c.Hash, f); err != nil { 99 return nil, fmt.Errorf("Failed to hash: %s", err) 100 } 101 return c.Hash.Sum(nil), nil 102 } 103 104 func (c *Checksummer) Checksum(expected []byte, f io.Reader) error { 105 actual, err := c.Sum(f) 106 if err != nil { 107 return err 108 } 109 110 if !bytes.Equal(actual, expected) { 111 return &ChecksumError{ 112 Hash: c.Hash, 113 Actual: actual, 114 Expected: expected, 115 } 116 } 117 118 return nil 119 }