...

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

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

     1  //go:build windows
     2  
     3  package ociwclayer
     4  
     5  import (
     6  	"archive/tar"
     7  	"context"
     8  	"io"
     9  	"path/filepath"
    10  
    11  	"github.com/Microsoft/go-winio/backuptar"
    12  	"github.com/Microsoft/hcsshim/internal/wclayer"
    13  )
    14  
    15  // ExportLayerToTar writes an OCI layer tar stream from the provided on-disk layer.
    16  // The caller must specify the parent layers, if any, ordered from lowest to
    17  // highest layer.
    18  //
    19  // The layer will be mounted for this process, so the caller should ensure that
    20  // it is not currently mounted.
    21  func ExportLayerToTar(ctx context.Context, w io.Writer, path string, parentLayerPaths []string) error {
    22  	err := wclayer.ActivateLayer(ctx, path)
    23  	if err != nil {
    24  		return err
    25  	}
    26  	defer func() {
    27  		_ = wclayer.DeactivateLayer(ctx, path)
    28  	}()
    29  
    30  	// Prepare and unprepare the layer to ensure that it has been initialized.
    31  	err = wclayer.PrepareLayer(ctx, path, parentLayerPaths)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	err = wclayer.UnprepareLayer(ctx, path)
    36  	if err != nil {
    37  		return err
    38  	}
    39  
    40  	r, err := wclayer.NewLayerReader(ctx, path, parentLayerPaths)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	err = writeTarFromLayer(ctx, r, w)
    46  	cerr := r.Close()
    47  	if err != nil {
    48  		return err
    49  	}
    50  	return cerr
    51  }
    52  
    53  func writeTarFromLayer(ctx context.Context, r wclayer.LayerReader, w io.Writer) error {
    54  	linkRecords := make(map[[16]byte]string)
    55  
    56  	t := tar.NewWriter(w)
    57  	for {
    58  		select {
    59  		case <-ctx.Done():
    60  			return ctx.Err()
    61  		default:
    62  		}
    63  
    64  		name, size, fileInfo, err := r.Next()
    65  		if err == io.EOF {
    66  			break
    67  		}
    68  		if err != nil {
    69  			return err
    70  		}
    71  		if fileInfo == nil {
    72  			// Write a whiteout file.
    73  			hdr := &tar.Header{
    74  				Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), whiteoutPrefix+filepath.Base(name))),
    75  			}
    76  			err := t.WriteHeader(hdr)
    77  			if err != nil {
    78  				return err
    79  			}
    80  		} else {
    81  			numberOfLinks, fileIDInfo, err := r.LinkInfo()
    82  			if err != nil {
    83  				return err
    84  			}
    85  			if numberOfLinks > 1 {
    86  				if linkName, ok := linkRecords[fileIDInfo.FileID]; ok {
    87  					// We've seen this file before, by another name, so put a hardlink in the tar stream.
    88  					hdr := backuptar.BasicInfoHeader(name, 0, fileInfo)
    89  					hdr.Mode = 0644
    90  					hdr.Typeflag = tar.TypeLink
    91  					hdr.Linkname = linkName
    92  					if err := t.WriteHeader(hdr); err != nil {
    93  						return err
    94  					}
    95  					continue
    96  				}
    97  
    98  				// All subsequent names for this file will be hard-linked to this name
    99  				linkRecords[fileIDInfo.FileID] = filepath.ToSlash(name)
   100  			}
   101  
   102  			err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
   103  			if err != nil {
   104  				return err
   105  			}
   106  		}
   107  	}
   108  	return t.Close()
   109  }
   110  

View as plain text