aboutsummaryrefslogtreecommitdiff
path: root/chksum/chksum.go
blob: 0931567bce34c6b9cc6b914f938cce3b668250a0 (plain)
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package chksum

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"hash"
	"io"
	"os"
	"regexp"
)

/* checksum file format
	SHA512 (filename) = hex-encoded checksum
   or
	SHA256 (filename) = hex-encoded checksum
*/

type Checksum struct {
	FileName string
	Alg      string
	Bytes    []byte
	Hash     hash.Hash
}

var hashes = map[string]func() hash.Hash{
	"SHA512": sha512.New,
	"SHA256": sha256.New,
	"SHA1":   sha1.New,
	"MD5":    md5.New,
}

func ParseFile(fname string) ([]Checksum, error) {
	fd, err := os.Open(fname)
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	var checklist []Checksum
	re := regexp.MustCompile(`(\w+) \(([^)]+)\) = (\w+)`)
	scanner := bufio.NewScanner(fd)
	for scanner.Scan() {
		//var cs Checksum
		r := re.FindStringSubmatch(scanner.Text())
		if len(r) != 4 {
			return nil, errors.New("invalid content")
		}
		h, ok := hashes[r[1]]
		if !ok {
			return nil, errors.New("unknown hash alg")
		}
		bytes, err := hex.DecodeString(r[3])
		if err != nil {
			return nil, err
		}
		cs := Checksum{
			FileName: r[2],
			Alg:      r[1],
			Bytes:    bytes,
			Hash:     h(),
		}
		checklist = append(checklist, cs)
	}
	return checklist, scanner.Err()
}

func (c Checksum) Check() error {
	fd, err := os.Open(c.FileName)
	if err != nil {
		return err
	}
	defer fd.Close()
	io.Copy(c.Hash, fd)
	if !bytes.Equal(c.Hash.Sum(nil), c.Bytes) {
		return errors.New("hash mismatch")
	}
	return nil
}