...

Source file src/github.com/Microsoft/hcsshim/internal/wclayer/converttobaselayer.go

Documentation: github.com/Microsoft/hcsshim/internal/wclayer

     1  package wclayer
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"syscall"
     9  
    10  	"github.com/Microsoft/hcsshim/internal/hcserror"
    11  	"github.com/Microsoft/hcsshim/internal/longpath"
    12  	"github.com/Microsoft/hcsshim/internal/oc"
    13  	"github.com/Microsoft/hcsshim/internal/safefile"
    14  	"github.com/Microsoft/hcsshim/internal/winapi"
    15  	"github.com/pkg/errors"
    16  	"go.opencensus.io/trace"
    17  	"golang.org/x/sys/windows"
    18  )
    19  
    20  var hiveNames = []string{"DEFAULT", "SAM", "SECURITY", "SOFTWARE", "SYSTEM"}
    21  
    22  // Ensure the given file exists as an ordinary file, and create a minimal hive file if not.
    23  func ensureHive(path string, root *os.File) (err error) {
    24  	_, err = safefile.LstatRelative(path, root)
    25  	if err != nil && !os.IsNotExist(err) {
    26  		return fmt.Errorf("accessing %s: %w", path, err)
    27  	}
    28  
    29  	version := windows.RtlGetVersion()
    30  	if version == nil {
    31  		return fmt.Errorf("failed to get OS version")
    32  	}
    33  
    34  	var fullPath string
    35  	fullPath, err = longpath.LongAbs(filepath.Join(root.Name(), path))
    36  	if err != nil {
    37  		return fmt.Errorf("getting path: %w", err)
    38  	}
    39  
    40  	var key syscall.Handle
    41  	err = winapi.ORCreateHive(&key)
    42  	if err != nil {
    43  		return fmt.Errorf("creating hive: %w", err)
    44  	}
    45  
    46  	defer func() {
    47  		closeErr := winapi.ORCloseHive(key)
    48  		if closeErr != nil && err == nil {
    49  			err = fmt.Errorf("closing hive key: %w", closeErr)
    50  		}
    51  	}()
    52  
    53  	err = winapi.ORSaveHive(key, fullPath, version.MajorVersion, version.MinorVersion)
    54  	if err != nil {
    55  		return fmt.Errorf("saving hive: %w", err)
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  func ensureBaseLayer(root *os.File) (hasUtilityVM bool, err error) {
    62  	// The base layer registry hives will be copied from here
    63  	const hiveSourcePath = "Files\\Windows\\System32\\config"
    64  	if err = safefile.MkdirAllRelative(hiveSourcePath, root); err != nil {
    65  		return
    66  	}
    67  
    68  	for _, hiveName := range hiveNames {
    69  		hivePath := filepath.Join(hiveSourcePath, hiveName)
    70  		if err = ensureHive(hivePath, root); err != nil {
    71  			return
    72  		}
    73  	}
    74  
    75  	stat, err := safefile.LstatRelative(utilityVMFilesPath, root)
    76  
    77  	if os.IsNotExist(err) {
    78  		return false, nil
    79  	}
    80  
    81  	if err != nil {
    82  		return
    83  	}
    84  
    85  	if !stat.Mode().IsDir() {
    86  		fullPath := filepath.Join(root.Name(), utilityVMFilesPath)
    87  		return false, errors.Errorf("%s has unexpected file mode %s", fullPath, stat.Mode().String())
    88  	}
    89  
    90  	const bcdRelativePath = "EFI\\Microsoft\\Boot\\BCD"
    91  
    92  	// Just check that this exists as a regular file. If it exists but is not a valid registry hive,
    93  	// ProcessUtilityVMImage will complain:
    94  	// "The registry could not read in, or write out, or flush, one of the files that contain the system's image of the registry."
    95  	bcdPath := filepath.Join(utilityVMFilesPath, bcdRelativePath)
    96  
    97  	stat, err = safefile.LstatRelative(bcdPath, root)
    98  	if err != nil {
    99  		return false, errors.Wrapf(err, "UtilityVM must contain '%s'", bcdRelativePath)
   100  	}
   101  
   102  	if !stat.Mode().IsRegular() {
   103  		fullPath := filepath.Join(root.Name(), bcdPath)
   104  		return false, errors.Errorf("%s has unexpected file mode %s", fullPath, stat.Mode().String())
   105  	}
   106  
   107  	return true, nil
   108  }
   109  
   110  func convertToBaseLayer(ctx context.Context, root *os.File) error {
   111  	hasUtilityVM, err := ensureBaseLayer(root)
   112  
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	if err := ProcessBaseLayer(ctx, root.Name()); err != nil {
   118  		return err
   119  	}
   120  
   121  	if !hasUtilityVM {
   122  		return nil
   123  	}
   124  
   125  	err = safefile.EnsureNotReparsePointRelative(utilityVMPath, root)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	utilityVMPath := filepath.Join(root.Name(), utilityVMPath)
   131  	return ProcessUtilityVMImage(ctx, utilityVMPath)
   132  }
   133  
   134  // ConvertToBaseLayer processes a candidate base layer, i.e. a directory
   135  // containing the desired file content under Files/, and optionally the
   136  // desired file content for a UtilityVM under UtilityVM/Files/
   137  func ConvertToBaseLayer(ctx context.Context, path string) (err error) {
   138  	title := "hcsshim::ConvertToBaseLayer"
   139  	ctx, span := trace.StartSpan(ctx, title)
   140  	defer span.End()
   141  	defer func() { oc.SetSpanStatus(span, err) }()
   142  	span.AddAttributes(trace.StringAttribute("path", path))
   143  
   144  	root, err := safefile.OpenRoot(path)
   145  	if err != nil {
   146  		return hcserror.New(err, title+" - failed", "")
   147  	}
   148  	defer func() {
   149  		if err2 := root.Close(); err == nil && err2 != nil {
   150  			err = hcserror.New(err2, title+" - failed", "")
   151  		}
   152  	}()
   153  
   154  	if err = convertToBaseLayer(ctx, root); err != nil {
   155  		return hcserror.New(err, title+" - failed", "")
   156  	}
   157  	return nil
   158  }
   159  

View as plain text