...

Source file src/github.com/Microsoft/hcsshim/internal/wclayer/importlayer.go

Documentation: github.com/Microsoft/hcsshim/internal/wclayer

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

View as plain text