Add cimfs differ and snapshotter
Details about CimFs project are discussed in #8346 Signed-off-by: Amit Barve <ambarve@microsoft.com>
This commit is contained in:
2
vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go
generated
vendored
@@ -63,7 +63,7 @@ func (process *Process) SystemID() string {
|
||||
}
|
||||
|
||||
func (process *Process) processSignalResult(ctx context.Context, err error) (bool, error) {
|
||||
switch err {
|
||||
switch err { //nolint:errorlint
|
||||
case nil:
|
||||
return true, nil
|
||||
case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound:
|
||||
|
||||
7
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/layer.go
generated
vendored
7
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/layer.go
generated
vendored
@@ -9,6 +9,13 @@
|
||||
|
||||
package hcsschema
|
||||
|
||||
type FileSystemFilterType string
|
||||
|
||||
const (
|
||||
UnionFS FileSystemFilterType = "UnionFS"
|
||||
WCIFS FileSystemFilterType = "WCIFS"
|
||||
)
|
||||
|
||||
type Layer struct {
|
||||
Id string `json:"Id,omitempty"`
|
||||
|
||||
|
||||
13
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_hive.go
generated
vendored
Normal file
13
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_hive.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package hcsschema
|
||||
|
||||
// NOTE: manually added
|
||||
|
||||
type RegistryHive string
|
||||
|
||||
// List of RegistryHive
|
||||
const (
|
||||
RegistryHive_SYSTEM RegistryHive = "System"
|
||||
RegistryHive_SOFTWARE RegistryHive = "Software"
|
||||
RegistryHive_SECURITY RegistryHive = "Security"
|
||||
RegistryHive_SAM RegistryHive = "Sam"
|
||||
)
|
||||
2
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_key.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_key.go
generated
vendored
@@ -10,7 +10,7 @@
|
||||
package hcsschema
|
||||
|
||||
type RegistryKey struct {
|
||||
Hive string `json:"Hive,omitempty"`
|
||||
Hive RegistryHive `json:"Hive,omitempty"`
|
||||
|
||||
Name string `json:"Name,omitempty"`
|
||||
|
||||
|
||||
2
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_value.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_value.go
generated
vendored
@@ -14,7 +14,7 @@ type RegistryValue struct {
|
||||
|
||||
Name string `json:"Name,omitempty"`
|
||||
|
||||
Type_ string `json:"Type,omitempty"`
|
||||
Type_ RegistryValueType `json:"Type,omitempty"`
|
||||
|
||||
// One and only one value type must be set.
|
||||
StringValue string `json:"StringValue,omitempty"`
|
||||
|
||||
17
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_value_type.go
generated
vendored
Normal file
17
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/registry_value_type.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package hcsschema
|
||||
|
||||
// NOTE: manually added
|
||||
|
||||
type RegistryValueType string
|
||||
|
||||
// List of RegistryValueType
|
||||
const (
|
||||
RegistryValueType_NONE RegistryValueType = "None"
|
||||
RegistryValueType_STRING RegistryValueType = "String"
|
||||
RegistryValueType_EXPANDED_STRING RegistryValueType = "ExpandedString"
|
||||
RegistryValueType_MULTI_STRING RegistryValueType = "MultiString"
|
||||
RegistryValueType_BINARY RegistryValueType = "Binary"
|
||||
RegistryValueType_D_WORD RegistryValueType = "DWord"
|
||||
RegistryValueType_Q_WORD RegistryValueType = "QWord"
|
||||
RegistryValueType_CUSTOM_TYPE RegistryValueType = "CustomType"
|
||||
)
|
||||
8
vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
generated
vendored
8
vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
generated
vendored
@@ -97,7 +97,7 @@ func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface in
|
||||
events, err := processAsyncHcsResult(ctx, createError, resultJSON, computeSystem.callbackNumber,
|
||||
hcsNotificationSystemCreateCompleted, &timeout.SystemCreate)
|
||||
if err != nil {
|
||||
if err == ErrTimeout {
|
||||
if errors.Is(err, ErrTimeout) {
|
||||
// Terminate the compute system if it still exists. We're okay to
|
||||
// ignore a failure here.
|
||||
_ = computeSystem.Terminate(ctx)
|
||||
@@ -238,7 +238,7 @@ func (computeSystem *System) Shutdown(ctx context.Context) error {
|
||||
|
||||
resultJSON, err := vmcompute.HcsShutdownComputeSystem(ctx, computeSystem.handle, "")
|
||||
events := processHcsResult(ctx, resultJSON)
|
||||
switch err {
|
||||
switch err { //nolint:errorlint
|
||||
case nil, ErrVmcomputeAlreadyStopped, ErrComputeSystemDoesNotExist, ErrVmcomputeOperationPending:
|
||||
default:
|
||||
return makeSystemError(computeSystem, operation, err, events)
|
||||
@@ -259,7 +259,7 @@ func (computeSystem *System) Terminate(ctx context.Context) error {
|
||||
|
||||
resultJSON, err := vmcompute.HcsTerminateComputeSystem(ctx, computeSystem.handle, "")
|
||||
events := processHcsResult(ctx, resultJSON)
|
||||
switch err {
|
||||
switch err { //nolint:errorlint
|
||||
case nil, ErrVmcomputeAlreadyStopped, ErrComputeSystemDoesNotExist, ErrVmcomputeOperationPending:
|
||||
default:
|
||||
return makeSystemError(computeSystem, operation, err, events)
|
||||
@@ -279,7 +279,7 @@ func (computeSystem *System) waitBackground() {
|
||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
||||
|
||||
err := waitForNotification(ctx, computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
|
||||
switch err {
|
||||
switch err { //nolint:errorlint
|
||||
case nil:
|
||||
log.G(ctx).Debug("system exited")
|
||||
case ErrVmcomputeUnexpectedExit:
|
||||
|
||||
2
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsfuncs.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsfuncs.go
generated
vendored
@@ -31,7 +31,7 @@ func hnsCallRawResponse(method, path, request string) (*hnsResponse, error) {
|
||||
func hnsCall(method, path, request string, returnResponse interface{}) error {
|
||||
hnsresponse, err := hnsCallRawResponse(method, path, request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed during hnsCallRawResponse: %v", err)
|
||||
return fmt.Errorf("failed during hnsCallRawResponse: %w", err)
|
||||
}
|
||||
if !hnsresponse.Success {
|
||||
return fmt.Errorf("hns failed with error : %s", hnsresponse.Error)
|
||||
|
||||
4
vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go
generated
vendored
4
vendor/github.com/Microsoft/hcsshim/internal/hns/namespace.go
generated
vendored
@@ -56,7 +56,7 @@ func issueNamespaceRequest(id *string, method, subpath string, request interface
|
||||
if strings.Contains(err.Error(), "Element not found.") {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return nil, fmt.Errorf("%s %s: %s", method, hnspath, err)
|
||||
return nil, fmt.Errorf("%s %s: %w", method, hnspath, err)
|
||||
}
|
||||
return &ns, err
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func GetNamespaceEndpoints(id string) ([]string, error) {
|
||||
var endpoint namespaceEndpointRequest
|
||||
err = json.Unmarshal(rsrc.Data, &endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unmarshal endpoint: %s", err)
|
||||
return nil, fmt.Errorf("unmarshal endpoint: %w", err)
|
||||
}
|
||||
endpoints = append(endpoints, endpoint.ID)
|
||||
}
|
||||
|
||||
3
vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go
generated
vendored
3
vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go
generated
vendored
@@ -4,6 +4,7 @@ package jobobject
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
@@ -59,7 +60,7 @@ func pollIOCP(ctx context.Context, iocpHandle windows.Handle) {
|
||||
}).Warn("failed to parse job object message")
|
||||
continue
|
||||
}
|
||||
if err := msq.Enqueue(notification); err == queue.ErrQueueClosed {
|
||||
if err := msq.Enqueue(notification); errors.Is(err, queue.ErrQueueClosed) {
|
||||
// Write will only return an error when the queue is closed.
|
||||
// The only time a queue would ever be closed is when we call `Close` on
|
||||
// the job it belongs to which also removes it from the jobMap, so something
|
||||
|
||||
2
vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go
generated
vendored
@@ -374,7 +374,7 @@ func (job *JobObject) Pids() ([]uint32, error) {
|
||||
return []uint32{}, nil
|
||||
}
|
||||
|
||||
if err != winapi.ERROR_MORE_DATA {
|
||||
if err != winapi.ERROR_MORE_DATA { //nolint:errorlint
|
||||
return nil, fmt.Errorf("failed initial query for PIDs in job object: %w", err)
|
||||
}
|
||||
|
||||
|
||||
7
vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go
generated
vendored
7
vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go
generated
vendored
@@ -143,6 +143,13 @@ func (job *JobObject) SetCPUAffinity(affinityBitMask uint64) error {
|
||||
return err
|
||||
}
|
||||
info.BasicLimitInformation.LimitFlags |= uint32(windows.JOB_OBJECT_LIMIT_AFFINITY)
|
||||
|
||||
// We really, really shouldn't be running on 32 bit, but just in case (and to satisfy CodeQL) ...
|
||||
const maxUintptr = ^uintptr(0)
|
||||
if affinityBitMask > uint64(maxUintptr) {
|
||||
return fmt.Errorf("affinity bitmask (%d) exceeds max allowable value (%d)", affinityBitMask, maxUintptr)
|
||||
}
|
||||
|
||||
info.BasicLimitInformation.Affinity = uintptr(affinityBitMask)
|
||||
return job.setExtendedInformation(info)
|
||||
}
|
||||
|
||||
1
vendor/github.com/Microsoft/hcsshim/internal/log/format.go
generated
vendored
1
vendor/github.com/Microsoft/hcsshim/internal/log/format.go
generated
vendored
@@ -104,6 +104,7 @@ func encode(v interface{}) (_ []byte, err error) {
|
||||
if jErr := enc.Encode(v); jErr != nil {
|
||||
if err != nil {
|
||||
// TODO (go1.20): use multierror via fmt.Errorf("...: %w; ...: %w", ...)
|
||||
//nolint:errorlint // non-wrapping format verb for fmt.Errorf
|
||||
return nil, fmt.Errorf("protojson encoding: %v; json encoding: %w", err, jErr)
|
||||
}
|
||||
return nil, fmt.Errorf("json encoding: %w", jErr)
|
||||
|
||||
1
vendor/github.com/Microsoft/hcsshim/internal/logfields/fields.go
generated
vendored
1
vendor/github.com/Microsoft/hcsshim/internal/logfields/fields.go
generated
vendored
@@ -46,6 +46,7 @@ const (
|
||||
|
||||
ExpectedType = "expected-type"
|
||||
Bool = "bool"
|
||||
Int32 = "int32"
|
||||
Uint32 = "uint32"
|
||||
Uint64 = "uint64"
|
||||
|
||||
|
||||
6
vendor/github.com/Microsoft/hcsshim/internal/memory/pool.go
generated
vendored
6
vendor/github.com/Microsoft/hcsshim/internal/memory/pool.go
generated
vendored
@@ -126,7 +126,7 @@ func (pa *PoolAllocator) Allocate(size uint64) (MappedRegion, error) {
|
||||
// this means that there are no more regions for the current class, try expanding
|
||||
if nextCls != memCls {
|
||||
if err := pa.split(memCls); err != nil {
|
||||
if err == ErrInvalidMemoryClass {
|
||||
if errors.Is(err, ErrInvalidMemoryClass) {
|
||||
return nil, ErrNotEnoughSpace
|
||||
}
|
||||
return nil, err
|
||||
@@ -147,7 +147,7 @@ func (pa *PoolAllocator) Allocate(size uint64) (MappedRegion, error) {
|
||||
}
|
||||
|
||||
// Release marks a memory region of class `memCls` and offset `offset` as free and tries to merge smaller regions into
|
||||
// a bigger one
|
||||
// a bigger one.
|
||||
func (pa *PoolAllocator) Release(reg MappedRegion) error {
|
||||
mp := pa.pools[reg.Type()]
|
||||
if mp == nil {
|
||||
@@ -164,7 +164,7 @@ func (pa *PoolAllocator) Release(reg MappedRegion) error {
|
||||
return ErrNotAllocated
|
||||
}
|
||||
if err := pa.merge(n.parent); err != nil {
|
||||
if err != ErrEarlyMerge {
|
||||
if !errors.Is(err, ErrEarlyMerge) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
16
vendor/github.com/Microsoft/hcsshim/internal/regstate/regstate.go
generated
vendored
16
vendor/github.com/Microsoft/hcsshim/internal/regstate/regstate.go
generated
vendored
@@ -4,6 +4,7 @@ package regstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -44,8 +45,8 @@ func (err *NotFoundError) Error() string {
|
||||
}
|
||||
|
||||
func IsNotFoundError(err error) bool {
|
||||
_, ok := err.(*NotFoundError)
|
||||
return ok
|
||||
var e *NotFoundError
|
||||
return errors.As(err, &e)
|
||||
}
|
||||
|
||||
type NoStateError struct {
|
||||
@@ -152,7 +153,8 @@ func (k *Key) openid(id string) (*Key, error) {
|
||||
escaped := url.PathEscape(id)
|
||||
fullpath := filepath.Join(k.Name, escaped)
|
||||
nk, err := k.open(escaped)
|
||||
if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.ERROR_FILE_NOT_FOUND {
|
||||
var perr *os.PathError
|
||||
if errors.As(err, &perr) && errors.Is(perr.Err, syscall.ERROR_FILE_NOT_FOUND) {
|
||||
return nil, &NotFoundError{id}
|
||||
}
|
||||
if err != nil {
|
||||
@@ -165,7 +167,7 @@ func (k *Key) Remove(id string) error {
|
||||
escaped := url.PathEscape(id)
|
||||
err := registry.DeleteKey(k.Key, escaped)
|
||||
if err != nil {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND { //nolint:errorlint
|
||||
return &NotFoundError{id}
|
||||
}
|
||||
return &os.PathError{Op: "RegDeleteKey", Path: filepath.Join(k.Name, escaped), Err: err}
|
||||
@@ -215,7 +217,7 @@ func (k *Key) set(id string, create bool, key string, state interface{}) error {
|
||||
err = sk.SetBinaryValue(key, js)
|
||||
}
|
||||
if err != nil {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND { //nolint:errorlint
|
||||
return &NoStateError{id, key}
|
||||
}
|
||||
return &os.PathError{Op: "RegSetValueEx", Path: sk.Name + ":" + key, Err: err}
|
||||
@@ -239,7 +241,7 @@ func (k *Key) Clear(id, key string) error {
|
||||
defer sk.Close()
|
||||
err = sk.DeleteValue(key)
|
||||
if err != nil {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND { //nolint:errorlint
|
||||
return &NoStateError{id, key}
|
||||
}
|
||||
return &os.PathError{Op: "RegDeleteValue", Path: sk.Name + ":" + key, Err: err}
|
||||
@@ -278,7 +280,7 @@ func (k *Key) Get(id, key string, state interface{}) error {
|
||||
js, _, err = sk.GetBinaryValue(key)
|
||||
}
|
||||
if err != nil {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND {
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND { //nolint:errorlint
|
||||
return &NoStateError{id, key}
|
||||
}
|
||||
return &os.PathError{Op: "RegQueryValueEx", Path: sk.Name + ":" + key, Err: err}
|
||||
|
||||
2
vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
generated
vendored
@@ -243,7 +243,7 @@ func RemoveRelative(path string, root *os.File) error {
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
err = deleteOnClose(f)
|
||||
if err == syscall.ERROR_ACCESS_DENIED {
|
||||
if err == syscall.ERROR_ACCESS_DENIED { //nolint:errorlint
|
||||
// Maybe the file is marked readonly. Clear the bit and retry.
|
||||
_ = clearReadOnly(f)
|
||||
err = deleteOnClose(f)
|
||||
|
||||
3
vendor/github.com/Microsoft/hcsshim/internal/vhdx/doc.go
generated
vendored
Normal file
3
vendor/github.com/Microsoft/hcsshim/internal/vhdx/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// vhdx package adds the utility methods necessary to deal with the vhdx that are used as the scratch
|
||||
// space for the containers and the uvm.
|
||||
package vhdx
|
||||
233
vendor/github.com/Microsoft/hcsshim/internal/vhdx/info.go
generated
vendored
Normal file
233
vendor/github.com/Microsoft/hcsshim/internal/vhdx/info.go
generated
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
//go:build windows
|
||||
|
||||
package vhdx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
"github.com/Microsoft/go-winio/vhd"
|
||||
"github.com/Microsoft/hcsshim/internal/log"
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const _IOCTL_DISK_GET_DRIVE_LAYOUT_EX = 0x00070050
|
||||
|
||||
var partitionBasicDataGUID = guid.GUID{
|
||||
Data1: 0xebd0a0a2,
|
||||
Data2: 0xb9e5,
|
||||
Data3: 0x4433,
|
||||
Data4: [8]byte{0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7},
|
||||
}
|
||||
|
||||
const (
|
||||
partitionStyleMBR uint32 = iota
|
||||
partitionStyleGPT
|
||||
partitionStyleRaw
|
||||
)
|
||||
|
||||
// type partitionInformationMBR struct {
|
||||
// PartitionType uint8
|
||||
// BootIndicator uint8
|
||||
// RecognizedPartition uint8
|
||||
// HiddenSectors uint32
|
||||
// PartitionId guid.GUID
|
||||
// }
|
||||
|
||||
type partitionInformationGPT struct {
|
||||
PartitionType guid.GUID
|
||||
PartitionId guid.GUID
|
||||
Attributes uint64
|
||||
Name [72]byte // wide char
|
||||
}
|
||||
|
||||
type partitionInformationEx struct {
|
||||
PartitionStyle uint32
|
||||
StartingOffset int64
|
||||
PartitionLength int64
|
||||
PartitionNumber uint32
|
||||
RewritePartition uint8
|
||||
IsServicePartition uint8
|
||||
_ uint16
|
||||
// A union of partitionInformationMBR and partitionInformationGPT
|
||||
// since partitionInformationGPT is largest with 112 bytes
|
||||
GptMbrUnion [112]byte
|
||||
}
|
||||
|
||||
type driveLayoutInformationGPT struct {
|
||||
DiskID guid.GUID
|
||||
StartingUsableOffset int64
|
||||
UsableLength int64
|
||||
MaxPartitionCount uint32
|
||||
}
|
||||
|
||||
// type driveLayoutInformationMBR struct {
|
||||
// Signature uint32
|
||||
// Checksum uint32
|
||||
// }
|
||||
|
||||
type driveLayoutInformationEx struct {
|
||||
PartitionStyle uint32
|
||||
PartitionCount uint32
|
||||
// A union of driveLayoutInformationGPT and driveLayoutInformationMBR
|
||||
// since driveLayoutInformationGPT is largest with 40 bytes
|
||||
GptMbrUnion [40]byte
|
||||
PartitionEntry [1]partitionInformationEx
|
||||
}
|
||||
|
||||
// Takes the physical path of a disk and retrieves the drive layout information of that disk. Returns the
|
||||
// driveLayoutInformationEx struct and a slice of partitionInfomrationEx struct containing one element for
|
||||
// each partition found on the vhdx. Note: some of the members like (GptMbrUnion) of these structs are raw
|
||||
// byte arrays and it is the responsibility of the calling function to properly parse them.
|
||||
func getDriveLayout(ctx context.Context, drivePhysicalPath string) (driveLayoutInformationEx, []partitionInformationEx, error) {
|
||||
var (
|
||||
outBytes uint32
|
||||
err error
|
||||
volume *os.File
|
||||
)
|
||||
|
||||
layoutData := struct {
|
||||
info driveLayoutInformationEx
|
||||
// driveLayoutInformationEx has a flexible array member at the end. The data returned
|
||||
// by IOCTL_DISK_GET_DRIVE_LAYOUT_EX usually has driveLayoutInformationEx.PartitionCount
|
||||
// number of elements in this array. For all practical purposes we don't expect to have
|
||||
// more than 64 partitions in a container/uvm vhdx.
|
||||
partitions [63]partitionInformationEx
|
||||
}{}
|
||||
|
||||
volume, err = os.OpenFile(drivePhysicalPath, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return layoutData.info, layoutData.partitions[:0], fmt.Errorf("failed to open drive: %w", err)
|
||||
}
|
||||
defer volume.Close()
|
||||
|
||||
err = windows.DeviceIoControl(windows.Handle(volume.Fd()),
|
||||
_IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
||||
nil,
|
||||
0,
|
||||
(*byte)(unsafe.Pointer(&layoutData)),
|
||||
uint32(unsafe.Sizeof(layoutData)),
|
||||
&outBytes,
|
||||
nil)
|
||||
if err != nil {
|
||||
return layoutData.info, layoutData.partitions[:0], fmt.Errorf("IOCTL to get disk layout failed: %w", err)
|
||||
}
|
||||
|
||||
if layoutData.info.PartitionCount == 0 {
|
||||
return layoutData.info, []partitionInformationEx{}, nil
|
||||
} else {
|
||||
// parse the retrieved data into driveLayoutInformationEx and partitionInformationEx
|
||||
partitions := make([]partitionInformationEx, layoutData.info.PartitionCount)
|
||||
partitions[0] = layoutData.info.PartitionEntry[0]
|
||||
copy(partitions[1:], layoutData.partitions[:layoutData.info.PartitionCount-1])
|
||||
return layoutData.info, partitions, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Scratch VHDs are formatted with GPT style and have 1 MSFT_RESERVED
|
||||
// partition and 1 BASIC_DATA partition. This struct contains the
|
||||
// partitionID of this BASIC_DATA partition and the DiskID of this
|
||||
// scratch vhdx.
|
||||
type ScratchVhdxPartitionInfo struct {
|
||||
DiskID guid.GUID
|
||||
PartitionID guid.GUID
|
||||
}
|
||||
|
||||
// Returns the VhdxInfo of a GPT vhdx at path vhdxPath.
|
||||
func GetScratchVhdPartitionInfo(ctx context.Context, vhdxPath string) (_ ScratchVhdxPartitionInfo, err error) {
|
||||
var (
|
||||
diskHandle syscall.Handle
|
||||
driveLayout driveLayoutInformationEx
|
||||
partitions []partitionInformationEx
|
||||
gptDriveLayout driveLayoutInformationGPT
|
||||
gptPartitionInfo partitionInformationGPT
|
||||
volumePath string
|
||||
)
|
||||
|
||||
title := "hcsshim::GetScratchVhdPartitionInfo"
|
||||
ctx, span := trace.StartSpan(ctx, title)
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("path", vhdxPath))
|
||||
|
||||
diskHandle, err = vhd.OpenVirtualDisk(vhdxPath, vhd.VirtualDiskAccessNone, vhd.OpenVirtualDiskFlagNone)
|
||||
if err != nil {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("get scratch vhd info failed: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if closeErr := syscall.CloseHandle(diskHandle); closeErr != nil {
|
||||
log.G(ctx).WithFields(logrus.Fields{
|
||||
"disk path": vhdxPath,
|
||||
"error": closeErr,
|
||||
}).Warn("failed to close vhd handle")
|
||||
}
|
||||
}()
|
||||
|
||||
err = vhd.AttachVirtualDisk(diskHandle, vhd.AttachVirtualDiskFlagNone, &vhd.AttachVirtualDiskParameters{Version: 2})
|
||||
if err != nil {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("get scratch vhd info failed: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if detachErr := vhd.DetachVirtualDisk(diskHandle); detachErr != nil {
|
||||
log.G(ctx).WithFields(logrus.Fields{
|
||||
"disk path": vhdxPath,
|
||||
"error": detachErr,
|
||||
}).Warn("failed to detach vhd")
|
||||
}
|
||||
}()
|
||||
|
||||
volumePath, err = vhd.GetVirtualDiskPhysicalPath(diskHandle)
|
||||
if err != nil {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("get vhd physical path: %w", err)
|
||||
}
|
||||
|
||||
driveLayout, partitions, err = getDriveLayout(ctx, volumePath)
|
||||
if err != nil {
|
||||
return ScratchVhdxPartitionInfo{}, err
|
||||
}
|
||||
|
||||
if driveLayout.PartitionStyle != partitionStyleGPT {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("drive Layout:Expected partition style GPT(%d) found %d", partitionStyleGPT, driveLayout.PartitionStyle)
|
||||
}
|
||||
|
||||
if driveLayout.PartitionCount != 2 || len(partitions) != 2 {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("expected exactly 2 partitions. Got %d partitions and partition count of %d", len(partitions), driveLayout.PartitionCount)
|
||||
}
|
||||
|
||||
if partitions[1].PartitionStyle != partitionStyleGPT {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("partition Info:Expected partition style GPT(%d) found %d", partitionStyleGPT, partitions[1].PartitionStyle)
|
||||
}
|
||||
|
||||
bufReader := bytes.NewBuffer(driveLayout.GptMbrUnion[:])
|
||||
if err := binary.Read(bufReader, binary.LittleEndian, &gptDriveLayout); err != nil {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("failed to parse drive GPT layout: %w", err)
|
||||
}
|
||||
|
||||
bufReader = bytes.NewBuffer(partitions[1].GptMbrUnion[:])
|
||||
if err := binary.Read(bufReader, binary.LittleEndian, &gptPartitionInfo); err != nil {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("failed to parse GPT partition info: %w", err)
|
||||
}
|
||||
|
||||
if gptPartitionInfo.PartitionType != partitionBasicDataGUID {
|
||||
return ScratchVhdxPartitionInfo{}, fmt.Errorf("expected partition type to have %s GUID found %s instead", partitionBasicDataGUID, gptPartitionInfo.PartitionType)
|
||||
}
|
||||
|
||||
log.G(ctx).WithFields(logrus.Fields{
|
||||
"Disk ID": gptDriveLayout.DiskID,
|
||||
"GPT Partition ID": gptPartitionInfo.PartitionId,
|
||||
}).Debug("Scratch VHD partition info")
|
||||
|
||||
return ScratchVhdxPartitionInfo{DiskID: gptDriveLayout.DiskID, PartitionID: gptPartitionInfo.PartitionId}, nil
|
||||
|
||||
}
|
||||
16
vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go
generated
vendored
16
vendor/github.com/Microsoft/hcsshim/internal/vmcompute/vmcompute.go
generated
vendored
@@ -104,7 +104,7 @@ func execute(ctx gcontext.Context, timeout time.Duration, f func() error) error
|
||||
}()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if ctx.Err() == gcontext.DeadlineExceeded {
|
||||
if ctx.Err() == gcontext.DeadlineExceeded { //nolint:errorlint
|
||||
log.G(ctx).WithField(logfields.Timeout, trueTimeout).
|
||||
Warning("Syscall did not complete within operation timeout. This may indicate a platform issue. " +
|
||||
"If it appears to be making no forward progress, obtain the stacks and see if there is a syscall " +
|
||||
@@ -150,7 +150,7 @@ func HcsCreateComputeSystem(ctx gcontext.Context, id string, configuration strin
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
@@ -205,7 +205,7 @@ func HcsStartComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, option
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
@@ -228,7 +228,7 @@ func HcsShutdownComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, opt
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
@@ -251,7 +251,7 @@ func HcsTerminateComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, op
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
@@ -274,7 +274,7 @@ func HcsPauseComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, option
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
@@ -297,7 +297,7 @@ func HcsResumeComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, optio
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
@@ -621,7 +621,7 @@ func HcsSaveComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, options
|
||||
if result != "" {
|
||||
span.AddAttributes(trace.StringAttribute("result", result))
|
||||
}
|
||||
if hr != errVmcomputeOperationPending {
|
||||
if hr != errVmcomputeOperationPending { //nolint:errorlint // explicitly returned
|
||||
oc.SetSpanStatus(span, hr)
|
||||
}
|
||||
}()
|
||||
|
||||
6
vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayerreader.go
generated
vendored
6
vendor/github.com/Microsoft/hcsshim/internal/wclayer/baselayerreader.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package wclayer
|
||||
|
||||
import (
|
||||
@@ -64,7 +66,7 @@ func (r *baseLayerReader) walkUntilCancelled() error {
|
||||
return nil
|
||||
})
|
||||
|
||||
if err == errorIterationCanceled {
|
||||
if err == errorIterationCanceled { //nolint:errorlint // explicitly returned
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -103,7 +105,7 @@ func (r *baseLayerReader) walkUntilCancelled() error {
|
||||
return nil
|
||||
})
|
||||
|
||||
if err == errorIterationCanceled {
|
||||
if err == errorIterationCanceled { //nolint:errorlint // explicitly returned
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
289
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/LayerWriter.go
generated
vendored
Normal file
289
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/LayerWriter.go
generated
vendored
Normal file
@@ -0,0 +1,289 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
"github.com/Microsoft/hcsshim/internal/log"
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/Microsoft/hcsshim/internal/wclayer"
|
||||
"github.com/Microsoft/hcsshim/osversion"
|
||||
"github.com/Microsoft/hcsshim/pkg/cimfs"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// A CimLayerWriter implements the wclayer.LayerWriter interface to allow writing container
|
||||
// image layers in the cim format.
|
||||
// A cim layer consist of cim files (which are usually stored in the `cim-layers` directory and
|
||||
// some other files which are stored in the directory of that layer (i.e the `path` directory).
|
||||
type CimLayerWriter struct {
|
||||
ctx context.Context
|
||||
s *trace.Span
|
||||
// path to the layer (i.e layer's directory) as provided by the caller.
|
||||
// Even if a layer is stored as a cim in the cim directory, some files associated
|
||||
// with a layer are still stored in this path.
|
||||
path string
|
||||
// parent layer paths
|
||||
parentLayerPaths []string
|
||||
// Handle to the layer cim - writes to the cim file
|
||||
cimWriter *cimfs.CimFsWriter
|
||||
// Handle to the writer for writing files in the local filesystem
|
||||
stdFileWriter *stdFileWriter
|
||||
// reference to currently active writer either cimWriter or stdFileWriter
|
||||
activeWriter io.Writer
|
||||
// denotes if this layer has the UtilityVM directory
|
||||
hasUtilityVM bool
|
||||
// some files are written outside the cim during initial import (via stdFileWriter) because we need to
|
||||
// make some modifications to these files before writing them to the cim. The pendingOps slice
|
||||
// maintains a list of such delayed modifications to the layer cim. These modifications are applied at
|
||||
// the very end of layer import process.
|
||||
pendingOps []pendingCimOp
|
||||
}
|
||||
|
||||
type hive struct {
|
||||
name string
|
||||
base string
|
||||
delta string
|
||||
}
|
||||
|
||||
var (
|
||||
hives = []hive{
|
||||
{"SYSTEM", "SYSTEM_BASE", "SYSTEM_DELTA"},
|
||||
{"SOFTWARE", "SOFTWARE_BASE", "SOFTWARE_DELTA"},
|
||||
{"SAM", "SAM_BASE", "SAM_DELTA"},
|
||||
{"SECURITY", "SECURITY_BASE", "SECURITY_DELTA"},
|
||||
{"DEFAULT", "DEFAULTUSER_BASE", "DEFAULTUSER_DELTA"},
|
||||
}
|
||||
)
|
||||
|
||||
func isDeltaOrBaseHive(path string) bool {
|
||||
for _, hv := range hives {
|
||||
if strings.EqualFold(path, filepath.Join(wclayer.HivesPath, hv.delta)) ||
|
||||
strings.EqualFold(path, filepath.Join(wclayer.RegFilesPath, hv.name)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// checks if this particular file should be written with a stdFileWriter instead of
|
||||
// using the cimWriter.
|
||||
func isStdFile(path string) bool {
|
||||
return (isDeltaOrBaseHive(path) ||
|
||||
path == filepath.Join(wclayer.UtilityVMPath, wclayer.RegFilesPath, "SYSTEM") ||
|
||||
path == filepath.Join(wclayer.UtilityVMPath, wclayer.RegFilesPath, "SOFTWARE") ||
|
||||
path == wclayer.BcdFilePath || path == wclayer.BootMgrFilePath)
|
||||
}
|
||||
|
||||
// Add adds a file to the layer with given metadata.
|
||||
func (cw *CimLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo, fileSize int64, securityDescriptor []byte, extendedAttributes []byte, reparseData []byte) error {
|
||||
if name == wclayer.UtilityVMPath {
|
||||
cw.hasUtilityVM = true
|
||||
}
|
||||
if isStdFile(name) {
|
||||
// create a pending op for this file
|
||||
cw.pendingOps = append(cw.pendingOps, &addOp{
|
||||
pathInCim: name,
|
||||
hostPath: filepath.Join(cw.path, name),
|
||||
fileInfo: fileInfo,
|
||||
securityDescriptor: securityDescriptor,
|
||||
extendedAttributes: extendedAttributes,
|
||||
reparseData: reparseData,
|
||||
})
|
||||
if err := cw.stdFileWriter.Add(name); err != nil {
|
||||
return err
|
||||
}
|
||||
cw.activeWriter = cw.stdFileWriter
|
||||
} else {
|
||||
if err := cw.cimWriter.AddFile(name, fileInfo, fileSize, securityDescriptor, extendedAttributes, reparseData); err != nil {
|
||||
return err
|
||||
}
|
||||
cw.activeWriter = cw.cimWriter
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddLink adds a hard link to the layer. The target must already have been added.
|
||||
func (cw *CimLayerWriter) AddLink(name string, target string) error {
|
||||
// set active write to nil so that we panic if layer tar is incorrectly formatted.
|
||||
cw.activeWriter = nil
|
||||
if isStdFile(target) {
|
||||
// If this is a link to a std file it will have to be added later once the
|
||||
// std file is written to the CIM. Create a pending op for this
|
||||
cw.pendingOps = append(cw.pendingOps, &linkOp{
|
||||
oldPath: target,
|
||||
newPath: name,
|
||||
})
|
||||
return nil
|
||||
} else if isStdFile(name) {
|
||||
// None of the predefined std files are links. If they show up as links this is unexpected
|
||||
// behavior. Error out.
|
||||
return fmt.Errorf("unexpected link %s in layer", name)
|
||||
} else {
|
||||
return cw.cimWriter.AddLink(target, name)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAlternateStream creates another alternate stream at the given
|
||||
// path. Any writes made after this call will go to that stream.
|
||||
func (cw *CimLayerWriter) AddAlternateStream(name string, size uint64) error {
|
||||
if isStdFile(name) {
|
||||
// As of now there is no known case of std file having multiple data streams.
|
||||
// If such a file is encountered our assumptions are wrong. Error out.
|
||||
return fmt.Errorf("unexpected alternate stream %s in layer", name)
|
||||
}
|
||||
|
||||
if err := cw.cimWriter.CreateAlternateStream(name, size); err != nil {
|
||||
return err
|
||||
}
|
||||
cw.activeWriter = cw.cimWriter
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes a file that was present in a parent layer from the layer.
|
||||
func (cw *CimLayerWriter) Remove(name string) error {
|
||||
// set active write to nil so that we panic if layer tar is incorrectly formatted.
|
||||
cw.activeWriter = nil
|
||||
return cw.cimWriter.Unlink(name)
|
||||
}
|
||||
|
||||
// Write writes data to the current file. The data must be in the format of a Win32
|
||||
// backup stream.
|
||||
func (cw *CimLayerWriter) Write(b []byte) (int, error) {
|
||||
return cw.activeWriter.Write(b)
|
||||
}
|
||||
|
||||
// Close finishes the layer writing process and releases any resources.
|
||||
func (cw *CimLayerWriter) Close(ctx context.Context) (retErr error) {
|
||||
if err := cw.stdFileWriter.Close(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cimWriter must be closed even if there are errors.
|
||||
defer func() {
|
||||
if err := cw.cimWriter.Close(); retErr == nil {
|
||||
retErr = err
|
||||
}
|
||||
}()
|
||||
|
||||
// Find out the osversion of this layer, both base & non-base layers can have UtilityVM layer.
|
||||
processUtilityVM := false
|
||||
if cw.hasUtilityVM {
|
||||
uvmSoftwareHivePath := filepath.Join(cw.path, wclayer.UtilityVMPath, wclayer.RegFilesPath, "SOFTWARE")
|
||||
osvStr, err := getOsBuildNumberFromRegistry(uvmSoftwareHivePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read os version string from UtilityVM SOFTWARE hive: %w", err)
|
||||
}
|
||||
|
||||
osv, err := strconv.ParseUint(osvStr, 10, 16)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse os version string (%s): %w", osvStr, err)
|
||||
}
|
||||
|
||||
// write this version to a file for future reference by the shim process
|
||||
if err = wclayer.WriteLayerUvmBuildFile(cw.path, uint16(osv)); err != nil {
|
||||
return fmt.Errorf("write uvm build version: %w", err)
|
||||
}
|
||||
|
||||
// CIMFS for hyperV isolated is only supported after 20348, processing UtilityVM layer on 2048
|
||||
// & lower will cause failures since those images won't have CIMFS specific UVM files (mostly
|
||||
// BCD entries required for CIMFS)
|
||||
processUtilityVM = (osv > osversion.LTSC2022)
|
||||
log.G(ctx).Debugf("import image os version %d, processing UtilityVM layer: %t\n", osv, processUtilityVM)
|
||||
}
|
||||
|
||||
if len(cw.parentLayerPaths) == 0 {
|
||||
if err := cw.processBaseLayer(ctx, processUtilityVM); err != nil {
|
||||
return fmt.Errorf("process base layer: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err := cw.processNonBaseLayer(ctx, processUtilityVM); err != nil {
|
||||
return fmt.Errorf("process non base layer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, op := range cw.pendingOps {
|
||||
if err := op.apply(cw.cimWriter); err != nil {
|
||||
return fmt.Errorf("apply pending operations: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCimLayerWriter(ctx context.Context, path string, parentLayerPaths []string) (_ *CimLayerWriter, err error) {
|
||||
if !cimfs.IsCimFSSupported() {
|
||||
return nil, fmt.Errorf("CimFs not supported on this build")
|
||||
}
|
||||
|
||||
ctx, span := trace.StartSpan(ctx, "hcsshim::NewCimLayerWriter")
|
||||
defer func() {
|
||||
if err != nil {
|
||||
oc.SetSpanStatus(span, err)
|
||||
span.End()
|
||||
}
|
||||
}()
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("path", path),
|
||||
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
|
||||
|
||||
parentCim := ""
|
||||
cimDirPath := GetCimDirFromLayer(path)
|
||||
if _, err = os.Stat(cimDirPath); os.IsNotExist(err) {
|
||||
// create cim directory
|
||||
if err = os.Mkdir(cimDirPath, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed while creating cim layers directory: %w", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("unable to access cim layers directory: %w", err)
|
||||
|
||||
}
|
||||
|
||||
if len(parentLayerPaths) > 0 {
|
||||
parentCim = GetCimNameFromLayer(parentLayerPaths[0])
|
||||
}
|
||||
|
||||
cim, err := cimfs.Create(cimDirPath, parentCim, GetCimNameFromLayer(path))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in creating a new cim: %w", err)
|
||||
}
|
||||
|
||||
sfw, err := newStdFileWriter(path, parentLayerPaths)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in creating new standard file writer: %w", err)
|
||||
}
|
||||
return &CimLayerWriter{
|
||||
ctx: ctx,
|
||||
s: span,
|
||||
path: path,
|
||||
parentLayerPaths: parentLayerPaths,
|
||||
cimWriter: cim,
|
||||
stdFileWriter: sfw,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DestroyCimLayer destroys a cim layer i.e it removes all the cimfs files for the given layer as well as
|
||||
// all of the other files that are stored in the layer directory (at path `layerPath`).
|
||||
// If this is not a cimfs layer (i.e a cim file for the given layer does not exist) then nothing is done.
|
||||
func DestroyCimLayer(ctx context.Context, layerPath string) error {
|
||||
cimPath := GetCimPathFromLayer(layerPath)
|
||||
|
||||
// verify that such a cim exists first, sometimes containerd tries to call
|
||||
// this with the root snapshot directory as the layer path. We don't want to
|
||||
// destroy everything inside the snapshots directory.
|
||||
if _, err := os.Stat(cimPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return cimfs.DestroyCim(ctx, cimPath)
|
||||
}
|
||||
107
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/bcd.go
generated
vendored
Normal file
107
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/bcd.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
)
|
||||
|
||||
const (
|
||||
bcdFilePath = "UtilityVM\\Files\\EFI\\Microsoft\\Boot\\BCD"
|
||||
cimfsDeviceOptionsID = "{763e9fea-502d-434f-aad9-5fabe9c91a7b}"
|
||||
vmbusDeviceID = "{c63c9bdf-5fa5-4208-b03f-6b458b365592}"
|
||||
compositeDeviceOptionsID = "{e1787220-d17f-49e7-977a-d8fe4c8537e2}"
|
||||
bootContainerID = "{b890454c-80de-4e98-a7ab-56b74b4fbd0c}"
|
||||
)
|
||||
|
||||
func bcdExec(storePath string, args ...string) error {
|
||||
var out bytes.Buffer
|
||||
argsArr := []string{"/store", storePath, "/offline"}
|
||||
argsArr = append(argsArr, args...)
|
||||
cmd := exec.Command("bcdedit.exe", argsArr...)
|
||||
cmd.Stdout = &out
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("bcd command (%s) failed: %w", cmd, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A registry configuration required for the uvm.
|
||||
func setBcdRestartOnFailure(storePath string) error {
|
||||
return bcdExec(storePath, "/set", "{default}", "restartonfailure", "yes")
|
||||
}
|
||||
|
||||
func setBcdCimBootDevice(storePath, cimPathRelativeToVSMB string, diskID, partitionID guid.GUID) error {
|
||||
// create options for cimfs boot device
|
||||
if err := bcdExec(storePath, "/create", cimfsDeviceOptionsID, "/d", "CimFS Device Options", "/device"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set options. For now we need to set 2 options. First is the parent device i.e the device under
|
||||
// which all cim files will be available. Second is the path of the cim (from which this UVM should
|
||||
// boot) relative to the parent device. Note that even though the 2nd option is named
|
||||
// `cimfsrootdirectory` it expects a path to the cim file and not a directory path.
|
||||
if err := bcdExec(storePath, "/set", cimfsDeviceOptionsID, "cimfsparentdevice", fmt.Sprintf("vmbus=%s", vmbusDeviceID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bcdExec(storePath, "/set", cimfsDeviceOptionsID, "cimfsrootdirectory", fmt.Sprintf("\\%s", cimPathRelativeToVSMB)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create options for the composite device
|
||||
if err := bcdExec(storePath, "/create", compositeDeviceOptionsID, "/d", "Composite Device Options", "/device"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We need to specify the diskID & the partition ID of the boot disk and we need to set the cimfs boot
|
||||
// options ID
|
||||
partitionStr := fmt.Sprintf("gpt_partition={%s};{%s}", diskID, partitionID)
|
||||
if err := bcdExec(storePath, "/set", compositeDeviceOptionsID, "primarydevice", partitionStr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bcdExec(storePath, "/set", compositeDeviceOptionsID, "secondarydevice", fmt.Sprintf("cimfs=%s,%s", bootContainerID, cimfsDeviceOptionsID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bcdExec(storePath, "/set", "{default}", "device", fmt.Sprintf("composite=0,%s", compositeDeviceOptionsID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bcdExec(storePath, "/set", "{default}", "osdevice", fmt.Sprintf("composite=0,%s", compositeDeviceOptionsID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since our UVM file are stored under UtilityVM\Files directory inside the CIM we must prepend that
|
||||
// directory in front of paths used by bootmgr
|
||||
if err := bcdExec(storePath, "/set", "{default}", "path", "\\UtilityVM\\Files\\Windows\\System32\\winload.efi"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bcdExec(storePath, "/set", "{default}", "systemroot", "\\UtilityVM\\Files\\Windows"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateBcdStoreForBoot Updates the bcd store at path layerPath + UtilityVM\Files\EFI\Microsoft\Boot\BCD` to
|
||||
// boot with the disk with given ID and given partitionID. cimPathRelativeToVSMB is the path of the cim which
|
||||
// will be used for booting this UVM relative to the VSMB share. (Usually, the entire snapshots directory will
|
||||
// be shared over VSMB, so if this is the cim-layers\1.cim under that directory, the value of
|
||||
// `cimPathRelativeToVSMB` should be cim-layers\1.cim)
|
||||
func updateBcdStoreForBoot(storePath string, cimPathRelativeToVSMB string, diskID, partitionID guid.GUID) error {
|
||||
if err := setBcdRestartOnFailure(storePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setBcdCimBootDevice(storePath, cimPathRelativeToVSMB, diskID, partitionID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
41
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/common.go
generated
vendored
Normal file
41
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/common.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
// name of the directory in which cims are stored
|
||||
cimDir = "cim-layers"
|
||||
)
|
||||
|
||||
// Usually layers are stored at ./root/io.containerd.snapshotter.v1.windows/snapshots/<layerid>. For cimfs we
|
||||
// must store all layer cims in the same directory (for forked cims to work). So all cim layers are stored in
|
||||
// /root/io.containerd.snapshotter.v1.windows/snapshots/cim-layers. And the cim file representing each
|
||||
// individual layer is stored at /root/io.containerd.snapshotter.v1.windows/snapshots/cim-layers/<layerid>.cim
|
||||
|
||||
// CimName is the filename (<layerid>.cim) of the file representing the cim
|
||||
func GetCimNameFromLayer(layerPath string) string {
|
||||
return filepath.Base(layerPath) + ".cim"
|
||||
}
|
||||
|
||||
// CimPath is the path to the CimDir/<layerid>.cim file that represents a layer cim.
|
||||
func GetCimPathFromLayer(layerPath string) string {
|
||||
return filepath.Join(GetCimDirFromLayer(layerPath), GetCimNameFromLayer(layerPath))
|
||||
}
|
||||
|
||||
// CimDir is the directory inside which all cims are stored.
|
||||
func GetCimDirFromLayer(layerPath string) string {
|
||||
dir := filepath.Dir(layerPath)
|
||||
return filepath.Join(dir, cimDir)
|
||||
}
|
||||
|
||||
// IsCimLayer returns `true` if the layer at path `layerPath` is a cim layer. Returns `false` otherwise.
|
||||
func IsCimLayer(layerPath string) bool {
|
||||
cimPath := GetCimPathFromLayer(layerPath)
|
||||
_, err := os.Stat(cimPath)
|
||||
return (err == nil)
|
||||
}
|
||||
3
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/doc.go
generated
vendored
Normal file
3
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// This package provides utilities for working with container image layers in the cim format
|
||||
// via the wclayer APIs.
|
||||
package cim
|
||||
90
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/file_writer.go
generated
vendored
Normal file
90
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/file_writer.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
"github.com/Microsoft/hcsshim/internal/safefile"
|
||||
"github.com/Microsoft/hcsshim/internal/winapi"
|
||||
)
|
||||
|
||||
// stdFileWriter writes the files of a layer to the layer folder instead of writing them inside the cim.
|
||||
// For some files (like the Hive files or some UtilityVM files) it is necessary to write them as a normal file
|
||||
// first, do some modifications on them (for example merging of hives or processing of UtilityVM files)
|
||||
// and then write the modified versions into the cim. This writer is used for such files.
|
||||
type stdFileWriter struct {
|
||||
activeFile *os.File
|
||||
// parent layer paths
|
||||
parentLayerPaths []string
|
||||
// path to the current layer
|
||||
path string
|
||||
// the open handle to the path directory
|
||||
root *os.File
|
||||
}
|
||||
|
||||
func newStdFileWriter(root string, parentRoots []string) (sfw *stdFileWriter, err error) {
|
||||
sfw = &stdFileWriter{
|
||||
path: root,
|
||||
parentLayerPaths: parentRoots,
|
||||
}
|
||||
sfw.root, err = safefile.OpenRoot(root)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (sfw *stdFileWriter) closeActiveFile() (err error) {
|
||||
if sfw.activeFile != nil {
|
||||
err = sfw.activeFile.Close()
|
||||
sfw.activeFile = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Adds a new file or an alternate data stream to an existing file inside the layer directory.
|
||||
func (sfw *stdFileWriter) Add(name string) error {
|
||||
if err := sfw.closeActiveFile(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The directory of this file might be created inside the cim.
|
||||
// make sure we have the same parent directory chain here
|
||||
if err := safefile.MkdirAllRelative(filepath.Dir(name), sfw.root); err != nil {
|
||||
return fmt.Errorf("failed to create file %s: %w", name, err)
|
||||
}
|
||||
|
||||
f, err := safefile.OpenRelative(
|
||||
name,
|
||||
sfw.root,
|
||||
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER,
|
||||
syscall.FILE_SHARE_READ,
|
||||
winapi.FILE_CREATE,
|
||||
0,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating file %s: %w", name, err)
|
||||
}
|
||||
sfw.activeFile = f
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes data to the current file. The data must be in the format of a Win32
|
||||
// backup stream.
|
||||
func (sfw *stdFileWriter) Write(b []byte) (int, error) {
|
||||
return sfw.activeFile.Write(b)
|
||||
}
|
||||
|
||||
// Close finishes the layer writing process and releases any resources.
|
||||
func (sfw *stdFileWriter) Close(ctx context.Context) error {
|
||||
if err := sfw.closeActiveFile(); err != nil {
|
||||
return fmt.Errorf("failed to close active file %s : %w", sfw.activeFile.Name(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
89
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/mount.go
generated
vendored
Normal file
89
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/mount.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
||||
cimfs "github.com/Microsoft/hcsshim/pkg/cimfs"
|
||||
)
|
||||
|
||||
// a cache of cim layer to its mounted volume - The mount manager plugin currently doesn't have an option of
|
||||
// querying a mounted cim to get the volume at which it is mounted, so we maintain a cache of that here
|
||||
var (
|
||||
cimMounts map[string]string = make(map[string]string)
|
||||
cimMountMapLock sync.Mutex
|
||||
// A random GUID used as a namespace for generating cim mount volume GUIDs: 6827367b-c388-4e9b-95ec-961c6d2c936c
|
||||
cimMountNamespace guid.GUID = guid.GUID{Data1: 0x6827367b, Data2: 0xc388, Data3: 0x4e9b, Data4: [8]byte{0x96, 0x1c, 0x6d, 0x2c, 0x93, 0x6c}}
|
||||
)
|
||||
|
||||
// MountCimLayer mounts the cim at path `cimPath` and returns the mount location of that cim. This method
|
||||
// uses the `CimMountFlagCacheFiles` mount flag when mounting the cim. The containerID is used to generated
|
||||
// the volumeID for the volume at which this CIM is mounted. containerID is used so that if the shim process
|
||||
// crashes for any reason, the mounted cim can be correctly cleaned up during `shim delete` call.
|
||||
func MountCimLayer(ctx context.Context, cimPath, containerID string) (string, error) {
|
||||
volumeGUID, err := guid.NewV5(cimMountNamespace, []byte(containerID))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generated cim mount GUID: %w", err)
|
||||
}
|
||||
|
||||
vol, err := cimfs.Mount(cimPath, volumeGUID, hcsschema.CimMountFlagCacheFiles)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cimMountMapLock.Lock()
|
||||
defer cimMountMapLock.Unlock()
|
||||
cimMounts[fmt.Sprintf("%s_%s", containerID, cimPath)] = vol
|
||||
|
||||
return vol, nil
|
||||
}
|
||||
|
||||
// Unmount unmounts the cim at mounted for given container.
|
||||
func UnmountCimLayer(ctx context.Context, cimPath, containerID string) error {
|
||||
cimMountMapLock.Lock()
|
||||
defer cimMountMapLock.Unlock()
|
||||
if vol, ok := cimMounts[fmt.Sprintf("%s_%s", containerID, cimPath)]; !ok {
|
||||
return fmt.Errorf("cim %s not mounted", cimPath)
|
||||
} else {
|
||||
delete(cimMounts, fmt.Sprintf("%s_%s", containerID, cimPath))
|
||||
err := cimfs.Unmount(vol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCimMountPath returns the volume at which a cim is mounted. If the cim is not mounted returns error
|
||||
func GetCimMountPath(cimPath, containerID string) (string, error) {
|
||||
cimMountMapLock.Lock()
|
||||
defer cimMountMapLock.Unlock()
|
||||
|
||||
if vol, ok := cimMounts[fmt.Sprintf("%s_%s", containerID, cimPath)]; !ok {
|
||||
return "", fmt.Errorf("cim %s not mounted", cimPath)
|
||||
} else {
|
||||
return vol, nil
|
||||
}
|
||||
}
|
||||
|
||||
func CleanupContainerMounts(containerID string) error {
|
||||
volumeGUID, err := guid.NewV5(cimMountNamespace, []byte(containerID))
|
||||
if err != nil {
|
||||
return fmt.Errorf("generated cim mount GUID: %w", err)
|
||||
}
|
||||
|
||||
volPath := fmt.Sprintf("\\\\?\\Volume{%s}\\", volumeGUID.String())
|
||||
if _, err := os.Stat(volPath); err == nil {
|
||||
err = cimfs.Unmount(volPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
68
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/pending.go
generated
vendored
Normal file
68
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/pending.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
"github.com/Microsoft/hcsshim/pkg/cimfs"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type pendingCimOp interface {
|
||||
apply(cw *cimfs.CimFsWriter) error
|
||||
}
|
||||
|
||||
// add op represents a pending operation of adding a new file inside the cim
|
||||
type addOp struct {
|
||||
// path inside the cim at which the file should be added
|
||||
pathInCim string
|
||||
// host path where this file was temporarily written.
|
||||
hostPath string
|
||||
// other file metadata fields that were provided during the add call.
|
||||
fileInfo *winio.FileBasicInfo
|
||||
securityDescriptor []byte
|
||||
extendedAttributes []byte
|
||||
reparseData []byte
|
||||
}
|
||||
|
||||
func (o *addOp) apply(cw *cimfs.CimFsWriter) error {
|
||||
f, err := os.Open(o.hostPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open file %s: %w", o.hostPath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fs, err := f.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("stat file %s: %w", o.hostPath, err)
|
||||
}
|
||||
|
||||
if err := cw.AddFile(o.pathInCim, o.fileInfo, fs.Size(), o.securityDescriptor, o.extendedAttributes, o.reparseData); err != nil {
|
||||
return fmt.Errorf("cim add file %s: %w", o.hostPath, err)
|
||||
}
|
||||
|
||||
if o.fileInfo.FileAttributes != windows.FILE_ATTRIBUTE_DIRECTORY {
|
||||
written, err := io.Copy(cw, f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("write file %s inside cim: %w", o.hostPath, err)
|
||||
} else if written != fs.Size() {
|
||||
return fmt.Errorf("short write to cim for file %s, expected %d bytes wrote %d", o.hostPath, fs.Size(), written)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// linkOp represents a pending link file operation inside the cim
|
||||
type linkOp struct {
|
||||
// old & new paths inside the cim where the link should be created
|
||||
oldPath string
|
||||
newPath string
|
||||
}
|
||||
|
||||
func (o *linkOp) apply(cw *cimfs.CimFsWriter) error {
|
||||
return cw.AddLink(o.oldPath, o.newPath)
|
||||
}
|
||||
293
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/process.go
generated
vendored
Normal file
293
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/process.go
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
"github.com/Microsoft/go-winio/vhd"
|
||||
"github.com/Microsoft/hcsshim/computestorage"
|
||||
"github.com/Microsoft/hcsshim/internal/memory"
|
||||
"github.com/Microsoft/hcsshim/internal/security"
|
||||
"github.com/Microsoft/hcsshim/internal/vhdx"
|
||||
"github.com/Microsoft/hcsshim/internal/wclayer"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const defaultVHDXBlockSizeInMB = 1
|
||||
|
||||
func createContainerBaseLayerVHDs(ctx context.Context, layerPath string) (err error) {
|
||||
baseVhdPath := filepath.Join(layerPath, wclayer.ContainerBaseVhd)
|
||||
diffVhdPath := filepath.Join(layerPath, wclayer.ContainerScratchVhd)
|
||||
defaultVhdSize := uint64(20)
|
||||
|
||||
if _, err := os.Stat(baseVhdPath); err == nil {
|
||||
if err := os.RemoveAll(baseVhdPath); err != nil {
|
||||
return fmt.Errorf("failed to remove base vhdx path: %w", err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(diffVhdPath); err == nil {
|
||||
if err := os.RemoveAll(diffVhdPath); err != nil {
|
||||
return fmt.Errorf("failed to remove differencing vhdx: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
createParams := &vhd.CreateVirtualDiskParameters{
|
||||
Version: 2,
|
||||
Version2: vhd.CreateVersion2{
|
||||
MaximumSize: defaultVhdSize * memory.GiB,
|
||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
|
||||
},
|
||||
}
|
||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create vhdx: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
os.RemoveAll(baseVhdPath)
|
||||
os.RemoveAll(diffVhdPath)
|
||||
}
|
||||
}()
|
||||
|
||||
err = computestorage.FormatWritableLayerVhd(ctx, windows.Handle(handle))
|
||||
// we always wanna close the handle whether format succeeds for not.
|
||||
closeErr := syscall.CloseHandle(handle)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if closeErr != nil {
|
||||
return fmt.Errorf("failed to close vhdx handle: %w", closeErr)
|
||||
}
|
||||
|
||||
// Create the differencing disk that will be what's copied for the final rw layer
|
||||
// for a container.
|
||||
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
|
||||
return fmt.Errorf("failed to create differencing disk: %w", err)
|
||||
}
|
||||
|
||||
if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
|
||||
return fmt.Errorf("failed to grant vm group access to %s: %w", baseVhdPath, err)
|
||||
}
|
||||
if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
|
||||
return fmt.Errorf("failed to grant vm group access to %s: %w", diffVhdPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processUtilityVMLayer is similar to createContainerBaseLayerVHDs but along with the scratch creation it
|
||||
// also does some BCD modifications to allow the UVM to boot from the CIM. It expects that the UVM BCD file is
|
||||
// present at layerPath/`wclayer.BcdFilePath` and a UVM SYSTEM hive is present at
|
||||
// layerPath/UtilityVM/`wclayer.RegFilesPath`/SYSTEM. The scratch VHDs are created under the `layerPath`
|
||||
// directory.
|
||||
func processUtilityVMLayer(ctx context.Context, layerPath string) error {
|
||||
// func createUtilityVMLayerVHDs(ctx context.Context, layerPath string) error {
|
||||
baseVhdPath := filepath.Join(layerPath, wclayer.UtilityVMPath, wclayer.UtilityVMBaseVhd)
|
||||
diffVhdPath := filepath.Join(layerPath, wclayer.UtilityVMPath, wclayer.UtilityVMScratchVhd)
|
||||
defaultVhdSize := uint64(10)
|
||||
|
||||
// Just create the vhdx for utilityVM layer, no need to format it.
|
||||
createParams := &vhd.CreateVirtualDiskParameters{
|
||||
Version: 2,
|
||||
Version2: vhd.CreateVersion2{
|
||||
MaximumSize: defaultVhdSize * memory.GiB,
|
||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
|
||||
},
|
||||
}
|
||||
|
||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create vhdx: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
os.RemoveAll(baseVhdPath)
|
||||
os.RemoveAll(diffVhdPath)
|
||||
}
|
||||
}()
|
||||
|
||||
err = computestorage.FormatWritableLayerVhd(ctx, windows.Handle(handle))
|
||||
closeErr := syscall.CloseHandle(handle)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if closeErr != nil {
|
||||
return fmt.Errorf("failed to close vhdx handle: %w", closeErr)
|
||||
}
|
||||
|
||||
partitionInfo, err := vhdx.GetScratchVhdPartitionInfo(ctx, baseVhdPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get base vhd layout info: %w", err)
|
||||
}
|
||||
// relativeCimPath needs to be the cim path relative to the snapshots directory. The snapshots
|
||||
// directory is shared inside the UVM over VSMB, so during the UVM boot this relative path will be
|
||||
// used to find the cim file under that VSMB share.
|
||||
relativeCimPath := filepath.Join(filepath.Base(GetCimDirFromLayer(layerPath)), GetCimNameFromLayer(layerPath))
|
||||
bcdPath := filepath.Join(layerPath, bcdFilePath)
|
||||
if err = updateBcdStoreForBoot(bcdPath, relativeCimPath, partitionInfo.DiskID, partitionInfo.PartitionID); err != nil {
|
||||
return fmt.Errorf("failed to update BCD: %w", err)
|
||||
}
|
||||
|
||||
if err := enableCimBoot(filepath.Join(layerPath, wclayer.UtilityVMPath, wclayer.RegFilesPath, "SYSTEM")); err != nil {
|
||||
return fmt.Errorf("failed to setup cim image for uvm boot: %w", err)
|
||||
}
|
||||
|
||||
// Note: diff vhd creation and granting of vm group access must be done AFTER
|
||||
// getting the partition info of the base VHD. Otherwise it causes the vhd parent
|
||||
// chain to get corrupted.
|
||||
// TODO(ambarve): figure out why this happens so that bcd update can be moved to a separate function
|
||||
|
||||
// Create the differencing disk that will be what's copied for the final rw layer
|
||||
// for a container.
|
||||
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
|
||||
return fmt.Errorf("failed to create differencing disk: %w", err)
|
||||
}
|
||||
|
||||
if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
|
||||
return fmt.Errorf("failed to grant vm group access to %s: %w", baseVhdPath, err)
|
||||
}
|
||||
if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
|
||||
return fmt.Errorf("failed to grant vm group access to %s: %w", diffVhdPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processBaseLayerHives make the base layer specific modifications on the hives and emits equivalent the
|
||||
// pendingCimOps that should be applied on the CIM. In base layer we need to create hard links from registry
|
||||
// hives under Files/Windows/Sysetm32/config into Hives/*_BASE. This function creates these links outside so
|
||||
// that the registry hives under Hives/ are available during children layers import. Then we write these hive
|
||||
// files inside the cim and create links inside the cim.
|
||||
func processBaseLayerHives(layerPath string) ([]pendingCimOp, error) {
|
||||
pendingOps := []pendingCimOp{}
|
||||
|
||||
// make hives directory both outside and in the cim
|
||||
if err := os.Mkdir(filepath.Join(layerPath, wclayer.HivesPath), 0755); err != nil {
|
||||
return pendingOps, fmt.Errorf("hives directory creation: %w", err)
|
||||
}
|
||||
|
||||
hivesDirInfo := &winio.FileBasicInfo{
|
||||
CreationTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
LastAccessTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
LastWriteTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
ChangeTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
FileAttributes: windows.FILE_ATTRIBUTE_DIRECTORY,
|
||||
}
|
||||
pendingOps = append(pendingOps, &addOp{
|
||||
pathInCim: wclayer.HivesPath,
|
||||
hostPath: filepath.Join(layerPath, wclayer.HivesPath),
|
||||
fileInfo: hivesDirInfo,
|
||||
})
|
||||
|
||||
// add hard links from base hive files.
|
||||
for _, hv := range hives {
|
||||
oldHivePathRelative := filepath.Join(wclayer.RegFilesPath, hv.name)
|
||||
newHivePathRelative := filepath.Join(wclayer.HivesPath, hv.base)
|
||||
if err := os.Link(filepath.Join(layerPath, oldHivePathRelative), filepath.Join(layerPath, newHivePathRelative)); err != nil {
|
||||
return pendingOps, fmt.Errorf("hive link creation: %w", err)
|
||||
}
|
||||
|
||||
pendingOps = append(pendingOps, &linkOp{
|
||||
oldPath: oldHivePathRelative,
|
||||
newPath: newHivePathRelative,
|
||||
})
|
||||
}
|
||||
return pendingOps, nil
|
||||
}
|
||||
|
||||
// processLayoutFile creates a file named "layout" in the root of the base layer. This allows certain
|
||||
// container startup related functions to understand that the hives are a part of the container rootfs.
|
||||
func processLayoutFile(layerPath string) ([]pendingCimOp, error) {
|
||||
fileContents := "vhd-with-hives\n"
|
||||
if err := os.WriteFile(filepath.Join(layerPath, "layout"), []byte(fileContents), 0755); err != nil {
|
||||
return []pendingCimOp{}, fmt.Errorf("write layout file: %w", err)
|
||||
}
|
||||
|
||||
layoutFileInfo := &winio.FileBasicInfo{
|
||||
CreationTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
LastAccessTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
LastWriteTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
ChangeTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
FileAttributes: windows.FILE_ATTRIBUTE_NORMAL,
|
||||
}
|
||||
|
||||
op := &addOp{
|
||||
pathInCim: "layout",
|
||||
hostPath: filepath.Join(layerPath, "layout"),
|
||||
fileInfo: layoutFileInfo,
|
||||
}
|
||||
return []pendingCimOp{op}, nil
|
||||
}
|
||||
|
||||
// Some of the layer files that are generated during the processBaseLayer call must be added back
|
||||
// inside the cim, some registry file links must be updated. This function takes care of all those
|
||||
// steps. This function opens the cim file for writing and updates it.
|
||||
func (cw *CimLayerWriter) processBaseLayer(ctx context.Context, processUtilityVM bool) (err error) {
|
||||
if err = createContainerBaseLayerVHDs(ctx, cw.path); err != nil {
|
||||
return fmt.Errorf("failed to create container base VHDs: %w", err)
|
||||
}
|
||||
|
||||
if processUtilityVM {
|
||||
if err = processUtilityVMLayer(ctx, cw.path); err != nil {
|
||||
return fmt.Errorf("process utilityVM layer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ops, err := processBaseLayerHives(cw.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cw.pendingOps = append(cw.pendingOps, ops...)
|
||||
|
||||
ops, err = processLayoutFile(cw.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cw.pendingOps = append(cw.pendingOps, ops...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// processNonBaseLayer takes care of the processing required for a non base layer. As of now
|
||||
// the only processing required for non base layer is to merge the delta registry hives of the
|
||||
// non-base layer with it's parent layer.
|
||||
func (cw *CimLayerWriter) processNonBaseLayer(ctx context.Context, processUtilityVM bool) (err error) {
|
||||
for _, hv := range hives {
|
||||
baseHive := filepath.Join(wclayer.HivesPath, hv.base)
|
||||
deltaHive := filepath.Join(wclayer.HivesPath, hv.delta)
|
||||
_, err := os.Stat(filepath.Join(cw.path, deltaHive))
|
||||
// merge with parent layer if delta exists.
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("stat delta hive %s: %w", filepath.Join(cw.path, deltaHive), err)
|
||||
} else if err == nil {
|
||||
// merge base hive of parent layer with the delta hive of this layer and write it as
|
||||
// the base hive of this layer.
|
||||
err = mergeHive(filepath.Join(cw.parentLayerPaths[0], baseHive), filepath.Join(cw.path, deltaHive), filepath.Join(cw.path, baseHive))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// the newly created merged file must be added to the cim
|
||||
cw.pendingOps = append(cw.pendingOps, &addOp{
|
||||
pathInCim: baseHive,
|
||||
hostPath: filepath.Join(cw.path, baseHive),
|
||||
fileInfo: &winio.FileBasicInfo{
|
||||
CreationTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
LastAccessTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
LastWriteTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
ChangeTime: windows.NsecToFiletime(time.Now().UnixNano()),
|
||||
FileAttributes: windows.FILE_ATTRIBUTE_NORMAL,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if processUtilityVM {
|
||||
return processUtilityVMLayer(ctx, cw.path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
172
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/registry.go
generated
vendored
Normal file
172
vendor/github.com/Microsoft/hcsshim/internal/wclayer/cim/registry.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
//go:build windows
|
||||
|
||||
package cim
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/log"
|
||||
"github.com/Microsoft/hcsshim/internal/winapi"
|
||||
"github.com/Microsoft/hcsshim/osversion"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// enableCimBoot Opens the SYSTEM registry hive at path `hivePath` and updates it to include a CIMFS Start
|
||||
// registry key. This prepares the uvm to boot from a cim file if requested. The registry changes required to
|
||||
// actually make the uvm boot from a cim will be added in the uvm config (look at
|
||||
// addBootFromCimRegistryChanges for details). This registry key needs to be available in the early boot
|
||||
// phase and so including it in the uvm config doesn't work.
|
||||
func enableCimBoot(hivePath string) (err error) {
|
||||
dataZero := make([]byte, 4)
|
||||
dataOne := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(dataOne, 1)
|
||||
dataFour := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(dataFour, 4)
|
||||
|
||||
bootGUID, err := windows.UTF16FromString(bootContainerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to encode boot guid to utf16: %w", err)
|
||||
}
|
||||
|
||||
overrideBootPath, err := windows.UTF16FromString("\\Windows\\")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to encode override boot path to utf16: %w", err)
|
||||
}
|
||||
|
||||
regChanges := []struct {
|
||||
keyPath string
|
||||
valueName string
|
||||
valueType winapi.RegType
|
||||
data *byte
|
||||
dataLen uint32
|
||||
}{
|
||||
{"ControlSet001\\Control", "BootContainerGuid", winapi.REG_TYPE_SZ, (*byte)(unsafe.Pointer(&bootGUID[0])), 2 * uint32(len(bootGUID))},
|
||||
{"ControlSet001\\Services\\UnionFS", "Start", winapi.REG_TYPE_DWORD, &dataZero[0], uint32(len(dataZero))},
|
||||
{"ControlSet001\\Services\\wcifs", "Start", winapi.REG_TYPE_DWORD, &dataFour[0], uint32(len(dataZero))},
|
||||
// The bootmgr loads the uvm files from the cim and so uses the relative path `UtilityVM\\Files` inside the cim to access the uvm files. However, once the cim is mounted UnionFS will merge the correct directory (UtilityVM\\Files) of the cim with the scratch and then that point onwards we don't need to use the relative path. Below registry key tells the kernel that the boot path that was provided in BCD should now be overriden with this new path.
|
||||
{"Setup", "BootPathOverride", winapi.REG_TYPE_SZ, (*byte)(unsafe.Pointer(&overrideBootPath[0])), 2 * uint32(len(overrideBootPath))},
|
||||
}
|
||||
|
||||
var storeHandle winapi.ORHKey
|
||||
if err = winapi.OROpenHive(hivePath, &storeHandle); err != nil {
|
||||
return fmt.Errorf("failed to open registry store at %s: %w", hivePath, err)
|
||||
}
|
||||
|
||||
for _, change := range regChanges {
|
||||
var changeKey winapi.ORHKey
|
||||
if err = winapi.ORCreateKey(storeHandle, change.keyPath, 0, 0, 0, &changeKey, nil); err != nil {
|
||||
return fmt.Errorf("failed to open reg key %s: %w", change.keyPath, err)
|
||||
}
|
||||
|
||||
if err = winapi.ORSetValue(changeKey, change.valueName, uint32(change.valueType), change.data, change.dataLen); err != nil {
|
||||
return fmt.Errorf("failed to set value for regkey %s\\%s : %w", change.keyPath, change.valueName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// remove the existing file first
|
||||
if err := os.Remove(hivePath); err != nil {
|
||||
return fmt.Errorf("failed to remove existing registry %s: %w", hivePath, err)
|
||||
}
|
||||
|
||||
if err = winapi.ORSaveHive(winapi.ORHKey(storeHandle), hivePath, uint32(osversion.Get().MajorVersion), uint32(osversion.Get().MinorVersion)); err != nil {
|
||||
return fmt.Errorf("error saving the registry store: %w", err)
|
||||
}
|
||||
|
||||
// close hive irrespective of the errors
|
||||
if err := winapi.ORCloseHive(winapi.ORHKey(storeHandle)); err != nil {
|
||||
return fmt.Errorf("error closing registry store; %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// mergeHive merges the hive located at parentHivePath with the hive located at deltaHivePath and stores
|
||||
// the result into the file at mergedHivePath. If a file already exists at path `mergedHivePath` then it
|
||||
// throws an error.
|
||||
func mergeHive(parentHivePath, deltaHivePath, mergedHivePath string) (err error) {
|
||||
var baseHive, deltaHive, mergedHive winapi.ORHKey
|
||||
if err := winapi.OROpenHive(parentHivePath, &baseHive); err != nil {
|
||||
return fmt.Errorf("failed to open base hive %s: %w", parentHivePath, err)
|
||||
}
|
||||
defer func() {
|
||||
err2 := winapi.ORCloseHive(baseHive)
|
||||
if err == nil {
|
||||
err = errors.Wrap(err2, "failed to close base hive")
|
||||
}
|
||||
}()
|
||||
if err := winapi.OROpenHive(deltaHivePath, &deltaHive); err != nil {
|
||||
return fmt.Errorf("failed to open delta hive %s: %w", deltaHivePath, err)
|
||||
}
|
||||
defer func() {
|
||||
err2 := winapi.ORCloseHive(deltaHive)
|
||||
if err == nil {
|
||||
err = errors.Wrap(err2, "failed to close delta hive")
|
||||
}
|
||||
}()
|
||||
if err := winapi.ORMergeHives([]winapi.ORHKey{baseHive, deltaHive}, &mergedHive); err != nil {
|
||||
return fmt.Errorf("failed to merge hives: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err2 := winapi.ORCloseHive(mergedHive)
|
||||
if err == nil {
|
||||
err = errors.Wrap(err2, "failed to close merged hive")
|
||||
}
|
||||
}()
|
||||
if err := winapi.ORSaveHive(mergedHive, mergedHivePath, uint32(osversion.Get().MajorVersion), uint32(osversion.Get().MinorVersion)); err != nil {
|
||||
return fmt.Errorf("failed to save hive: %w", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getOsBuildNumberFromRegistry fetches the "CurrentBuild" value at path
|
||||
// "Microsoft\Windows NT\CurrentVersion" from the SOFTWARE registry hive at path
|
||||
// `regHivePath`. This is used to detect the build version of the uvm.
|
||||
func getOsBuildNumberFromRegistry(regHivePath string) (_ string, err error) {
|
||||
var storeHandle, keyHandle winapi.ORHKey
|
||||
var dataType, dataLen uint32
|
||||
keyPath := "Microsoft\\Windows NT\\CurrentVersion"
|
||||
valueName := "CurrentBuild"
|
||||
dataLen = 16 // build version string can't be more than 5 wide chars?
|
||||
dataBuf := make([]byte, dataLen)
|
||||
|
||||
if err = winapi.OROpenHive(regHivePath, &storeHandle); err != nil {
|
||||
return "", fmt.Errorf("failed to open registry store at %s: %w", regHivePath, err)
|
||||
}
|
||||
defer func() {
|
||||
if closeErr := winapi.ORCloseHive(storeHandle); closeErr != nil {
|
||||
log.L.WithFields(logrus.Fields{
|
||||
"error": closeErr,
|
||||
"hive": regHivePath,
|
||||
}).Warnf("failed to close hive")
|
||||
}
|
||||
}()
|
||||
|
||||
if err = winapi.OROpenKey(storeHandle, keyPath, &keyHandle); err != nil {
|
||||
return "", fmt.Errorf("failed to open key at %s: %w", keyPath, err)
|
||||
}
|
||||
defer func() {
|
||||
if closeErr := winapi.ORCloseKey(keyHandle); closeErr != nil {
|
||||
log.L.WithFields(logrus.Fields{
|
||||
"error": closeErr,
|
||||
"hive": regHivePath,
|
||||
"key": keyPath,
|
||||
"value": valueName,
|
||||
}).Warnf("failed to close hive key")
|
||||
}
|
||||
}()
|
||||
|
||||
if err = winapi.ORGetValue(keyHandle, "", valueName, &dataType, &dataBuf[0], &dataLen); err != nil {
|
||||
return "", fmt.Errorf("failed to get value of %s: %w", valueName, err)
|
||||
}
|
||||
|
||||
if dataType != uint32(winapi.REG_TYPE_SZ) {
|
||||
return "", fmt.Errorf("unexpected build number data type (%d)", dataType)
|
||||
}
|
||||
|
||||
return winapi.ParseUtf16LE(dataBuf[:(dataLen - 2)]), nil
|
||||
}
|
||||
2
vendor/github.com/Microsoft/hcsshim/internal/wclayer/converttobaselayer.go
generated
vendored
2
vendor/github.com/Microsoft/hcsshim/internal/wclayer/converttobaselayer.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package wclayer
|
||||
|
||||
import (
|
||||
|
||||
18
vendor/github.com/Microsoft/hcsshim/internal/wclayer/expandscratchsize.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/wclayer/expandscratchsize.go
generated
vendored
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/Microsoft/hcsshim/osversion"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -30,14 +29,17 @@ func ExpandScratchSize(ctx context.Context, path string, size uint64) (err error
|
||||
return hcserror.New(err, title, "")
|
||||
}
|
||||
|
||||
// Manually expand the volume now in order to work around bugs in 19H1 and
|
||||
// prerelease versions of Vb. Remove once this is fixed in Windows.
|
||||
if build := osversion.Build(); build >= osversion.V19H1 && build < 19020 {
|
||||
err = expandSandboxVolume(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Always expand the volume too. In case of legacy layers not expanding the volume here works because
|
||||
// the PrepareLayer call internally handles the expansion. However, in other cases (like CimFS) we
|
||||
// don't call PrepareLayer and so the volume will never be expanded. This also means in case of
|
||||
// legacy layers, we might have a small perf hit because the VHD is mounted twice for expansion (once
|
||||
// here and once during the PrepareLayer call). But as long as the perf hit is minimal, we should be
|
||||
// okay.
|
||||
err = expandSandboxVolume(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
8
vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go
generated
vendored
8
vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go
generated
vendored
@@ -154,7 +154,7 @@ func (r *legacyLayerReader) walkUntilCancelled() error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err == errorIterationCanceled {
|
||||
if err == errorIterationCanceled { //nolint:errorlint // explicitly returned
|
||||
return nil
|
||||
}
|
||||
if err == nil {
|
||||
@@ -196,7 +196,7 @@ func findBackupStreamSize(r io.Reader) (int64, error) {
|
||||
for {
|
||||
hdr, err := br.Next()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
err = nil
|
||||
}
|
||||
return 0, err
|
||||
@@ -428,7 +428,7 @@ func (w *legacyLayerWriter) initUtilityVM() error {
|
||||
// immutable.
|
||||
err = cloneTree(w.parentRoots[0], w.destRoot, UtilityVMFilesPath, mutatedUtilityVMFiles)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloning the parent utility VM image failed: %s", err)
|
||||
return fmt.Errorf("cloning the parent utility VM image failed: %w", err)
|
||||
}
|
||||
w.HasUtilityVM = true
|
||||
}
|
||||
@@ -451,7 +451,7 @@ func (w *legacyLayerWriter) reset() error {
|
||||
|
||||
for {
|
||||
bhdr, err := br.Next()
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// end of backupstream data
|
||||
break
|
||||
}
|
||||
|
||||
4
vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs.go
generated
vendored
4
vendor/github.com/Microsoft/hcsshim/internal/winapi/cimfs.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package winapi
|
||||
|
||||
import (
|
||||
@@ -34,7 +36,7 @@ type CimFsFileMetadata struct {
|
||||
//sys CimDismountImage(volumeID *g) (hr error) = cimfs.CimDismountImage?
|
||||
|
||||
//sys CimCreateImage(imagePath string, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimfs.CimCreateImage?
|
||||
//sys CimCloseImage(cimFSHandle FsHandle) (hr error) = cimfs.CimCloseImage?
|
||||
//sys CimCloseImage(cimFSHandle FsHandle) = cimfs.CimCloseImage?
|
||||
//sys CimCommitImage(cimFSHandle FsHandle) (hr error) = cimfs.CimCommitImage?
|
||||
|
||||
//sys CimCreateFile(cimFSHandle FsHandle, path string, file *CimFsFileMetadata, cimStreamHandle *StreamHandle) (hr error) = cimfs.CimCreateFile?
|
||||
|
||||
14
vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go
generated
vendored
@@ -184,18 +184,12 @@ func _CMLocateDevNode(pdnDevInst *uint32, pDeviceID *uint16, uFlags uint32) (hr
|
||||
return
|
||||
}
|
||||
|
||||
func CimCloseImage(cimFSHandle FsHandle) (hr error) {
|
||||
hr = procCimCloseImage.Find()
|
||||
if hr != nil {
|
||||
func CimCloseImage(cimFSHandle FsHandle) (err error) {
|
||||
err = procCimCloseImage.Find()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procCimCloseImage.Addr(), 1, uintptr(cimFSHandle), 0, 0)
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
syscall.Syscall(procCimCloseImage.Addr(), 1, uintptr(cimFSHandle), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user