...

Source file src/github.com/Microsoft/hcsshim/pkg/ociwclayer/import.go

Documentation: github.com/Microsoft/hcsshim/pkg/ociwclayer

     1  //go:build windows
     2  
     3  package ociwclayer
     4  
     5  import (
     6  	"archive/tar"
     7  	"bufio"
     8  	"context"
     9  	"io"
    10  	"os"
    11  	"path"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	winio "github.com/Microsoft/go-winio"
    16  	"github.com/Microsoft/go-winio/backuptar"
    17  	"github.com/Microsoft/hcsshim/internal/wclayer"
    18  )
    19  
    20  const whiteoutPrefix = ".wh."
    21  
    22  var (
    23  	// mutatedFiles is a list of files that are mutated by the import process
    24  	// and must be backed up and restored.
    25  	mutatedFiles = map[string]string{
    26  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD":      "bcd.bak",
    27  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG":  "bcd.log.bak",
    28  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
    29  		"UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
    30  	}
    31  )
    32  
    33  // ImportLayerFromTar  reads a layer from an OCI layer tar stream and extracts it to the
    34  // specified path. The caller must specify the parent layers, if any, ordered
    35  // from lowest to highest layer.
    36  //
    37  // The caller must ensure that the thread or process has acquired backup and
    38  // restore privileges.
    39  //
    40  // This function returns the total size of the layer's files, in bytes.
    41  func ImportLayerFromTar(ctx context.Context, r io.Reader, path string, parentLayerPaths []string) (int64, error) {
    42  	err := os.MkdirAll(path, 0)
    43  	if err != nil {
    44  		return 0, err
    45  	}
    46  	w, err := wclayer.NewLayerWriter(ctx, path, parentLayerPaths)
    47  	if err != nil {
    48  		return 0, err
    49  	}
    50  	n, err := writeLayerFromTar(ctx, r, w, path)
    51  	cerr := w.Close()
    52  	if err != nil {
    53  		return 0, err
    54  	}
    55  	if cerr != nil {
    56  		return 0, cerr
    57  	}
    58  	return n, nil
    59  }
    60  
    61  func writeLayerFromTar(ctx context.Context, r io.Reader, w wclayer.LayerWriter, root string) (int64, error) {
    62  	t := tar.NewReader(r)
    63  	hdr, err := t.Next()
    64  	totalSize := int64(0)
    65  	buf := bufio.NewWriter(nil)
    66  	for err == nil {
    67  		select {
    68  		case <-ctx.Done():
    69  			return 0, ctx.Err()
    70  		default:
    71  		}
    72  
    73  		base := path.Base(hdr.Name)
    74  		if strings.HasPrefix(base, whiteoutPrefix) {
    75  			name := path.Join(path.Dir(hdr.Name), base[len(whiteoutPrefix):])
    76  			err = w.Remove(filepath.FromSlash(name))
    77  			if err != nil {
    78  				return 0, err
    79  			}
    80  			hdr, err = t.Next()
    81  		} else if hdr.Typeflag == tar.TypeLink {
    82  			err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
    83  			if err != nil {
    84  				return 0, err
    85  			}
    86  			hdr, err = t.Next()
    87  		} else {
    88  			var (
    89  				name     string
    90  				size     int64
    91  				fileInfo *winio.FileBasicInfo
    92  			)
    93  			name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
    94  			if err != nil {
    95  				return 0, err
    96  			}
    97  			err = w.Add(filepath.FromSlash(name), fileInfo)
    98  			if err != nil {
    99  				return 0, err
   100  			}
   101  			hdr, err = writeBackupStreamFromTarAndSaveMutatedFiles(buf, w, t, hdr, root)
   102  			totalSize += size
   103  		}
   104  	}
   105  	if err != io.EOF {
   106  		return 0, err
   107  	}
   108  	return totalSize, nil
   109  }
   110  
   111  // writeBackupStreamFromTarAndSaveMutatedFiles reads data from a tar stream and
   112  // writes it to a backup stream, and also saves any files that will be mutated
   113  // by the import layer process to a backup location.
   114  func writeBackupStreamFromTarAndSaveMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
   115  	var bcdBackup *os.File
   116  	var bcdBackupWriter *winio.BackupFileWriter
   117  	if backupPath, ok := mutatedFiles[hdr.Name]; ok {
   118  		bcdBackup, err = os.Create(filepath.Join(root, backupPath))
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		defer func() {
   123  			cerr := bcdBackup.Close()
   124  			if err == nil {
   125  				err = cerr
   126  			}
   127  		}()
   128  
   129  		bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false)
   130  		defer func() {
   131  			cerr := bcdBackupWriter.Close()
   132  			if err == nil {
   133  				err = cerr
   134  			}
   135  		}()
   136  
   137  		buf.Reset(io.MultiWriter(w, bcdBackupWriter))
   138  	} else {
   139  		buf.Reset(w)
   140  	}
   141  
   142  	defer func() {
   143  		ferr := buf.Flush()
   144  		if err == nil {
   145  			err = ferr
   146  		}
   147  	}()
   148  
   149  	return backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
   150  }
   151  

View as plain text