File: digests.go

package info (click to toggle)
continuity 0.0~git20180216.d8fb858-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 620 kB
  • sloc: makefile: 46; sh: 28; asm: 3
file content (88 lines) | stat: -rw-r--r-- 2,290 bytes parent folder | download
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
85
86
87
88
package continuity

import (
	"fmt"
	"io"
	"sort"

	"github.com/opencontainers/go-digest"
)

// Digester produces a digest for a given read stream
type Digester interface {
	Digest(io.Reader) (digest.Digest, error)
}

// ContentProvider produces a read stream for a given digest
type ContentProvider interface {
	Reader(digest.Digest) (io.ReadCloser, error)
}

type simpleDigester struct {
	algorithm digest.Algorithm
}

func (sd simpleDigester) Digest(r io.Reader) (digest.Digest, error) {
	digester := sd.algorithm.Digester()

	if _, err := io.Copy(digester.Hash(), r); err != nil {
		return "", err
	}

	return digester.Digest(), nil
}

// uniqifyDigests sorts and uniqifies the provided digest, ensuring that the
// digests are not repeated and no two digests with the same algorithm have
// different values. Because a stable sort is used, this has the effect of
// "zipping" digest collections from multiple resources.
func uniqifyDigests(digests ...digest.Digest) ([]digest.Digest, error) {
	sort.Stable(digestSlice(digests)) // stable sort is important for the behavior here.
	seen := map[digest.Digest]struct{}{}
	algs := map[digest.Algorithm][]digest.Digest{} // detect different digests.

	var out []digest.Digest
	// uniqify the digests
	for _, d := range digests {
		if _, ok := seen[d]; ok {
			continue
		}

		seen[d] = struct{}{}
		algs[d.Algorithm()] = append(algs[d.Algorithm()], d)

		if len(algs[d.Algorithm()]) > 1 {
			return nil, fmt.Errorf("conflicting digests for %v found", d.Algorithm())
		}

		out = append(out, d)
	}

	return out, nil
}

// digestsMatch compares the two sets of digests to see if they match.
func digestsMatch(as, bs []digest.Digest) bool {
	all := append(as, bs...)

	uniqified, err := uniqifyDigests(all...)
	if err != nil {
		// the only error uniqifyDigests returns is when the digests disagree.
		return false
	}

	disjoint := len(as) + len(bs)
	if len(uniqified) == disjoint {
		// if these two sets have the same cardinality, we know both sides
		// didn't share any digests.
		return false
	}

	return true
}

type digestSlice []digest.Digest

func (p digestSlice) Len() int           { return len(p) }
func (p digestSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p digestSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }