go.mod: github.com/Microsoft/hcsshim v0.10.0-rc.7

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2023-03-07 21:48:06 +09:00
parent c77ddf5381
commit da1ffdd757
No known key found for this signature in database
GPG Key ID: 49524C6F9F638F1A
17 changed files with 483 additions and 12 deletions

2
go.mod
View File

@ -6,7 +6,7 @@ require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652 github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652
github.com/Microsoft/go-winio v0.6.0 github.com/Microsoft/go-winio v0.6.0
github.com/Microsoft/hcsshim v0.10.0-rc.5 github.com/Microsoft/hcsshim v0.10.0-rc.7
github.com/container-orchestrated-devices/container-device-interface v0.5.4 github.com/container-orchestrated-devices/container-device-interface v0.5.4
github.com/containerd/aufs v1.0.0 github.com/containerd/aufs v1.0.0
github.com/containerd/btrfs/v2 v2.0.0 github.com/containerd/btrfs/v2 v2.0.0

4
go.sum
View File

@ -89,8 +89,8 @@ github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwT
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.10.0-rc.5 h1:JfkknPHBtfdC2Ezd+jpl8Kicw7UyhvUSzoy6xsqirwY= github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8=
github.com/Microsoft/hcsshim v0.10.0-rc.5/go.mod h1:NNb9uh/cgA52AVhc9+Y7U+YyHQS9nHHA4STcAjdg2xk= github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=

View File

@ -4,7 +4,7 @@ go 1.19
require ( require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1
github.com/Microsoft/hcsshim v0.10.0-rc.5 github.com/Microsoft/hcsshim v0.10.0-rc.7
github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1 github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1
github.com/containerd/cgroups/v3 v3.0.0 github.com/containerd/cgroups/v3 v3.0.0
github.com/containerd/containerd v1.7.0-beta.0 // see replace; the actual version of containerd is replaced with the code at the root of this repository github.com/containerd/containerd v1.7.0-beta.0 // see replace; the actual version of containerd is replaced with the code at the root of this repository

View File

@ -408,8 +408,8 @@ github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2B
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.10.0-rc.5 h1:JfkknPHBtfdC2Ezd+jpl8Kicw7UyhvUSzoy6xsqirwY= github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8=
github.com/Microsoft/hcsshim v0.10.0-rc.5/go.mod h1:NNb9uh/cgA52AVhc9+Y7U+YyHQS9nHHA4STcAjdg2xk= github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE=
github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1 h1:pVKfKyPkXna29XlGjxSr9J0A7vNucOUHZ/2ClcTWalw= github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1 h1:pVKfKyPkXna29XlGjxSr9J0A7vNucOUHZ/2ClcTWalw=
github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1/go.mod h1:Cmvnhlie15Ha2UYrJs9EhgSx76Bq9RV2FgfEiT78GhI= github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1/go.mod h1:Cmvnhlie15Ha2UYrJs9EhgSx76Bq9RV2FgfEiT78GhI=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=

View File

@ -99,8 +99,10 @@ func MerkleTree(r io.Reader) ([]byte, error) {
nextLevel.Write(h) nextLevel.Write(h)
} }
padding := bytes.Repeat([]byte{0}, blockSize-(nextLevel.Len()%blockSize)) if nextLevel.Len()%blockSize != 0 {
nextLevel.Write(padding) padding := bytes.Repeat([]byte{0}, blockSize-(nextLevel.Len()%blockSize))
nextLevel.Write(padding)
}
layers = append(layers, nextLevel.Bytes()) layers = append(layers, nextLevel.Bytes())
currentLevel = bufio.NewReaderSize(nextLevel, MerkleTreeBufioSize) currentLevel = bufio.NewReaderSize(nextLevel, MerkleTreeBufioSize)

View File

@ -249,6 +249,7 @@ func ConvertAndComputeRootDigest(r io.Reader) (string, error) {
defer func() { defer func() {
_ = os.Remove(out.Name()) _ = os.Remove(out.Name())
}() }()
defer out.Close()
options := []Option{ options := []Option{
ConvertWhiteout, ConvertWhiteout,

View File

@ -0,0 +1,216 @@
package wclayer
import (
"errors"
"io"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/longpath"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
type baseLayerReader struct {
s *trace.Span
root string
result chan *fileEntry
proceed chan bool
currentFile *os.File
backupReader *winio.BackupFileReader
}
func newBaseLayerReader(root string, s *trace.Span) (r *baseLayerReader) {
r = &baseLayerReader{
s: s,
root: root,
result: make(chan *fileEntry),
proceed: make(chan bool),
}
go r.walk()
return r
}
func (r *baseLayerReader) walkUntilCancelled() error {
root, err := longpath.LongAbs(r.root)
if err != nil {
return err
}
r.root = root
err = filepath.Walk(filepath.Join(r.root, filesPath), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Indirect fix for https://github.com/moby/moby/issues/32838#issuecomment-343610048.
// Handle failure from what may be a golang bug in the conversion of
// UTF16 to UTF8 in files which are left in the recycle bin. Os.Lstat
// which is called by filepath.Walk will fail when a filename contains
// unicode characters. Skip the recycle bin regardless which is goodness.
if strings.EqualFold(path, filepath.Join(r.root, `Files\$Recycle.Bin`)) && info.IsDir() {
return filepath.SkipDir
}
r.result <- &fileEntry{path, info, nil}
if !<-r.proceed {
return errorIterationCanceled
}
return nil
})
if err == errorIterationCanceled {
return nil
}
if err != nil {
return err
}
utilityVMAbsPath := filepath.Join(r.root, utilityVMPath)
utilityVMFilesAbsPath := filepath.Join(r.root, utilityVMFilesPath)
// Ignore a UtilityVM without Files, that's not _really_ a UtiltyVM
if _, err = os.Lstat(utilityVMFilesAbsPath); err != nil {
if os.IsNotExist(err) {
return io.EOF
}
return err
}
err = filepath.Walk(utilityVMAbsPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path != utilityVMAbsPath && path != utilityVMFilesAbsPath && !hasPathPrefix(path, utilityVMFilesAbsPath) {
if info.IsDir() {
return filepath.SkipDir
}
return nil
}
r.result <- &fileEntry{path, info, nil}
if !<-r.proceed {
return errorIterationCanceled
}
return nil
})
if err == errorIterationCanceled {
return nil
}
if err != nil {
return err
}
return io.EOF
}
func (r *baseLayerReader) walk() {
defer close(r.result)
if !<-r.proceed {
return
}
err := r.walkUntilCancelled()
if err != nil {
for {
r.result <- &fileEntry{err: err}
if !<-r.proceed {
return
}
}
}
}
func (r *baseLayerReader) reset() {
if r.backupReader != nil {
r.backupReader.Close()
r.backupReader = nil
}
if r.currentFile != nil {
r.currentFile.Close()
r.currentFile = nil
}
}
func (r *baseLayerReader) Next() (path string, size int64, fileInfo *winio.FileBasicInfo, err error) {
r.reset()
r.proceed <- true
fe := <-r.result
if fe == nil {
err = errors.New("BaseLayerReader closed")
return
}
if fe.err != nil {
err = fe.err
return
}
path, err = filepath.Rel(r.root, fe.path)
if err != nil {
return
}
f, err := openFileOrDir(fe.path, syscall.GENERIC_READ, syscall.OPEN_EXISTING)
if err != nil {
return
}
defer func() {
if f != nil {
f.Close()
}
}()
fileInfo, err = winio.GetFileBasicInfo(f)
if err != nil {
return
}
size = fe.fi.Size()
r.backupReader = winio.NewBackupFileReader(f, true)
r.currentFile = f
f = nil
return
}
func (r *baseLayerReader) LinkInfo() (uint32, *winio.FileIDInfo, error) {
fileStandardInfo, err := winio.GetFileStandardInfo(r.currentFile)
if err != nil {
return 0, nil, err
}
fileIDInfo, err := winio.GetFileID(r.currentFile)
if err != nil {
return 0, nil, err
}
return fileStandardInfo.NumberOfLinks, fileIDInfo, nil
}
func (r *baseLayerReader) Read(b []byte) (int, error) {
if r.backupReader == nil {
return 0, io.EOF
}
return r.backupReader.Read(b)
}
func (r *baseLayerReader) Close() (err error) {
defer r.s.End()
defer func() {
oc.SetSpanStatus(r.s, err)
close(r.proceed)
}()
r.proceed <- false
// The r.result channel will be closed once walk() returns
<-r.result
r.reset()
return nil
}

View File

@ -0,0 +1,158 @@
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
}

View File

@ -45,6 +45,8 @@ func ExportLayer(ctx context.Context, path string, exportFolderPath string, pare
type LayerReader interface { type LayerReader interface {
// Next advances to the next file and returns the name, size, and file info // Next advances to the next file and returns the name, size, and file info
Next() (string, int64, *winio.FileBasicInfo, error) Next() (string, int64, *winio.FileBasicInfo, error)
// LinkInfo returns the number of links and the file identifier for the current file.
LinkInfo() (uint32, *winio.FileIDInfo, error)
// Read reads data from the current file, in the format of a Win32 backup stream, and // Read reads data from the current file, in the format of a Win32 backup stream, and
// returns the number of bytes read. // returns the number of bytes read.
Read(b []byte) (int, error) Read(b []byte) (int, error)
@ -67,6 +69,11 @@ func NewLayerReader(ctx context.Context, path string, parentLayerPaths []string)
trace.StringAttribute("path", path), trace.StringAttribute("path", path),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", "))) trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
if len(parentLayerPaths) == 0 {
// This is a base layer. It gets exported differently.
return newBaseLayerReader(path, span), nil
}
exportPath, err := os.MkdirTemp("", "hcs") exportPath, err := os.MkdirTemp("", "hcs")
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -294,6 +294,18 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil
return return
} }
func (r *legacyLayerReader) LinkInfo() (uint32, *winio.FileIDInfo, error) {
fileStandardInfo, err := winio.GetFileStandardInfo(r.currentFile)
if err != nil {
return 0, nil, err
}
fileIDInfo, err := winio.GetFileID(r.currentFile)
if err != nil {
return 0, nil, err
}
return fileStandardInfo.NumberOfLinks, fileIDInfo, nil
}
func (r *legacyLayerReader) Read(b []byte) (int, error) { func (r *legacyLayerReader) Read(b []byte) (int, error) {
if r.backupReader == nil { if r.backupReader == nil {
if r.currentFile == nil { if r.currentFile == nil {

View File

@ -0,0 +1,5 @@
package winapi
//sys ORCreateHive(key *syscall.Handle) (regerrno error) = offreg.ORCreateHive
//sys ORSaveHive(key syscall.Handle, file string, OsMajorVersion uint32, OsMinorVersion uint32) (regerrno error) = offreg.ORSaveHive
//sys ORCloseHive(key syscall.Handle) (regerrno error) = offreg.ORCloseHive

View File

@ -47,6 +47,7 @@ var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modnetapi32 = windows.NewLazySystemDLL("netapi32.dll") modnetapi32 = windows.NewLazySystemDLL("netapi32.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll") modntdll = windows.NewLazySystemDLL("ntdll.dll")
modoffreg = windows.NewLazySystemDLL("offreg.dll")
procLogonUserW = modadvapi32.NewProc("LogonUserW") procLogonUserW = modadvapi32.NewProc("LogonUserW")
procBfSetupFilter = modbindfltapi.NewProc("BfSetupFilter") procBfSetupFilter = modbindfltapi.NewProc("BfSetupFilter")
@ -82,6 +83,9 @@ var (
procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation") procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation")
procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
procRtlNtStatusToDosError = modntdll.NewProc("RtlNtStatusToDosError") procRtlNtStatusToDosError = modntdll.NewProc("RtlNtStatusToDosError")
procORCloseHive = modoffreg.NewProc("ORCloseHive")
procORCreateHive = modoffreg.NewProc("ORCreateHive")
procORSaveHive = modoffreg.NewProc("ORSaveHive")
) )
func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) { func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) {
@ -376,3 +380,36 @@ func RtlNtStatusToDosError(status uint32) (winerr error) {
} }
return return
} }
func ORCloseHive(key syscall.Handle) (regerrno error) {
r0, _, _ := syscall.Syscall(procORCloseHive.Addr(), 1, uintptr(key), 0, 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func ORCreateHive(key *syscall.Handle) (regerrno error) {
r0, _, _ := syscall.Syscall(procORCreateHive.Addr(), 1, uintptr(unsafe.Pointer(key)), 0, 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}
func ORSaveHive(key syscall.Handle, file string, OsMajorVersion uint32, OsMinorVersion uint32) (regerrno error) {
var _p0 *uint16
_p0, regerrno = syscall.UTF16PtrFromString(file)
if regerrno != nil {
return
}
return _ORSaveHive(key, _p0, OsMajorVersion, OsMinorVersion)
}
func _ORSaveHive(key syscall.Handle, file *uint16, OsMajorVersion uint32, OsMinorVersion uint32) (regerrno error) {
r0, _, _ := syscall.Syscall6(procORSaveHive.Addr(), 4, uintptr(key), uintptr(unsafe.Pointer(file)), uintptr(OsMajorVersion), uintptr(OsMinorVersion), 0, 0)
if r0 != 0 {
regerrno = syscall.Errno(r0)
}
return
}

View File

@ -70,6 +70,9 @@ func ProcessUtilityVMImage(path string) error {
func UnprepareLayer(info DriverInfo, layerId string) error { func UnprepareLayer(info DriverInfo, layerId string) error {
return wclayer.UnprepareLayer(context.Background(), layerPath(&info, layerId)) return wclayer.UnprepareLayer(context.Background(), layerPath(&info, layerId))
} }
func ConvertToBaseLayer(path string) error {
return wclayer.ConvertToBaseLayer(context.Background(), path)
}
type DriverInfo struct { type DriverInfo struct {
Flavour int Flavour int

View File

@ -1,5 +1,3 @@
//go:build windows
package osversion package osversion
import ( import (
@ -47,6 +45,15 @@ func Build() uint16 {
return Get().Build return Get().Build
} }
func (osv OSVersion) ToString() string { // String returns the OSVersion formatted as a string. It implements the
// [fmt.Stringer] interface.
func (osv OSVersion) String() string {
return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build) return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
} }
// ToString returns the OSVersion formatted as a string.
//
// Deprecated: use [OSVersion.String].
func (osv OSVersion) ToString() string {
return osv.String()
}

View File

@ -51,6 +51,8 @@ func ExportLayerToTar(ctx context.Context, w io.Writer, path string, parentLayer
} }
func writeTarFromLayer(ctx context.Context, r wclayer.LayerReader, w io.Writer) error { func writeTarFromLayer(ctx context.Context, r wclayer.LayerReader, w io.Writer) error {
linkRecords := make(map[[16]byte]string)
t := tar.NewWriter(w) t := tar.NewWriter(w)
for { for {
select { select {
@ -76,6 +78,27 @@ func writeTarFromLayer(ctx context.Context, r wclayer.LayerReader, w io.Writer)
return err return err
} }
} else { } else {
numberOfLinks, fileIDInfo, err := r.LinkInfo()
if err != nil {
return err
}
if numberOfLinks > 1 {
if linkName, ok := linkRecords[fileIDInfo.FileID]; ok {
// We've seen this file before, by another name, so put a hardlink in the tar stream.
hdr := backuptar.BasicInfoHeader(name, 0, fileInfo)
hdr.Mode = 0644
hdr.Typeflag = tar.TypeLink
hdr.Linkname = linkName
if err := t.WriteHeader(hdr); err != nil {
return err
}
continue
}
// All subsequent names for this file will be hard-linked to this name
linkRecords[fileIDInfo.FileID] = filepath.ToSlash(name)
}
err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo) err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
if err != nil { if err != nil {
return err return err

2
vendor/modules.txt vendored
View File

@ -16,7 +16,7 @@ github.com/Microsoft/go-winio/pkg/guid
github.com/Microsoft/go-winio/pkg/security github.com/Microsoft/go-winio/pkg/security
github.com/Microsoft/go-winio/tools/mkwinsyscall github.com/Microsoft/go-winio/tools/mkwinsyscall
github.com/Microsoft/go-winio/vhd github.com/Microsoft/go-winio/vhd
# github.com/Microsoft/hcsshim v0.10.0-rc.5 # github.com/Microsoft/hcsshim v0.10.0-rc.7
## explicit; go 1.18 ## explicit; go 1.18
github.com/Microsoft/hcsshim github.com/Microsoft/hcsshim
github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options