summaryrefslogtreecommitdiff
path: root/vendor/github.com/Microsoft/hcsshim/importlayer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Microsoft/hcsshim/importlayer.go')
-rw-r--r--vendor/github.com/Microsoft/hcsshim/importlayer.go212
1 files changed, 212 insertions, 0 deletions
diff --git a/vendor/github.com/Microsoft/hcsshim/importlayer.go b/vendor/github.com/Microsoft/hcsshim/importlayer.go
new file mode 100644
index 000000000..3aed14376
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/importlayer.go
@@ -0,0 +1,212 @@
+package hcsshim
+
+import (
+ "errors"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/Microsoft/go-winio"
+ "github.com/sirupsen/logrus"
+)
+
+// ImportLayer will take the contents of the folder at importFolderPath and import
+// that into a layer with the id layerId. Note that in order to correctly populate
+// the layer and interperet the transport format, all parent layers must already
+// be present on the system at the paths provided in parentLayerPaths.
+func ImportLayer(info DriverInfo, layerID string, importFolderPath string, parentLayerPaths []string) error {
+ title := "hcsshim::ImportLayer "
+ logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerID, importFolderPath)
+
+ // Generate layer descriptors
+ layers, err := layerPathsToDescriptors(parentLayerPaths)
+ if err != nil {
+ return err
+ }
+
+ // Convert info to API calling convention
+ infop, err := convertDriverInfo(info)
+ if err != nil {
+ logrus.Error(err)
+ return err
+ }
+
+ err = importLayer(&infop, layerID, importFolderPath, layers)
+ if err != nil {
+ err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerID, info.Flavour, importFolderPath)
+ logrus.Error(err)
+ return err
+ }
+
+ logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerID, importFolderPath)
+ return nil
+}
+
+// LayerWriter is an interface that supports writing a new container image layer.
+type LayerWriter interface {
+ // Add adds a file to the layer with given metadata.
+ Add(name string, fileInfo *winio.FileBasicInfo) error
+ // AddLink adds a hard link to the layer. The target must already have been added.
+ AddLink(name string, target string) error
+ // Remove removes a file that was present in a parent layer from the layer.
+ Remove(name string) error
+ // Write writes data to the current file. The data must be in the format of a Win32
+ // backup stream.
+ Write(b []byte) (int, error)
+ // Close finishes the layer writing process and releases any resources.
+ Close() error
+}
+
+// FilterLayerWriter provides an interface to write the contents of a layer to the file system.
+type FilterLayerWriter struct {
+ context uintptr
+}
+
+// Add adds a file or directory to the layer. The file's parent directory must have already been added.
+//
+// name contains the file's relative path. fileInfo contains file times and file attributes; the rest
+// of the file metadata and the file data must be written as a Win32 backup stream to the Write() method.
+// winio.BackupStreamWriter can be used to facilitate this.
+func (w *FilterLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
+ if name[0] != '\\' {
+ name = `\` + name
+ }
+ err := importLayerNext(w.context, name, fileInfo)
+ if err != nil {
+ return makeError(err, "ImportLayerNext", "")
+ }
+ return nil
+}
+
+// AddLink adds a hard link to the layer. The target of the link must have already been added.
+func (w *FilterLayerWriter) AddLink(name string, target string) error {
+ return errors.New("hard links not yet supported")
+}
+
+// Remove removes a file from the layer. The file must have been present in the parent layer.
+//
+// name contains the file's relative path.
+func (w *FilterLayerWriter) Remove(name string) error {
+ if name[0] != '\\' {
+ name = `\` + name
+ }
+ err := importLayerNext(w.context, name, nil)
+ if err != nil {
+ return makeError(err, "ImportLayerNext", "")
+ }
+ return nil
+}
+
+// Write writes more backup stream data to the current file.
+func (w *FilterLayerWriter) Write(b []byte) (int, error) {
+ err := importLayerWrite(w.context, b)
+ if err != nil {
+ err = makeError(err, "ImportLayerWrite", "")
+ return 0, err
+ }
+ return len(b), err
+}
+
+// Close completes the layer write operation. The error must be checked to ensure that the
+// operation was successful.
+func (w *FilterLayerWriter) Close() (err error) {
+ if w.context != 0 {
+ err = importLayerEnd(w.context)
+ if err != nil {
+ err = makeError(err, "ImportLayerEnd", "")
+ }
+ w.context = 0
+ }
+ return
+}
+
+type legacyLayerWriterWrapper struct {
+ *legacyLayerWriter
+ info DriverInfo
+ layerID string
+ path string
+ parentLayerPaths []string
+}
+
+func (r *legacyLayerWriterWrapper) Close() error {
+ defer os.RemoveAll(r.root)
+ err := r.legacyLayerWriter.Close()
+ if err != nil {
+ return err
+ }
+
+ // Use the original path here because ImportLayer does not support long paths for the source in TP5.
+ // But do use a long path for the destination to work around another bug with directories
+ // with MAX_PATH - 12 < length < MAX_PATH.
+ info := r.info
+ fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID))
+ if err != nil {
+ return err
+ }
+
+ info.HomeDir = ""
+ if err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths); err != nil {
+ return err
+ }
+ // Add any hard links that were collected.
+ for _, lnk := range r.PendingLinks {
+ if err = os.Remove(lnk.Path); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ if err = os.Link(lnk.Target, lnk.Path); err != nil {
+ return err
+ }
+ }
+ // Prepare the utility VM for use if one is present in the layer.
+ if r.HasUtilityVM {
+ err = ProcessUtilityVMImage(filepath.Join(fullPath, "UtilityVM"))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// NewLayerWriter returns a new layer writer for creating a layer on disk.
+// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
+// to call this and any methods on the resulting LayerWriter.
+func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) {
+ if len(parentLayerPaths) == 0 {
+ // This is a base layer. It gets imported differently.
+ return &baseLayerWriter{
+ root: filepath.Join(info.HomeDir, layerID),
+ }, nil
+ }
+
+ if procImportLayerBegin.Find() != nil {
+ // The new layer reader is not available on this Windows build. Fall back to the
+ // legacy export code path.
+ path, err := ioutil.TempDir("", "hcs")
+ if err != nil {
+ return nil, err
+ }
+ return &legacyLayerWriterWrapper{
+ legacyLayerWriter: newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)),
+ info: info,
+ layerID: layerID,
+ path: path,
+ parentLayerPaths: parentLayerPaths,
+ }, nil
+ }
+ layers, err := layerPathsToDescriptors(parentLayerPaths)
+ if err != nil {
+ return nil, err
+ }
+
+ infop, err := convertDriverInfo(info)
+ if err != nil {
+ return nil, err
+ }
+
+ w := &FilterLayerWriter{}
+ err = importLayerBegin(&infop, layerID, layers, &w.context)
+ if err != nil {
+ return nil, makeError(err, "ImportLayerStart", "")
+ }
+ return w, nil
+}