| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- //go:build windows
- 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/internal/wclayer"
- )
- 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 := wclayer.NewLayerWriter(ctx, 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 wclayer.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)
- }
|