github.com/moby/docker@v26.1.3+incompatible/pkg/tarsum/fileinfosums.go (about) 1 package tarsum // import "github.com/docker/docker/pkg/tarsum" 2 3 import ( 4 "runtime" 5 "sort" 6 "strings" 7 ) 8 9 // FileInfoSumInterface provides an interface for accessing file checksum 10 // information within a tar file. This info is accessed through interface 11 // so the actual name and sum cannot be melded with. 12 type FileInfoSumInterface interface { 13 // File name 14 Name() string 15 // Checksum of this particular file and its headers 16 Sum() string 17 // Position of file in the tar 18 Pos() int64 19 } 20 21 type fileInfoSum struct { 22 name string 23 sum string 24 pos int64 25 } 26 27 func (fis fileInfoSum) Name() string { 28 return fis.name 29 } 30 31 func (fis fileInfoSum) Sum() string { 32 return fis.sum 33 } 34 35 func (fis fileInfoSum) Pos() int64 { 36 return fis.pos 37 } 38 39 // FileInfoSums provides a list of FileInfoSumInterfaces. 40 type FileInfoSums []FileInfoSumInterface 41 42 // GetFile returns the first FileInfoSumInterface with a matching name. 43 func (fis FileInfoSums) GetFile(name string) FileInfoSumInterface { 44 // We do case insensitive matching on Windows as c:\APP and c:\app are 45 // the same. See issue #33107. 46 for i := range fis { 47 if (runtime.GOOS == "windows" && strings.EqualFold(fis[i].Name(), name)) || 48 (runtime.GOOS != "windows" && fis[i].Name() == name) { 49 return fis[i] 50 } 51 } 52 return nil 53 } 54 55 // GetAllFile returns a FileInfoSums with all matching names. 56 func (fis FileInfoSums) GetAllFile(name string) FileInfoSums { 57 f := FileInfoSums{} 58 for i := range fis { 59 if fis[i].Name() == name { 60 f = append(f, fis[i]) 61 } 62 } 63 return f 64 } 65 66 // GetDuplicatePaths returns a FileInfoSums with all duplicated paths. 67 func (fis FileInfoSums) GetDuplicatePaths() (dups FileInfoSums) { 68 seen := make(map[string]int, len(fis)) // allocate earl. no need to grow this map. 69 for i := range fis { 70 f := fis[i] 71 if _, ok := seen[f.Name()]; ok { 72 dups = append(dups, f) 73 } else { 74 seen[f.Name()] = 0 75 } 76 } 77 return dups 78 } 79 80 // Len returns the size of the FileInfoSums. 81 func (fis FileInfoSums) Len() int { return len(fis) } 82 83 // Swap swaps two FileInfoSum values if a FileInfoSums list. 84 func (fis FileInfoSums) Swap(i, j int) { fis[i], fis[j] = fis[j], fis[i] } 85 86 // SortByPos sorts FileInfoSums content by position. 87 func (fis FileInfoSums) SortByPos() { 88 sort.Sort(byPos{fis}) 89 } 90 91 // SortByNames sorts FileInfoSums content by name. 92 func (fis FileInfoSums) SortByNames() { 93 sort.Sort(byName{fis}) 94 } 95 96 // SortBySums sorts FileInfoSums content by sums. 97 func (fis FileInfoSums) SortBySums() { 98 dups := fis.GetDuplicatePaths() 99 if len(dups) > 0 { 100 sort.Sort(bySum{fis, dups}) 101 } else { 102 sort.Sort(bySum{fis, nil}) 103 } 104 } 105 106 // byName is a sort.Sort helper for sorting by file names. 107 // If names are the same, order them by their appearance in the tar archive 108 type byName struct{ FileInfoSums } 109 110 func (bn byName) Less(i, j int) bool { 111 if bn.FileInfoSums[i].Name() == bn.FileInfoSums[j].Name() { 112 return bn.FileInfoSums[i].Pos() < bn.FileInfoSums[j].Pos() 113 } 114 return bn.FileInfoSums[i].Name() < bn.FileInfoSums[j].Name() 115 } 116 117 // bySum is a sort.Sort helper for sorting by the sums of all the fileinfos in the tar archive 118 type bySum struct { 119 FileInfoSums 120 dups FileInfoSums 121 } 122 123 func (bs bySum) Less(i, j int) bool { 124 if bs.dups != nil && bs.FileInfoSums[i].Name() == bs.FileInfoSums[j].Name() { 125 return bs.FileInfoSums[i].Pos() < bs.FileInfoSums[j].Pos() 126 } 127 return bs.FileInfoSums[i].Sum() < bs.FileInfoSums[j].Sum() 128 } 129 130 // byPos is a sort.Sort helper for sorting by the sums of all the fileinfos by their original order 131 type byPos struct{ FileInfoSums } 132 133 func (bp byPos) Less(i, j int) bool { 134 return bp.FileInfoSums[i].Pos() < bp.FileInfoSums[j].Pos() 135 }