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() }