tarsum.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package remotecontext
  2. import (
  3. "io"
  4. "os"
  5. "path/filepath"
  6. "github.com/docker/docker/builder"
  7. "github.com/docker/docker/pkg/archive"
  8. "github.com/docker/docker/pkg/chrootarchive"
  9. "github.com/docker/docker/pkg/ioutils"
  10. "github.com/docker/docker/pkg/symlink"
  11. "github.com/docker/docker/pkg/tarsum"
  12. "github.com/pkg/errors"
  13. )
  14. type tarSumContext struct {
  15. root string
  16. sums tarsum.FileInfoSums
  17. }
  18. func (c *tarSumContext) Close() error {
  19. return os.RemoveAll(c.root)
  20. }
  21. func convertPathError(err error, cleanpath string) error {
  22. if err, ok := err.(*os.PathError); ok {
  23. err.Path = cleanpath
  24. return err
  25. }
  26. return err
  27. }
  28. type modifiableContext interface {
  29. builder.Source
  30. // Remove deletes the entry specified by `path`.
  31. // It is usual for directory entries to delete all its subentries.
  32. Remove(path string) error
  33. }
  34. // MakeTarSumContext returns a build Context from a tar stream.
  35. //
  36. // It extracts the tar stream to a temporary folder that is deleted as soon as
  37. // the Context is closed.
  38. // As the extraction happens, a tarsum is calculated for every file, and the set of
  39. // all those sums then becomes the source of truth for all operations on this Context.
  40. //
  41. // Closing tarStream has to be done by the caller.
  42. func MakeTarSumContext(tarStream io.Reader) (builder.Source, error) {
  43. root, err := ioutils.TempDir("", "docker-builder")
  44. if err != nil {
  45. return nil, err
  46. }
  47. tsc := &tarSumContext{root: root}
  48. // Make sure we clean-up upon error. In the happy case the caller
  49. // is expected to manage the clean-up
  50. defer func() {
  51. if err != nil {
  52. tsc.Close()
  53. }
  54. }()
  55. decompressedStream, err := archive.DecompressStream(tarStream)
  56. if err != nil {
  57. return nil, err
  58. }
  59. sum, err := tarsum.NewTarSum(decompressedStream, true, tarsum.Version1)
  60. if err != nil {
  61. return nil, err
  62. }
  63. err = chrootarchive.Untar(sum, root, nil)
  64. if err != nil {
  65. return nil, err
  66. }
  67. tsc.sums = sum.GetSums()
  68. return tsc, nil
  69. }
  70. func (c *tarSumContext) Root() string {
  71. return c.root
  72. }
  73. func (c *tarSumContext) Remove(path string) error {
  74. _, fullpath, err := normalize(path, c.root)
  75. if err != nil {
  76. return err
  77. }
  78. return os.RemoveAll(fullpath)
  79. }
  80. func (c *tarSumContext) Hash(path string) (string, error) {
  81. cleanpath, fullpath, err := normalize(path, c.root)
  82. if err != nil {
  83. return "", err
  84. }
  85. rel, err := filepath.Rel(c.root, fullpath)
  86. if err != nil {
  87. return "", convertPathError(err, cleanpath)
  88. }
  89. // Use the checksum of the followed path(not the possible symlink) because
  90. // this is the file that is actually copied.
  91. if tsInfo := c.sums.GetFile(filepath.ToSlash(rel)); tsInfo != nil {
  92. return tsInfo.Sum(), nil
  93. }
  94. // We set sum to path by default for the case where GetFile returns nil.
  95. // The usual case is if relative path is empty.
  96. return path, nil // backwards compat TODO: see if really needed
  97. }
  98. func normalize(path, root string) (cleanPath, fullPath string, err error) {
  99. cleanPath = filepath.Clean(string(os.PathSeparator) + path)[1:]
  100. fullPath, err = symlink.FollowSymlinkInScope(filepath.Join(root, path), root)
  101. if err != nil {
  102. return "", "", errors.Wrapf(err, "forbidden path outside the build context: %s (%s)", path, cleanPath)
  103. }
  104. if _, err := os.Lstat(fullPath); err != nil {
  105. return "", "", convertPathError(err, path)
  106. }
  107. return
  108. }