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  }