Replace inline applyWindowsLayer using hcsshim
Signed-off-by: Paul "TBBle" Hampson <Paul.Hampson@Pobox.com>
This commit is contained in:
parent
149fa366f9
commit
a64a76846c
@ -18,6 +18,19 @@
|
|||||||
|
|
||||||
package archive
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/pkg/ociwclayer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows layer
|
||||||
|
// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
|
||||||
|
func applyWindowsLayer(ctx context.Context, root string, r io.Reader, options ApplyOptions) (size int64, err error) {
|
||||||
|
return ociwclayer.ImportLayerFromTar(ctx, r, root, options.Parents)
|
||||||
|
}
|
||||||
|
|
||||||
// AsWindowsContainerLayer indicates that the tar stream to apply is that of
|
// AsWindowsContainerLayer indicates that the tar stream to apply is that of
|
||||||
// a Windows Container Layer. The caller must be holding SeBackupPrivilege and
|
// a Windows Container Layer. The caller must be holding SeBackupPrivilege and
|
||||||
// SeRestorePrivilege.
|
// SeRestorePrivilege.
|
||||||
|
@ -20,33 +20,14 @@ package archive
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bufio"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
|
||||||
"github.com/Microsoft/go-winio/backuptar"
|
|
||||||
"github.com/Microsoft/hcsshim"
|
|
||||||
"github.com/containerd/containerd/sys"
|
"github.com/containerd/containerd/sys"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// tarName returns platform-specific filepath
|
// tarName returns platform-specific filepath
|
||||||
// to canonical posix-style path for tar archival. p is relative
|
// to canonical posix-style path for tar archival. p is relative
|
||||||
// path.
|
// path.
|
||||||
@ -141,121 +122,3 @@ func copyDirInfo(fi os.FileInfo, path string) error {
|
|||||||
func copyUpXAttrs(dst, src string) error {
|
func copyUpXAttrs(dst, src string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows
|
|
||||||
// layer using the hcsshim layer writer and backup streams.
|
|
||||||
// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets
|
|
||||||
func applyWindowsLayer(ctx context.Context, root string, r io.Reader, options ApplyOptions) (size int64, err error) {
|
|
||||||
home, id := filepath.Split(root)
|
|
||||||
info := hcsshim.DriverInfo{
|
|
||||||
HomeDir: home,
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err := hcsshim.NewLayerWriter(info, id, options.Parents)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err2 := w.Close(); err2 != nil {
|
|
||||||
// This error should not be discarded as a failure here
|
|
||||||
// could result in an invalid layer on disk
|
|
||||||
if err == nil {
|
|
||||||
err = err2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
tr := tar.NewReader(r)
|
|
||||||
buf := bufio.NewWriter(nil)
|
|
||||||
hdr, nextErr := tr.Next()
|
|
||||||
// Iterate through the files in the archive.
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return 0, ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if nextErr == io.EOF {
|
|
||||||
// end of tar archive
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nextErr != nil {
|
|
||||||
return 0, nextErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: path is used instead of filepath to prevent OS specific handling
|
|
||||||
// of the tar path
|
|
||||||
base := path.Base(hdr.Name)
|
|
||||||
if strings.HasPrefix(base, whiteoutPrefix) {
|
|
||||||
dir := path.Dir(hdr.Name)
|
|
||||||
originalBase := base[len(whiteoutPrefix):]
|
|
||||||
originalPath := path.Join(dir, originalBase)
|
|
||||||
if err := w.Remove(filepath.FromSlash(originalPath)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
hdr, nextErr = tr.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, nextErr = tr.Next()
|
|
||||||
} else {
|
|
||||||
name, fileSize, fileInfo, err := backuptar.FileInfoFromHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if err := w.Add(filepath.FromSlash(name), fileInfo); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
size += fileSize
|
|
||||||
hdr, nextErr = tarToBackupStreamWithMutatedFiles(buf, w, tr, hdr, root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// tarToBackupStreamWithMutatedFiles 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 tarToBackupStreamWithMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
|
|
||||||
var (
|
|
||||||
bcdBackup *os.File
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
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)
|
||||||
|
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -40,6 +40,7 @@ github.com/Microsoft/hcsshim/internal/wclayer
|
|||||||
github.com/Microsoft/hcsshim/internal/winapi
|
github.com/Microsoft/hcsshim/internal/winapi
|
||||||
github.com/Microsoft/hcsshim/osversion
|
github.com/Microsoft/hcsshim/osversion
|
||||||
github.com/Microsoft/hcsshim/pkg/go-runhcs
|
github.com/Microsoft/hcsshim/pkg/go-runhcs
|
||||||
|
github.com/Microsoft/hcsshim/pkg/ociwclayer
|
||||||
# github.com/beorn7/perks v1.0.1
|
# github.com/beorn7/perks v1.0.1
|
||||||
github.com/beorn7/perks/quantile
|
github.com/beorn7/perks/quantile
|
||||||
# github.com/cespare/xxhash/v2 v2.1.1
|
# github.com/cespare/xxhash/v2 v2.1.1
|
||||||
|
Loading…
Reference in New Issue
Block a user