summaryrefslogtreecommitdiff
path: root/vendor/github.com/Microsoft/hcsshim/exportlayer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Microsoft/hcsshim/exportlayer.go')
-rw-r--r--vendor/github.com/Microsoft/hcsshim/exportlayer.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/vendor/github.com/Microsoft/hcsshim/exportlayer.go b/vendor/github.com/Microsoft/hcsshim/exportlayer.go
new file mode 100644
index 000000000..d7025f20b
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/exportlayer.go
@@ -0,0 +1,156 @@
+package hcsshim
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "syscall"
+
+ "github.com/Microsoft/go-winio"
+ "github.com/sirupsen/logrus"
+)
+
+// ExportLayer will create a folder at exportFolderPath and fill that folder with
+// the transport format version of the layer identified by layerId. This transport
+// format includes any metadata required for later importing the layer (using
+// ImportLayer), and requires the full list of parent layer paths in order to
+// perform the export.
+func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, parentLayerPaths []string) error {
+ title := "hcsshim::ExportLayer "
+ logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, exportFolderPath)
+
+ // 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 = exportLayer(&infop, layerId, exportFolderPath, layers)
+ if err != nil {
+ err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, exportFolderPath)
+ logrus.Error(err)
+ return err
+ }
+
+ logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, exportFolderPath)
+ return nil
+}
+
+type LayerReader interface {
+ Next() (string, int64, *winio.FileBasicInfo, error)
+ Read(b []byte) (int, error)
+ Close() error
+}
+
+// FilterLayerReader provides an interface for extracting the contents of an on-disk layer.
+type FilterLayerReader struct {
+ context uintptr
+}
+
+// Next reads the next available file from a layer, ensuring that parent directories are always read
+// before child files and directories.
+//
+// Next returns the file's relative path, size, and basic file metadata. Read() should be used to
+// extract a Win32 backup stream with the remainder of the metadata and the data.
+func (r *FilterLayerReader) Next() (string, int64, *winio.FileBasicInfo, error) {
+ var fileNamep *uint16
+ fileInfo := &winio.FileBasicInfo{}
+ var deleted uint32
+ var fileSize int64
+ err := exportLayerNext(r.context, &fileNamep, fileInfo, &fileSize, &deleted)
+ if err != nil {
+ if err == syscall.ERROR_NO_MORE_FILES {
+ err = io.EOF
+ } else {
+ err = makeError(err, "ExportLayerNext", "")
+ }
+ return "", 0, nil, err
+ }
+ fileName := convertAndFreeCoTaskMemString(fileNamep)
+ if deleted != 0 {
+ fileInfo = nil
+ }
+ if fileName[0] == '\\' {
+ fileName = fileName[1:]
+ }
+ return fileName, fileSize, fileInfo, nil
+}
+
+// Read reads from the current file's Win32 backup stream.
+func (r *FilterLayerReader) Read(b []byte) (int, error) {
+ var bytesRead uint32
+ err := exportLayerRead(r.context, b, &bytesRead)
+ if err != nil {
+ return 0, makeError(err, "ExportLayerRead", "")
+ }
+ if bytesRead == 0 {
+ return 0, io.EOF
+ }
+ return int(bytesRead), nil
+}
+
+// Close frees resources associated with the layer reader. It will return an
+// error if there was an error while reading the layer or of the layer was not
+// completely read.
+func (r *FilterLayerReader) Close() (err error) {
+ if r.context != 0 {
+ err = exportLayerEnd(r.context)
+ if err != nil {
+ err = makeError(err, "ExportLayerEnd", "")
+ }
+ r.context = 0
+ }
+ return
+}
+
+// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
+// The caller must have taken the SeBackupPrivilege privilege
+// to call this and any methods on the resulting LayerReader.
+func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) (LayerReader, error) {
+ if procExportLayerBegin.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
+ }
+ err = ExportLayer(info, layerID, path, parentLayerPaths)
+ if err != nil {
+ os.RemoveAll(path)
+ return nil, err
+ }
+ return &legacyLayerReaderWrapper{newLegacyLayerReader(path)}, nil
+ }
+
+ layers, err := layerPathsToDescriptors(parentLayerPaths)
+ if err != nil {
+ return nil, err
+ }
+ infop, err := convertDriverInfo(info)
+ if err != nil {
+ return nil, err
+ }
+ r := &FilterLayerReader{}
+ err = exportLayerBegin(&infop, layerID, layers, &r.context)
+ if err != nil {
+ return nil, makeError(err, "ExportLayerBegin", "")
+ }
+ return r, err
+}
+
+type legacyLayerReaderWrapper struct {
+ *legacyLayerReader
+}
+
+func (r *legacyLayerReaderWrapper) Close() error {
+ err := r.legacyLayerReader.Close()
+ os.RemoveAll(r.root)
+ return err
+}