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 }