123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- 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
- }
|