importlayer.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package wclayer
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "path/filepath"
  6. "github.com/Microsoft/go-winio"
  7. "github.com/Microsoft/hcsshim/internal/hcserror"
  8. "github.com/Microsoft/hcsshim/internal/safefile"
  9. "github.com/sirupsen/logrus"
  10. )
  11. // ImportLayer will take the contents of the folder at importFolderPath and import
  12. // that into a layer with the id layerId. Note that in order to correctly populate
  13. // the layer and interperet the transport format, all parent layers must already
  14. // be present on the system at the paths provided in parentLayerPaths.
  15. func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) (err error) {
  16. title := "hcsshim::ImportLayer"
  17. fields := logrus.Fields{
  18. "path": path,
  19. "importFolderPath": importFolderPath,
  20. }
  21. logrus.WithFields(fields).Debug(title)
  22. defer func() {
  23. if err != nil {
  24. fields[logrus.ErrorKey] = err
  25. logrus.WithFields(fields).Error(err)
  26. } else {
  27. logrus.WithFields(fields).Debug(title + " - succeeded")
  28. }
  29. }()
  30. // Generate layer descriptors
  31. layers, err := layerPathsToDescriptors(parentLayerPaths)
  32. if err != nil {
  33. return err
  34. }
  35. err = importLayer(&stdDriverInfo, path, importFolderPath, layers)
  36. if err != nil {
  37. return hcserror.New(err, title+" - failed", "")
  38. }
  39. return nil
  40. }
  41. // LayerWriter is an interface that supports writing a new container image layer.
  42. type LayerWriter interface {
  43. // Add adds a file to the layer with given metadata.
  44. Add(name string, fileInfo *winio.FileBasicInfo) error
  45. // AddLink adds a hard link to the layer. The target must already have been added.
  46. AddLink(name string, target string) error
  47. // Remove removes a file that was present in a parent layer from the layer.
  48. Remove(name string) error
  49. // Write writes data to the current file. The data must be in the format of a Win32
  50. // backup stream.
  51. Write(b []byte) (int, error)
  52. // Close finishes the layer writing process and releases any resources.
  53. Close() error
  54. }
  55. type legacyLayerWriterWrapper struct {
  56. *legacyLayerWriter
  57. path string
  58. parentLayerPaths []string
  59. }
  60. func (r *legacyLayerWriterWrapper) Close() error {
  61. defer os.RemoveAll(r.root.Name())
  62. defer r.legacyLayerWriter.CloseRoots()
  63. err := r.legacyLayerWriter.Close()
  64. if err != nil {
  65. return err
  66. }
  67. if err = ImportLayer(r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
  68. return err
  69. }
  70. for _, name := range r.Tombstones {
  71. if err = safefile.RemoveRelative(name, r.destRoot); err != nil && !os.IsNotExist(err) {
  72. return err
  73. }
  74. }
  75. // Add any hard links that were collected.
  76. for _, lnk := range r.PendingLinks {
  77. if err = safefile.RemoveRelative(lnk.Path, r.destRoot); err != nil && !os.IsNotExist(err) {
  78. return err
  79. }
  80. if err = safefile.LinkRelative(lnk.Target, lnk.TargetRoot, lnk.Path, r.destRoot); err != nil {
  81. return err
  82. }
  83. }
  84. // Prepare the utility VM for use if one is present in the layer.
  85. if r.HasUtilityVM {
  86. err := safefile.EnsureNotReparsePointRelative("UtilityVM", r.destRoot)
  87. if err != nil {
  88. return err
  89. }
  90. err = ProcessUtilityVMImage(filepath.Join(r.destRoot.Name(), "UtilityVM"))
  91. if err != nil {
  92. return err
  93. }
  94. }
  95. return nil
  96. }
  97. // NewLayerWriter returns a new layer writer for creating a layer on disk.
  98. // The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
  99. // to call this and any methods on the resulting LayerWriter.
  100. func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error) {
  101. if len(parentLayerPaths) == 0 {
  102. // This is a base layer. It gets imported differently.
  103. f, err := safefile.OpenRoot(path)
  104. if err != nil {
  105. return nil, err
  106. }
  107. return &baseLayerWriter{
  108. root: f,
  109. }, nil
  110. }
  111. importPath, err := ioutil.TempDir("", "hcs")
  112. if err != nil {
  113. return nil, err
  114. }
  115. w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
  116. if err != nil {
  117. return nil, err
  118. }
  119. return &legacyLayerWriterWrapper{
  120. legacyLayerWriter: w,
  121. path: importPath,
  122. parentLayerPaths: parentLayerPaths,
  123. }, nil
  124. }