123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- package wclayer
- import (
- "context"
- "fmt"
- "os"
- "path/filepath"
- "syscall"
- "github.com/Microsoft/hcsshim/internal/hcserror"
- "github.com/Microsoft/hcsshim/internal/longpath"
- "github.com/Microsoft/hcsshim/internal/oc"
- "github.com/Microsoft/hcsshim/internal/safefile"
- "github.com/Microsoft/hcsshim/internal/winapi"
- "github.com/pkg/errors"
- "go.opencensus.io/trace"
- "golang.org/x/sys/windows"
- )
- var hiveNames = []string{"DEFAULT", "SAM", "SECURITY", "SOFTWARE", "SYSTEM"}
- // Ensure the given file exists as an ordinary file, and create a minimal hive file if not.
- func ensureHive(path string, root *os.File) (err error) {
- _, err = safefile.LstatRelative(path, root)
- if err != nil && !os.IsNotExist(err) {
- return fmt.Errorf("accessing %s: %w", path, err)
- }
- version := windows.RtlGetVersion()
- if version == nil {
- return fmt.Errorf("failed to get OS version")
- }
- var fullPath string
- fullPath, err = longpath.LongAbs(filepath.Join(root.Name(), path))
- if err != nil {
- return fmt.Errorf("getting path: %w", err)
- }
- var key syscall.Handle
- err = winapi.ORCreateHive(&key)
- if err != nil {
- return fmt.Errorf("creating hive: %w", err)
- }
- defer func() {
- closeErr := winapi.ORCloseHive(key)
- if closeErr != nil && err == nil {
- err = fmt.Errorf("closing hive key: %w", closeErr)
- }
- }()
- err = winapi.ORSaveHive(key, fullPath, version.MajorVersion, version.MinorVersion)
- if err != nil {
- return fmt.Errorf("saving hive: %w", err)
- }
- return nil
- }
- func ensureBaseLayer(root *os.File) (hasUtilityVM bool, err error) {
- // The base layer registry hives will be copied from here
- const hiveSourcePath = "Files\\Windows\\System32\\config"
- if err = safefile.MkdirAllRelative(hiveSourcePath, root); err != nil {
- return
- }
- for _, hiveName := range hiveNames {
- hivePath := filepath.Join(hiveSourcePath, hiveName)
- if err = ensureHive(hivePath, root); err != nil {
- return
- }
- }
- stat, err := safefile.LstatRelative(utilityVMFilesPath, root)
- if os.IsNotExist(err) {
- return false, nil
- }
- if err != nil {
- return
- }
- if !stat.Mode().IsDir() {
- fullPath := filepath.Join(root.Name(), utilityVMFilesPath)
- return false, errors.Errorf("%s has unexpected file mode %s", fullPath, stat.Mode().String())
- }
- const bcdRelativePath = "EFI\\Microsoft\\Boot\\BCD"
- // Just check that this exists as a regular file. If it exists but is not a valid registry hive,
- // ProcessUtilityVMImage will complain:
- // "The registry could not read in, or write out, or flush, one of the files that contain the system's image of the registry."
- bcdPath := filepath.Join(utilityVMFilesPath, bcdRelativePath)
- stat, err = safefile.LstatRelative(bcdPath, root)
- if err != nil {
- return false, errors.Wrapf(err, "UtilityVM must contain '%s'", bcdRelativePath)
- }
- if !stat.Mode().IsRegular() {
- fullPath := filepath.Join(root.Name(), bcdPath)
- return false, errors.Errorf("%s has unexpected file mode %s", fullPath, stat.Mode().String())
- }
- return true, nil
- }
- func convertToBaseLayer(ctx context.Context, root *os.File) error {
- hasUtilityVM, err := ensureBaseLayer(root)
- if err != nil {
- return err
- }
- if err := ProcessBaseLayer(ctx, root.Name()); err != nil {
- return err
- }
- if !hasUtilityVM {
- return nil
- }
- err = safefile.EnsureNotReparsePointRelative(utilityVMPath, root)
- if err != nil {
- return err
- }
- utilityVMPath := filepath.Join(root.Name(), utilityVMPath)
- return ProcessUtilityVMImage(ctx, utilityVMPath)
- }
- // ConvertToBaseLayer processes a candidate base layer, i.e. a directory
- // containing the desired file content under Files/, and optionally the
- // desired file content for a UtilityVM under UtilityVM/Files/
- func ConvertToBaseLayer(ctx context.Context, path string) (err error) {
- title := "hcsshim::ConvertToBaseLayer"
- ctx, span := trace.StartSpan(ctx, title)
- defer span.End()
- defer func() { oc.SetSpanStatus(span, err) }()
- span.AddAttributes(trace.StringAttribute("path", path))
- root, err := safefile.OpenRoot(path)
- if err != nil {
- return hcserror.New(err, title+" - failed", "")
- }
- defer func() {
- if err2 := root.Close(); err == nil && err2 != nil {
- err = hcserror.New(err2, title+" - failed", "")
- }
- }()
- if err = convertToBaseLayer(ctx, root); err != nil {
- return hcserror.New(err, title+" - failed", "")
- }
- return nil
- }
|