Merge pull request #3385 from ehotinger/ehotinger/refactor-winio

Bump go-winio and refactor Windows snapshotters
This commit is contained in:
Michael Crosby 2019-07-02 10:54:05 -04:00 committed by GitHub
commit 3ce077e740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 796 additions and 188 deletions

View File

@ -93,7 +93,7 @@ func setupDumpStacks() {
}()
}
func etwCallback(sourceID *guid.GUID, state etw.ProviderState, level etw.Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr) {
func etwCallback(sourceID guid.GUID, state etw.ProviderState, level etw.Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr) {
if state == etw.ProviderStateCaptureState {
dumpStacks(false)
}

View File

@ -28,10 +28,9 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"time"
"unsafe"
winfs "github.com/Microsoft/go-winio/pkg/fs"
"github.com/Microsoft/hcsshim/pkg/go-runhcs"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log"
@ -42,7 +41,6 @@ import (
"github.com/containerd/continuity/fs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
func init() {
@ -68,7 +66,7 @@ type snapshotter struct {
// NewSnapshotter returns a new windows snapshotter
func NewSnapshotter(root string) (snapshots.Snapshotter, error) {
fsType, err := getFileSystemType(root)
fsType, err := winfs.GetFileSystemType(root)
if err != nil {
return nil, err
}
@ -404,35 +402,3 @@ func (s *snapshotter) parentIDsToParentPaths(parentIDs []string) []string {
}
return parentLayerPaths
}
// getFileSystemType obtains the type of a file system through GetVolumeInformation
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
func getFileSystemType(path string) (fsType string, hr error) {
drive := filepath.VolumeName(path)
if len(drive) != 2 {
return "", errors.New("getFileSystemType path must start with a drive letter")
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW")
buf = make([]uint16, 255)
size = windows.MAX_PATH + 1
)
drive += `\`
n := uintptr(unsafe.Pointer(nil))
r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
fsType = windows.UTF16ToString(buf)
return
}
// win32FromHresult is a helper function to get the win32 error code from an HRESULT
func win32FromHresult(hr uintptr) uintptr {
if hr&0x1fff0000 == 0x00070000 {
return hr & 0xffff
}
return hr
}

View File

@ -24,9 +24,8 @@ import (
"os"
"path/filepath"
"strings"
"syscall"
"unsafe"
winfs "github.com/Microsoft/go-winio/pkg/fs"
"github.com/Microsoft/go-winio/vhd"
"github.com/Microsoft/hcsshim"
"github.com/containerd/containerd/errdefs"
@ -37,7 +36,6 @@ import (
"github.com/containerd/containerd/snapshots/storage"
"github.com/containerd/continuity/fs"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
func init() {
@ -58,7 +56,7 @@ type snapshotter struct {
// NewSnapshotter returns a new windows snapshotter
func NewSnapshotter(root string) (snapshots.Snapshotter, error) {
fsType, err := getFileSystemType(root)
fsType, err := winfs.GetFileSystemType(root)
if err != nil {
return nil, err
}
@ -338,35 +336,3 @@ func (s *snapshotter) parentIDsToParentPaths(parentIDs []string) []string {
}
return parentLayerPaths
}
// getFileSystemType obtains the type of a file system through GetVolumeInformation
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
func getFileSystemType(path string) (fsType string, hr error) {
drive := filepath.VolumeName(path)
if len(drive) != 2 {
return "", errors.New("getFileSystemType path must start with a drive letter")
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW")
buf = make([]uint16, 255)
size = windows.MAX_PATH + 1
)
drive += `\`
n := uintptr(unsafe.Pointer(nil))
r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
fsType = windows.UTF16ToString(buf)
return
}
// win32FromHresult is a helper function to get the win32 error code from an HRESULT
func win32FromHresult(hr uintptr) uintptr {
if hr&0x1fff0000 == 0x00070000 {
return hr & 0xffff
}
return hr
}

View File

@ -33,7 +33,7 @@ github.com/opencontainers/image-spec v1.0.1
golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e
github.com/BurntSushi/toml v0.3.1
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
github.com/Microsoft/go-winio 84b4ab48a50763fe7b3abcef38e5205c12027fac
github.com/Microsoft/go-winio 7cdfd71a950d40d0da2167ccb690b541f7ba98c0
github.com/Microsoft/hcsshim 8abdbb8205e4192c68b5f84c31197156f31be517
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4

View File

@ -16,6 +16,7 @@ import (
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
type atomicBool int32
@ -79,6 +80,7 @@ type win32File struct {
wg sync.WaitGroup
wgLock sync.RWMutex
closing atomicBool
socket bool
readDeadline deadlineHandler
writeDeadline deadlineHandler
}
@ -109,7 +111,13 @@ func makeWin32File(h syscall.Handle) (*win32File, error) {
}
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
return makeWin32File(h)
// If we return the result of makeWin32File directly, it can result in an
// interface-wrapped nil, rather than a nil interface value.
f, err := makeWin32File(h)
if err != nil {
return nil, err
}
return f, nil
}
// closeHandle closes the resources associated with a Win32 handle
@ -190,6 +198,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
if f.closing.isSet() {
err = ErrFileClosed
}
} else if err != nil && f.socket {
// err is from Win32. Query the overlapped structure to get the winsock error.
var bytes, flags uint32
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
}
case <-timeout:
cancelIoEx(f.handle, &c.o)
@ -265,6 +277,10 @@ func (f *win32File) Flush() error {
return syscall.FlushFileBuffers(f.handle)
}
func (f *win32File) Fd() uintptr {
return uintptr(f.handle)
}
func (d *deadlineHandler) set(deadline time.Time) error {
d.setLock.Lock()
defer d.setLock.Unlock()

9
vendor/github.com/Microsoft/go-winio/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module github.com/Microsoft/go-winio
go 1.12
require (
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.1
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b
)

305
vendor/github.com/Microsoft/go-winio/hvsock.go generated vendored Normal file
View File

@ -0,0 +1,305 @@
package winio
import (
"fmt"
"io"
"net"
"os"
"syscall"
"time"
"unsafe"
"github.com/Microsoft/go-winio/pkg/guid"
)
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
const (
afHvSock = 34 // AF_HYPERV
socketError = ^uintptr(0)
)
// An HvsockAddr is an address for a AF_HYPERV socket.
type HvsockAddr struct {
VMID guid.GUID
ServiceID guid.GUID
}
type rawHvsockAddr struct {
Family uint16
_ uint16
VMID guid.GUID
ServiceID guid.GUID
}
// Network returns the address's network name, "hvsock".
func (addr *HvsockAddr) Network() string {
return "hvsock"
}
func (addr *HvsockAddr) String() string {
return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
}
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
func VsockServiceID(port uint32) guid.GUID {
g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
g.Data1 = port
return g
}
func (addr *HvsockAddr) raw() rawHvsockAddr {
return rawHvsockAddr{
Family: afHvSock,
VMID: addr.VMID,
ServiceID: addr.ServiceID,
}
}
func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
addr.VMID = raw.VMID
addr.ServiceID = raw.ServiceID
}
// HvsockListener is a socket listener for the AF_HYPERV address family.
type HvsockListener struct {
sock *win32File
addr HvsockAddr
}
// HvsockConn is a connected socket of the AF_HYPERV address family.
type HvsockConn struct {
sock *win32File
local, remote HvsockAddr
}
func newHvSocket() (*win32File, error) {
fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
if err != nil {
return nil, os.NewSyscallError("socket", err)
}
f, err := makeWin32File(fd)
if err != nil {
syscall.Close(fd)
return nil, err
}
f.socket = true
return f, nil
}
// ListenHvsock listens for connections on the specified hvsock address.
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
l := &HvsockListener{addr: *addr}
sock, err := newHvSocket()
if err != nil {
return nil, l.opErr("listen", err)
}
sa := addr.raw()
err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
}
err = syscall.Listen(sock.handle, 16)
if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("listen", err))
}
return &HvsockListener{sock: sock, addr: *addr}, nil
}
func (l *HvsockListener) opErr(op string, err error) error {
return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
}
// Addr returns the listener's network address.
func (l *HvsockListener) Addr() net.Addr {
return &l.addr
}
// Accept waits for the next connection and returns it.
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
sock, err := newHvSocket()
if err != nil {
return nil, l.opErr("accept", err)
}
defer func() {
if sock != nil {
sock.Close()
}
}()
c, err := l.sock.prepareIo()
if err != nil {
return nil, l.opErr("accept", err)
}
defer l.sock.wg.Done()
// AcceptEx, per documentation, requires an extra 16 bytes per address.
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
var addrbuf [addrlen * 2]byte
var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
_, err = l.sock.asyncIo(c, nil, bytes, err)
if err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
}
conn := &HvsockConn{
sock: sock,
}
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
sock = nil
return conn, nil
}
// Close closes the listener, causing any pending Accept calls to fail.
func (l *HvsockListener) Close() error {
return l.sock.Close()
}
/* Need to finish ConnectEx handling
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
sock, err := newHvSocket()
if err != nil {
return nil, err
}
defer func() {
if sock != nil {
sock.Close()
}
}()
c, err := sock.prepareIo()
if err != nil {
return nil, err
}
defer sock.wg.Done()
var bytes uint32
err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
_, err = sock.asyncIo(ctx, c, nil, bytes, err)
if err != nil {
return nil, err
}
conn := &HvsockConn{
sock: sock,
remote: *addr,
}
sock = nil
return conn, nil
}
*/
func (conn *HvsockConn) opErr(op string, err error) error {
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
}
func (conn *HvsockConn) Read(b []byte) (int, error) {
c, err := conn.sock.prepareIo()
if err != nil {
return 0, conn.opErr("read", err)
}
defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var flags, bytes uint32
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
if err != nil {
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsarecv", err)
}
return 0, conn.opErr("read", err)
} else if n == 0 {
err = io.EOF
}
return n, err
}
func (conn *HvsockConn) Write(b []byte) (int, error) {
t := 0
for len(b) != 0 {
n, err := conn.write(b)
if err != nil {
return t + n, err
}
t += n
b = b[n:]
}
return t, nil
}
func (conn *HvsockConn) write(b []byte) (int, error) {
c, err := conn.sock.prepareIo()
if err != nil {
return 0, conn.opErr("write", err)
}
defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var bytes uint32
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
if err != nil {
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsasend", err)
}
return 0, conn.opErr("write", err)
}
return n, err
}
// Close closes the socket connection, failing any pending read or write calls.
func (conn *HvsockConn) Close() error {
return conn.sock.Close()
}
func (conn *HvsockConn) shutdown(how int) error {
err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
if err != nil {
return os.NewSyscallError("shutdown", err)
}
return nil
}
// CloseRead shuts down the read end of the socket.
func (conn *HvsockConn) CloseRead() error {
err := conn.shutdown(syscall.SHUT_RD)
if err != nil {
return conn.opErr("close", err)
}
return nil
}
// CloseWrite shuts down the write end of the socket, notifying the other endpoint that
// no more data will be written.
func (conn *HvsockConn) CloseWrite() error {
err := conn.shutdown(syscall.SHUT_WR)
if err != nil {
return conn.opErr("close", err)
}
return nil
}
// LocalAddr returns the local address of the connection.
func (conn *HvsockConn) LocalAddr() net.Addr {
return &conn.local
}
// RemoteAddr returns the remote address of the connection.
func (conn *HvsockConn) RemoteAddr() net.Addr {
return &conn.remote
}
// SetDeadline implements the net.Conn SetDeadline method.
func (conn *HvsockConn) SetDeadline(t time.Time) error {
conn.SetReadDeadline(t)
conn.SetWriteDeadline(t)
return nil
}
// SetReadDeadline implements the net.Conn SetReadDeadline method.
func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
return conn.sock.SetReadDeadline(t)
}
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
return conn.sock.SetWriteDeadline(t)
}

View File

@ -7,9 +7,14 @@
// set of C macros.
package etw
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go etw.go
//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
//sys eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
//sys eventUnregister_64(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
//sys eventWriteTransfer_64(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
//sys eventSetInformation_64(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
//sys eventUnregister_32(providerHandle_low uint32, providerHandle_high uint32) (win32err error) = advapi32.EventUnregister
//sys eventWriteTransfer_32(providerHandle_low uint32, providerHandle_high uint32, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
//sys eventSetInformation_32(providerHandle_low uint32, providerHandle_high uint32, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation

View File

@ -3,6 +3,7 @@ package etw
import (
"bytes"
"encoding/binary"
"syscall"
)
// eventData maintains a buffer which builds up the data for an ETW event. It
@ -63,3 +64,8 @@ func (ed *eventData) writeUint32(value uint32) {
func (ed *eventData) writeUint64(value uint64) {
binary.Write(&ed.buffer, binary.LittleEndian, value)
}
// writeFiletime appends a FILETIME to the buffer.
func (ed *eventData) writeFiletime(value syscall.Filetime) {
binary.Write(&ed.buffer, binary.LittleEndian, value)
}

View File

@ -6,8 +6,8 @@ import (
type eventOptions struct {
descriptor *eventDescriptor
activityID *guid.GUID
relatedActivityID *guid.GUID
activityID guid.GUID
relatedActivityID guid.GUID
tags uint32
}
@ -59,14 +59,14 @@ func WithTags(newTags uint32) EventOpt {
}
// WithActivityID specifies the activity ID of the event to be written.
func WithActivityID(activityID *guid.GUID) EventOpt {
func WithActivityID(activityID guid.GUID) EventOpt {
return func(options *eventOptions) {
options.activityID = activityID
}
}
// WithRelatedActivityID specifies the parent activity ID of the event to be written.
func WithRelatedActivityID(activityID *guid.GUID) EventOpt {
func WithRelatedActivityID(activityID guid.GUID) EventOpt {
return func(options *eventOptions) {
options.relatedActivityID = activityID
}

View File

@ -4,6 +4,8 @@ import (
"fmt"
"math"
"reflect"
"syscall"
"time"
"unsafe"
)
@ -380,6 +382,14 @@ func Struct(name string, opts ...FieldOpt) FieldOpt {
}
}
// Time adds a time to the event.
func Time(name string, value time.Time) FieldOpt {
return func(em *eventMetadata, ed *eventData) {
em.writeField(name, inTypeFileTime, outTypeDateTimeUTC, 0)
ed.writeFiletime(syscall.NsecToFiletime(value.UTC().UnixNano()))
}
}
// Currently, we support logging basic builtin types (int, string, etc), slices
// of basic builtin types, error, types derived from the basic types (e.g. "type
// foo int"), and structs (recursively logging their fields). We do not support
@ -454,6 +464,8 @@ func SmartField(name string, v interface{}) FieldOpt {
return Float64Array(name, v)
case error:
return StringField(name, v.Error())
case time.Time:
return Time(name, v)
default:
switch rv := reflect.ValueOf(v); rv.Kind() {
case reflect.Bool:

View File

@ -0,0 +1,53 @@
// +build amd64 arm64 386
package etw
import (
"bytes"
"encoding/binary"
"unsafe"
"github.com/Microsoft/go-winio/pkg/guid"
"golang.org/x/sys/windows"
)
// NewProviderWithID creates and registers a new ETW provider, allowing the
// provider ID to be manually specified. This is most useful when there is an
// existing provider ID that must be used to conform to existing diagnostic
// infrastructure.
func NewProviderWithID(name string, id guid.GUID, callback EnableCallback) (provider *Provider, err error) {
providerCallbackOnce.Do(func() {
globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
})
provider = providers.newProvider()
defer func(provider *Provider) {
if err != nil {
providers.removeProvider(provider)
}
}(provider)
provider.ID = id
provider.callback = callback
if err := eventRegister((*windows.GUID)(&provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
return nil, err
}
metadata := &bytes.Buffer{}
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
metadata.WriteString(name)
metadata.WriteByte(0) // Null terminator for name
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
provider.metadata = metadata.Bytes()
if err := eventSetInformation(
provider.handle,
eventInfoClassProviderSetTraits,
uintptr(unsafe.Pointer(&provider.metadata[0])),
uint32(len(provider.metadata))); err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1,12 @@
// +build arm
package etw
import (
"github.com/Microsoft/go-winio/pkg/guid"
)
// NewProviderWithID returns a nil provider on unsupported platforms.
func NewProviderWithID(name string, id guid.GUID, callback EnableCallback) (provider *Provider, err error) {
return nil, nil
}

View File

@ -1,12 +1,10 @@
package etw
import (
"bytes"
"crypto/sha1"
"encoding/binary"
"strings"
"unicode/utf16"
"unsafe"
"github.com/Microsoft/go-winio/pkg/guid"
"golang.org/x/sys/windows"
@ -16,7 +14,7 @@ import (
// name and ID (GUID), which should always have a 1:1 mapping to each other
// (e.g. don't use multiple provider names with the same ID, or vice versa).
type Provider struct {
ID *guid.GUID
ID guid.GUID
handle providerHandle
metadata []byte
callback EnableCallback
@ -29,10 +27,14 @@ type Provider struct {
// String returns the `provider`.ID as a string
func (provider *Provider) String() string {
if provider == nil {
return "<nil>"
}
return provider.ID.String()
}
type providerHandle windows.Handle
type providerHandle uint64
// ProviderState informs the provider EnableCallback what action is being
// performed.
@ -59,9 +61,9 @@ const (
// EnableCallback is the form of the callback function that receives provider
// enable/disable notifications from ETW.
type EnableCallback func(*guid.GUID, ProviderState, Level, uint64, uint64, uintptr)
type EnableCallback func(guid.GUID, ProviderState, Level, uint64, uint64, uintptr)
func providerCallback(sourceID *guid.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
func providerCallback(sourceID guid.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
provider := providers.getProvider(uint(i))
switch state {
@ -84,7 +86,7 @@ func providerCallback(sourceID *guid.GUID, state ProviderState, level Level, mat
// different size, it has only pointer-sized arguments, which are then cast to
// the appropriate types when calling providerCallback.
func providerCallbackAdapter(sourceID *guid.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
providerCallback(*sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
return 0
}
@ -95,7 +97,7 @@ func providerCallbackAdapter(sourceID *guid.GUID, state uintptr, level uintptr,
// The algorithm is roughly:
// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
func providerIDFromName(name string) *guid.GUID {
func providerIDFromName(name string) guid.GUID {
buffer := sha1.New()
namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
@ -106,7 +108,7 @@ func providerIDFromName(name string) *guid.GUID {
sum := buffer.Sum(nil)
sum[7] = (sum[7] & 0xf) | 0x50
return &guid.GUID{
return guid.GUID{
Data1: binary.LittleEndian.Uint32(sum[0:4]),
Data2: binary.LittleEndian.Uint16(sum[4:6]),
Data3: binary.LittleEndian.Uint16(sum[6:8]),
@ -120,49 +122,12 @@ func NewProvider(name string, callback EnableCallback) (provider *Provider, err
return NewProviderWithID(name, providerIDFromName(name), callback)
}
// NewProviderWithID creates and registers a new ETW provider, allowing the
// provider ID to be manually specified. This is most useful when there is an
// existing provider ID that must be used to conform to existing diagnostic
// infrastructure.
func NewProviderWithID(name string, id *guid.GUID, callback EnableCallback) (provider *Provider, err error) {
providerCallbackOnce.Do(func() {
globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
})
provider = providers.newProvider()
defer func() {
if err != nil {
providers.removeProvider(provider)
}
}()
provider.ID = id
provider.callback = callback
if err := eventRegister((*windows.GUID)(provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
return nil, err
}
metadata := &bytes.Buffer{}
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
metadata.WriteString(name)
metadata.WriteByte(0) // Null terminator for name
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
provider.metadata = metadata.Bytes()
if err := eventSetInformation(
provider.handle,
eventInfoClassProviderSetTraits,
uintptr(unsafe.Pointer(&provider.metadata[0])),
uint32(len(provider.metadata))); err != nil {
return nil, err
}
return provider, nil
}
// Close unregisters the provider.
func (provider *Provider) Close() error {
if provider == nil {
return nil
}
providers.removeProvider(provider)
return eventUnregister(provider.handle)
}
@ -185,6 +150,10 @@ func (provider *Provider) IsEnabledForLevel(level Level) bool {
// infrastructure, it can be useful to check if an event will actually be
// consumed before doing expensive work to build the event data.
func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool {
if provider == nil {
return false
}
if !provider.enabled {
return false
}
@ -206,6 +175,10 @@ func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uin
// constructed based on the EventOpt and FieldOpt values that are passed as
// opts.
func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
if provider == nil {
return nil
}
options := eventOptions{descriptor: newEventDescriptor()}
em := &eventMetadata{}
ed := &eventData{}
@ -246,8 +219,8 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt
// the ETW infrastructure.
func (provider *Provider) writeEventRaw(
descriptor *eventDescriptor,
activityID *guid.GUID,
relatedActivityID *guid.GUID,
activityID guid.GUID,
relatedActivityID guid.GUID,
metadataBlobs [][]byte,
dataBlobs [][]byte) error {
@ -262,5 +235,5 @@ func (provider *Provider) writeEventRaw(
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
}
return eventWriteTransfer(provider.handle, descriptor, (*windows.GUID)(activityID), (*windows.GUID)(relatedActivityID), dataDescriptorCount, &dataDescriptors[0])
return eventWriteTransfer(provider.handle, descriptor, (*windows.GUID)(&activityID), (*windows.GUID)(&relatedActivityID), dataDescriptorCount, &dataDescriptors[0])
}

View File

@ -0,0 +1,51 @@
// +build 386 arm
package etw
import (
"golang.org/x/sys/windows"
)
func low(v providerHandle) uint32 {
return uint32(v & 0xffffffff)
}
func high(v providerHandle) uint32 {
return low(v >> 32)
}
func eventUnregister(providerHandle providerHandle) (win32err error) {
return eventUnregister_32(low(providerHandle), high(providerHandle))
}
func eventWriteTransfer(
providerHandle providerHandle,
descriptor *eventDescriptor,
activityID *windows.GUID,
relatedActivityID *windows.GUID,
dataDescriptorCount uint32,
dataDescriptors *eventDataDescriptor) (win32err error) {
return eventWriteTransfer_32(
low(providerHandle),
high(providerHandle),
descriptor,
activityID,
relatedActivityID,
dataDescriptorCount,
dataDescriptors)
}
func eventSetInformation(
providerHandle providerHandle,
class eventInfoClass,
information uintptr,
length uint32) (win32err error) {
return eventSetInformation_32(
low(providerHandle),
high(providerHandle),
class,
information,
length)
}

View File

@ -0,0 +1,41 @@
// +build amd64 arm64
package etw
import (
"golang.org/x/sys/windows"
)
func eventUnregister(providerHandle providerHandle) (win32err error) {
return eventUnregister_64(providerHandle)
}
func eventWriteTransfer(
providerHandle providerHandle,
descriptor *eventDescriptor,
activityID *windows.GUID,
relatedActivityID *windows.GUID,
dataDescriptorCount uint32,
dataDescriptors *eventDataDescriptor) (win32err error) {
return eventWriteTransfer_64(
providerHandle,
descriptor,
activityID,
relatedActivityID,
dataDescriptorCount,
dataDescriptors)
}
func eventSetInformation(
providerHandle providerHandle,
class eventInfoClass,
information uintptr,
length uint32) (win32err error) {
return eventSetInformation_64(
providerHandle,
class,
information,
length)
}

View File

@ -53,7 +53,7 @@ func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext u
return
}
func eventUnregister(providerHandle providerHandle) (win32err error) {
func eventUnregister_64(providerHandle providerHandle) (win32err error) {
r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0)
if r0 != 0 {
win32err = syscall.Errno(r0)
@ -61,7 +61,7 @@ func eventUnregister(providerHandle providerHandle) (win32err error) {
return
}
func eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
func eventWriteTransfer_64(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
if r0 != 0 {
win32err = syscall.Errno(r0)
@ -69,10 +69,34 @@ func eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescript
return
}
func eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
func eventSetInformation_64(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 4, uintptr(providerHandle), uintptr(class), uintptr(information), uintptr(length), 0, 0)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func eventUnregister_32(providerHandle_low uint32, providerHandle_high uint32) (win32err error) {
r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 2, uintptr(providerHandle_low), uintptr(providerHandle_high), 0)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func eventWriteTransfer_32(providerHandle_low uint32, providerHandle_high uint32, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
r0, _, _ := syscall.Syscall9(procEventWriteTransfer.Addr(), 7, uintptr(providerHandle_low), uintptr(providerHandle_high), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)), 0, 0)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func eventSetInformation_32(providerHandle_low uint32, providerHandle_high uint32, class eventInfoClass, information uintptr, length uint32) (win32err error) {
r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 5, uintptr(providerHandle_low), uintptr(providerHandle_high), uintptr(class), uintptr(information), uintptr(length), 0)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}

View File

@ -1,6 +1,8 @@
package etwlogrus
import (
"sort"
"github.com/Microsoft/go-winio/pkg/etw"
"github.com/sirupsen/logrus"
)
@ -31,15 +33,7 @@ func NewHookFromProvider(provider *etw.Provider) (*Hook, error) {
// Levels returns the set of levels that this hook wants to receive log entries
// for.
func (h *Hook) Levels() []logrus.Level {
return []logrus.Level{
logrus.TraceLevel,
logrus.DebugLevel,
logrus.InfoLevel,
logrus.WarnLevel,
logrus.ErrorLevel,
logrus.FatalLevel,
logrus.PanicLevel,
}
return logrus.AllLevels
}
var logrusToETWLevelMap = map[logrus.Level]etw.Level{
@ -62,19 +56,42 @@ func (h *Hook) Fire(e *logrus.Entry) error {
return nil
}
// Reserve extra space for the message field.
fields := make([]etw.FieldOpt, 0, len(e.Data)+1)
// Sort the fields by name so they are consistent in each instance
// of an event. Otherwise, the fields don't line up in WPA.
names := make([]string, 0, len(e.Data))
hasError := false
for k := range e.Data {
if k == logrus.ErrorKey {
// Always put the error last because it is optional in some events.
hasError = true
} else {
names = append(names, k)
}
}
sort.Strings(names)
// Reserve extra space for the message and time fields.
fields := make([]etw.FieldOpt, 0, len(e.Data)+2)
fields = append(fields, etw.StringField("Message", e.Message))
for k, v := range e.Data {
fields = append(fields, etw.SmartField(k, v))
fields = append(fields, etw.Time("Time", e.Time))
for _, k := range names {
fields = append(fields, etw.SmartField(k, e.Data[k]))
}
if hasError {
fields = append(fields, etw.SmartField(logrus.ErrorKey, e.Data[logrus.ErrorKey]))
}
return h.provider.WriteEvent(
// Firing an ETW event is essentially best effort, as the event write can
// fail for reasons completely out of the control of the event writer (such
// as a session listening for the event having no available space in its
// buffers). Therefore, we don't return the error from WriteEvent, as it is
// just noise in many cases.
h.provider.WriteEvent(
"LogrusEntry",
etw.WithEventOpts(etw.WithLevel(level)),
fields)
return nil
}
// Close cleans up the hook and closes the ETW provider. If the provder was

View File

@ -0,0 +1,42 @@
package fs
import (
"errors"
"path/filepath"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// GetFileSystemType obtains the type of a file system through GetVolumeInformation.
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
func GetFileSystemType(path string) (fsType string, hr error) {
drive := filepath.VolumeName(path)
if len(drive) != 2 {
return "", errors.New("getFileSystemType path must start with a drive letter")
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW")
buf = make([]uint16, 255)
size = windows.MAX_PATH + 1
)
drive += `\`
n := uintptr(unsafe.Pointer(nil))
r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0)
if int32(r0) < 0 {
hr = syscall.Errno(win32FromHresult(r0))
}
fsType = windows.UTF16ToString(buf)
return
}
// win32FromHresult is a helper function to get the win32 error code from an HRESULT.
func win32FromHresult(hr uintptr) uintptr {
if hr&0x1fff0000 == 0x00070000 {
return hr & 0xffff
}
return hr
}

View File

@ -1,19 +1,42 @@
// Package guid provides a GUID type. The backing structure for a GUID is
// identical to that used by the golang.org/x/sys/windows GUID type.
// There are two main binary encodings used for a GUID, the big-endian encoding,
// and the Windows (mixed-endian) encoding. See here for details:
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
package guid
import (
"crypto/rand"
"encoding"
"encoding/binary"
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
var _ = (json.Marshaler)(&GUID{})
var _ = (json.Unmarshaler)(&GUID{})
// Variant specifies which GUID variant (or "type") of the GUID. It determines
// how the entirety of the rest of the GUID is interpreted.
type Variant uint8
// The variants specified by RFC 4122.
const (
// VariantUnknown specifies a GUID variant which does not conform to one of
// the variant encodings specified in RFC 4122.
VariantUnknown Variant = iota
VariantNCS
VariantRFC4122
VariantMicrosoft
VariantFuture
)
// Version specifies how the bits in the GUID were generated. For instance, a
// version 4 GUID is randomly generated, and a version 5 is generated from the
// hash of an input string.
type Version uint8
var _ = (encoding.TextMarshaler)(GUID{})
var _ = (encoding.TextUnmarshaler)(&GUID{})
// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
@ -23,24 +46,59 @@ var _ = (json.Unmarshaler)(&GUID{})
type GUID windows.GUID
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
func NewV4() (*GUID, error) {
func NewV4() (GUID, error) {
var b [16]byte
if _, err := rand.Read(b[:]); err != nil {
return nil, err
return GUID{}, err
}
b[6] = (b[6] & 0x0f) | 0x40 // Version 4 (randomly generated)
b[8] = (b[8] & 0x3f) | 0x80 // RFC4122 variant
return FromArray(b), nil
}
func fromArray(b [16]byte, order binary.ByteOrder) GUID {
var g GUID
g.Data1 = binary.LittleEndian.Uint32(b[0:4])
g.Data2 = binary.LittleEndian.Uint16(b[4:6])
g.Data3 = binary.LittleEndian.Uint16(b[6:8])
g.Data1 = order.Uint32(b[0:4])
g.Data2 = order.Uint16(b[4:6])
g.Data3 = order.Uint16(b[6:8])
copy(g.Data4[:], b[8:16])
g.Data3 = (g.Data3 & 0x0fff) | 0x4000 // Version 4 (randomly generated)
g.Data4[0] = (g.Data4[0] & 0x3f) | 0x80 // RFC4122 variant
return &g, nil
return g
}
func (g *GUID) String() string {
func (g GUID) toArray(order binary.ByteOrder) [16]byte {
b := [16]byte{}
order.PutUint32(b[0:4], g.Data1)
order.PutUint16(b[4:6], g.Data2)
order.PutUint16(b[6:8], g.Data3)
copy(b[8:16], g.Data4[:])
return b
}
// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
func FromArray(b [16]byte) GUID {
return fromArray(b, binary.BigEndian)
}
// ToArray returns an array of 16 bytes representing the GUID in big-endian
// encoding.
func (g GUID) ToArray() [16]byte {
return g.toArray(binary.BigEndian)
}
// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
func FromWindowsArray(b [16]byte) GUID {
return fromArray(b, binary.LittleEndian)
}
// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
// encoding.
func (g GUID) ToWindowsArray() [16]byte {
return g.toArray(binary.LittleEndian)
}
func (g GUID) String() string {
return fmt.Sprintf(
"%08x-%04x-%04x-%04x-%012x",
g.Data1,
@ -53,58 +111,77 @@ func (g *GUID) String() string {
// FromString parses a string containing a GUID and returns the GUID. The only
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
// format.
func FromString(s string) (*GUID, error) {
func FromString(s string) (GUID, error) {
if len(s) != 36 {
return nil, errors.New("invalid GUID format (length)")
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return nil, errors.New("invalid GUID format (dashes)")
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
var g GUID
data1, err := strconv.ParseUint(s[0:8], 16, 32)
if err != nil {
return nil, errors.Wrap(err, "invalid GUID format (Data1)")
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data1 = uint32(data1)
data2, err := strconv.ParseUint(s[9:13], 16, 16)
if err != nil {
return nil, errors.Wrap(err, "invalid GUID format (Data2)")
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data2 = uint16(data2)
data3, err := strconv.ParseUint(s[14:18], 16, 16)
if err != nil {
return nil, errors.Wrap(err, "invalid GUID format (Data3)")
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data3 = uint16(data3)
for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
v, err := strconv.ParseUint(s[x:x+2], 16, 8)
if err != nil {
return nil, errors.Wrap(err, "invalid GUID format (Data4)")
return GUID{}, fmt.Errorf("invalid GUID %q", s)
}
g.Data4[i] = uint8(v)
}
return &g, nil
return g, nil
}
// MarshalJSON marshals the GUID to JSON representation and returns it as a
// slice of bytes.
func (g *GUID) MarshalJSON() ([]byte, error) {
return json.Marshal(g.String())
// Variant returns the GUID variant, as defined in RFC 4122.
func (g GUID) Variant() Variant {
b := g.Data4[0]
if b&0x80 == 0 {
return VariantNCS
} else if b&0xc0 == 0x80 {
return VariantRFC4122
} else if b&0xe0 == 0xc0 {
return VariantMicrosoft
} else if b&0xe0 == 0xe0 {
return VariantFuture
}
return VariantUnknown
}
// UnmarshalJSON unmarshals a GUID from JSON representation and sets itself to
// the unmarshaled GUID.
func (g *GUID) UnmarshalJSON(data []byte) error {
g2, err := FromString(strings.Trim(string(data), "\""))
// Version returns the GUID version, as defined in RFC 4122.
func (g GUID) Version() Version {
return Version((g.Data3 & 0xF000) >> 12)
}
// MarshalText returns the textual representation of the GUID.
func (g GUID) MarshalText() ([]byte, error) {
return []byte(g.String()), nil
}
// UnmarshalText takes the textual representation of a GUID, and unmarhals it
// into this GUID.
func (g *GUID) UnmarshalText(text []byte) error {
g2, err := FromString(string(text))
if err != nil {
return err
}
*g = *g2
*g = g2
return nil
}

View File

@ -1,3 +1,3 @@
package winio
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go

View File

@ -38,6 +38,7 @@ func errnoErr(e syscall.Errno) error {
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
@ -45,6 +46,7 @@ var (
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procCreateFileW = modkernel32.NewProc("CreateFileW")
@ -73,6 +75,7 @@ var (
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
procBackupRead = modkernel32.NewProc("BackupRead")
procBackupWrite = modkernel32.NewProc("BackupWrite")
procbind = modws2_32.NewProc("bind")
)
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
@ -124,6 +127,24 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
return
}
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
var _p0 uint32
if wait {
_p0 = 1
} else {
_p0 = 0
}
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
@ -527,3 +548,15 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
}
return
}
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socketError {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}