aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Godeps/Godeps.json6
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/LICENSE22
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/README.md15
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/backup.go266
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/file.go219
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/fileinfo.go54
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/pipe.go398
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/privilege.go150
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/reparse.go124
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/sd.go96
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/syscall.go3
-rw-r--r--Godeps/_workspace/src/github.com/microsoft/go-winio/zsyscall.go492
-rw-r--r--rpc/ipc_windows.go626
13 files changed, 1849 insertions, 622 deletions
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index f92b07481..119ed6205 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -1,6 +1,7 @@
{
"ImportPath": "github.com/ethereum/go-ethereum",
"GoVersion": "go1.5.2",
+ "GodepVersion": "v60",
"Packages": [
"./..."
],
@@ -94,6 +95,11 @@
"Rev": "e882a96ec18dd43fa283187b66af74497c9101c0"
},
{
+ "ImportPath": "github.com/microsoft/go-winio",
+ "Comment": "v0.2.0",
+ "Rev": "9e2895e5f6c3f16473b91d37fae6e89990a4520c"
+ },
+ {
"ImportPath": "github.com/nsf/termbox-go",
"Rev": "362329b0aa6447eadd52edd8d660ec1dff470295"
},
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/LICENSE b/Godeps/_workspace/src/github.com/microsoft/go-winio/LICENSE
new file mode 100644
index 000000000..b8b569d77
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/README.md b/Godeps/_workspace/src/github.com/microsoft/go-winio/README.md
new file mode 100644
index 000000000..478862a8b
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/README.md
@@ -0,0 +1,15 @@
+# go-winio
+
+This repository contains utilities for efficiently performing Win32 IO operations in
+Go. Currently, this is focused on accessing named pipes and other file handles, and
+for using named pipes as a net transport.
+
+This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
+to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
+newer operating systems. This is similar to the implementation of network sockets in Go's net
+package.
+
+Please see the LICENSE file for licensing information.
+
+Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
+for another named pipe implementation.
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/backup.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/backup.go
new file mode 100644
index 000000000..864935175
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/backup.go
@@ -0,0 +1,266 @@
+package winio
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "syscall"
+ "unicode/utf16"
+)
+
+//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
+//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
+
+const (
+ BackupData = uint32(iota + 1)
+ BackupEaData
+ BackupSecurity
+ BackupAlternateData
+ BackupLink
+ BackupPropertyData
+ BackupObjectId
+ BackupReparseData
+ BackupSparseBlock
+ BackupTxfsData
+)
+
+const (
+ StreamSparseAttributes = uint32(8)
+)
+
+const (
+ WRITE_DAC = 0x40000
+ WRITE_OWNER = 0x80000
+ ACCESS_SYSTEM_SECURITY = 0x1000000
+)
+
+// BackupHeader represents a backup stream of a file.
+type BackupHeader struct {
+ Id uint32 // The backup stream ID
+ Attributes uint32 // Stream attributes
+ Size int64 // The size of the stream in bytes
+ Name string // The name of the stream (for BackupAlternateData only).
+ Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
+}
+
+type win32StreamId struct {
+ StreamId uint32
+ Attributes uint32
+ Size uint64
+ NameSize uint32
+}
+
+// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
+// of BackupHeader values.
+type BackupStreamReader struct {
+ r io.Reader
+ bytesLeft int64
+}
+
+// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
+func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
+ return &BackupStreamReader{r, 0}
+}
+
+// Next returns the next backup stream and prepares for calls to Write(). It skips the remainder of the current stream if
+// it was not completely read.
+func (r *BackupStreamReader) Next() (*BackupHeader, error) {
+ if r.bytesLeft > 0 {
+ if _, err := io.Copy(ioutil.Discard, r); err != nil {
+ return nil, err
+ }
+ }
+ var wsi win32StreamId
+ if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
+ return nil, err
+ }
+ hdr := &BackupHeader{
+ Id: wsi.StreamId,
+ Attributes: wsi.Attributes,
+ Size: int64(wsi.Size),
+ }
+ if wsi.NameSize != 0 {
+ name := make([]uint16, int(wsi.NameSize/2))
+ if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
+ return nil, err
+ }
+ hdr.Name = syscall.UTF16ToString(name)
+ }
+ if wsi.StreamId == BackupSparseBlock {
+ if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
+ return nil, err
+ }
+ hdr.Size -= 8
+ }
+ r.bytesLeft = hdr.Size
+ return hdr, nil
+}
+
+// Read reads from the current backup stream.
+func (r *BackupStreamReader) Read(b []byte) (int, error) {
+ if r.bytesLeft == 0 {
+ return 0, io.EOF
+ }
+ if int64(len(b)) > r.bytesLeft {
+ b = b[:r.bytesLeft]
+ }
+ n, err := r.r.Read(b)
+ r.bytesLeft -= int64(n)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if r.bytesLeft == 0 && err == nil {
+ err = io.EOF
+ }
+ return n, err
+}
+
+// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
+type BackupStreamWriter struct {
+ w io.Writer
+ bytesLeft int64
+}
+
+// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
+func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
+ return &BackupStreamWriter{w, 0}
+}
+
+// WriteHeader writes the next backup stream header and prepares for calls to Write().
+func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
+ if w.bytesLeft != 0 {
+ return fmt.Errorf("missing %d bytes", w.bytesLeft)
+ }
+ name := utf16.Encode([]rune(hdr.Name))
+ wsi := win32StreamId{
+ StreamId: hdr.Id,
+ Attributes: hdr.Attributes,
+ Size: uint64(hdr.Size),
+ NameSize: uint32(len(name) * 2),
+ }
+ if hdr.Id == BackupSparseBlock {
+ // Include space for the int64 block offset
+ wsi.Size += 8
+ }
+ if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
+ return err
+ }
+ if len(name) != 0 {
+ if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
+ return err
+ }
+ }
+ if hdr.Id == BackupSparseBlock {
+ if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
+ return err
+ }
+ }
+ w.bytesLeft = hdr.Size
+ return nil
+}
+
+// Write writes to the current backup stream.
+func (w *BackupStreamWriter) Write(b []byte) (int, error) {
+ if w.bytesLeft < int64(len(b)) {
+ return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
+ }
+ n, err := w.w.Write(b)
+ w.bytesLeft -= int64(n)
+ return n, err
+}
+
+// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
+type BackupFileReader struct {
+ f *os.File
+ includeSecurity bool
+ ctx uintptr
+}
+
+// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
+// Read will attempt to read the security descriptor of the file.
+func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
+ r := &BackupFileReader{f, includeSecurity, 0}
+ runtime.SetFinalizer(r, func(r *BackupFileReader) { r.Close() })
+ return r
+}
+
+// Read reads a backup stream from the file by calling the Win32 API BackupRead().
+func (r *BackupFileReader) Read(b []byte) (int, error) {
+ var bytesRead uint32
+ err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
+ if err != nil {
+ return 0, &os.PathError{"BackupRead", r.f.Name(), err}
+ }
+ if bytesRead == 0 {
+ return 0, io.EOF
+ }
+ return int(bytesRead), nil
+}
+
+// Close frees Win32 resources associated with the BackupFileReader. It does not close
+// the underlying file.
+func (r *BackupFileReader) Close() error {
+ if r.ctx != 0 {
+ backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
+ r.ctx = 0
+ }
+ return nil
+}
+
+// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
+type BackupFileWriter struct {
+ f *os.File
+ includeSecurity bool
+ ctx uintptr
+}
+
+// NewBackupFileWrtier returns a new BackupFileWriter from a file handle. If includeSecurity is true,
+// Write() will attempt to restore the security descriptor from the stream.
+func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
+ w := &BackupFileWriter{f, includeSecurity, 0}
+ runtime.SetFinalizer(w, func(w *BackupFileWriter) { w.Close() })
+ return w
+}
+
+// Write restores a portion of the file using the provided backup stream.
+func (w *BackupFileWriter) Write(b []byte) (int, error) {
+ var bytesWritten uint32
+ err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
+ if err != nil {
+ return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
+ }
+ if int(bytesWritten) != len(b) {
+ return int(bytesWritten), errors.New("not all bytes could be written")
+ }
+ return len(b), nil
+}
+
+// Close frees Win32 resources associated with the BackupFileWriter. It does not
+// close the underlying file.
+func (w *BackupFileWriter) Close() error {
+ if w.ctx != 0 {
+ backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
+ w.ctx = 0
+ }
+ return nil
+}
+
+// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
+// or restore privileges have been acquired.
+//
+// If the file opened was a directory, it cannot be used with Readdir().
+func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
+ winPath, err := syscall.UTF16FromString(path)
+ if err != nil {
+ return nil, err
+ }
+ h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+ if err != nil {
+ err = &os.PathError{Op: "open", Path: path, Err: err}
+ return nil, err
+ }
+ return os.NewFile(uintptr(h), path), nil
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/file.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/file.go
new file mode 100644
index 000000000..fd16f0075
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/file.go
@@ -0,0 +1,219 @@
+package winio
+
+import (
+ "errors"
+ "io"
+ "runtime"
+ "sync"
+ "syscall"
+ "time"
+)
+
+//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
+//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 timeBeginPeriod(period uint32) (n int32) = winmm.timeBeginPeriod
+
+const (
+ cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
+ cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
+)
+
+var (
+ ErrFileClosed = errors.New("file has already been closed")
+ ErrTimeout = &timeoutError{}
+)
+
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string { return "i/o timeout" }
+func (e *timeoutError) Timeout() bool { return true }
+func (e *timeoutError) Temporary() bool { return true }
+
+var ioInitOnce sync.Once
+var ioCompletionPort syscall.Handle
+
+// ioResult contains the result of an asynchronous IO operation
+type ioResult struct {
+ bytes uint32
+ err error
+}
+
+// ioOperation represents an outstanding asynchronous Win32 IO
+type ioOperation struct {
+ o syscall.Overlapped
+ ch chan ioResult
+}
+
+func initIo() {
+ h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
+ if err != nil {
+ panic(err)
+ }
+ ioCompletionPort = h
+ go ioCompletionProcessor(h)
+}
+
+// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
+// It takes ownership of this handle and will close it if it is garbage collected.
+type win32File struct {
+ handle syscall.Handle
+ wg sync.WaitGroup
+ closing bool
+ readDeadline time.Time
+ writeDeadline time.Time
+}
+
+// makeWin32File makes a new win32File from an existing file handle
+func makeWin32File(h syscall.Handle) (*win32File, error) {
+ f := &win32File{handle: h}
+ ioInitOnce.Do(initIo)
+ _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
+ if err != nil {
+ return nil, err
+ }
+ err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
+ if err != nil {
+ return nil, err
+ }
+ runtime.SetFinalizer(f, (*win32File).closeHandle)
+ return f, nil
+}
+
+func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
+ return makeWin32File(h)
+}
+
+// closeHandle closes the resources associated with a Win32 handle
+func (f *win32File) closeHandle() {
+ if !f.closing {
+ // cancel all IO and wait for it to complete
+ f.closing = true
+ cancelIoEx(f.handle, nil)
+ f.wg.Wait()
+ // at this point, no new IO can start
+ syscall.Close(f.handle)
+ f.handle = 0
+ }
+}
+
+// Close closes a win32File.
+func (f *win32File) Close() error {
+ f.closeHandle()
+ runtime.SetFinalizer(f, nil)
+ return nil
+}
+
+// prepareIo prepares for a new IO operation
+func (f *win32File) prepareIo() (*ioOperation, error) {
+ f.wg.Add(1)
+ if f.closing {
+ return nil, ErrFileClosed
+ }
+ c := &ioOperation{}
+ c.ch = make(chan ioResult)
+ return c, nil
+}
+
+// ioCompletionProcessor processes completed async IOs forever
+func ioCompletionProcessor(h syscall.Handle) {
+ // Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
+ timeBeginPeriod(1)
+ for {
+ var bytes uint32
+ var key uintptr
+ var op *ioOperation
+ err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
+ if op == nil {
+ panic(err)
+ }
+ op.ch <- ioResult{bytes, err}
+ }
+}
+
+// asyncIo processes the return value from ReadFile or WriteFile, blocking until
+// the operation has actually completed.
+func (f *win32File) asyncIo(c *ioOperation, deadline time.Time, bytes uint32, err error) (int, error) {
+ if err != syscall.ERROR_IO_PENDING {
+ f.wg.Done()
+ return int(bytes), err
+ } else {
+ var r ioResult
+ wait := true
+ timedout := false
+ if f.closing {
+ cancelIoEx(f.handle, &c.o)
+ } else if !deadline.IsZero() {
+ now := time.Now()
+ if !deadline.After(now) {
+ timedout = true
+ } else {
+ timeout := time.After(deadline.Sub(now))
+ select {
+ case r = <-c.ch:
+ wait = false
+ case <-timeout:
+ timedout = true
+ }
+ }
+ }
+ if timedout {
+ cancelIoEx(f.handle, &c.o)
+ }
+ if wait {
+ r = <-c.ch
+ }
+ err = r.err
+ if err == syscall.ERROR_OPERATION_ABORTED {
+ if f.closing {
+ err = ErrFileClosed
+ } else if timedout {
+ err = ErrTimeout
+ }
+ }
+ f.wg.Done()
+ return int(r.bytes), err
+ }
+}
+
+// Read reads from a file handle.
+func (f *win32File) Read(b []byte) (int, error) {
+ c, err := f.prepareIo()
+ if err != nil {
+ return 0, err
+ }
+ var bytes uint32
+ err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
+ n, err := f.asyncIo(c, f.readDeadline, bytes, err)
+
+ // Handle EOF conditions.
+ if err == nil && n == 0 && len(b) != 0 {
+ return 0, io.EOF
+ } else if err == syscall.ERROR_BROKEN_PIPE {
+ return 0, io.EOF
+ } else {
+ return n, err
+ }
+}
+
+// Write writes to a file handle.
+func (f *win32File) Write(b []byte) (int, error) {
+ c, err := f.prepareIo()
+ if err != nil {
+ return 0, err
+ }
+ var bytes uint32
+ err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
+ return f.asyncIo(c, f.writeDeadline, bytes, err)
+}
+
+func (f *win32File) SetReadDeadline(t time.Time) error {
+ f.readDeadline = t
+ return nil
+}
+
+func (f *win32File) SetWriteDeadline(t time.Time) error {
+ f.writeDeadline = t
+ return nil
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/fileinfo.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/fileinfo.go
new file mode 100644
index 000000000..d5acb72d5
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/fileinfo.go
@@ -0,0 +1,54 @@
+package winio
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
+//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
+
+const (
+ fileBasicInfo = 0
+ fileIDInfo = 0x12
+)
+
+// FileBasicInfo contains file access time and file attributes information.
+type FileBasicInfo struct {
+ CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
+ FileAttributes uintptr // includes padding
+}
+
+// GetFileBasicInfo retrieves times and attributes for a file.
+func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
+ bi := &FileBasicInfo{}
+ if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
+ return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
+ }
+ return bi, nil
+}
+
+// SetFileBasicInfo sets times and attributes for a file.
+func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
+ if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
+ return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
+ }
+ return nil
+}
+
+// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
+// unique on a system.
+type FileIDInfo struct {
+ VolumeSerialNumber uint64
+ FileID [16]byte
+}
+
+// GetFileID retrieves the unique (volume, file ID) pair for a file.
+func GetFileID(f *os.File) (*FileIDInfo, error) {
+ fileID := &FileIDInfo{}
+ if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
+ return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
+ }
+ return fileID, nil
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/pipe.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/pipe.go
new file mode 100644
index 000000000..82db28306
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/pipe.go
@@ -0,0 +1,398 @@
+package winio
+
+import (
+ "errors"
+ "io"
+ "net"
+ "os"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
+//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
+//sys createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
+//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
+//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
+
+type securityAttributes struct {
+ Length uint32
+ SecurityDescriptor *byte
+ InheritHandle uint32
+}
+
+const (
+ cERROR_PIPE_BUSY = syscall.Errno(231)
+ 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
+
+ cPIPE_TYPE_MESSAGE = 4
+
+ cPIPE_READMODE_MESSAGE = 2
+)
+
+var (
+ // ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
+ // This error should match net.errClosing since docker takes a dependency on its text.
+ ErrPipeListenerClosed = errors.New("use of closed network connection")
+
+ errPipeWriteClosed = errors.New("pipe has been closed for write")
+)
+
+type win32Pipe struct {
+ *win32File
+ path string
+}
+
+type win32MessageBytePipe struct {
+ win32Pipe
+ writeClosed bool
+ readEOF bool
+}
+
+type pipeAddress string
+
+func (f *win32Pipe) LocalAddr() net.Addr {
+ return pipeAddress(f.path)
+}
+
+func (f *win32Pipe) RemoteAddr() net.Addr {
+ return pipeAddress(f.path)
+}
+
+func (f *win32Pipe) SetDeadline(t time.Time) error {
+ f.SetReadDeadline(t)
+ f.SetWriteDeadline(t)
+ return nil
+}
+
+// CloseWrite closes the write side of a message pipe in byte mode.
+func (f *win32MessageBytePipe) CloseWrite() error {
+ if f.writeClosed {
+ return errPipeWriteClosed
+ }
+ _, err := f.win32File.Write(nil)
+ if err != nil {
+ return err
+ }
+ f.writeClosed = true
+ return nil
+}
+
+// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
+// they are used to implement CloseWrite().
+func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
+ if f.writeClosed {
+ return 0, errPipeWriteClosed
+ }
+ if len(b) == 0 {
+ return 0, nil
+ }
+ return f.win32File.Write(b)
+}
+
+// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
+// mode pipe will return io.EOF, as will all subsequent reads.
+func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
+ if f.readEOF {
+ return 0, io.EOF
+ }
+ n, err := f.win32File.Read(b)
+ if err == io.EOF {
+ // If this was the result of a zero-byte read, then
+ // it is possible that the read was due to a zero-size
+ // message. Since we are simulating CloseWrite with a
+ // zero-byte message, ensure that all future Read() calls
+ // also return EOF.
+ f.readEOF = true
+ }
+ return n, err
+}
+
+func (s pipeAddress) Network() string {
+ return "pipe"
+}
+
+func (s pipeAddress) String() string {
+ return string(s)
+}
+
+// DialPipe connects to a named pipe by path, timing out if the connection
+// takes longer than the specified duration. If timeout is nil, then the timeout
+// is the default timeout established by the pipe server.
+func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
+ var absTimeout time.Time
+ if timeout != nil {
+ absTimeout = time.Now().Add(*timeout)
+ }
+ 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
+ }
+ now := time.Now()
+ var ms uint32
+ if absTimeout.IsZero() {
+ ms = cNMPWAIT_USE_DEFAULT_WAIT
+ } else if now.After(absTimeout) {
+ ms = cNMPWAIT_NOWAIT
+ } else {
+ ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
+ }
+ err = waitNamedPipe(path, ms)
+ if err != nil {
+ if err == cERROR_SEM_TIMEOUT {
+ return nil, ErrTimeout
+ }
+ break
+ }
+ }
+ if err != nil {
+ return nil, &os.PathError{Op: "open", Path: path, Err: err}
+ }
+
+ var flags uint32
+ err = getNamedPipeInfo(h, &flags, nil, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ var state uint32
+ err = getNamedPipeHandleState(h, &state, nil, nil, nil, nil, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ if state&cPIPE_READMODE_MESSAGE != 0 {
+ return nil, &os.PathError{Op: "open", Path: path, Err: errors.New("message readmode pipes not supported")}
+ }
+
+ f, err := makeWin32File(h)
+ if err != nil {
+ syscall.Close(h)
+ return nil, err
+ }
+
+ // If the pipe is in message mode, return a message byte pipe, which
+ // supports CloseWrite().
+ if flags&cPIPE_TYPE_MESSAGE != 0 {
+ return &win32MessageBytePipe{
+ win32Pipe: win32Pipe{win32File: f, path: path},
+ }, nil
+ }
+ return &win32Pipe{win32File: f, path: path}, nil
+}
+
+type acceptResponse struct {
+ f *win32File
+ err error
+}
+
+type win32PipeListener struct {
+ firstHandle syscall.Handle
+ path string
+ securityDescriptor []byte
+ 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
+ }
+
+ var sa securityAttributes
+ sa.Length = uint32(unsafe.Sizeof(sa))
+ if securityDescriptor != nil {
+ sa.SecurityDescriptor = &securityDescriptor[0]
+ }
+ h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, &sa)
+ if err != nil {
+ return 0, &os.PathError{Op: "open", Path: path, Err: err}
+ }
+ return h, nil
+}
+
+func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
+ h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
+ if err != nil {
+ return nil, err
+ }
+ f, err := makeWin32File(h)
+ if err != nil {
+ syscall.Close(h)
+ return nil, err
+ }
+ return f, nil
+}
+
+func (l *win32PipeListener) listenerRoutine() {
+ closed := false
+ for !closed {
+ select {
+ case <-l.closeCh:
+ closed = true
+ case responseCh := <-l.acceptCh:
+ p, err := l.makeServerPipe()
+ if err == nil {
+ // Wait for the client to connect.
+ ch := make(chan error)
+ go func() {
+ ch <- connectPipe(p)
+ }()
+ select {
+ case err = <-ch:
+ if err != nil {
+ p.Close()
+ p = nil
+ }
+ case <-l.closeCh:
+ // Abort the connect request by closing the handle.
+ p.Close()
+ p = nil
+ err = <-ch
+ if err == nil || err == ErrFileClosed {
+ err = ErrPipeListenerClosed
+ }
+ closed = true
+ }
+ }
+ responseCh <- acceptResponse{p, err}
+ }
+ }
+ syscall.Close(l.firstHandle)
+ l.firstHandle = 0
+ // Notify Close() and Accept() callers that the handle has been closed.
+ close(l.doneCh)
+}
+
+// PipeConfig contain configuration for the pipe listener.
+type PipeConfig struct {
+ // SecurityDescriptor contains a Windows security descriptor in SDDL format.
+ SecurityDescriptor string
+
+ // MessageMode determines whether the pipe is in byte or message mode. In either
+ // case the pipe is read in byte mode by default. The only practical difference in
+ // this implementation is that CloseWrite() is only supported for message mode pipes;
+ // CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
+ // transferred to the reader (and returned as io.EOF in this implementation)
+ // when the pipe is in message mode.
+ MessageMode bool
+
+ // InputBufferSize specifies the size the input buffer, in bytes.
+ InputBufferSize int32
+
+ // OutputBufferSize specifies the size the input buffer, in bytes.
+ OutputBufferSize int32
+}
+
+// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
+// The pipe must not already exist.
+func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
+ var (
+ sd []byte
+ err error
+ )
+ if c == nil {
+ c = &PipeConfig{}
+ }
+ if c.SecurityDescriptor != "" {
+ sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
+ if err != nil {
+ return nil, err
+ }
+ }
+ h, err := makeServerPipeHandle(path, sd, c, true)
+ if err != nil {
+ return nil, err
+ }
+ // Immediately open and then close a client handle so that the named pipe is
+ // created but not currently accepting connections.
+ 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
+ }
+ 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),
+ }
+ go l.listenerRoutine()
+ return l, nil
+}
+
+func connectPipe(p *win32File) error {
+ c, err := p.prepareIo()
+ if err != nil {
+ return err
+ }
+ err = connectNamedPipe(p.handle, &c.o)
+ _, err = p.asyncIo(c, time.Time{}, 0, err)
+ if err != nil && err != cERROR_PIPE_CONNECTED {
+ return err
+ }
+ return nil
+}
+
+func (l *win32PipeListener) Accept() (net.Conn, error) {
+ ch := make(chan acceptResponse)
+ select {
+ case l.acceptCh <- ch:
+ response := <-ch
+ err := response.err
+ if err != nil {
+ return nil, err
+ }
+ if l.config.MessageMode {
+ return &win32MessageBytePipe{
+ win32Pipe: win32Pipe{win32File: response.f, path: l.path},
+ }, nil
+ }
+ return &win32Pipe{win32File: response.f, path: l.path}, nil
+ case <-l.doneCh:
+ return nil, ErrPipeListenerClosed
+ }
+}
+
+func (l *win32PipeListener) Close() error {
+ select {
+ case l.closeCh <- 1:
+ <-l.doneCh
+ case <-l.doneCh:
+ }
+ return nil
+}
+
+func (l *win32PipeListener) Addr() net.Addr {
+ return pipeAddress(l.path)
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/privilege.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/privilege.go
new file mode 100644
index 000000000..81f9af7b7
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/privilege.go
@@ -0,0 +1,150 @@
+package winio
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "runtime"
+ "syscall"
+ "unicode/utf16"
+)
+
+//sys adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
+//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
+//sys revertToSelf() (err error) = advapi32.RevertToSelf
+//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) = advapi32.OpenThreadToken
+//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
+//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
+//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
+//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
+
+const (
+ SE_PRIVILEGE_ENABLED = 2
+
+ ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
+
+ SeBackupPrivilege = "SeBackupPrivilege"
+ SeRestorePrivilege = "SeRestorePrivilege"
+)
+
+const (
+ securityAnonymous = iota
+ securityIdentification
+ securityImpersonation
+ securityDelegation
+)
+
+type PrivilegeError struct {
+ privileges []uint64
+}
+
+func (e *PrivilegeError) Error() string {
+ s := ""
+ if len(e.privileges) > 1 {
+ s = "Could not enable privileges "
+ } else {
+ s = "Could not enable privilege "
+ }
+ for i, p := range e.privileges {
+ if i != 0 {
+ s += ", "
+ }
+ s += `"`
+ s += getPrivilegeName(p)
+ s += `"`
+ }
+ return s
+}
+
+func RunWithPrivilege(name string, fn func() error) error {
+ return RunWithPrivileges([]string{name}, fn)
+}
+
+func RunWithPrivileges(names []string, fn func() error) error {
+ var privileges []uint64
+ for _, name := range names {
+ p := uint64(0)
+ err := lookupPrivilegeValue("", name, &p)
+ if err != nil {
+ return err
+ }
+ privileges = append(privileges, p)
+ }
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ token, err := newThreadToken()
+ if err != nil {
+ return err
+ }
+ defer releaseThreadToken(token)
+ err = adjustPrivileges(token, privileges)
+ if err != nil {
+ return err
+ }
+ return fn()
+}
+
+func adjustPrivileges(token syscall.Handle, privileges []uint64) error {
+ var b bytes.Buffer
+ binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
+ for _, p := range privileges {
+ binary.Write(&b, binary.LittleEndian, p)
+ binary.Write(&b, binary.LittleEndian, uint32(SE_PRIVILEGE_ENABLED))
+ }
+ prevState := make([]byte, b.Len())
+ reqSize := uint32(0)
+ success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
+ if !success {
+ return err
+ }
+ if err == ERROR_NOT_ALL_ASSIGNED {
+ return &PrivilegeError{privileges}
+ }
+ return nil
+}
+
+func getPrivilegeName(luid uint64) string {
+ var nameBuffer [256]uint16
+ bufSize := uint32(len(nameBuffer))
+ err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
+ if err != nil {
+ return fmt.Sprintf("<unknown privilege %d>", luid)
+ }
+
+ var displayNameBuffer [256]uint16
+ displayBufSize := uint32(len(displayNameBuffer))
+ var langId uint32
+ err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langId)
+ if err != nil {
+ return fmt.Sprintf("<unknown privilege %s>", utf16.Decode(nameBuffer[:bufSize]))
+ }
+
+ return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
+}
+
+func newThreadToken() (syscall.Handle, error) {
+ err := impersonateSelf(securityImpersonation)
+ if err != nil {
+ panic(err)
+ return 0, err
+ }
+
+ var token syscall.Handle
+ err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
+ if err != nil {
+ rerr := revertToSelf()
+ if rerr != nil {
+ panic(rerr)
+ }
+ return 0, err
+ }
+ return token, nil
+}
+
+func releaseThreadToken(h syscall.Handle) {
+ err := revertToSelf()
+ if err != nil {
+ panic(err)
+ }
+ syscall.Close(h)
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/reparse.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/reparse.go
new file mode 100644
index 000000000..96d7b9a87
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/reparse.go
@@ -0,0 +1,124 @@
+package winio
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "strings"
+ "unicode/utf16"
+ "unsafe"
+)
+
+const (
+ reparseTagMountPoint = 0xA0000003
+ reparseTagSymlink = 0xA000000C
+)
+
+type reparseDataBuffer struct {
+ ReparseTag uint32
+ ReparseDataLength uint16
+ Reserved uint16
+ SubstituteNameOffset uint16
+ SubstituteNameLength uint16
+ PrintNameOffset uint16
+ PrintNameLength uint16
+}
+
+// ReparsePoint describes a Win32 symlink or mount point.
+type ReparsePoint struct {
+ Target string
+ IsMountPoint bool
+}
+
+// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
+// mount point reparse point.
+type UnsupportedReparsePointError struct {
+ Tag uint32
+}
+
+func (e *UnsupportedReparsePointError) Error() string {
+ return fmt.Sprintf("unsupported reparse point %x", e.Tag)
+}
+
+// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
+// or a mount point.
+func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
+ isMountPoint := false
+ tag := binary.LittleEndian.Uint32(b[0:4])
+ switch tag {
+ case reparseTagMountPoint:
+ isMountPoint = true
+ case reparseTagSymlink:
+ default:
+ return nil, &UnsupportedReparsePointError{tag}
+ }
+ nameOffset := 16 + binary.LittleEndian.Uint16(b[12:14])
+ if !isMountPoint {
+ nameOffset += 4
+ }
+ nameLength := binary.LittleEndian.Uint16(b[14:16])
+ name := make([]uint16, nameLength/2)
+ err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
+ if err != nil {
+ return nil, err
+ }
+ return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
+}
+
+func isDriveLetter(c byte) bool {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
+// mount point.
+func EncodeReparsePoint(rp *ReparsePoint) []byte {
+ // Generate an NT path and determine if this is a relative path.
+ var ntTarget string
+ relative := false
+ if strings.HasPrefix(rp.Target, `\\?\`) {
+ ntTarget = rp.Target
+ } else if strings.HasPrefix(rp.Target, `\\`) {
+ ntTarget = `\??\UNC\` + rp.Target[2:]
+ } else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
+ ntTarget = `\??\` + rp.Target
+ } else {
+ ntTarget = rp.Target
+ relative = true
+ }
+
+ // The paths must be NUL-terminated even though they are counted strings.
+ target16 := utf16.Encode([]rune(rp.Target + "\x00"))
+ ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
+
+ size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
+ size += len(ntTarget16)*2 + len(target16)*2
+
+ tag := uint32(reparseTagMountPoint)
+ if !rp.IsMountPoint {
+ tag = reparseTagSymlink
+ size += 4 // Add room for symlink flags
+ }
+
+ data := reparseDataBuffer{
+ ReparseTag: tag,
+ ReparseDataLength: uint16(size),
+ SubstituteNameOffset: 0,
+ SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
+ PrintNameOffset: uint16(len(ntTarget16) * 2),
+ PrintNameLength: uint16((len(target16) - 1) * 2),
+ }
+
+ var b bytes.Buffer
+ binary.Write(&b, binary.LittleEndian, &data)
+ if !rp.IsMountPoint {
+ flags := uint32(0)
+ if relative {
+ flags |= 1
+ }
+ binary.Write(&b, binary.LittleEndian, flags)
+ }
+
+ binary.Write(&b, binary.LittleEndian, ntTarget16)
+ binary.Write(&b, binary.LittleEndian, target16)
+ return b.Bytes()
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/sd.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/sd.go
new file mode 100644
index 000000000..60ab56ce7
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/sd.go
@@ -0,0 +1,96 @@
+package winio
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
+//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
+//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
+//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
+//sys localFree(mem uintptr) = LocalFree
+//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
+
+const (
+ cERROR_NONE_MAPPED = syscall.Errno(1332)
+)
+
+type AccountLookupError struct {
+ Name string
+ Err error
+}
+
+func (e *AccountLookupError) Error() string {
+ if e.Name == "" {
+ return "lookup account: empty account name specified"
+ }
+ var s string
+ switch e.Err {
+ case cERROR_NONE_MAPPED:
+ s = "not found"
+ default:
+ s = e.Err.Error()
+ }
+ return "lookup account " + e.Name + ": " + s
+}
+
+type SddlConversionError struct {
+ Sddl string
+ Err error
+}
+
+func (e *SddlConversionError) Error() string {
+ return "convert " + e.Sddl + ": " + e.Err.Error()
+}
+
+// LookupSidByName looks up the SID of an account by name
+func LookupSidByName(name string) (sid string, err error) {
+ if name == "" {
+ return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
+ }
+
+ var sidSize, sidNameUse, refDomainSize uint32
+ err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
+ if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
+ return "", &AccountLookupError{name, err}
+ }
+ sidBuffer := make([]byte, sidSize)
+ refDomainBuffer := make([]uint16, refDomainSize)
+ err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
+ if err != nil {
+ return "", &AccountLookupError{name, err}
+ }
+ var strBuffer *uint16
+ err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
+ if err != nil {
+ return "", &AccountLookupError{name, err}
+ }
+ sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
+ localFree(uintptr(unsafe.Pointer(strBuffer)))
+ return sid, nil
+}
+
+func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
+ var sdBuffer uintptr
+ err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
+ if err != nil {
+ return nil, &SddlConversionError{sddl, err}
+ }
+ defer localFree(sdBuffer)
+ sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
+ copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
+ return sd, nil
+}
+
+func SecurityDescriptorToSddl(sd []byte) (string, error) {
+ var sddl *uint16
+ // The returned string length seems to including an aribtrary number of terminating NULs.
+ // Don't use it.
+ err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
+ if err != nil {
+ return "", err
+ }
+ defer localFree(uintptr(unsafe.Pointer(sddl)))
+ return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
+}
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/syscall.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/syscall.go
new file mode 100644
index 000000000..96fdff7b4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/syscall.go
@@ -0,0 +1,3 @@
+package winio
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
diff --git a/Godeps/_workspace/src/github.com/microsoft/go-winio/zsyscall.go b/Godeps/_workspace/src/github.com/microsoft/go-winio/zsyscall.go
new file mode 100644
index 000000000..74b6e97a6
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/microsoft/go-winio/zsyscall.go
@@ -0,0 +1,492 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package winio
+
+import "unsafe"
+import "syscall"
+
+var _ unsafe.Pointer
+
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+ modwinmm = syscall.NewLazyDLL("winmm.dll")
+ modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
+
+ procCancelIoEx = modkernel32.NewProc("CancelIoEx")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
+ proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
+ procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
+ procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
+ procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
+ procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
+ procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
+ procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
+ procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
+ procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
+ procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
+ procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
+ procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
+ procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
+ procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
+ procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
+ procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
+ procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
+ procBackupRead = modkernel32.NewProc("BackupRead")
+ procBackupWrite = modkernel32.NewProc("BackupWrite")
+)
+
+func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
+ newport = syscall.Handle(r0)
+ if newport == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func timeBeginPeriod(period uint32) (n int32) {
+ r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
+ n = int32(r0)
+ 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 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return
+ }
+ return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
+}
+
+func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
+ handle = syscall.Handle(r0)
+ if handle == syscall.InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return
+ }
+ return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
+}
+
+func _createFile(name *uint16, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
+ handle = syscall.Handle(r0)
+ if handle == syscall.InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ 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 = error(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 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
+ r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ 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)
+ if err != nil {
+ return
+ }
+ return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
+}
+
+func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func convertSidToStringSid(sid *byte, str **uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(str)
+ if err != nil {
+ return
+ }
+ return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
+}
+
+func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func localFree(mem uintptr) {
+ syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
+ return
+}
+
+func getSecurityDescriptorLength(sd uintptr) (len uint32) {
+ r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
+ len = uint32(r0)
+ return
+}
+
+func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
+ var _p0 uint32
+ if releaseAll {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
+ success = r0 != 0
+ if true {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func impersonateSelf(level uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func revertToSelf() (err error) {
+ r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) {
+ var _p0 uint32
+ if openAsSelf {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getCurrentThread() (h syscall.Handle) {
+ r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
+ h = syscall.Handle(r0)
+ return
+}
+
+func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(systemName)
+ if err != nil {
+ return
+ }
+ var _p1 *uint16
+ _p1, err = syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return
+ }
+ return _lookupPrivilegeValue(_p0, _p1, luid)
+}
+
+func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
+ r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(systemName)
+ if err != nil {
+ return
+ }
+ return _lookupPrivilegeName(_p0, luid, buffer, size)
+}
+
+func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(systemName)
+ if err != nil {
+ return
+ }
+ return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
+}
+
+func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
+ var _p0 *byte
+ if len(b) > 0 {
+ _p0 = &b[0]
+ }
+ var _p1 uint32
+ if abort {
+ _p1 = 1
+ } else {
+ _p1 = 0
+ }
+ var _p2 uint32
+ if processSecurity {
+ _p2 = 1
+ } else {
+ _p2 = 0
+ }
+ r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
+ var _p0 *byte
+ if len(b) > 0 {
+ _p0 = &b[0]
+ }
+ var _p1 uint32
+ if abort {
+ _p1 = 1
+ } else {
+ _p1 = 0
+ }
+ var _p2 uint32
+ if processSecurity {
+ _p2 = 1
+ } else {
+ _p2 = 0
+ }
+ r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
diff --git a/rpc/ipc_windows.go b/rpc/ipc_windows.go
index 1d4672ad2..c5f69589e 100644
--- a/rpc/ipc_windows.go
+++ b/rpc/ipc_windows.go
@@ -19,637 +19,19 @@
package rpc
import (
- "fmt"
- "io"
"net"
- "sync"
- "syscall"
"time"
- "unsafe"
-)
-
-var (
- modkernel32 = syscall.NewLazyDLL("kernel32.dll")
- procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
- procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
- procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
- procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
- procCreateEventW = modkernel32.NewProc("CreateEventW")
- procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
- procCancelIoEx = modkernel32.NewProc("CancelIoEx")
+ "github.com/microsoft/go-winio"
)
-func createNamedPipe(name *uint16, openMode uint32, pipeMode uint32, maxInstances uint32, outBufSize uint32, inBufSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(openMode), uintptr(pipeMode), uintptr(maxInstances), uintptr(outBufSize), uintptr(inBufSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
- handle = syscall.Handle(r0)
- if handle == syscall.InvalidHandle {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func cancelIoEx(handle syscall.Handle, overlapped *syscall.Overlapped) (err error) {
- r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), 0)
- if r1 == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func connectNamedPipe(handle syscall.Handle, overlapped *syscall.Overlapped) (err error) {
- r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), 0)
- if r1 == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func disconnectNamedPipe(handle syscall.Handle) (err error) {
- r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(handle), 0, 0)
- if r1 == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-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 = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
- var _p0 uint32
- if manualReset {
- _p0 = 1
- } else {
- _p0 = 0
- }
- var _p1 uint32
- if initialState {
- _p1 = 1
- } else {
- _p1 = 0
- }
- r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(sa)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0)
- handle = syscall.Handle(r0)
- if handle == syscall.InvalidHandle {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func getOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped, transferred *uint32, wait bool) (err error) {
- var _p0 uint32
- if wait {
- _p0 = 1
- } else {
- _p0 = 0
- }
- r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transferred)), uintptr(_p0), 0, 0)
- if r1 == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-const (
- // openMode
- pipe_access_duplex = 0x3
- pipe_access_inbound = 0x1
- pipe_access_outbound = 0x2
-
- // openMode write flags
- file_flag_first_pipe_instance = 0x00080000
- file_flag_write_through = 0x80000000
- file_flag_overlapped = 0x40000000
-
- // openMode ACL flags
- write_dac = 0x00040000
- write_owner = 0x00080000
- access_system_security = 0x01000000
-
- // pipeMode
- pipe_type_byte = 0x0
- pipe_type_message = 0x4
-
- // pipeMode read mode flags
- pipe_readmode_byte = 0x0
- pipe_readmode_message = 0x2
-
- // pipeMode wait mode flags
- pipe_wait = 0x0
- pipe_nowait = 0x1
-
- // pipeMode remote-client mode flags
- pipe_accept_remote_clients = 0x0
- pipe_reject_remote_clients = 0x8
-
- pipe_unlimited_instances = 255
-
- nmpwait_wait_forever = 0xFFFFFFFF
-
- // the two not-an-errors below occur if a client connects to the pipe between
- // the server's CreateNamedPipe and ConnectNamedPipe calls.
- error_no_data syscall.Errno = 0xE8
- error_pipe_connected syscall.Errno = 0x217
- error_pipe_busy syscall.Errno = 0xE7
- error_sem_timeout syscall.Errno = 0x79
-
- error_bad_pathname syscall.Errno = 0xA1
- error_invalid_name syscall.Errno = 0x7B
-
- error_io_incomplete syscall.Errno = 0x3e4
-)
-
-var _ net.Conn = (*PipeConn)(nil)
-var _ net.Listener = (*PipeListener)(nil)
-
-// ErrClosed is the error returned by PipeListener.Accept when Close is called
-// on the PipeListener.
-var ErrClosed = PipeError{"Pipe has been closed.", false}
-
-// PipeError is an error related to a call to a pipe
-type PipeError struct {
- msg string
- timeout bool
-}
-
-// Error implements the error interface
-func (e PipeError) Error() string {
- return e.msg
-}
-
-// Timeout implements net.AddrError.Timeout()
-func (e PipeError) Timeout() bool {
- return e.timeout
-}
-
-// Temporary implements net.AddrError.Temporary()
-func (e PipeError) Temporary() bool {
- return false
-}
-
-// Dial connects to a named pipe with the given address. If the specified pipe is not available,
-// it will wait indefinitely for the pipe to become available.
-//
-// The address must be of the form \\.\\pipe\<name> for local pipes and \\<computer>\pipe\<name>
-// for remote pipes.
-//
-// Dial will return a PipeError if you pass in a badly formatted pipe name.
-//
-// Examples:
-// // local pipe
-// conn, err := Dial(`\\.\pipe\mypipename`)
-//
-// // remote pipe
-// conn, err := Dial(`\\othercomp\pipe\mypipename`)
-func Dial(address string) (*PipeConn, error) {
- for {
- conn, err := dial(address, nmpwait_wait_forever)
- if err == nil {
- return conn, nil
- }
- if isPipeNotReady(err) {
- <-time.After(100 * time.Millisecond)
- continue
- }
- return nil, err
- }
-}
-
-// DialTimeout acts like Dial, but will time out after the duration of timeout
-func DialTimeout(address string, timeout time.Duration) (*PipeConn, error) {
- deadline := time.Now().Add(timeout)
-
- now := time.Now()
- for now.Before(deadline) {
- millis := uint32(deadline.Sub(now) / time.Millisecond)
- conn, err := dial(address, millis)
- if err == nil {
- return conn, nil
- }
- if err == error_sem_timeout {
- // This is WaitNamedPipe's timeout error, so we know we're done
- return nil, PipeError{fmt.Sprintf(
- "Timed out waiting for pipe '%s' to come available", address), true}
- }
- if isPipeNotReady(err) {
- left := deadline.Sub(time.Now())
- retry := 100 * time.Millisecond
- if left > retry {
- <-time.After(retry)
- } else {
- <-time.After(left - time.Millisecond)
- }
- now = time.Now()
- continue
- }
- return nil, err
- }
- return nil, PipeError{fmt.Sprintf(
- "Timed out waiting for pipe '%s' to come available", address), true}
-}
-
-// isPipeNotReady checks the error to see if it indicates the pipe is not ready
-func isPipeNotReady(err error) bool {
- // Pipe Busy means another client just grabbed the open pipe end,
- // and the server hasn't made a new one yet.
- // File Not Found means the server hasn't created the pipe yet.
- // Neither is a fatal error.
-
- return err == syscall.ERROR_FILE_NOT_FOUND || err == error_pipe_busy
-}
-
-// newOverlapped creates a structure used to track asynchronous
-// I/O requests that have been issued.
-func newOverlapped() (*syscall.Overlapped, error) {
- event, err := createEvent(nil, true, true, nil)
- if err != nil {
- return nil, err
- }
- return &syscall.Overlapped{HEvent: event}, nil
-}
-
-// waitForCompletion waits for an asynchronous I/O request referred to by overlapped to complete.
-// This function returns the number of bytes transferred by the operation and an error code if
-// applicable (nil otherwise).
-func waitForCompletion(handle syscall.Handle, overlapped *syscall.Overlapped) (uint32, error) {
- _, err := syscall.WaitForSingleObject(overlapped.HEvent, syscall.INFINITE)
- if err != nil {
- return 0, err
- }
- var transferred uint32
- err = getOverlappedResult(handle, overlapped, &transferred, true)
- return transferred, err
-}
-
-// dial is a helper to initiate a connection to a named pipe that has been started by a server.
-// The timeout is only enforced if the pipe server has already created the pipe, otherwise
-// this function will return immediately.
-func dial(address string, timeout uint32) (*PipeConn, error) {
- name, err := syscall.UTF16PtrFromString(string(address))
- if err != nil {
- return nil, err
- }
- // If at least one instance of the pipe has been created, this function
- // will wait timeout milliseconds for it to become available.
- // It will return immediately regardless of timeout, if no instances
- // of the named pipe have been created yet.
- // If this returns with no error, there is a pipe available.
- if err := waitNamedPipe(name, timeout); err != nil {
- if err == error_bad_pathname {
- // badly formatted pipe name
- return nil, badAddr(address)
- }
- return nil, err
- }
- pathp, err := syscall.UTF16PtrFromString(address)
- if err != nil {
- return nil, err
- }
- handle, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE,
- uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), nil, syscall.OPEN_EXISTING,
- syscall.FILE_FLAG_OVERLAPPED, 0)
- if err != nil {
- return nil, err
- }
- return &PipeConn{handle: handle, addr: PipeAddr(address)}, nil
-}
-
-// Listen returns a new PipeListener that will listen on a pipe with the given
-// address. The address must be of the form \\.\pipe\<name>
-//
-// Listen will return a PipeError for an incorrectly formatted pipe name.
-func Listen(address string) (*PipeListener, error) {
- handle, err := createPipe(address, true)
- if err == error_invalid_name {
- return nil, badAddr(address)
- }
- if err != nil {
- return nil, err
- }
- return &PipeListener{
- addr: PipeAddr(address),
- handle: handle,
- }, nil
-}
-
-// PipeListener is a named pipe listener. Clients should typically
-// use variables of type net.Listener instead of assuming named pipe.
-type PipeListener struct {
- addr PipeAddr
- handle syscall.Handle
- closed bool
-
- // acceptHandle contains the current handle waiting for
- // an incoming connection or nil.
- acceptHandle syscall.Handle
- // acceptOverlapped is set before waiting on a connection.
- // If not waiting, it is nil.
- acceptOverlapped *syscall.Overlapped
- // acceptMutex protects the handle and overlapped structure.
- acceptMutex sync.Mutex
-}
-
-// Accept implements the Accept method in the net.Listener interface; it
-// waits for the next call and returns a generic net.Conn.
-func (l *PipeListener) Accept() (net.Conn, error) {
- c, err := l.AcceptPipe()
- for err == error_no_data {
- // Ignore clients that connect and immediately disconnect.
- c, err = l.AcceptPipe()
- }
- if err != nil {
- return nil, err
- }
- return c, nil
-}
-
-// AcceptPipe accepts the next incoming call and returns the new connection.
-// It might return an error if a client connected and immediately cancelled
-// the connection.
-func (l *PipeListener) AcceptPipe() (*PipeConn, error) {
- if l == nil || l.addr == "" || l.closed {
- return nil, syscall.EINVAL
- }
-
- // the first time we call accept, the handle will have been created by the Listen
- // call. This is to prevent race conditions where the client thinks the server
- // isn't listening because it hasn't actually called create yet. After the first time, we'll
- // have to create a new handle each time
- handle := l.handle
- if handle == 0 {
- var err error
- handle, err = createPipe(string(l.addr), false)
- if err != nil {
- return nil, err
- }
- } else {
- l.handle = 0
- }
-
- overlapped, err := newOverlapped()
- if err != nil {
- return nil, err
- }
- defer syscall.CloseHandle(overlapped.HEvent)
- if err := connectNamedPipe(handle, overlapped); err != nil && err != error_pipe_connected {
- if err == error_io_incomplete || err == syscall.ERROR_IO_PENDING {
- l.acceptMutex.Lock()
- l.acceptOverlapped = overlapped
- l.acceptHandle = handle
- l.acceptMutex.Unlock()
- defer func() {
- l.acceptMutex.Lock()
- l.acceptOverlapped = nil
- l.acceptHandle = 0
- l.acceptMutex.Unlock()
- }()
-
- _, err = waitForCompletion(handle, overlapped)
- }
- if err == syscall.ERROR_OPERATION_ABORTED {
- // Return error compatible to net.Listener.Accept() in case the
- // listener was closed.
- return nil, ErrClosed
- }
- if err != nil {
- return nil, err
- }
- }
- return &PipeConn{handle: handle, addr: l.addr}, nil
-}
-
-// Close stops listening on the address.
-// Already Accepted connections are not closed.
-func (l *PipeListener) Close() error {
- if l.closed {
- return nil
- }
- l.closed = true
- if l.handle != 0 {
- err := disconnectNamedPipe(l.handle)
- if err != nil {
- return err
- }
- err = syscall.CloseHandle(l.handle)
- if err != nil {
- return err
- }
- l.handle = 0
- }
- l.acceptMutex.Lock()
- defer l.acceptMutex.Unlock()
- if l.acceptOverlapped != nil && l.acceptHandle != 0 {
- // Cancel the pending IO. This call does not block, so it is safe
- // to hold onto the mutex above.
- if err := cancelIoEx(l.acceptHandle, l.acceptOverlapped); err != nil {
- return err
- }
- err := syscall.CloseHandle(l.acceptOverlapped.HEvent)
- if err != nil {
- return err
- }
- l.acceptOverlapped.HEvent = 0
- err = syscall.CloseHandle(l.acceptHandle)
- if err != nil {
- return err
- }
- l.acceptHandle = 0
- }
- return nil
-}
-
-// Addr returns the listener's network address, a PipeAddr.
-func (l *PipeListener) Addr() net.Addr { return l.addr }
-
-// PipeConn is the implementation of the net.Conn interface for named pipe connections.
-type PipeConn struct {
- handle syscall.Handle
- addr PipeAddr
-
- // these aren't actually used yet
- readDeadline *time.Time
- writeDeadline *time.Time
-}
-
-type iodata struct {
- n uint32
- err error
-}
-
-// completeRequest looks at iodata to see if a request is pending. If so, it waits for it to either complete or to
-// abort due to hitting the specified deadline. Deadline may be set to nil to wait forever. If no request is pending,
-// the content of iodata is returned.
-func (c *PipeConn) completeRequest(data iodata, deadline *time.Time, overlapped *syscall.Overlapped) (int, error) {
- if data.err == error_io_incomplete || data.err == syscall.ERROR_IO_PENDING {
- var timer <-chan time.Time
- if deadline != nil {
- if timeDiff := deadline.Sub(time.Now()); timeDiff > 0 {
- timer = time.After(timeDiff)
- }
- }
- done := make(chan iodata)
- go func() {
- n, err := waitForCompletion(c.handle, overlapped)
- done <- iodata{n, err}
- }()
- select {
- case data = <-done:
- case <-timer:
- syscall.CancelIoEx(c.handle, overlapped)
- data = iodata{0, timeout(c.addr.String())}
- }
- }
- // Windows will produce ERROR_BROKEN_PIPE upon closing
- // a handle on the other end of a connection. Go RPC
- // expects an io.EOF error in this case.
- if data.err == syscall.ERROR_BROKEN_PIPE {
- data.err = io.EOF
- }
- return int(data.n), data.err
-}
-
-// Read implements the net.Conn Read method.
-func (c *PipeConn) Read(b []byte) (int, error) {
- // Use ReadFile() rather than Read() because the latter
- // contains a workaround that eats ERROR_BROKEN_PIPE.
- overlapped, err := newOverlapped()
- if err != nil {
- return 0, err
- }
- defer syscall.CloseHandle(overlapped.HEvent)
- var n uint32
- err = syscall.ReadFile(c.handle, b, &n, overlapped)
- return c.completeRequest(iodata{n, err}, c.readDeadline, overlapped)
-}
-
-// Write implements the net.Conn Write method.
-func (c *PipeConn) Write(b []byte) (int, error) {
- overlapped, err := newOverlapped()
- if err != nil {
- return 0, err
- }
- defer syscall.CloseHandle(overlapped.HEvent)
- var n uint32
- err = syscall.WriteFile(c.handle, b, &n, overlapped)
- return c.completeRequest(iodata{n, err}, c.writeDeadline, overlapped)
-}
-
-// Close closes the connection.
-func (c *PipeConn) Close() error {
- return syscall.CloseHandle(c.handle)
-}
-
-// LocalAddr returns the local network address.
-func (c *PipeConn) LocalAddr() net.Addr {
- return c.addr
-}
-
-// RemoteAddr returns the remote network address.
-func (c *PipeConn) RemoteAddr() net.Addr {
- // not sure what to do here, we don't have remote addr....
- return c.addr
-}
-
-// SetDeadline implements the net.Conn SetDeadline method.
-// Note that timeouts are only supported on Windows Vista/Server 2008 and above
-func (c *PipeConn) SetDeadline(t time.Time) error {
- c.SetReadDeadline(t)
- c.SetWriteDeadline(t)
- return nil
-}
-
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
-// Note that timeouts are only supported on Windows Vista/Server 2008 and above
-func (c *PipeConn) SetReadDeadline(t time.Time) error {
- c.readDeadline = &t
- return nil
-}
-
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
-// Note that timeouts are only supported on Windows Vista/Server 2008 and above
-func (c *PipeConn) SetWriteDeadline(t time.Time) error {
- c.writeDeadline = &t
- return nil
-}
-
-// PipeAddr represents the address of a named pipe.
-type PipeAddr string
-
-// Network returns the address's network name, "pipe".
-func (a PipeAddr) Network() string { return "pipe" }
-
-// String returns the address of the pipe
-func (a PipeAddr) String() string {
- return string(a)
-}
-
-// createPipe is a helper function to make sure we always create pipes
-// with the same arguments, since subsequent calls to create pipe need
-// to use the same arguments as the first one. If first is set, fail
-// if the pipe already exists.
-func createPipe(address string, first bool) (syscall.Handle, error) {
- n, err := syscall.UTF16PtrFromString(address)
- if err != nil {
- return 0, err
- }
- mode := uint32(pipe_access_duplex | syscall.FILE_FLAG_OVERLAPPED)
- if first {
- mode |= file_flag_first_pipe_instance
- }
- return createNamedPipe(n,
- mode,
- pipe_type_byte,
- pipe_unlimited_instances,
- 512, 512, 0, nil)
-}
-
-func badAddr(addr string) PipeError {
- return PipeError{fmt.Sprintf("Invalid pipe address '%s'.", addr), false}
-}
-func timeout(addr string) PipeError {
- return PipeError{fmt.Sprintf("Pipe IO timed out waiting for '%s'", addr), true}
-}
-
// ipcListen will create a named pipe on the given endpoint.
func ipcListen(endpoint string) (net.Listener, error) {
- return Listen(endpoint)
+ return winio.ListenPipe(endpoint, &winio.PipeConfig{})
}
// newIPCConnection will connect to a named pipe with the given endpoint as name.
func newIPCConnection(endpoint string) (net.Conn, error) {
- return Dial(endpoint)
+ timeout := 5 * time.Second
+ return winio.DialPipe(endpoint, &timeout)
}