TarSum: versioning

This introduces Versions for TarSum checksums.
Fixes: https://github.com/docker/docker/issues/7526

It preserves current functionality and abstracts the interface for
future flexibility of hashing algorithms. As a POC, the VersionDev
Tarsum does not include the mtime in the checksum calculation, and would
solve https://github.com/docker/docker/issues/7387 though this is not a
settled Version is subject to change until a version number is assigned.

Signed-off-by: Vincent Batts <vbatts@redhat.com>
This commit is contained in:
Vincent Batts 2014-08-21 16:12:52 -04:00
parent 47dabd55c0
commit 14689ec238
5 changed files with 193 additions and 24 deletions

View file

@ -22,6 +22,29 @@ const (
buf32K = 32 * 1024
)
// NewTarSum creates a new interface for calculating a fixed time checksum of a
// tar archive.
//
// This is used for calculating checksums of layers of an image, in some cases
// including the byte payload of the image's json metadata as well, and for
// calculating the checksums for buildcache.
func NewTarSum(r io.Reader, dc bool, v Version) (TarSumInterface, error) {
if _, ok := tarSumVersions[v]; !ok {
return nil, ErrVersionNotImplemented
}
return &TarSum{Reader: r, DisableCompression: dc, tarSumVersion: v}, nil
}
// TarSumInterface is the generic interface for calculating fixed time
// checksums of a tar archive
type TarSumInterface interface {
io.Reader
GetSums() map[string]string
Sum([]byte) string
Version() Version
}
// TarSum struct is the structure for a Version0 checksum calculation
type TarSum struct {
io.Reader
tarR *tar.Reader
@ -35,27 +58,15 @@ type TarSum struct {
currentFile string
finished bool
first bool
DisableCompression bool
DisableCompression bool // false by default. When false, the output gzip compressed.
tarSumVersion Version // this field is not exported so it can not be mutated during use
}
type writeCloseFlusher interface {
io.WriteCloser
Flush() error
func (ts TarSum) Version() Version {
return ts.tarSumVersion
}
type nopCloseFlusher struct {
io.Writer
}
func (n *nopCloseFlusher) Close() error {
return nil
}
func (n *nopCloseFlusher) Flush() error {
return nil
}
func (ts *TarSum) encodeHeader(h *tar.Header) error {
func (ts TarSum) selectHeaders(h *tar.Header, v Version) (set [][2]string) {
for _, elem := range [][2]string{
{"name", h.Name},
{"mode", strconv.Itoa(int(h.Mode))},
@ -69,9 +80,17 @@ func (ts *TarSum) encodeHeader(h *tar.Header) error {
{"gname", h.Gname},
{"devmajor", strconv.Itoa(int(h.Devmajor))},
{"devminor", strconv.Itoa(int(h.Devminor))},
// {"atime", strconv.Itoa(int(h.AccessTime.UTC().Unix()))},
// {"ctime", strconv.Itoa(int(h.ChangeTime.UTC().Unix()))},
} {
if v == VersionDev && elem[0] == "mtime" {
continue
}
set = append(set, elem)
}
return
}
func (ts *TarSum) encodeHeader(h *tar.Header) error {
for _, elem := range ts.selectHeaders(h, ts.Version()) {
if _, err := ts.h.Write([]byte(elem[0] + elem[1])); err != nil {
return err
}
@ -193,7 +212,7 @@ func (ts *TarSum) Sum(extra []byte) string {
log.Debugf("-->%s<--", sum)
h.Write([]byte(sum))
}
checksum := "tarsum+sha256:" + hex.EncodeToString(h.Sum(nil))
checksum := ts.Version().String() + "+sha256:" + hex.EncodeToString(h.Sum(nil))
log.Debugf("checksum processed: %s", checksum)
return checksum
}