328a6bbf4e
While the v2 pull operation is writing the body of the layer blob to disk it now computes the tarsum checksum of the archive before extracting it to the backend storage driver. If the checksum does not match that from the image manifest an error is raised. Also adds more debug logging to the pull operation and fixes existing test cases which were failing. Adds a reverse lookup constructor to the tarsum package so that you can get a tarsum object using a checksum label. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
139 lines
3.6 KiB
Go
139 lines
3.6 KiB
Go
package tarsum
|
|
|
|
import (
|
|
"errors"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
|
)
|
|
|
|
// versioning of the TarSum algorithm
|
|
// based on the prefix of the hash used
|
|
// i.e. "tarsum+sha256:e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b"
|
|
type Version int
|
|
|
|
// Prefix of "tarsum"
|
|
const (
|
|
Version0 Version = iota
|
|
Version1
|
|
// NOTE: this variable will be either the latest or an unsettled next-version of the TarSum calculation
|
|
VersionDev
|
|
)
|
|
|
|
// Get a list of all known tarsum Version
|
|
func GetVersions() []Version {
|
|
v := []Version{}
|
|
for k := range tarSumVersions {
|
|
v = append(v, k)
|
|
}
|
|
return v
|
|
}
|
|
|
|
var (
|
|
tarSumVersions = map[Version]string{
|
|
Version0: "tarsum",
|
|
Version1: "tarsum.v1",
|
|
VersionDev: "tarsum.dev",
|
|
}
|
|
tarSumVersionsByName = map[string]Version{
|
|
"tarsum": Version0,
|
|
"tarsum.v1": Version1,
|
|
"tarsum.dev": VersionDev,
|
|
}
|
|
)
|
|
|
|
func (tsv Version) String() string {
|
|
return tarSumVersions[tsv]
|
|
}
|
|
|
|
// GetVersionFromTarsum returns the Version from the provided string
|
|
func GetVersionFromTarsum(tarsum string) (Version, error) {
|
|
tsv := tarsum
|
|
if strings.Contains(tarsum, "+") {
|
|
tsv = strings.SplitN(tarsum, "+", 2)[0]
|
|
}
|
|
for v, s := range tarSumVersions {
|
|
if s == tsv {
|
|
return v, nil
|
|
}
|
|
}
|
|
return -1, ErrNotVersion
|
|
}
|
|
|
|
// Errors that may be returned by functions in this package
|
|
var (
|
|
ErrNotVersion = errors.New("string does not include a TarSum Version")
|
|
ErrVersionNotImplemented = errors.New("TarSum Version is not yet implemented")
|
|
)
|
|
|
|
// tarHeaderSelector is the interface which different versions
|
|
// of tarsum should use for selecting and ordering tar headers
|
|
// for each item in the archive.
|
|
type tarHeaderSelector interface {
|
|
selectHeaders(h *tar.Header) (orderedHeaders [][2]string)
|
|
}
|
|
|
|
type tarHeaderSelectFunc func(h *tar.Header) (orderedHeaders [][2]string)
|
|
|
|
func (f tarHeaderSelectFunc) selectHeaders(h *tar.Header) (orderedHeaders [][2]string) {
|
|
return f(h)
|
|
}
|
|
|
|
func v0TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
|
|
return [][2]string{
|
|
{"name", h.Name},
|
|
{"mode", strconv.Itoa(int(h.Mode))},
|
|
{"uid", strconv.Itoa(h.Uid)},
|
|
{"gid", strconv.Itoa(h.Gid)},
|
|
{"size", strconv.Itoa(int(h.Size))},
|
|
{"mtime", strconv.Itoa(int(h.ModTime.UTC().Unix()))},
|
|
{"typeflag", string([]byte{h.Typeflag})},
|
|
{"linkname", h.Linkname},
|
|
{"uname", h.Uname},
|
|
{"gname", h.Gname},
|
|
{"devmajor", strconv.Itoa(int(h.Devmajor))},
|
|
{"devminor", strconv.Itoa(int(h.Devminor))},
|
|
}
|
|
}
|
|
|
|
func v1TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
|
|
// Get extended attributes.
|
|
xAttrKeys := make([]string, len(h.Xattrs))
|
|
for k := range h.Xattrs {
|
|
xAttrKeys = append(xAttrKeys, k)
|
|
}
|
|
sort.Strings(xAttrKeys)
|
|
|
|
// Make the slice with enough capacity to hold the 11 basic headers
|
|
// we want from the v0 selector plus however many xattrs we have.
|
|
orderedHeaders = make([][2]string, 0, 11+len(xAttrKeys))
|
|
|
|
// Copy all headers from v0 excluding the 'mtime' header (the 5th element).
|
|
v0headers := v0TarHeaderSelect(h)
|
|
orderedHeaders = append(orderedHeaders, v0headers[0:5]...)
|
|
orderedHeaders = append(orderedHeaders, v0headers[6:]...)
|
|
|
|
// Finally, append the sorted xattrs.
|
|
for _, k := range xAttrKeys {
|
|
orderedHeaders = append(orderedHeaders, [2]string{k, h.Xattrs[k]})
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
var registeredHeaderSelectors = map[Version]tarHeaderSelectFunc{
|
|
Version0: v0TarHeaderSelect,
|
|
Version1: v1TarHeaderSelect,
|
|
VersionDev: v1TarHeaderSelect,
|
|
}
|
|
|
|
func getTarHeaderSelector(v Version) (tarHeaderSelector, error) {
|
|
headerSelector, ok := registeredHeaderSelectors[v]
|
|
if !ok {
|
|
return nil, ErrVersionNotImplemented
|
|
}
|
|
|
|
return headerSelector, nil
|
|
}
|