123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- /*
- Copyright The containerd Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- 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] }
|