| package tarsum // import "github.com/docker/docker/pkg/tarsum" |
| |
| import ( |
| "runtime" |
| "sort" |
| "strings" |
| ) |
| |
| // FileInfoSumInterface provides an interface for accessing file checksum |
| // information within a tar file. This info is accessed through interface |
| // so the actual name and sum cannot be melded with. |
| type FileInfoSumInterface interface { |
| // File name |
| Name() string |
| // Checksum of this particular file and its headers |
| Sum() string |
| // Position of file in the tar |
| Pos() int64 |
| } |
| |
| type fileInfoSum struct { |
| name string |
| sum string |
| pos int64 |
| } |
| |
| func (fis fileInfoSum) Name() string { |
| return fis.name |
| } |
| func (fis fileInfoSum) Sum() string { |
| return fis.sum |
| } |
| func (fis fileInfoSum) Pos() int64 { |
| return fis.pos |
| } |
| |
| // FileInfoSums provides a list of FileInfoSumInterfaces. |
| type FileInfoSums []FileInfoSumInterface |
| |
| // GetFile returns the first FileInfoSumInterface with a matching name. |
| func (fis FileInfoSums) GetFile(name string) FileInfoSumInterface { |
| // We do case insensitive matching on Windows as c:\APP and c:\app are |
| // the same. See issue #33107. |
| for i := range fis { |
| if (runtime.GOOS == "windows" && strings.EqualFold(fis[i].Name(), name)) || |
| (runtime.GOOS != "windows" && fis[i].Name() == name) { |
| return fis[i] |
| } |
| } |
| return nil |
| } |
| |
| // GetAllFile returns a FileInfoSums with all matching names. |
| func (fis FileInfoSums) GetAllFile(name string) FileInfoSums { |
| f := FileInfoSums{} |
| for i := range fis { |
| if fis[i].Name() == name { |
| f = append(f, fis[i]) |
| } |
| } |
| return f |
| } |
| |
| // GetDuplicatePaths returns a FileInfoSums with all duplicated paths. |
| func (fis FileInfoSums) GetDuplicatePaths() (dups FileInfoSums) { |
| seen := make(map[string]int, len(fis)) // allocate earl. no need to grow this map. |
| for i := range fis { |
| f := fis[i] |
| if _, ok := seen[f.Name()]; ok { |
| dups = append(dups, f) |
| } else { |
| seen[f.Name()] = 0 |
| } |
| } |
| return dups |
| } |
| |
| // Len returns the size of the FileInfoSums. |
| func (fis FileInfoSums) Len() int { return len(fis) } |
| |
| // Swap swaps two FileInfoSum values if a FileInfoSums list. |
| func (fis FileInfoSums) Swap(i, j int) { fis[i], fis[j] = fis[j], fis[i] } |
| |
| // SortByPos sorts FileInfoSums content by position. |
| func (fis FileInfoSums) SortByPos() { |
| sort.Sort(byPos{fis}) |
| } |
| |
| // SortByNames sorts FileInfoSums content by name. |
| func (fis FileInfoSums) SortByNames() { |
| sort.Sort(byName{fis}) |
| } |
| |
| // SortBySums sorts FileInfoSums content by sums. |
| func (fis FileInfoSums) SortBySums() { |
| dups := fis.GetDuplicatePaths() |
| if len(dups) > 0 { |
| sort.Sort(bySum{fis, dups}) |
| } else { |
| sort.Sort(bySum{fis, nil}) |
| } |
| } |
| |
| // byName is a sort.Sort helper for sorting by file names. |
| // If names are the same, order them by their appearance in the tar archive |
| type byName struct{ FileInfoSums } |
| |
| func (bn byName) Less(i, j int) bool { |
| if bn.FileInfoSums[i].Name() == bn.FileInfoSums[j].Name() { |
| return bn.FileInfoSums[i].Pos() < bn.FileInfoSums[j].Pos() |
| } |
| return bn.FileInfoSums[i].Name() < bn.FileInfoSums[j].Name() |
| } |
| |
| // bySum is a sort.Sort helper for sorting by the sums of all the fileinfos in the tar archive |
| type bySum struct { |
| FileInfoSums |
| dups FileInfoSums |
| } |
| |
| func (bs bySum) Less(i, j int) bool { |
| if bs.dups != nil && bs.FileInfoSums[i].Name() == bs.FileInfoSums[j].Name() { |
| return bs.FileInfoSums[i].Pos() < bs.FileInfoSums[j].Pos() |
| } |
| return bs.FileInfoSums[i].Sum() < bs.FileInfoSums[j].Sum() |
| } |
| |
| // byPos is a sort.Sort helper for sorting by the sums of all the fileinfos by their original order |
| type byPos struct{ FileInfoSums } |
| |
| func (bp byPos) Less(i, j int) bool { |
| return bp.FileInfoSums[i].Pos() < bp.FileInfoSums[j].Pos() |
| } |