Merge pull request #2322 from darrenstahlmsft/revendorHcsshim

Update hcsshim to v0.6.10
This commit is contained in:
Michael Crosby 2018-05-03 13:10:39 -04:00 committed by GitHub
commit 40c3acd36c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1469 additions and 927 deletions

View File

@ -34,7 +34,7 @@ golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
github.com/Microsoft/go-winio v0.4.5 github.com/Microsoft/go-winio v0.4.5
github.com/Microsoft/hcsshim v0.6.7 github.com/Microsoft/hcsshim v0.6.10
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4

View File

@ -10,7 +10,7 @@ import (
) )
type baseLayerWriter struct { type baseLayerWriter struct {
root string root *os.File
f *os.File f *os.File
bw *winio.BackupFileWriter bw *winio.BackupFileWriter
err error err error
@ -26,10 +26,10 @@ type dirInfo struct {
// reapplyDirectoryTimes reapplies directory modification, creation, etc. times // reapplyDirectoryTimes reapplies directory modification, creation, etc. times
// after processing of the directory tree has completed. The times are expected // after processing of the directory tree has completed. The times are expected
// to be ordered such that parent directories come before child directories. // to be ordered such that parent directories come before child directories.
func reapplyDirectoryTimes(dis []dirInfo) error { func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
for i := range dis { for i := range dis {
di := &dis[len(dis)-i-1] // reverse order: process child directories first di := &dis[len(dis)-i-1] // reverse order: process child directories first
f, err := winio.OpenForBackup(di.path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) f, err := openRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, _FILE_OPEN, _FILE_DIRECTORY_FILE)
if err != nil { if err != nil {
return err return err
} }
@ -75,12 +75,6 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
w.hasUtilityVM = true w.hasUtilityVM = true
} }
path := filepath.Join(w.root, name)
path, err = makeLongAbsPath(path)
if err != nil {
return err
}
var f *os.File var f *os.File
defer func() { defer func() {
if f != nil { if f != nil {
@ -88,27 +82,23 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
} }
}() }()
createmode := uint32(syscall.CREATE_NEW) extraFlags := uint32(0)
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
err := os.Mkdir(path, 0) extraFlags |= _FILE_DIRECTORY_FILE
if err != nil && !os.IsExist(err) {
return err
}
createmode = syscall.OPEN_EXISTING
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
w.dirInfo = append(w.dirInfo, dirInfo{path, *fileInfo}) w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
} }
} }
mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY) mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode) f, err = openRelative(name, w.root, mode, syscall.FILE_SHARE_READ, _FILE_CREATE, extraFlags)
if err != nil { if err != nil {
return makeError(err, "Failed to OpenForBackup", path) return makeError(err, "Failed to openRelative", name)
} }
err = winio.SetFileBasicInfo(f, fileInfo) err = winio.SetFileBasicInfo(f, fileInfo)
if err != nil { if err != nil {
return makeError(err, "Failed to SetFileBasicInfo", path) return makeError(err, "Failed to SetFileBasicInfo", name)
} }
w.f = f w.f = f
@ -129,17 +119,7 @@ func (w *baseLayerWriter) AddLink(name string, target string) (err error) {
return err return err
} }
linkpath, err := makeLongAbsPath(filepath.Join(w.root, name)) return linkRelative(target, w.root, name, w.root)
if err != nil {
return err
}
linktarget, err := makeLongAbsPath(filepath.Join(w.root, target))
if err != nil {
return err
}
return os.Link(linktarget, linkpath)
} }
func (w *baseLayerWriter) Remove(name string) error { func (w *baseLayerWriter) Remove(name string) error {
@ -155,6 +135,10 @@ func (w *baseLayerWriter) Write(b []byte) (int, error) {
} }
func (w *baseLayerWriter) Close() error { func (w *baseLayerWriter) Close() error {
defer func() {
w.root.Close()
w.root = nil
}()
err := w.closeCurrentFile() err := w.closeCurrentFile()
if err != nil { if err != nil {
return err return err
@ -162,18 +146,22 @@ func (w *baseLayerWriter) Close() error {
if w.err == nil { if w.err == nil {
// Restore the file times of all the directories, since they may have // Restore the file times of all the directories, since they may have
// been modified by creating child directories. // been modified by creating child directories.
err = reapplyDirectoryTimes(w.dirInfo) err = reapplyDirectoryTimes(w.root, w.dirInfo)
if err != nil { if err != nil {
return err return err
} }
err = ProcessBaseLayer(w.root) err = ProcessBaseLayer(w.root.Name())
if err != nil { if err != nil {
return err return err
} }
if w.hasUtilityVM { if w.hasUtilityVM {
err = ProcessUtilityVMImage(filepath.Join(w.root, "UtilityVM")) err := ensureNotReparsePointRelative("UtilityVM", w.root)
if err != nil {
return err
}
err = ProcessUtilityVMImage(filepath.Join(w.root.Name(), "UtilityVM"))
if err != nil { if err != nil {
return err return err
} }

View File

@ -11,7 +11,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go //go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go safeopen.go
//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree //sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId //sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId

View File

@ -129,37 +129,39 @@ type legacyLayerWriterWrapper struct {
} }
func (r *legacyLayerWriterWrapper) Close() error { func (r *legacyLayerWriterWrapper) Close() error {
defer os.RemoveAll(r.root) defer os.RemoveAll(r.root.Name())
defer r.legacyLayerWriter.CloseRoots()
err := r.legacyLayerWriter.Close() err := r.legacyLayerWriter.Close()
if err != nil { if err != nil {
return err return err
} }
// Use the original path here because ImportLayer does not support long paths for the source in TP5.
// But do use a long path for the destination to work around another bug with directories
// with MAX_PATH - 12 < length < MAX_PATH.
info := r.info info := r.info
fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) info.HomeDir = ""
if err != nil { if err = ImportLayer(info, r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
return err return err
} }
for _, name := range r.Tombstones {
info.HomeDir = "" if err = removeRelative(name, r.destRoot); err != nil && !os.IsNotExist(err) {
if err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths); err != nil { return err
return err }
} }
// Add any hard links that were collected. // Add any hard links that were collected.
for _, lnk := range r.PendingLinks { for _, lnk := range r.PendingLinks {
if err = os.Remove(lnk.Path); err != nil && !os.IsNotExist(err) { if err = removeRelative(lnk.Path, r.destRoot); err != nil && !os.IsNotExist(err) {
return err return err
} }
if err = os.Link(lnk.Target, lnk.Path); err != nil { if err = linkRelative(lnk.Target, lnk.TargetRoot, lnk.Path, r.destRoot); err != nil {
return err return err
} }
} }
// Prepare the utility VM for use if one is present in the layer. // Prepare the utility VM for use if one is present in the layer.
if r.HasUtilityVM { if r.HasUtilityVM {
err = ProcessUtilityVMImage(filepath.Join(fullPath, "UtilityVM")) err := ensureNotReparsePointRelative("UtilityVM", r.destRoot)
if err != nil {
return err
}
err = ProcessUtilityVMImage(filepath.Join(r.destRoot.Name(), "UtilityVM"))
if err != nil { if err != nil {
return err return err
} }
@ -173,8 +175,12 @@ func (r *legacyLayerWriterWrapper) Close() error {
func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) { func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) {
if len(parentLayerPaths) == 0 { if len(parentLayerPaths) == 0 {
// This is a base layer. It gets imported differently. // This is a base layer. It gets imported differently.
f, err := openRoot(filepath.Join(info.HomeDir, layerID))
if err != nil {
return nil, err
}
return &baseLayerWriter{ return &baseLayerWriter{
root: filepath.Join(info.HomeDir, layerID), root: f,
}, nil }, nil
} }
@ -185,8 +191,12 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string)
if err != nil { if err != nil {
return nil, err return nil, err
} }
w, err := newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID))
if err != nil {
return nil, err
}
return &legacyLayerWriterWrapper{ return &legacyLayerWriterWrapper{
legacyLayerWriter: newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)), legacyLayerWriter: w,
info: info, info: info,
layerID: layerID, layerID: layerID,
path: path, path: path,

View File

@ -121,6 +121,16 @@ func (r *legacyLayerReader) walkUntilCancelled() error {
if err != nil { if err != nil {
return err 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 path == filepath.Join(r.root, `Files\$Recycle.Bin`) && info.IsDir() {
return filepath.SkipDir
}
if path == r.root || path == filepath.Join(r.root, "tombstones.txt") || strings.HasSuffix(path, ".$wcidirs$") { if path == r.root || path == filepath.Join(r.root, "tombstones.txt") || strings.HasSuffix(path, ".$wcidirs$") {
return nil return nil
} }
@ -326,59 +336,79 @@ func (r *legacyLayerReader) Close() error {
type pendingLink struct { type pendingLink struct {
Path, Target string Path, Target string
TargetRoot *os.File
}
type pendingDir struct {
Path string
Root *os.File
} }
type legacyLayerWriter struct { type legacyLayerWriter struct {
root string root *os.File
parentRoots []string destRoot *os.File
destRoot string parentRoots []*os.File
currentFile *os.File currentFile *os.File
backupWriter *winio.BackupFileWriter currentFileName string
tombstones []string currentFileRoot *os.File
pathFixed bool backupWriter *winio.BackupFileWriter
HasUtilityVM bool Tombstones []string
uvmDi []dirInfo HasUtilityVM bool
addedFiles map[string]bool uvmDi []dirInfo
PendingLinks []pendingLink addedFiles map[string]bool
PendingLinks []pendingLink
pendingDirs []pendingDir
currentIsDir bool
} }
// newLegacyLayerWriter returns a LayerWriter that can write the contaler layer // newLegacyLayerWriter returns a LayerWriter that can write the contaler layer
// transport format to disk. // transport format to disk.
func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) *legacyLayerWriter { func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) (w *legacyLayerWriter, err error) {
return &legacyLayerWriter{ w = &legacyLayerWriter{
root: root, addedFiles: make(map[string]bool),
parentRoots: parentRoots,
destRoot: destRoot,
addedFiles: make(map[string]bool),
} }
defer func() {
if err != nil {
w.CloseRoots()
w = nil
}
}()
w.root, err = openRoot(root)
if err != nil {
return
}
w.destRoot, err = openRoot(destRoot)
if err != nil {
return
}
for _, r := range parentRoots {
f, err := openRoot(r)
if err != nil {
return w, err
}
w.parentRoots = append(w.parentRoots, f)
}
return
} }
func (w *legacyLayerWriter) init() error { func (w *legacyLayerWriter) CloseRoots() {
if !w.pathFixed { if w.root != nil {
path, err := makeLongAbsPath(w.root) w.root.Close()
if err != nil { w.root = nil
return err
}
for i, p := range w.parentRoots {
w.parentRoots[i], err = makeLongAbsPath(p)
if err != nil {
return err
}
}
destPath, err := makeLongAbsPath(w.destRoot)
if err != nil {
return err
}
w.root = path
w.destRoot = destPath
w.pathFixed = true
} }
return nil if w.destRoot != nil {
w.destRoot.Close()
w.destRoot = nil
}
for i := range w.parentRoots {
w.parentRoots[i].Close()
}
w.parentRoots = nil
} }
func (w *legacyLayerWriter) initUtilityVM() error { func (w *legacyLayerWriter) initUtilityVM() error {
if !w.HasUtilityVM { if !w.HasUtilityVM {
err := os.Mkdir(filepath.Join(w.destRoot, utilityVMPath), 0) err := mkdirRelative(utilityVMPath, w.destRoot)
if err != nil { if err != nil {
return err return err
} }
@ -386,7 +416,7 @@ func (w *legacyLayerWriter) initUtilityVM() error {
// clone the utility VM from the parent layer into this layer. Use hard // clone the utility VM from the parent layer into this layer. Use hard
// links to avoid unnecessary copying, since most of the files are // links to avoid unnecessary copying, since most of the files are
// immutable. // immutable.
err = cloneTree(filepath.Join(w.parentRoots[0], utilityVMFilesPath), filepath.Join(w.destRoot, utilityVMFilesPath), mutatedUtilityVMFiles) err = cloneTree(w.parentRoots[0], w.destRoot, utilityVMFilesPath, mutatedUtilityVMFiles)
if err != nil { 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: %s", err)
} }
@ -395,7 +425,40 @@ func (w *legacyLayerWriter) initUtilityVM() error {
return nil return nil
} }
func (w *legacyLayerWriter) reset() { func (w *legacyLayerWriter) reset() error {
if w.currentIsDir {
r := w.currentFile
br := winio.NewBackupStreamReader(r)
// Seek to the beginning of the backup stream, skipping the fileattrs
if _, err := r.Seek(4, io.SeekStart); err != nil {
return err
}
for {
bhdr, err := br.Next()
if err == io.EOF {
// end of backupstream data
break
}
if err != nil {
return err
}
switch bhdr.Id {
case winio.BackupReparseData:
// The current file is a `.$wcidirs$` metadata file that
// describes a directory reparse point. Delete the placeholder
// directory to prevent future files being added into the
// destination of the reparse point during the ImportLayer call
if err := removeRelative(w.currentFileName, w.currentFileRoot); err != nil {
return err
}
w.pendingDirs = append(w.pendingDirs, pendingDir{Path: w.currentFileName, Root: w.currentFileRoot})
default:
// ignore all other stream types, as we only care about directory reparse points
}
}
w.currentIsDir = false
}
if w.backupWriter != nil { if w.backupWriter != nil {
w.backupWriter.Close() w.backupWriter.Close()
w.backupWriter = nil w.backupWriter = nil
@ -403,21 +466,21 @@ func (w *legacyLayerWriter) reset() {
if w.currentFile != nil { if w.currentFile != nil {
w.currentFile.Close() w.currentFile.Close()
w.currentFile = nil w.currentFile = nil
w.currentFileName = ""
w.currentFileRoot = nil
} }
return nil
} }
// copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata // copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata
func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) { func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) {
createDisposition := uint32(syscall.CREATE_NEW) src, err := openRelative(
if isDir { subPath,
err = os.Mkdir(destPath, 0) srcRoot,
if err != nil { syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY,
return nil, err syscall.FILE_SHARE_READ,
} _FILE_OPEN,
createDisposition = syscall.OPEN_EXISTING _FILE_OPEN_REPARSE_POINT)
}
src, err := openFileOrDir(srcPath, syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY, syscall.OPEN_EXISTING)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -430,7 +493,17 @@ func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio
return nil, err return nil, err
} }
dest, err := openFileOrDir(destPath, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition) extraFlags := uint32(0)
if isDir {
extraFlags |= _FILE_DIRECTORY_FILE
}
dest, err := openRelative(
subPath,
destRoot,
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
_FILE_CREATE,
extraFlags)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -459,18 +532,21 @@ func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio
// cloneTree clones a directory tree using hard links. It skips hard links for // cloneTree clones a directory tree using hard links. It skips hard links for
// the file names in the provided map and just copies those files. // the file names in the provided map and just copies those files.
func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error { func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles map[string]bool) error {
var di []dirInfo var di []dirInfo
err := filepath.Walk(srcPath, func(srcFilePath string, info os.FileInfo, err error) error { err := ensureNotReparsePointRelative(subPath, srcRoot)
if err != nil {
return err
}
err = filepath.Walk(filepath.Join(srcRoot.Name(), subPath), func(srcFilePath string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
relPath, err := filepath.Rel(srcPath, srcFilePath) relPath, err := filepath.Rel(srcRoot.Name(), srcFilePath)
if err != nil { if err != nil {
return err return err
} }
destFilePath := filepath.Join(destPath, relPath)
fileAttributes := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes fileAttributes := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes
// Directories, reparse points, and files that will be mutated during // Directories, reparse points, and files that will be mutated during
@ -482,15 +558,15 @@ func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error {
isDir := fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 isDir := fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0
if isDir || isReparsePoint || mutatedFiles[relPath] { if isDir || isReparsePoint || mutatedFiles[relPath] {
fi, err := copyFileWithMetadata(srcFilePath, destFilePath, isDir) fi, err := copyFileWithMetadata(srcRoot, destRoot, relPath, isDir)
if err != nil { if err != nil {
return err return err
} }
if isDir && !isReparsePoint { if isDir && !isReparsePoint {
di = append(di, dirInfo{path: destFilePath, fileInfo: *fi}) di = append(di, dirInfo{path: relPath, fileInfo: *fi})
} }
} else { } else {
err = os.Link(srcFilePath, destFilePath) err = linkRelative(relPath, srcRoot, relPath, destRoot)
if err != nil { if err != nil {
return err return err
} }
@ -508,13 +584,11 @@ func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error {
return err return err
} }
return reapplyDirectoryTimes(di) return reapplyDirectoryTimes(destRoot, di)
} }
func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error { func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
w.reset() if err := w.reset(); err != nil {
err := w.init()
if err != nil {
return err return err
} }
@ -522,6 +596,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return w.initUtilityVM() return w.initUtilityVM()
} }
name = filepath.Clean(name)
if hasPathPrefix(name, utilityVMPath) { if hasPathPrefix(name, utilityVMPath) {
if !w.HasUtilityVM { if !w.HasUtilityVM {
return errors.New("missing UtilityVM directory") return errors.New("missing UtilityVM directory")
@ -529,10 +604,9 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath { if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
return errors.New("invalid UtilityVM layer") return errors.New("invalid UtilityVM layer")
} }
path := filepath.Join(w.destRoot, name) createDisposition := uint32(_FILE_OPEN)
createDisposition := uint32(syscall.OPEN_EXISTING)
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
st, err := os.Lstat(path) st, err := lstatRelative(name, w.destRoot)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return err
} }
@ -540,37 +614,44 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
// Delete the existing file/directory if it is not the same type as this directory. // Delete the existing file/directory if it is not the same type as this directory.
existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes
if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 { if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
if err = os.RemoveAll(path); err != nil { if err = removeAllRelative(name, w.destRoot); err != nil {
return err return err
} }
st = nil st = nil
} }
} }
if st == nil { if st == nil {
if err = os.Mkdir(path, 0); err != nil { if err = mkdirRelative(name, w.destRoot); err != nil {
return err return err
} }
} }
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
w.uvmDi = append(w.uvmDi, dirInfo{path: path, fileInfo: *fileInfo}) w.uvmDi = append(w.uvmDi, dirInfo{path: name, fileInfo: *fileInfo})
} }
} else { } else {
// Overwrite any existing hard link. // Overwrite any existing hard link.
err = os.Remove(path) err := removeRelative(name, w.destRoot)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return err
} }
createDisposition = syscall.CREATE_NEW createDisposition = _FILE_CREATE
} }
f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition) f, err := openRelative(
name,
w.destRoot,
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
createDisposition,
_FILE_OPEN_REPARSE_POINT,
)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
if f != nil { if f != nil {
f.Close() f.Close()
os.Remove(path) removeRelative(name, w.destRoot)
} }
}() }()
@ -581,28 +662,31 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
w.backupWriter = winio.NewBackupFileWriter(f, true) w.backupWriter = winio.NewBackupFileWriter(f, true)
w.currentFile = f w.currentFile = f
w.currentFileName = name
w.currentFileRoot = w.destRoot
w.addedFiles[name] = true w.addedFiles[name] = true
f = nil f = nil
return nil return nil
} }
path := filepath.Join(w.root, name) fname := name
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
err := os.Mkdir(path, 0) err := mkdirRelative(name, w.root)
if err != nil { if err != nil {
return err return err
} }
path += ".$wcidirs$" fname += ".$wcidirs$"
w.currentIsDir = true
} }
f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.CREATE_NEW) f, err := openRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, _FILE_CREATE, 0)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
if f != nil { if f != nil {
f.Close() f.Close()
os.Remove(path) removeRelative(fname, w.root)
} }
}() }()
@ -624,19 +708,20 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
} }
w.currentFile = f w.currentFile = f
w.currentFileName = name
w.currentFileRoot = w.root
w.addedFiles[name] = true w.addedFiles[name] = true
f = nil f = nil
return nil return nil
} }
func (w *legacyLayerWriter) AddLink(name string, target string) error { func (w *legacyLayerWriter) AddLink(name string, target string) error {
w.reset() if err := w.reset(); err != nil {
err := w.init()
if err != nil {
return err return err
} }
var roots []string target = filepath.Clean(target)
var roots []*os.File
if hasPathPrefix(target, filesPath) { if hasPathPrefix(target, filesPath) {
// Look for cross-layer hard link targets in the parent layers, since // Look for cross-layer hard link targets in the parent layers, since
// nothing is in the destination path yet. // nothing is in the destination path yet.
@ -645,7 +730,7 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
// Since the utility VM is fully cloned into the destination path // Since the utility VM is fully cloned into the destination path
// already, look for cross-layer hard link targets directly in the // already, look for cross-layer hard link targets directly in the
// destination path. // destination path.
roots = []string{w.destRoot} roots = []*os.File{w.destRoot}
} }
if roots == nil || (!hasPathPrefix(name, filesPath) && !hasPathPrefix(name, utilityVMFilesPath)) { if roots == nil || (!hasPathPrefix(name, filesPath) && !hasPathPrefix(name, utilityVMFilesPath)) {
@ -654,12 +739,12 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
// Find to try the target of the link in a previously added file. If that // Find to try the target of the link in a previously added file. If that
// fails, search in parent layers. // fails, search in parent layers.
var selectedRoot string var selectedRoot *os.File
if _, ok := w.addedFiles[target]; ok { if _, ok := w.addedFiles[target]; ok {
selectedRoot = w.destRoot selectedRoot = w.destRoot
} else { } else {
for _, r := range roots { for _, r := range roots {
if _, err = os.Lstat(filepath.Join(r, target)); err != nil { if _, err := lstatRelative(target, r); err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return err return err
} }
@ -668,22 +753,25 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
break break
} }
} }
if selectedRoot == "" { if selectedRoot == nil {
return fmt.Errorf("failed to find link target for '%s' -> '%s'", name, target) return fmt.Errorf("failed to find link target for '%s' -> '%s'", name, target)
} }
} }
// The link can't be written until after the ImportLayer call. // The link can't be written until after the ImportLayer call.
w.PendingLinks = append(w.PendingLinks, pendingLink{ w.PendingLinks = append(w.PendingLinks, pendingLink{
Path: filepath.Join(w.destRoot, name), Path: name,
Target: filepath.Join(selectedRoot, target), Target: target,
TargetRoot: selectedRoot,
}) })
w.addedFiles[name] = true w.addedFiles[name] = true
return nil return nil
} }
func (w *legacyLayerWriter) Remove(name string) error { func (w *legacyLayerWriter) Remove(name string) error {
name = filepath.Clean(name)
if hasPathPrefix(name, filesPath) { if hasPathPrefix(name, filesPath) {
w.tombstones = append(w.tombstones, name[len(filesPath)+1:]) w.Tombstones = append(w.Tombstones, name)
} else if hasPathPrefix(name, utilityVMFilesPath) { } else if hasPathPrefix(name, utilityVMFilesPath) {
err := w.initUtilityVM() err := w.initUtilityVM()
if err != nil { if err != nil {
@ -692,11 +780,10 @@ func (w *legacyLayerWriter) Remove(name string) error {
// Make sure the path exists; os.RemoveAll will not fail if the file is // Make sure the path exists; os.RemoveAll will not fail if the file is
// already gone, and this needs to be a fatal error for diagnostics // already gone, and this needs to be a fatal error for diagnostics
// purposes. // purposes.
path := filepath.Join(w.destRoot, name) if _, err := lstatRelative(name, w.destRoot); err != nil {
if _, err := os.Lstat(path); err != nil {
return err return err
} }
err = os.RemoveAll(path) err = removeAllRelative(name, w.destRoot)
if err != nil { if err != nil {
return err return err
} }
@ -718,28 +805,20 @@ func (w *legacyLayerWriter) Write(b []byte) (int, error) {
} }
func (w *legacyLayerWriter) Close() error { func (w *legacyLayerWriter) Close() error {
w.reset() if err := w.reset(); err != nil {
err := w.init()
if err != nil {
return err return err
} }
tf, err := os.Create(filepath.Join(w.root, "tombstones.txt")) if err := removeRelative("tombstones.txt", w.root); err != nil && !os.IsNotExist(err) {
if err != nil {
return err return err
} }
defer tf.Close() for _, pd := range w.pendingDirs {
_, err = tf.Write([]byte("\xef\xbb\xbfVersion 1.0\n")) err := mkdirRelative(pd.Path, pd.Root)
if err != nil {
return err
}
for _, t := range w.tombstones {
_, err = tf.Write([]byte(filepath.Join(`\`, t) + "\n"))
if err != nil { if err != nil {
return err return err
} }
} }
if w.HasUtilityVM { if w.HasUtilityVM {
err = reapplyDirectoryTimes(w.uvmDi) err := reapplyDirectoryTimes(w.destRoot, w.uvmDi)
if err != nil { if err != nil {
return err return err
} }

427
vendor/github.com/Microsoft/hcsshim/safeopen.go generated vendored Normal file
View File

@ -0,0 +1,427 @@
package hcsshim
import (
"errors"
"io"
"os"
"path/filepath"
"strings"
"syscall"
"unicode/utf16"
"unsafe"
winio "github.com/Microsoft/go-winio"
)
//sys ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) = ntdll.NtCreateFile
//sys ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) = ntdll.NtSetInformationFile
//sys rtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
//sys localAlloc(flags uint32, size int) (ptr uintptr) = kernel32.LocalAlloc
//sys localFree(ptr uintptr) = kernel32.LocalFree
type ioStatusBlock struct {
Status, Information uintptr
}
type objectAttributes struct {
Length uintptr
RootDirectory uintptr
ObjectName uintptr
Attributes uintptr
SecurityDescriptor uintptr
SecurityQoS uintptr
}
type unicodeString struct {
Length uint16
MaximumLength uint16
Buffer uintptr
}
type fileLinkInformation struct {
ReplaceIfExists bool
RootDirectory uintptr
FileNameLength uint32
FileName [1]uint16
}
type fileDispositionInformationEx struct {
Flags uintptr
}
const (
_FileLinkInformation = 11
_FileDispositionInformationEx = 64
_FILE_READ_ATTRIBUTES = 0x0080
_FILE_WRITE_ATTRIBUTES = 0x0100
_DELETE = 0x10000
_FILE_OPEN = 1
_FILE_CREATE = 2
_FILE_DIRECTORY_FILE = 0x00000001
_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
_FILE_DELETE_ON_CLOSE = 0x00001000
_FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
_FILE_OPEN_REPARSE_POINT = 0x00200000
_FILE_DISPOSITION_DELETE = 0x00000001
_OBJ_DONT_REPARSE = 0x1000
_STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B
)
func openRoot(path string) (*os.File, error) {
longpath, err := makeLongAbsPath(path)
if err != nil {
return nil, err
}
return winio.OpenForBackup(longpath, syscall.GENERIC_READ, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, syscall.OPEN_EXISTING)
}
func ntRelativePath(path string) ([]uint16, error) {
path = filepath.Clean(path)
if strings.Contains(":", path) {
// Since alternate data streams must follow the file they
// are attached to, finding one here (out of order) is invalid.
return nil, errors.New("path contains invalid character `:`")
}
fspath := filepath.FromSlash(path)
if len(fspath) > 0 && fspath[0] == '\\' {
return nil, errors.New("expected relative path")
}
path16 := utf16.Encode(([]rune)(fspath))
if len(path16) > 32767 {
return nil, syscall.ENAMETOOLONG
}
return path16, nil
}
// openRelativeInternal opens a relative path from the given root, failing if
// any of the intermediate path components are reparse points.
func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
var (
h uintptr
iosb ioStatusBlock
oa objectAttributes
)
path16, err := ntRelativePath(path)
if err != nil {
return nil, err
}
if root == nil || root.Fd() == 0 {
return nil, errors.New("missing root directory")
}
upathBuffer := localAlloc(0, int(unsafe.Sizeof(unicodeString{}))+len(path16)*2)
defer localFree(upathBuffer)
upath := (*unicodeString)(unsafe.Pointer(upathBuffer))
upath.Length = uint16(len(path16) * 2)
upath.MaximumLength = upath.Length
upath.Buffer = upathBuffer + unsafe.Sizeof(*upath)
copy((*[32768]uint16)(unsafe.Pointer(upath.Buffer))[:], path16)
oa.Length = unsafe.Sizeof(oa)
oa.ObjectName = upathBuffer
oa.RootDirectory = uintptr(root.Fd())
oa.Attributes = _OBJ_DONT_REPARSE
status := ntCreateFile(
&h,
accessMask|syscall.SYNCHRONIZE,
&oa,
&iosb,
nil,
0,
shareFlags,
createDisposition,
_FILE_OPEN_FOR_BACKUP_INTENT|_FILE_SYNCHRONOUS_IO_NONALERT|flags,
nil,
0,
)
if status != 0 {
return nil, rtlNtStatusToDosError(status)
}
fullPath, err := makeLongAbsPath(filepath.Join(root.Name(), path))
if err != nil {
syscall.Close(syscall.Handle(h))
return nil, err
}
return os.NewFile(h, fullPath), nil
}
// openRelative opens a relative path from the given root, failing if
// any of the intermediate path components are reparse points.
func openRelative(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
f, err := openRelativeInternal(path, root, accessMask, shareFlags, createDisposition, flags)
if err != nil {
err = &os.PathError{Op: "open", Path: filepath.Join(root.Name(), path), Err: err}
}
return f, err
}
// linkRelative creates a hard link from oldname to newname (relative to oldroot
// and newroot), failing if any of the intermediate path components are reparse
// points.
func linkRelative(oldname string, oldroot *os.File, newname string, newroot *os.File) error {
// Open the old file.
oldf, err := openRelativeInternal(
oldname,
oldroot,
syscall.FILE_WRITE_ATTRIBUTES,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
_FILE_OPEN,
0,
)
if err != nil {
return &os.LinkError{Op: "link", Old: filepath.Join(oldroot.Name(), oldname), New: filepath.Join(newroot.Name(), newname), Err: err}
}
defer oldf.Close()
// Open the parent of the new file.
var parent *os.File
parentPath := filepath.Dir(newname)
if parentPath != "." {
parent, err = openRelativeInternal(
parentPath,
newroot,
syscall.GENERIC_READ,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
_FILE_OPEN,
_FILE_DIRECTORY_FILE)
if err != nil {
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err}
}
defer parent.Close()
fi, err := winio.GetFileBasicInfo(parent)
if err != nil {
return err
}
if (fi.FileAttributes & syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: rtlNtStatusToDosError(_STATUS_REPARSE_POINT_ENCOUNTERED)}
}
} else {
parent = newroot
}
// Issue an NT call to create the link. This will be safe because NT will
// not open any more directories to create the link, so it cannot walk any
// more reparse points.
newbase := filepath.Base(newname)
newbase16, err := ntRelativePath(newbase)
if err != nil {
return err
}
size := int(unsafe.Offsetof(fileLinkInformation{}.FileName)) + len(newbase16)*2
linkinfoBuffer := localAlloc(0, size)
defer localFree(linkinfoBuffer)
linkinfo := (*fileLinkInformation)(unsafe.Pointer(linkinfoBuffer))
linkinfo.RootDirectory = parent.Fd()
linkinfo.FileNameLength = uint32(len(newbase16) * 2)
copy((*[32768]uint16)(unsafe.Pointer(&linkinfo.FileName[0]))[:], newbase16)
var iosb ioStatusBlock
status := ntSetInformationFile(
oldf.Fd(),
&iosb,
linkinfoBuffer,
uint32(size),
_FileLinkInformation,
)
if status != 0 {
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(parent.Name(), newbase), Err: rtlNtStatusToDosError(status)}
}
return nil
}
// deleteOnClose marks a file to be deleted when the handle is closed.
func deleteOnClose(f *os.File) error {
disposition := fileDispositionInformationEx{Flags: _FILE_DISPOSITION_DELETE}
var iosb ioStatusBlock
status := ntSetInformationFile(
f.Fd(),
&iosb,
uintptr(unsafe.Pointer(&disposition)),
uint32(unsafe.Sizeof(disposition)),
_FileDispositionInformationEx,
)
if status != 0 {
return rtlNtStatusToDosError(status)
}
return nil
}
// clearReadOnly clears the readonly attribute on a file.
func clearReadOnly(f *os.File) error {
bi, err := winio.GetFileBasicInfo(f)
if err != nil {
return err
}
if bi.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY == 0 {
return nil
}
sbi := winio.FileBasicInfo{
FileAttributes: bi.FileAttributes &^ syscall.FILE_ATTRIBUTE_READONLY,
}
if sbi.FileAttributes == 0 {
sbi.FileAttributes = syscall.FILE_ATTRIBUTE_NORMAL
}
return winio.SetFileBasicInfo(f, &sbi)
}
// removeRelative removes a file or directory relative to a root, failing if any
// intermediate path components are reparse points.
func removeRelative(path string, root *os.File) error {
f, err := openRelativeInternal(
path,
root,
_FILE_READ_ATTRIBUTES|_FILE_WRITE_ATTRIBUTES|_DELETE,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
_FILE_OPEN,
_FILE_OPEN_REPARSE_POINT)
if err == nil {
defer f.Close()
err = deleteOnClose(f)
if err == syscall.ERROR_ACCESS_DENIED {
// Maybe the file is marked readonly. Clear the bit and retry.
clearReadOnly(f)
err = deleteOnClose(f)
}
}
if err != nil {
return &os.PathError{Op: "remove", Path: filepath.Join(root.Name(), path), Err: err}
}
return nil
}
// removeAllRelative removes a directory tree relative to a root, failing if any
// intermediate path components are reparse points.
func removeAllRelative(path string, root *os.File) error {
fi, err := lstatRelative(path, root)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
fileAttributes := fi.Sys().(*syscall.Win32FileAttributeData).FileAttributes
if fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 || fileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
// If this is a reparse point, it can't have children. Simple remove will do.
err := removeRelative(path, root)
if err == nil || os.IsNotExist(err) {
return nil
}
return err
}
// It is necessary to use os.Open as Readdirnames does not work with
// openRelative. This is safe because the above lstatrelative fails
// if the target is outside the root, and we know this is not a
// symlink from the above FILE_ATTRIBUTE_REPARSE_POINT check.
fd, err := os.Open(filepath.Join(root.Name(), path))
if err != nil {
if os.IsNotExist(err) {
// Race. It was deleted between the Lstat and Open.
// Return nil per RemoveAll's docs.
return nil
}
return err
}
// Remove contents & return first error.
for {
names, err1 := fd.Readdirnames(100)
for _, name := range names {
err1 := removeAllRelative(path+string(os.PathSeparator)+name, root)
if err == nil {
err = err1
}
}
if err1 == io.EOF {
break
}
// If Readdirnames returned an error, use it.
if err == nil {
err = err1
}
if len(names) == 0 {
break
}
}
fd.Close()
// Remove directory.
err1 := removeRelative(path, root)
if err1 == nil || os.IsNotExist(err1) {
return nil
}
if err == nil {
err = err1
}
return err
}
// mkdirRelative creates a directory relative to a root, failing if any
// intermediate path components are reparse points.
func mkdirRelative(path string, root *os.File) error {
f, err := openRelativeInternal(
path,
root,
0,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
_FILE_CREATE,
_FILE_DIRECTORY_FILE)
if err == nil {
f.Close()
} else {
err = &os.PathError{Op: "mkdir", Path: filepath.Join(root.Name(), path), Err: err}
}
return err
}
// lstatRelative performs a stat operation on a file relative to a root, failing
// if any intermediate path components are reparse points.
func lstatRelative(path string, root *os.File) (os.FileInfo, error) {
f, err := openRelativeInternal(
path,
root,
_FILE_READ_ATTRIBUTES,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
_FILE_OPEN,
_FILE_OPEN_REPARSE_POINT)
if err != nil {
return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err}
}
defer f.Close()
return f.Stat()
}
// ensureNotReparsePointRelative validates that a given file (relative to a
// root) and all intermediate path components are not a reparse points.
func ensureNotReparsePointRelative(path string, root *os.File) error {
// Perform an open with OBJ_DONT_REPARSE but without specifying FILE_OPEN_REPARSE_POINT.
f, err := openRelative(
path,
root,
0,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
_FILE_OPEN,
0)
if err != nil {
return err
}
f.Close()
return nil
}

View File

@ -41,6 +41,8 @@ var (
modole32 = windows.NewLazySystemDLL("ole32.dll") modole32 = windows.NewLazySystemDLL("ole32.dll")
modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
modvmcompute = windows.NewLazySystemDLL("vmcompute.dll") modvmcompute = windows.NewLazySystemDLL("vmcompute.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId")
@ -94,6 +96,11 @@ var (
procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback")
procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings")
procHNSCall = modvmcompute.NewProc("HNSCall") procHNSCall = modvmcompute.NewProc("HNSCall")
procNtCreateFile = modntdll.NewProc("NtCreateFile")
procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
procLocalFree = modkernel32.NewProc("LocalFree")
) )
func coTaskMemFree(buffer unsafe.Pointer) { func coTaskMemFree(buffer unsafe.Pointer) {
@ -1040,3 +1047,34 @@ func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16)
} }
return return
} }
func ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) {
r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength), 0)
status = uint32(r0)
return
}
func ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) {
r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class), 0)
status = uint32(r0)
return
}
func rtlNtStatusToDosError(status uint32) (winerr error) {
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
if r0 != 0 {
winerr = syscall.Errno(r0)
}
return
}
func localAlloc(flags uint32, size int) (ptr uintptr) {
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(size), 0)
ptr = uintptr(r0)
return
}
func localFree(ptr uintptr) {
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(ptr), 0, 0)
return
}