Merge pull request #4399 from TBBle/wcow_compare_layers_to_tar
Implement windowsDiff.Compare to allow outputting OCI images
This commit is contained in:
		
							
								
								
									
										86
									
								
								vendor/github.com/Microsoft/hcsshim/pkg/ociwclayer/export.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/Microsoft/hcsshim/pkg/ociwclayer/export.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
// Package ociwclayer provides functions for importing and exporting Windows
 | 
			
		||||
// container layers from and to their OCI tar representation.
 | 
			
		||||
package ociwclayer
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"archive/tar"
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/Microsoft/go-winio/backuptar"
 | 
			
		||||
	"github.com/Microsoft/hcsshim"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var driverInfo = hcsshim.DriverInfo{}
 | 
			
		||||
 | 
			
		||||
// ExportLayerToTar writes an OCI layer tar stream from the provided on-disk layer.
 | 
			
		||||
// The caller must specify the parent layers, if any, ordered from lowest to
 | 
			
		||||
// highest layer.
 | 
			
		||||
//
 | 
			
		||||
// The layer will be mounted for this process, so the caller should ensure that
 | 
			
		||||
// it is not currently mounted.
 | 
			
		||||
func ExportLayerToTar(ctx context.Context, w io.Writer, path string, parentLayerPaths []string) error {
 | 
			
		||||
	err := hcsshim.ActivateLayer(driverInfo, path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer hcsshim.DeactivateLayer(driverInfo, path)
 | 
			
		||||
 | 
			
		||||
	// Prepare and unprepare the layer to ensure that it has been initialized.
 | 
			
		||||
	err = hcsshim.PrepareLayer(driverInfo, path, parentLayerPaths)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = hcsshim.UnprepareLayer(driverInfo, path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r, err := hcsshim.NewLayerReader(driverInfo, path, parentLayerPaths)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = writeTarFromLayer(ctx, r, w)
 | 
			
		||||
	cerr := r.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return cerr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeTarFromLayer(ctx context.Context, r hcsshim.LayerReader, w io.Writer) error {
 | 
			
		||||
	t := tar.NewWriter(w)
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return ctx.Err()
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		name, size, fileInfo, err := r.Next()
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if fileInfo == nil {
 | 
			
		||||
			// Write a whiteout file.
 | 
			
		||||
			hdr := &tar.Header{
 | 
			
		||||
				Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), whiteoutPrefix+filepath.Base(name))),
 | 
			
		||||
			}
 | 
			
		||||
			err := t.WriteHeader(hdr)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return t.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								vendor/github.com/Microsoft/hcsshim/pkg/ociwclayer/import.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								vendor/github.com/Microsoft/hcsshim/pkg/ociwclayer/import.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
package ociwclayer
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"archive/tar"
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	winio "github.com/Microsoft/go-winio"
 | 
			
		||||
	"github.com/Microsoft/go-winio/backuptar"
 | 
			
		||||
	"github.com/Microsoft/hcsshim"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const whiteoutPrefix = ".wh."
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// mutatedFiles is a list of files that are mutated by the import process
 | 
			
		||||
	// and must be backed up and restored.
 | 
			
		||||
	mutatedFiles = map[string]string{
 | 
			
		||||
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD":      "bcd.bak",
 | 
			
		||||
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG":  "bcd.log.bak",
 | 
			
		||||
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
 | 
			
		||||
		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ImportLayerFromTar  reads a layer from an OCI layer tar stream and extracts it to the
 | 
			
		||||
// specified path. The caller must specify the parent layers, if any, ordered
 | 
			
		||||
// from lowest to highest layer.
 | 
			
		||||
//
 | 
			
		||||
// The caller must ensure that the thread or process has acquired backup and
 | 
			
		||||
// restore privileges.
 | 
			
		||||
//
 | 
			
		||||
// This function returns the total size of the layer's files, in bytes.
 | 
			
		||||
func ImportLayerFromTar(ctx context.Context, r io.Reader, path string, parentLayerPaths []string) (int64, error) {
 | 
			
		||||
	err := os.MkdirAll(path, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	w, err := hcsshim.NewLayerWriter(hcsshim.DriverInfo{}, path, parentLayerPaths)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	n, err := writeLayerFromTar(ctx, r, w, path)
 | 
			
		||||
	cerr := w.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if cerr != nil {
 | 
			
		||||
		return 0, cerr
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeLayerFromTar(ctx context.Context, r io.Reader, w hcsshim.LayerWriter, root string) (int64, error) {
 | 
			
		||||
	t := tar.NewReader(r)
 | 
			
		||||
	hdr, err := t.Next()
 | 
			
		||||
	totalSize := int64(0)
 | 
			
		||||
	buf := bufio.NewWriter(nil)
 | 
			
		||||
	for err == nil {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return 0, ctx.Err()
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		base := path.Base(hdr.Name)
 | 
			
		||||
		if strings.HasPrefix(base, whiteoutPrefix) {
 | 
			
		||||
			name := path.Join(path.Dir(hdr.Name), base[len(whiteoutPrefix):])
 | 
			
		||||
			err = w.Remove(filepath.FromSlash(name))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			hdr, err = t.Next()
 | 
			
		||||
		} else if hdr.Typeflag == tar.TypeLink {
 | 
			
		||||
			err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			hdr, err = t.Next()
 | 
			
		||||
		} else {
 | 
			
		||||
			var (
 | 
			
		||||
				name     string
 | 
			
		||||
				size     int64
 | 
			
		||||
				fileInfo *winio.FileBasicInfo
 | 
			
		||||
			)
 | 
			
		||||
			name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			err = w.Add(filepath.FromSlash(name), fileInfo)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			hdr, err = writeBackupStreamFromTarAndSaveMutatedFiles(buf, w, t, hdr, root)
 | 
			
		||||
			totalSize += size
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err != io.EOF {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return totalSize, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// writeBackupStreamFromTarAndSaveMutatedFiles reads data from a tar stream and
 | 
			
		||||
// writes it to a backup stream, and also saves any files that will be mutated
 | 
			
		||||
// by the import layer process to a backup location.
 | 
			
		||||
func writeBackupStreamFromTarAndSaveMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
 | 
			
		||||
	var bcdBackup *os.File
 | 
			
		||||
	var bcdBackupWriter *winio.BackupFileWriter
 | 
			
		||||
	if backupPath, ok := mutatedFiles[hdr.Name]; ok {
 | 
			
		||||
		bcdBackup, err = os.Create(filepath.Join(root, backupPath))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defer func() {
 | 
			
		||||
			cerr := bcdBackup.Close()
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				err = cerr
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false)
 | 
			
		||||
		defer func() {
 | 
			
		||||
			cerr := bcdBackupWriter.Close()
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				err = cerr
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		buf.Reset(io.MultiWriter(w, bcdBackupWriter))
 | 
			
		||||
	} else {
 | 
			
		||||
		buf.Reset(w)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		ferr := buf.Flush()
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			err = ferr
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user