Files
Packer-Cn/packer/plugin-getter/checksum.go
hashicorp-copywrite[bot] 19055df3ec [COMPLIANCE] License changes (#12568)
* Updating the license from MPL to Business Source License

Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at https://hashi.co/license-faq, and details of the license at www.hashicorp.com/bsl.

* Update copyright file headers to BUSL-1.1

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-08-10 15:53:29 -07:00

120 lines
2.5 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package plugingetter
import (
"bytes"
"encoding/hex"
"fmt"
"hash"
"io"
"os"
"strings"
)
// A ChecksumError is returned when a checksum differs
type ChecksumError struct {
Hash hash.Hash
Actual []byte
Expected []byte
File string
}
func (cerr *ChecksumError) Error() string {
if cerr == nil {
return "<nil>"
}
return fmt.Sprintf(
"Checksums (%T) did not match.\nExpected: %s\nGot : %s\n",
cerr.Hash, // ex: *sha256.digest
hex.EncodeToString(cerr.Expected),
hex.EncodeToString(cerr.Actual),
)
}
type Checksum []byte
func (c Checksum) String() string { return hex.EncodeToString(c) }
type FileChecksum struct {
Filename string
Expected Checksum
Checksummer
}
type Checksummer struct {
// Something like md5 or sha256
Type string
// Hash function
hash.Hash
}
func (c *Checksummer) FileExt() string {
return "_" + strings.ToUpper(c.Type) + "SUM"
}
// GetCacheChecksumOfFile will extract the checksum from file `filePath + c.FileExt()`.
// It expects the checksum file to only contains the checksum and nothing else.
func (c *Checksummer) GetCacheChecksumOfFile(filePath string) ([]byte, error) {
checksumFile := filePath + c.FileExt()
f, err := os.Open(checksumFile)
if err != nil {
return nil, err
}
defer f.Close()
return c.ParseChecksum(f)
}
// ParseChecksum expects the checksum reader to only contain the checksum and
// nothing else.
func (c *Checksummer) ParseChecksum(f io.Reader) (Checksum, error) {
res := make([]byte, c.Hash.Size())
_, err := hex.NewDecoder(f).Read(res)
if err == io.EOF {
err = nil
}
return res, err
}
// ChecksumFile compares the expected checksum to the checksum of the file in
// filePath using the hash function.
func (c *Checksummer) ChecksumFile(expected []byte, filePath string) error {
f, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("Checksum: failed to open file for checksum: %s", err)
}
defer f.Close()
err = c.Checksum(expected, f)
if cerr, ok := err.(*ChecksumError); ok {
cerr.File = filePath
}
return err
}
func (c *Checksummer) Sum(f io.Reader) ([]byte, error) {
c.Hash.Reset()
if _, err := io.Copy(c.Hash, f); err != nil {
return nil, fmt.Errorf("Failed to hash: %s", err)
}
return c.Hash.Sum(nil), nil
}
func (c *Checksummer) Checksum(expected []byte, f io.Reader) error {
actual, err := c.Sum(f)
if err != nil {
return err
}
if !bytes.Equal(actual, expected) {
return &ChecksumError{
Hash: c.Hash,
Actual: actual,
Expected: expected,
}
}
return nil
}