importlayer.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //go:build windows
  2. package wclayer
  3. import (
  4. "context"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "github.com/Microsoft/go-winio"
  9. "github.com/Microsoft/hcsshim/internal/hcserror"
  10. "github.com/Microsoft/hcsshim/internal/oc"
  11. "github.com/Microsoft/hcsshim/internal/safefile"
  12. "go.opencensus.io/trace"
  13. )
  14. // ImportLayer will take the contents of the folder at importFolderPath and import
  15. // that into a layer with the id layerId. Note that in order to correctly populate
  16. // the layer and interperet the transport format, all parent layers must already
  17. // be present on the system at the paths provided in parentLayerPaths.
  18. func ImportLayer(ctx context.Context, path string, importFolderPath string, parentLayerPaths []string) (err error) {
  19. title := "hcsshim::ImportLayer"
  20. ctx, span := oc.StartSpan(ctx, title)
  21. defer span.End()
  22. defer func() { oc.SetSpanStatus(span, err) }()
  23. span.AddAttributes(
  24. trace.StringAttribute("path", path),
  25. trace.StringAttribute("importFolderPath", importFolderPath),
  26. trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
  27. // Generate layer descriptors
  28. layers, err := layerPathsToDescriptors(ctx, parentLayerPaths)
  29. if err != nil {
  30. return err
  31. }
  32. err = importLayer(&stdDriverInfo, path, importFolderPath, layers)
  33. if err != nil {
  34. return hcserror.New(err, title, "")
  35. }
  36. return nil
  37. }
  38. // LayerWriter is an interface that supports writing a new container image layer.
  39. type LayerWriter interface {
  40. // Add adds a file to the layer with given metadata.
  41. Add(name string, fileInfo *winio.FileBasicInfo) error
  42. // AddLink adds a hard link to the layer. The target must already have been added.
  43. AddLink(name string, target string) error
  44. // Remove removes a file that was present in a parent layer from the layer.
  45. Remove(name string) error
  46. // Write writes data to the current file. The data must be in the format of a Win32
  47. // backup stream.
  48. Write(b []byte) (int, error)
  49. // Close finishes the layer writing process and releases any resources.
  50. Close() error
  51. }
  52. type legacyLayerWriterWrapper struct {
  53. ctx context.Context
  54. s *trace.Span
  55. *legacyLayerWriter
  56. path string
  57. parentLayerPaths []string
  58. }
  59. func (r *legacyLayerWriterWrapper) Close() (err error) {
  60. defer r.s.End()
  61. defer func() { oc.SetSpanStatus(r.s, err) }()
  62. defer os.RemoveAll(r.root.Name())
  63. defer r.legacyLayerWriter.CloseRoots()
  64. err = r.legacyLayerWriter.Close()
  65. if err != nil {
  66. return err
  67. }
  68. if err = ImportLayer(r.ctx, r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
  69. return err
  70. }
  71. for _, name := range r.Tombstones {
  72. if err = safefile.RemoveRelative(name, r.destRoot); err != nil && !os.IsNotExist(err) {
  73. return err
  74. }
  75. }
  76. // Add any hard links that were collected.
  77. for _, lnk := range r.PendingLinks {
  78. if err = safefile.RemoveRelative(lnk.Path, r.destRoot); err != nil && !os.IsNotExist(err) {
  79. return err
  80. }
  81. if err = safefile.LinkRelative(lnk.Target, lnk.TargetRoot, lnk.Path, r.destRoot); err != nil {
  82. return err
  83. }
  84. }
  85. // The reapplyDirectoryTimes must be called AFTER we are done with Tombstone
  86. // deletion and hard link creation. This is because Tombstone deletion and hard link
  87. // creation updates the directory last write timestamps so that will change the
  88. // timestamps added by the `Add` call. Some container applications depend on the
  89. // correctness of these timestamps and so we should change the timestamps back to
  90. // the original value (i.e the value provided in the Add call) after this
  91. // processing is done.
  92. err = reapplyDirectoryTimes(r.destRoot, r.changedDi)
  93. if err != nil {
  94. return err
  95. }
  96. // Prepare the utility VM for use if one is present in the layer.
  97. if r.HasUtilityVM {
  98. err := safefile.EnsureNotReparsePointRelative("UtilityVM", r.destRoot)
  99. if err != nil {
  100. return err
  101. }
  102. err = ProcessUtilityVMImage(r.ctx, filepath.Join(r.destRoot.Name(), "UtilityVM"))
  103. if err != nil {
  104. return err
  105. }
  106. }
  107. return nil
  108. }
  109. // NewLayerWriter returns a new layer writer for creating a layer on disk.
  110. // The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
  111. // to call this and any methods on the resulting LayerWriter.
  112. func NewLayerWriter(ctx context.Context, path string, parentLayerPaths []string) (_ LayerWriter, err error) {
  113. ctx, span := oc.StartSpan(ctx, "hcsshim::NewLayerWriter")
  114. defer func() {
  115. if err != nil {
  116. oc.SetSpanStatus(span, err)
  117. span.End()
  118. }
  119. }()
  120. span.AddAttributes(
  121. trace.StringAttribute("path", path),
  122. trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
  123. if len(parentLayerPaths) == 0 {
  124. // This is a base layer. It gets imported differently.
  125. f, err := safefile.OpenRoot(path)
  126. if err != nil {
  127. return nil, err
  128. }
  129. return &baseLayerWriter{
  130. ctx: ctx,
  131. s: span,
  132. root: f,
  133. }, nil
  134. }
  135. importPath, err := os.MkdirTemp("", "hcs")
  136. if err != nil {
  137. return nil, err
  138. }
  139. w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
  140. if err != nil {
  141. return nil, err
  142. }
  143. return &legacyLayerWriterWrapper{
  144. ctx: ctx,
  145. s: span,
  146. legacyLayerWriter: w,
  147. path: importPath,
  148. parentLayerPaths: parentLayerPaths,
  149. }, nil
  150. }