fileinfosums.go 3.5 KB

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