github.com/christopherobin/docker@v1.6.2/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 // VersionLabelForChecksum returns the label for the given tarsum 26 // checksum, i.e., everything before the first `+` character in 27 // the string or an empty string if no label separator is found. 28 func VersionLabelForChecksum(checksum string) string { 29 // Checksums are in the form: {versionLabel}+{hashID}:{hex} 30 sepIndex := strings.Index(checksum, "+") 31 if sepIndex < 0 { 32 return "" 33 } 34 return checksum[:sepIndex] 35 } 36 37 // Get a list of all known tarsum Version 38 func GetVersions() []Version { 39 v := []Version{} 40 for k := range tarSumVersions { 41 v = append(v, k) 42 } 43 return v 44 } 45 46 var ( 47 tarSumVersions = map[Version]string{ 48 Version0: "tarsum", 49 Version1: "tarsum.v1", 50 VersionDev: "tarsum.dev", 51 } 52 tarSumVersionsByName = map[string]Version{ 53 "tarsum": Version0, 54 "tarsum.v1": Version1, 55 "tarsum.dev": VersionDev, 56 } 57 ) 58 59 func (tsv Version) String() string { 60 return tarSumVersions[tsv] 61 } 62 63 // GetVersionFromTarsum returns the Version from the provided string 64 func GetVersionFromTarsum(tarsum string) (Version, error) { 65 tsv := tarsum 66 if strings.Contains(tarsum, "+") { 67 tsv = strings.SplitN(tarsum, "+", 2)[0] 68 } 69 for v, s := range tarSumVersions { 70 if s == tsv { 71 return v, nil 72 } 73 } 74 return -1, ErrNotVersion 75 } 76 77 // Errors that may be returned by functions in this package 78 var ( 79 ErrNotVersion = errors.New("string does not include a TarSum Version") 80 ErrVersionNotImplemented = errors.New("TarSum Version is not yet implemented") 81 ) 82 83 // tarHeaderSelector is the interface which different versions 84 // of tarsum should use for selecting and ordering tar headers 85 // for each item in the archive. 86 type tarHeaderSelector interface { 87 selectHeaders(h *tar.Header) (orderedHeaders [][2]string) 88 } 89 90 type tarHeaderSelectFunc func(h *tar.Header) (orderedHeaders [][2]string) 91 92 func (f tarHeaderSelectFunc) selectHeaders(h *tar.Header) (orderedHeaders [][2]string) { 93 return f(h) 94 } 95 96 func v0TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) { 97 return [][2]string{ 98 {"name", h.Name}, 99 {"mode", strconv.Itoa(int(h.Mode))}, 100 {"uid", strconv.Itoa(h.Uid)}, 101 {"gid", strconv.Itoa(h.Gid)}, 102 {"size", strconv.Itoa(int(h.Size))}, 103 {"mtime", strconv.Itoa(int(h.ModTime.UTC().Unix()))}, 104 {"typeflag", string([]byte{h.Typeflag})}, 105 {"linkname", h.Linkname}, 106 {"uname", h.Uname}, 107 {"gname", h.Gname}, 108 {"devmajor", strconv.Itoa(int(h.Devmajor))}, 109 {"devminor", strconv.Itoa(int(h.Devminor))}, 110 } 111 } 112 113 func v1TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) { 114 // Get extended attributes. 115 xAttrKeys := make([]string, len(h.Xattrs)) 116 for k := range h.Xattrs { 117 xAttrKeys = append(xAttrKeys, k) 118 } 119 sort.Strings(xAttrKeys) 120 121 // Make the slice with enough capacity to hold the 11 basic headers 122 // we want from the v0 selector plus however many xattrs we have. 123 orderedHeaders = make([][2]string, 0, 11+len(xAttrKeys)) 124 125 // Copy all headers from v0 excluding the 'mtime' header (the 5th element). 126 v0headers := v0TarHeaderSelect(h) 127 orderedHeaders = append(orderedHeaders, v0headers[0:5]...) 128 orderedHeaders = append(orderedHeaders, v0headers[6:]...) 129 130 // Finally, append the sorted xattrs. 131 for _, k := range xAttrKeys { 132 orderedHeaders = append(orderedHeaders, [2]string{k, h.Xattrs[k]}) 133 } 134 135 return 136 } 137 138 var registeredHeaderSelectors = map[Version]tarHeaderSelectFunc{ 139 Version0: v0TarHeaderSelect, 140 Version1: v1TarHeaderSelect, 141 VersionDev: v1TarHeaderSelect, 142 } 143 144 func getTarHeaderSelector(v Version) (tarHeaderSelector, error) { 145 headerSelector, ok := registeredHeaderSelectors[v] 146 if !ok { 147 return nil, ErrVersionNotImplemented 148 } 149 150 return headerSelector, nil 151 }