From 80376f9e13406a8e2ecc725f7d55821142d375a3 Mon Sep 17 00:00:00 2001 From: Kevin Parsons Date: Mon, 22 Apr 2019 14:11:46 -0700 Subject: [PATCH 1/2] Revendor go-winio This is needed to provide fixes for ETW on ARM. The updated ETW package will no-op on ARM, rather than crashing. Further changes are needed to Go itself to allow ETW on ARM to work properly. Signed-off-by: Kevin Parsons (cherry picked from commit e1f0f77bf49ca0fab29eb57ce25ac3f6eab0adf9) Signed-off-by: Sebastiaan van Stijn --- vendor.conf | 2 +- vendor/github.com/Microsoft/go-winio/file.go | 6 + .../github.com/Microsoft/go-winio/hvsock.go | 305 ++++++++++++++++++ vendor/github.com/Microsoft/go-winio/pipe.go | 247 +++++++++----- .../Microsoft/go-winio/pkg/etw/etw.go | 13 +- .../go-winio/pkg/etw/eventdescriptor.go | 21 +- .../Microsoft/go-winio/pkg/etw/eventopt.go | 20 +- .../Microsoft/go-winio/pkg/etw/fieldopt.go | 123 +++++++ .../Microsoft/go-winio/pkg/etw/newprovider.go | 53 +++ .../pkg/etw/newprovider_unsupported.go | 12 + .../Microsoft/go-winio/pkg/etw/provider.go | 98 ++---- .../Microsoft/go-winio/pkg/etw/wrapper_32.go | 51 +++ .../Microsoft/go-winio/pkg/etw/wrapper_64.go | 41 +++ .../go-winio/pkg/etw/zsyscall_windows.go | 30 +- .../Microsoft/go-winio/pkg/etwlogrus/hook.go | 126 +------- .../Microsoft/go-winio/pkg/guid/guid.go | 110 +++++++ .../github.com/Microsoft/go-winio/syscall.go | 2 +- .../Microsoft/go-winio/zsyscall_windows.go | 88 +++-- 18 files changed, 1036 insertions(+), 312 deletions(-) create mode 100644 vendor/github.com/Microsoft/go-winio/hvsock.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_32.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_64.go create mode 100644 vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go diff --git a/vendor.conf b/vendor.conf index 3acc763e32..850e6acaf4 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,6 +1,6 @@ github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 github.com/Microsoft/hcsshim 672e52e9209d1e53718c1b6a7d68cc9272654ab5 -github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13 +github.com/Microsoft/go-winio 3fe4fa31662f6ede2353d913e93907b8e096e0b6 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go index 4334ff1cbe..746d6dd44d 100644 --- a/vendor/github.com/Microsoft/go-winio/file.go +++ b/vendor/github.com/Microsoft/go-winio/file.go @@ -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 } @@ -190,6 +192,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) diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go new file mode 100644 index 0000000000..29389efded --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/hvsock.go @@ -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) +} diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go index d99eedb648..d6a46f6a24 100644 --- a/vendor/github.com/Microsoft/go-winio/pipe.go +++ b/vendor/github.com/Microsoft/go-winio/pipe.go @@ -3,10 +3,13 @@ package winio import ( + "context" "errors" + "fmt" "io" "net" "os" + "runtime" "syscall" "time" "unsafe" @@ -18,6 +21,48 @@ import ( //sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo //sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc +//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile +//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb +//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U +//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl + +type ioStatusBlock struct { + Status, Information uintptr +} + +type objectAttributes struct { + Length uintptr + RootDirectory uintptr + ObjectName *unicodeString + Attributes uintptr + SecurityDescriptor *securityDescriptor + SecurityQoS uintptr +} + +type unicodeString struct { + Length uint16 + MaximumLength uint16 + Buffer uintptr +} + +type securityDescriptor struct { + Revision byte + Sbz1 byte + Control uint16 + Owner uintptr + Group uintptr + Sacl uintptr + Dacl uintptr +} + +type ntstatus int32 + +func (status ntstatus) Err() error { + if status >= 0 { + return nil + } + return rtlNtStatusToDosError(status) +} const ( cERROR_PIPE_BUSY = syscall.Errno(231) @@ -25,21 +70,20 @@ const ( cERROR_PIPE_CONNECTED = syscall.Errno(535) cERROR_SEM_TIMEOUT = syscall.Errno(121) - cPIPE_ACCESS_DUPLEX = 0x3 - cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000 - cSECURITY_SQOS_PRESENT = 0x100000 - cSECURITY_ANONYMOUS = 0 - - cPIPE_REJECT_REMOTE_CLIENTS = 0x8 - - cPIPE_UNLIMITED_INSTANCES = 255 - - cNMPWAIT_USE_DEFAULT_WAIT = 0 - cNMPWAIT_NOWAIT = 1 + cSECURITY_SQOS_PRESENT = 0x100000 + cSECURITY_ANONYMOUS = 0 cPIPE_TYPE_MESSAGE = 4 cPIPE_READMODE_MESSAGE = 2 + + cFILE_OPEN = 1 + cFILE_CREATE = 2 + + cFILE_PIPE_MESSAGE_TYPE = 1 + cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2 + + cSE_DACL_PRESENT = 4 ) var ( @@ -137,9 +181,30 @@ func (s pipeAddress) String() string { return string(s) } +// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout. +func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) { + for { + select { + case <-ctx.Done(): + return syscall.Handle(0), ctx.Err() + default: + h, err := createFile(*path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) + if err == nil { + return h, nil + } + if err != cERROR_PIPE_BUSY { + return h, &os.PathError{Err: err, Op: "open", Path: *path} + } + // Wait 10 msec and try again. This is a rather simplistic + // view, as we always try each 10 milliseconds. + time.Sleep(time.Millisecond * 10) + } + } +} + // DialPipe connects to a named pipe by path, timing out if the connection // takes longer than the specified duration. If timeout is nil, then we use -// a default timeout of 5 seconds. (We do not use WaitNamedPipe.) +// a default timeout of 2 seconds. (We do not use WaitNamedPipe.) func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { var absTimeout time.Time if timeout != nil { @@ -147,23 +212,22 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { } else { absTimeout = time.Now().Add(time.Second * 2) } + ctx, _ := context.WithDeadline(context.Background(), absTimeout) + conn, err := DialPipeContext(ctx, path) + if err == context.DeadlineExceeded { + return nil, ErrTimeout + } + return conn, err +} + +// DialPipeContext attempts to connect to a named pipe by `path` until `ctx` +// cancellation or timeout. +func DialPipeContext(ctx context.Context, path string) (net.Conn, error) { var err error var h syscall.Handle - for { - h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) - if err != cERROR_PIPE_BUSY { - break - } - if time.Now().After(absTimeout) { - return nil, ErrTimeout - } - - // Wait 10 msec and try again. This is a rather simplistic - // view, as we always try each 10 milliseconds. - time.Sleep(time.Millisecond * 10) - } + h, err = tryDialPipe(ctx, &path) if err != nil { - return nil, &os.PathError{Op: "open", Path: path, Err: err} + return nil, err } var flags uint32 @@ -194,43 +258,87 @@ type acceptResponse struct { } type win32PipeListener struct { - firstHandle syscall.Handle - path string - securityDescriptor []byte - config PipeConfig - acceptCh chan (chan acceptResponse) - closeCh chan int - doneCh chan int + firstHandle syscall.Handle + path string + config PipeConfig + acceptCh chan (chan acceptResponse) + closeCh chan int + doneCh chan int } -func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) { - var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED - if first { - flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE - } - - var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS - if c.MessageMode { - mode |= cPIPE_TYPE_MESSAGE - } - - sa := &syscall.SecurityAttributes{} - sa.Length = uint32(unsafe.Sizeof(*sa)) - if securityDescriptor != nil { - len := uint32(len(securityDescriptor)) - sa.SecurityDescriptor = localAlloc(0, len) - defer localFree(sa.SecurityDescriptor) - copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor) - } - h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa) +func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) { + path16, err := syscall.UTF16FromString(path) if err != nil { return 0, &os.PathError{Op: "open", Path: path, Err: err} } + + var oa objectAttributes + oa.Length = unsafe.Sizeof(oa) + + var ntPath unicodeString + if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + defer localFree(ntPath.Buffer) + oa.ObjectName = &ntPath + + // The security descriptor is only needed for the first pipe. + if first { + if sd != nil { + len := uint32(len(sd)) + sdb := localAlloc(0, len) + defer localFree(sdb) + copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd) + oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb)) + } else { + // Construct the default named pipe security descriptor. + var dacl uintptr + if err := rtlDefaultNpAcl(&dacl).Err(); err != nil { + return 0, fmt.Errorf("getting default named pipe ACL: %s", err) + } + defer localFree(dacl) + + sdb := &securityDescriptor{ + Revision: 1, + Control: cSE_DACL_PRESENT, + Dacl: dacl, + } + oa.SecurityDescriptor = sdb + } + } + + typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS) + if c.MessageMode { + typ |= cFILE_PIPE_MESSAGE_TYPE + } + + disposition := uint32(cFILE_OPEN) + access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE) + if first { + disposition = cFILE_CREATE + // By not asking for read or write access, the named pipe file system + // will put this pipe into an initially disconnected state, blocking + // client connections until the next call with first == false. + access = syscall.SYNCHRONIZE + } + + timeout := int64(-50 * 10000) // 50ms + + var ( + h syscall.Handle + iosb ioStatusBlock + ) + err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err() + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + + runtime.KeepAlive(ntPath) return h, nil } func (l *win32PipeListener) makeServerPipe() (*win32File, error) { - h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false) + h, err := makeServerPipeHandle(l.path, nil, &l.config, false) if err != nil { return nil, err } @@ -341,32 +449,13 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { if err != nil { return nil, err } - // Create a client handle and connect it. This results in the pipe - // instance always existing, so that clients see ERROR_PIPE_BUSY - // rather than ERROR_FILE_NOT_FOUND. This ties the first instance - // up so that no other instances can be used. This would have been - // cleaner if the Win32 API matched CreateFile with ConnectNamedPipe - // instead of CreateNamedPipe. (Apparently created named pipes are - // considered to be in listening state regardless of whether any - // active calls to ConnectNamedPipe are outstanding.) - h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) - if err != nil { - syscall.Close(h) - return nil, err - } - // Close the client handle. The server side of the instance will - // still be busy, leading to ERROR_PIPE_BUSY instead of - // ERROR_NOT_FOUND, as long as we don't close the server handle, - // or disconnect the client with DisconnectNamedPipe. - syscall.Close(h2) l := &win32PipeListener{ - firstHandle: h, - path: path, - securityDescriptor: sd, - config: *c, - acceptCh: make(chan (chan acceptResponse)), - closeCh: make(chan int), - doneCh: make(chan int), + firstHandle: h, + path: path, + config: *c, + acceptCh: make(chan (chan acceptResponse)), + closeCh: make(chan int), + doneCh: make(chan int), } go l.listenerRoutine() return l, nil diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/etw.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/etw.go index a958b26cd4..10cd08d84c 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/etw.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/etw.go @@ -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 diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdescriptor.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdescriptor.go index b16ad57ecf..cc41f15999 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdescriptor.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdescriptor.go @@ -17,7 +17,7 @@ const ( // will always be collected. type Level uint8 -// Predefined ETW log levels. +// Predefined ETW log levels from winmeta.xml in the Windows SDK. const ( LevelAlways Level = iota LevelCritical @@ -27,13 +27,30 @@ const ( LevelVerbose ) +// Opcode represents the operation that the event indicates is being performed. +type Opcode uint8 + +// Predefined ETW opcodes from winmeta.xml in the Windows SDK. +const ( + // OpcodeInfo indicates an informational event. + OpcodeInfo Opcode = iota + // OpcodeStart indicates the start of an operation. + OpcodeStart + // OpcodeStop indicates the end of an operation. + OpcodeStop + // OpcodeDCStart indicates the start of a provider capture state operation. + OpcodeDCStart + // OpcodeDCStop indicates the end of a provider capture state operation. + OpcodeDCStop +) + // EventDescriptor represents various metadata for an ETW event. type eventDescriptor struct { id uint16 version uint8 channel Channel level Level - opcode uint8 + opcode Opcode task uint16 keyword uint64 } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go index 33ad6a47f2..a0a8176ff9 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go @@ -1,13 +1,13 @@ package etw import ( - "golang.org/x/sys/windows" + "github.com/Microsoft/go-winio/pkg/guid" ) type eventOptions struct { descriptor *eventDescriptor - activityID *windows.GUID - relatedActivityID *windows.GUID + activityID *guid.GUID + relatedActivityID *guid.GUID tags uint32 } @@ -36,12 +36,20 @@ func WithKeyword(keyword uint64) EventOpt { } } +// WithChannel specifies the channel of the event to be written. func WithChannel(channel Channel) EventOpt { return func(options *eventOptions) { options.descriptor.channel = channel } } +// WithOpcode specifies the opcode of the event to be written. +func WithOpcode(opcode Opcode) EventOpt { + return func(options *eventOptions) { + options.descriptor.opcode = opcode + } +} + // WithTags specifies the tags of the event to be written. Tags is a 28-bit // value (top 4 bits are ignored) which are interpreted by the event consumer. func WithTags(newTags uint32) EventOpt { @@ -50,13 +58,15 @@ func WithTags(newTags uint32) EventOpt { } } -func WithActivityID(activityID *windows.GUID) EventOpt { +// WithActivityID specifies the activity ID of the event to be written. +func WithActivityID(activityID *guid.GUID) EventOpt { return func(options *eventOptions) { options.activityID = activityID } } -func WithRelatedActivityID(activityID *windows.GUID) EventOpt { +// WithRelatedActivityID specifies the parent activity ID of the event to be written. +func WithRelatedActivityID(activityID *guid.GUID) EventOpt { return func(options *eventOptions) { options.relatedActivityID = activityID } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go index 630a321268..c29c6bd8f9 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go @@ -1,7 +1,9 @@ package etw import ( + "fmt" "math" + "reflect" "unsafe" ) @@ -377,3 +379,124 @@ func Struct(name string, opts ...FieldOpt) FieldOpt { } } } + +// 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 +// slices of derived types (e.g. "[]foo"). +// +// For types that we don't support, the value is formatted via fmt.Sprint, and +// we also log a message that the type is unsupported along with the formatted +// type. The intent of this is to make it easier to see which types are not +// supported in traces, so we can evaluate adding support for more types in the +// future. +func SmartField(name string, v interface{}) FieldOpt { + switch v := v.(type) { + case bool: + return BoolField(name, v) + case []bool: + return BoolArray(name, v) + case string: + return StringField(name, v) + case []string: + return StringArray(name, v) + case int: + return IntField(name, v) + case []int: + return IntArray(name, v) + case int8: + return Int8Field(name, v) + case []int8: + return Int8Array(name, v) + case int16: + return Int16Field(name, v) + case []int16: + return Int16Array(name, v) + case int32: + return Int32Field(name, v) + case []int32: + return Int32Array(name, v) + case int64: + return Int64Field(name, v) + case []int64: + return Int64Array(name, v) + case uint: + return UintField(name, v) + case []uint: + return UintArray(name, v) + case uint8: + return Uint8Field(name, v) + case []uint8: + return Uint8Array(name, v) + case uint16: + return Uint16Field(name, v) + case []uint16: + return Uint16Array(name, v) + case uint32: + return Uint32Field(name, v) + case []uint32: + return Uint32Array(name, v) + case uint64: + return Uint64Field(name, v) + case []uint64: + return Uint64Array(name, v) + case uintptr: + return UintptrField(name, v) + case []uintptr: + return UintptrArray(name, v) + case float32: + return Float32Field(name, v) + case []float32: + return Float32Array(name, v) + case float64: + return Float64Field(name, v) + case []float64: + return Float64Array(name, v) + case error: + return StringField(name, v.Error()) + default: + switch rv := reflect.ValueOf(v); rv.Kind() { + case reflect.Bool: + return SmartField(name, rv.Bool()) + case reflect.Int: + return SmartField(name, int(rv.Int())) + case reflect.Int8: + return SmartField(name, int8(rv.Int())) + case reflect.Int16: + return SmartField(name, int16(rv.Int())) + case reflect.Int32: + return SmartField(name, int32(rv.Int())) + case reflect.Int64: + return SmartField(name, int64(rv.Int())) + case reflect.Uint: + return SmartField(name, uint(rv.Uint())) + case reflect.Uint8: + return SmartField(name, uint8(rv.Uint())) + case reflect.Uint16: + return SmartField(name, uint16(rv.Uint())) + case reflect.Uint32: + return SmartField(name, uint32(rv.Uint())) + case reflect.Uint64: + return SmartField(name, uint64(rv.Uint())) + case reflect.Uintptr: + return SmartField(name, uintptr(rv.Uint())) + case reflect.Float32: + return SmartField(name, float32(rv.Float())) + case reflect.Float64: + return SmartField(name, float64(rv.Float())) + case reflect.String: + return SmartField(name, rv.String()) + case reflect.Struct: + fields := make([]FieldOpt, 0, rv.NumField()) + for i := 0; i < rv.NumField(); i++ { + field := rv.Field(i) + if field.CanInterface() { + fields = append(fields, SmartField(name, field.Interface())) + } + } + return Struct(name, fields...) + } + } + + return StringField(name, fmt.Sprintf("(Unsupported: %T) %v", v, v)) +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go new file mode 100644 index 0000000000..bf82fa57c3 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go @@ -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 +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go new file mode 100644 index 0000000000..43b8142c5c --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go @@ -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 +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go index a81652f6fb..f71dc7c305 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go @@ -1,15 +1,12 @@ package etw import ( - "bytes" "crypto/sha1" "encoding/binary" - "encoding/hex" - "fmt" "strings" "unicode/utf16" - "unsafe" + "github.com/Microsoft/go-winio/pkg/guid" "golang.org/x/sys/windows" ) @@ -17,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 *windows.GUID + ID *guid.GUID handle providerHandle metadata []byte callback EnableCallback @@ -30,22 +27,14 @@ type Provider struct { // String returns the `provider`.ID as a string func (provider *Provider) String() string { - data1 := make([]byte, 4) - binary.BigEndian.PutUint32(data1, provider.ID.Data1) - data2 := make([]byte, 2) - binary.BigEndian.PutUint16(data2, provider.ID.Data2) - data3 := make([]byte, 2) - binary.BigEndian.PutUint16(data3, provider.ID.Data3) - return fmt.Sprintf( - "%s-%s-%s-%s-%s", - hex.EncodeToString(data1), - hex.EncodeToString(data2), - hex.EncodeToString(data3), - hex.EncodeToString(provider.ID.Data4[:2]), - hex.EncodeToString(provider.ID.Data4[2:])) + if provider == nil { + return "" + } + + return provider.ID.String() } -type providerHandle windows.Handle +type providerHandle uint64 // ProviderState informs the provider EnableCallback what action is being // performed. @@ -72,9 +61,9 @@ const ( // EnableCallback is the form of the callback function that receives provider // enable/disable notifications from ETW. -type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr) +type EnableCallback func(*guid.GUID, ProviderState, Level, uint64, uint64, uintptr) -func providerCallback(sourceID *windows.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 { @@ -96,7 +85,7 @@ func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, // for provider notifications. Because Go has trouble with callback arguments of // different size, it has only pointer-sized arguments, which are then cast to // the appropriate types when calling providerCallback. -func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr { +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) return 0 } @@ -108,7 +97,7 @@ func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintpt // 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) *windows.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} @@ -119,7 +108,7 @@ func providerIDFromName(name string) *windows.GUID { sum := buffer.Sum(nil) sum[7] = (sum[7] & 0xf) | 0x50 - return &windows.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]), @@ -133,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 *windows.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(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) } @@ -198,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 } @@ -219,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{} @@ -247,7 +207,7 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt dataBlobs = [][]byte{ed.bytes()} } - return provider.writeEventRaw(options.descriptor, nil, nil, [][]byte{em.bytes()}, dataBlobs) + return provider.writeEventRaw(options.descriptor, options.activityID, options.relatedActivityID, [][]byte{em.bytes()}, dataBlobs) } // writeEventRaw writes a single ETW event from the provider. This function is @@ -259,8 +219,8 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt // the ETW infrastructure. func (provider *Provider) writeEventRaw( descriptor *eventDescriptor, - activityID *windows.GUID, - relatedActivityID *windows.GUID, + activityID *guid.GUID, + relatedActivityID *guid.GUID, metadataBlobs [][]byte, dataBlobs [][]byte) error { @@ -275,5 +235,5 @@ func (provider *Provider) writeEventRaw( dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob)) } - return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0]) + return eventWriteTransfer(provider.handle, descriptor, (*windows.GUID)(activityID), (*windows.GUID)(relatedActivityID), dataDescriptorCount, &dataDescriptors[0]) } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_32.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_32.go new file mode 100644 index 0000000000..d0a7dac0c1 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_32.go @@ -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) +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_64.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_64.go new file mode 100644 index 0000000000..ef8b599a69 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/wrapper_64.go @@ -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) +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/zsyscall_windows.go index 802cd69ddf..4e8a719222 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/zsyscall_windows.go @@ -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 +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go b/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go index 81c14e428d..3476f7a61c 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go @@ -1,9 +1,6 @@ package etwlogrus import ( - "fmt" - "reflect" - "github.com/Microsoft/go-winio/pkg/etw" "github.com/sirupsen/logrus" ) @@ -71,7 +68,7 @@ func (h *Hook) Fire(e *logrus.Entry) error { fields = append(fields, etw.StringField("Message", e.Message)) for k, v := range e.Data { - fields = append(fields, getFieldOpt(k, v)) + fields = append(fields, etw.SmartField(k, v)) } return h.provider.WriteEvent( @@ -80,127 +77,6 @@ func (h *Hook) Fire(e *logrus.Entry) error { fields) } -// 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 -// slices of derived types (e.g. "[]foo"). -// -// For types that we don't support, the value is formatted via fmt.Sprint, and -// we also log a message that the type is unsupported along with the formatted -// type. The intent of this is to make it easier to see which types are not -// supported in traces, so we can evaluate adding support for more types in the -// future. -func getFieldOpt(k string, v interface{}) etw.FieldOpt { - switch v := v.(type) { - case bool: - return etw.BoolField(k, v) - case []bool: - return etw.BoolArray(k, v) - case string: - return etw.StringField(k, v) - case []string: - return etw.StringArray(k, v) - case int: - return etw.IntField(k, v) - case []int: - return etw.IntArray(k, v) - case int8: - return etw.Int8Field(k, v) - case []int8: - return etw.Int8Array(k, v) - case int16: - return etw.Int16Field(k, v) - case []int16: - return etw.Int16Array(k, v) - case int32: - return etw.Int32Field(k, v) - case []int32: - return etw.Int32Array(k, v) - case int64: - return etw.Int64Field(k, v) - case []int64: - return etw.Int64Array(k, v) - case uint: - return etw.UintField(k, v) - case []uint: - return etw.UintArray(k, v) - case uint8: - return etw.Uint8Field(k, v) - case []uint8: - return etw.Uint8Array(k, v) - case uint16: - return etw.Uint16Field(k, v) - case []uint16: - return etw.Uint16Array(k, v) - case uint32: - return etw.Uint32Field(k, v) - case []uint32: - return etw.Uint32Array(k, v) - case uint64: - return etw.Uint64Field(k, v) - case []uint64: - return etw.Uint64Array(k, v) - case uintptr: - return etw.UintptrField(k, v) - case []uintptr: - return etw.UintptrArray(k, v) - case float32: - return etw.Float32Field(k, v) - case []float32: - return etw.Float32Array(k, v) - case float64: - return etw.Float64Field(k, v) - case []float64: - return etw.Float64Array(k, v) - case error: - return etw.StringField(k, v.Error()) - default: - switch rv := reflect.ValueOf(v); rv.Kind() { - case reflect.Bool: - return getFieldOpt(k, rv.Bool()) - case reflect.Int: - return getFieldOpt(k, int(rv.Int())) - case reflect.Int8: - return getFieldOpt(k, int8(rv.Int())) - case reflect.Int16: - return getFieldOpt(k, int16(rv.Int())) - case reflect.Int32: - return getFieldOpt(k, int32(rv.Int())) - case reflect.Int64: - return getFieldOpt(k, int64(rv.Int())) - case reflect.Uint: - return getFieldOpt(k, uint(rv.Uint())) - case reflect.Uint8: - return getFieldOpt(k, uint8(rv.Uint())) - case reflect.Uint16: - return getFieldOpt(k, uint16(rv.Uint())) - case reflect.Uint32: - return getFieldOpt(k, uint32(rv.Uint())) - case reflect.Uint64: - return getFieldOpt(k, uint64(rv.Uint())) - case reflect.Uintptr: - return getFieldOpt(k, uintptr(rv.Uint())) - case reflect.Float32: - return getFieldOpt(k, float32(rv.Float())) - case reflect.Float64: - return getFieldOpt(k, float64(rv.Float())) - case reflect.String: - return getFieldOpt(k, rv.String()) - case reflect.Struct: - fields := make([]etw.FieldOpt, 0, rv.NumField()) - for i := 0; i < rv.NumField(); i++ { - field := rv.Field(i) - if field.CanInterface() { - fields = append(fields, getFieldOpt(k, field.Interface())) - } - } - return etw.Struct(k, fields...) - } - } - - return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v)) -} - // Close cleans up the hook and closes the ETW provider. If the provder was // registered by etwlogrus, it will be closed as part of `Close`. If the // provider was passed in, it will not be closed. diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go new file mode 100644 index 0000000000..cc50972dac --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go @@ -0,0 +1,110 @@ +package guid + +import ( + "crypto/rand" + "encoding/binary" + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/pkg/errors" + "golang.org/x/sys/windows" +) + +var _ = (json.Marshaler)(&GUID{}) +var _ = (json.Unmarshaler)(&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 +// that type. It is defined as its own type so that stringification and +// marshaling can be supported. The representation matches that used by native +// Windows code. +type GUID windows.GUID + +// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122. +func NewV4() (*GUID, error) { + var b [16]byte + if _, err := rand.Read(b[:]); err != nil { + return nil, err + } + + 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]) + 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 +} + +func (g *GUID) String() string { + return fmt.Sprintf( + "%08x-%04x-%04x-%04x-%012x", + g.Data1, + g.Data2, + g.Data3, + g.Data4[:2], + g.Data4[2:]) +} + +// 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) { + if len(s) != 36 { + return nil, errors.New("invalid GUID format (length)") + } + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return nil, errors.New("invalid GUID format (dashes)") + } + + var g GUID + + data1, err := strconv.ParseUint(s[0:8], 16, 32) + if err != nil { + return nil, errors.Wrap(err, "invalid GUID format (Data1)") + } + 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)") + } + 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)") + } + 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)") + } + g.Data4[i] = uint8(v) + } + + 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()) +} + +// 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), "\"")) + if err != nil { + return err + } + *g = *g2 + return nil +} diff --git a/vendor/github.com/Microsoft/go-winio/syscall.go b/vendor/github.com/Microsoft/go-winio/syscall.go index 20d64cf41d..5cb52bc746 100644 --- a/vendor/github.com/Microsoft/go-winio/syscall.go +++ b/vendor/github.com/Microsoft/go-winio/syscall.go @@ -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 diff --git a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go index 3f527639a4..e26b01fafb 100644 --- a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go @@ -1,4 +1,4 @@ -// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT +// Code generated by 'go generate'; DO NOT EDIT. package winio @@ -38,19 +38,25 @@ 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") procCancelIoEx = modkernel32.NewProc("CancelIoEx") 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") - procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW") procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") + procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") + procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U") + procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl") procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") @@ -69,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) { @@ -120,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 { @@ -176,27 +201,6 @@ func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityA return } -func waitNamedPipe(name string, timeout uint32) (err error) { - var _p0 *uint16 - _p0, err = syscall.UTF16PtrFromString(name) - if err != nil { - return - } - return _waitNamedPipe(_p0, timeout) -} - -func _waitNamedPipe(name *uint16, timeout uint32) (err error) { - r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) if r1 == 0 { @@ -227,6 +231,32 @@ func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { return } +func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) { + r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) + status = ntstatus(r0) + return +} + +func rtlNtStatusToDosError(status ntstatus) (winerr error) { + r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) + if r0 != 0 { + winerr = syscall.Errno(r0) + } + return +} + +func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) { + r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) + status = ntstatus(r0) + return +} + +func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) { + r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) + status = ntstatus(r0) + return +} + func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { var _p0 *uint16 _p0, err = syscall.UTF16PtrFromString(accountName) @@ -518,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 +} From 8ba31dccd13aa28115d6691d47e669c92af3e68a Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Tue, 6 Aug 2019 13:31:43 -0700 Subject: [PATCH 2/2] Update Microsoft/go-winio v0.4.14 Signed-off-by: Justin Terry (VM) (cherry picked from commit 35fe16b7eb18584cbeff69c0732224616eca67cd) Signed-off-by: Sebastiaan van Stijn --- vendor.conf | 2 +- vendor/github.com/Microsoft/go-winio/file.go | 12 +- vendor/github.com/Microsoft/go-winio/go.mod | 9 + .../github.com/Microsoft/go-winio/hvsock.go | 2 +- .../Microsoft/go-winio/pkg/etw/eventdata.go | 6 + .../Microsoft/go-winio/pkg/etw/eventopt.go | 8 +- .../Microsoft/go-winio/pkg/etw/fieldopt.go | 12 ++ .../Microsoft/go-winio/pkg/etw/newprovider.go | 4 +- .../pkg/etw/newprovider_unsupported.go | 2 +- .../Microsoft/go-winio/pkg/etw/provider.go | 43 ++-- .../Microsoft/go-winio/pkg/etwlogrus/hook.go | 47 +++-- .../Microsoft/go-winio/pkg/guid/guid.go | 191 +++++++++++++++--- .../github.com/Microsoft/go-winio/vhd/vhd.go | 10 +- 13 files changed, 266 insertions(+), 82 deletions(-) create mode 100644 vendor/github.com/Microsoft/go-winio/go.mod diff --git a/vendor.conf b/vendor.conf index 850e6acaf4..7cf684b009 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,6 +1,6 @@ github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 github.com/Microsoft/hcsshim 672e52e9209d1e53718c1b6a7d68cc9272654ab5 -github.com/Microsoft/go-winio 3fe4fa31662f6ede2353d913e93907b8e096e0b6 +github.com/Microsoft/go-winio 6c72808b55902eae4c5943626030429ff20f3b63 # v0.4.14 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go index 746d6dd44d..0385e41081 100644 --- a/vendor/github.com/Microsoft/go-winio/file.go +++ b/vendor/github.com/Microsoft/go-winio/file.go @@ -111,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 @@ -271,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() diff --git a/vendor/github.com/Microsoft/go-winio/go.mod b/vendor/github.com/Microsoft/go-winio/go.mod new file mode 100644 index 0000000000..b3846826b4 --- /dev/null +++ b/vendor/github.com/Microsoft/go-winio/go.mod @@ -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 +) diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go index 29389efded..dbfe790ee0 100644 --- a/vendor/github.com/Microsoft/go-winio/hvsock.go +++ b/vendor/github.com/Microsoft/go-winio/hvsock.go @@ -46,7 +46,7 @@ func (addr *HvsockAddr) String() string { func VsockServiceID(port uint32) guid.GUID { g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3") g.Data1 = port - return *g + return g } func (addr *HvsockAddr) raw() rawHvsockAddr { diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdata.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdata.go index 79dc10a5fa..a524d8920a 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdata.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventdata.go @@ -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) +} diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go index a0a8176ff9..fb6ac7dbcc 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/eventopt.go @@ -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 } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go index c29c6bd8f9..d544a2998f 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/fieldopt.go @@ -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: diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go index bf82fa57c3..f344fb65f7 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider.go @@ -15,7 +15,7 @@ import ( // 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) { +func NewProviderWithID(name string, id guid.GUID, callback EnableCallback) (provider *Provider, err error) { providerCallbackOnce.Do(func() { globalProviderCallback = windows.NewCallback(providerCallbackAdapter) }) @@ -29,7 +29,7 @@ func NewProviderWithID(name string, id *guid.GUID, callback EnableCallback) (pro provider.ID = id provider.callback = callback - if err := eventRegister((*windows.GUID)(provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil { + if err := eventRegister((*windows.GUID)(&provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil { return nil, err } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go index 43b8142c5c..808455cc2d 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/newprovider_unsupported.go @@ -7,6 +7,6 @@ import ( ) // NewProviderWithID returns a nil provider on unsupported platforms. -func NewProviderWithID(name string, id *guid.GUID, callback EnableCallback) (provider *Provider, err error) { +func NewProviderWithID(name string, id guid.GUID, callback EnableCallback) (provider *Provider, err error) { return nil, nil } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go b/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go index f71dc7c305..236960182a 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etw/provider.go @@ -14,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 @@ -61,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 { @@ -86,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 } @@ -94,26 +94,27 @@ func providerCallbackAdapter(sourceID *guid.GUID, state uintptr, level uintptr, // uses the same algorithm as used by .NET's EventSource class, which is based // on RFC 4122. More information on the algorithm can be found here: // https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/ -// 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 { +// +// The algorithm is roughly the RFC 4122 algorithm for a V5 UUID, but differs in +// the following ways: +// - The input name is first upper-cased, UTF16-encoded, and converted to +// big-endian. +// - No variant is set on the result UUID. +// - The result UUID is treated as being in little-endian format, rather than +// big-endian. +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} - buffer.Write(namespace) - + namespace := guid.GUID{0x482C2DB2, 0xC390, 0x47C8, [8]byte{0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}} + namespaceBytes := namespace.ToArray() + buffer.Write(namespaceBytes[:]) binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name)))) sum := buffer.Sum(nil) sum[7] = (sum[7] & 0xf) | 0x50 - return &guid.GUID{ - Data1: binary.LittleEndian.Uint32(sum[0:4]), - Data2: binary.LittleEndian.Uint16(sum[4:6]), - Data3: binary.LittleEndian.Uint16(sum[6:8]), - Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]}, - } + a := [16]byte{} + copy(a[:], sum) + return guid.FromWindowsArray(a) } // NewProvider creates and registers a new ETW provider. The provider ID is @@ -219,8 +220,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 { @@ -235,5 +236,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]) } diff --git a/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go b/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go index 3476f7a61c..38228c39c7 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go @@ -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 diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go index cc50972dac..5864065770 100644 --- a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go +++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go @@ -1,19 +1,43 @@ +// 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" + "crypto/sha1" + "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 +47,83 @@ 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 } - 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]) - copy(g.Data4[:], b[8:16]) + g := FromArray(b) + g.setVersion(4) // Version 4 means randomly generated. + g.setVariant(VariantRFC4122) - 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, nil } -func (g *GUID) String() string { +// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing) +// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name, +// and the sample code treats it as a series of bytes, so we do the same here. +// +// Some implementations, such as those found on Windows, treat the name as a +// big-endian UTF16 stream of bytes. If that is desired, the string can be +// encoded as such before being passed to this function. +func NewV5(namespace GUID, name []byte) (GUID, error) { + b := sha1.New() + namespaceBytes := namespace.ToArray() + b.Write(namespaceBytes[:]) + b.Write(name) + + a := [16]byte{} + copy(a[:], b.Sum(nil)) + + g := FromArray(a) + g.setVersion(5) // Version 5 means generated from a string. + g.setVariant(VariantRFC4122) + + return g, nil +} + +func fromArray(b [16]byte, order binary.ByteOrder) GUID { + var g GUID + 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]) + return g +} + +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 +136,100 @@ 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()) +func (g *GUID) setVariant(v Variant) { + d := g.Data4[0] + switch v { + case VariantNCS: + d = (d & 0x7f) + case VariantRFC4122: + d = (d & 0x3f) | 0x80 + case VariantMicrosoft: + d = (d & 0x1f) | 0xc0 + case VariantFuture: + d = (d & 0x0f) | 0xe0 + case VariantUnknown: + fallthrough + default: + panic(fmt.Sprintf("invalid variant: %d", v)) + } + g.Data4[0] = d } -// 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), "\"")) +// 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 +} + +func (g *GUID) setVersion(v Version) { + g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12) +} + +// 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 } diff --git a/vendor/github.com/Microsoft/go-winio/vhd/vhd.go b/vendor/github.com/Microsoft/go-winio/vhd/vhd.go index 48fb1276da..229ac25565 100644 --- a/vendor/github.com/Microsoft/go-winio/vhd/vhd.go +++ b/vendor/github.com/Microsoft/go-winio/vhd/vhd.go @@ -117,9 +117,13 @@ func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error { return nil } -// DetachVhd detaches a VHD attached at the given path. +// DetachVhd detaches a mounted container layer vhd found at `path`. func DetachVhd(path string) error { - handle, err := OpenVirtualDisk(path, VirtualDiskAccessDetach, OpenVirtualDiskFlagNone) + handle, err := OpenVirtualDisk( + path, + VirtualDiskAccessNone, + OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator) + if err != nil { return err } @@ -127,7 +131,7 @@ func DetachVhd(path string) error { return detachVirtualDisk(handle, 0, 0) } -// OpenVirtuaDisk obtains a handle to a VHD opened with supplied access mask and flags. +// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags. func OpenVirtualDisk(path string, accessMask VirtualDiskAccessMask, flag VirtualDiskFlag) (syscall.Handle, error) { var ( defaultType virtualStorageType