github.com/fcwu/docker@v1.4.2-0.20150115145920-2a69ca89f0df/pkg/tarsum/versioning.go (about)

     1  package tarsum
     2  
     3  import (
     4  	"errors"
     5  	"sort"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
    10  )
    11  
    12  // versioning of the TarSum algorithm
    13  // based on the prefix of the hash used
    14  // i.e. "tarsum+sha256:e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b"
    15  type Version int
    16  
    17  // Prefix of "tarsum"
    18  const (
    19  	Version0 Version = iota
    20  	Version1
    21  	// NOTE: this variable will be either the latest or an unsettled next-version of the TarSum calculation
    22  	VersionDev
    23  )
    24  
    25  // Get a list of all known tarsum Version
    26  func GetVersions() []Version {
    27  	v := []Version{}
    28  	for k := range tarSumVersions {
    29  		v = append(v, k)
    30  	}
    31  	return v
    32  }
    33  
    34  var tarSumVersions = map[Version]string{
    35  	Version0:   "tarsum",
    36  	Version1:   "tarsum.v1",
    37  	VersionDev: "tarsum.dev",
    38  }
    39  
    40  func (tsv Version) String() string {
    41  	return tarSumVersions[tsv]
    42  }
    43  
    44  // GetVersionFromTarsum returns the Version from the provided string
    45  func GetVersionFromTarsum(tarsum string) (Version, error) {
    46  	tsv := tarsum
    47  	if strings.Contains(tarsum, "+") {
    48  		tsv = strings.SplitN(tarsum, "+", 2)[0]
    49  	}
    50  	for v, s := range tarSumVersions {
    51  		if s == tsv {
    52  			return v, nil
    53  		}
    54  	}
    55  	return -1, ErrNotVersion
    56  }
    57  
    58  // Errors that may be returned by functions in this package
    59  var (
    60  	ErrNotVersion            = errors.New("string does not include a TarSum Version")
    61  	ErrVersionNotImplemented = errors.New("TarSum Version is not yet implemented")
    62  )
    63  
    64  // tarHeaderSelector is the interface which different versions
    65  // of tarsum should use for selecting and ordering tar headers
    66  // for each item in the archive.
    67  type tarHeaderSelector interface {
    68  	selectHeaders(h *tar.Header) (orderedHeaders [][2]string)
    69  }
    70  
    71  type tarHeaderSelectFunc func(h *tar.Header) (orderedHeaders [][2]string)
    72  
    73  func (f tarHeaderSelectFunc) selectHeaders(h *tar.Header) (orderedHeaders [][2]string) {
    74  	return f(h)
    75  }
    76  
    77  func v0TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
    78  	return [][2]string{
    79  		{"name", h.Name},
    80  		{"mode", strconv.Itoa(int(h.Mode))},
    81  		{"uid", strconv.Itoa(h.Uid)},
    82  		{"gid", strconv.Itoa(h.Gid)},
    83  		{"size", strconv.Itoa(int(h.Size))},
    84  		{"mtime", strconv.Itoa(int(h.ModTime.UTC().Unix()))},
    85  		{"typeflag", string([]byte{h.Typeflag})},
    86  		{"linkname", h.Linkname},
    87  		{"uname", h.Uname},
    88  		{"gname", h.Gname},
    89  		{"devmajor", strconv.Itoa(int(h.Devmajor))},
    90  		{"devminor", strconv.Itoa(int(h.Devminor))},
    91  	}
    92  }
    93  
    94  func v1TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
    95  	// Get extended attributes.
    96  	xAttrKeys := make([]string, len(h.Xattrs))
    97  	for k := range h.Xattrs {
    98  		xAttrKeys = append(xAttrKeys, k)
    99  	}
   100  	sort.Strings(xAttrKeys)
   101  
   102  	// Make the slice with enough capacity to hold the 11 basic headers
   103  	// we want from the v0 selector plus however many xattrs we have.
   104  	orderedHeaders = make([][2]string, 0, 11+len(xAttrKeys))
   105  
   106  	// Copy all headers from v0 excluding the 'mtime' header (the 5th element).
   107  	v0headers := v0TarHeaderSelect(h)
   108  	orderedHeaders = append(orderedHeaders, v0headers[0:5]...)
   109  	orderedHeaders = append(orderedHeaders, v0headers[6:]...)
   110  
   111  	// Finally, append the sorted xattrs.
   112  	for _, k := range xAttrKeys {
   113  		orderedHeaders = append(orderedHeaders, [2]string{k, h.Xattrs[k]})
   114  	}
   115  
   116  	return
   117  }
   118  
   119  var registeredHeaderSelectors = map[Version]tarHeaderSelectFunc{
   120  	Version0:   v0TarHeaderSelect,
   121  	Version1:   v1TarHeaderSelect,
   122  	VersionDev: v1TarHeaderSelect,
   123  }
   124  
   125  func getTarHeaderSelector(v Version) (tarHeaderSelector, error) {
   126  	headerSelector, ok := registeredHeaderSelectors[v]
   127  	if !ok {
   128  		return nil, ErrVersionNotImplemented
   129  	}
   130  
   131  	return headerSelector, nil
   132  }