Browse code

Revendor Microsoft/hcsshim and vendor Microsoft/go-winio

This update changes the way hcsshim invokes Windows DLLs to avoid races
with the garbage collector. It also now uses go-winio to access the
pipes used for communication with processes running in the container;
this reduces the number of threads used by docker.exe, improving
scalability.

Signed-off-by: John Starks <jostarks@microsoft.com>

John Starks authored on 2016/02/02 08:09:35
Showing 34 changed files
... ...
@@ -7,6 +7,7 @@ source 'hack/.vendor-helpers.sh'
7 7
 
8 8
 # the following lines are in sorted order, FYI
9 9
 clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe
10
+clone git github.com/Microsoft/go-winio 2b085935f02c272e7a1855df6f8fe03029ffcadd
10 11
 clone git github.com/Sirupsen/logrus v0.8.7 # logrus is a common dependency among multiple deps
11 12
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
12 13
 clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1
... ...
@@ -15,7 +16,7 @@ clone git github.com/gorilla/mux e444e69cbd
15 15
 clone git github.com/kr/pty 5cf931ef8f
16 16
 clone git github.com/mattn/go-shellwords v1.0.0
17 17
 clone git github.com/mattn/go-sqlite3 v1.1.0
18
-clone git github.com/microsoft/hcsshim de43b42b5ce14dfdcbeedb0628b0032174d89caa
18
+clone git github.com/microsoft/hcsshim 35ad4d808a97203cb1748d7c43167e91f51e7f86
19 19
 clone git github.com/mistifyio/go-zfs v2.1.1
20 20
 clone git github.com/tchap/go-patricia v2.1.0
21 21
 clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
22 22
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+The MIT License (MIT)
1
+
2
+Copyright (c) 2015 Microsoft
3
+
4
+Permission is hereby granted, free of charge, to any person obtaining a copy
5
+of this software and associated documentation files (the "Software"), to deal
6
+in the Software without restriction, including without limitation the rights
7
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+copies of the Software, and to permit persons to whom the Software is
9
+furnished to do so, subject to the following conditions:
10
+
11
+The above copyright notice and this permission notice shall be included in all
12
+copies or substantial portions of the Software.
13
+
14
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+SOFTWARE.
21
+
0 22
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+# go-winio
1
+
2
+This repository contains utilities for efficiently performing Win32 IO operations in 
3
+Go. Currently, this is focused on accessing named pipes and other file handles, and
4
+for using named pipes as a net transport.
5
+
6
+This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go 
7
+to reuse the thread to schedule another goroutine. This limits support to Windows Vista and 
8
+newer operating systems. This is similar to the implementation of network sockets in Go's net
9
+package.
10
+
11
+Please see the LICENSE file for licensing information.
12
+
13
+Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe 
14
+for another named pipe implementation.
0 15
new file mode 100644
... ...
@@ -0,0 +1,216 @@
0
+package winio
1
+
2
+import (
3
+	"errors"
4
+	"io"
5
+	"runtime"
6
+	"sync"
7
+	"syscall"
8
+	"time"
9
+)
10
+
11
+//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
12
+//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
13
+//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
14
+//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
15
+
16
+const (
17
+	cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
18
+	cFILE_SKIP_SET_EVENT_ON_HANDLE        = 2
19
+)
20
+
21
+var (
22
+	ErrFileClosed = errors.New("file has already been closed")
23
+	ErrTimeout    = &timeoutError{}
24
+)
25
+
26
+type timeoutError struct{}
27
+
28
+func (e *timeoutError) Error() string   { return "i/o timeout" }
29
+func (e *timeoutError) Timeout() bool   { return true }
30
+func (e *timeoutError) Temporary() bool { return true }
31
+
32
+var ioInitOnce sync.Once
33
+var ioCompletionPort syscall.Handle
34
+
35
+// ioResult contains the result of an asynchronous IO operation
36
+type ioResult struct {
37
+	bytes uint32
38
+	err   error
39
+}
40
+
41
+// ioOperation represents an outstanding asynchronous Win32 IO
42
+type ioOperation struct {
43
+	o  syscall.Overlapped
44
+	ch chan ioResult
45
+}
46
+
47
+func initIo() {
48
+	h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
49
+	if err != nil {
50
+		panic(err)
51
+	}
52
+	ioCompletionPort = h
53
+	go ioCompletionProcessor(h)
54
+}
55
+
56
+// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
57
+// It takes ownership of this handle and will close it if it is garbage collected.
58
+type win32File struct {
59
+	handle        syscall.Handle
60
+	wg            sync.WaitGroup
61
+	closing       bool
62
+	readDeadline  time.Time
63
+	writeDeadline time.Time
64
+}
65
+
66
+// makeWin32File makes a new win32File from an existing file handle
67
+func makeWin32File(h syscall.Handle) (*win32File, error) {
68
+	f := &win32File{handle: h}
69
+	ioInitOnce.Do(initIo)
70
+	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
71
+	if err != nil {
72
+		return nil, err
73
+	}
74
+	err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
75
+	if err != nil {
76
+		return nil, err
77
+	}
78
+	runtime.SetFinalizer(f, (*win32File).closeHandle)
79
+	return f, nil
80
+}
81
+
82
+func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
83
+	return makeWin32File(h)
84
+}
85
+
86
+// closeHandle closes the resources associated with a Win32 handle
87
+func (f *win32File) closeHandle() {
88
+	if !f.closing {
89
+		// cancel all IO and wait for it to complete
90
+		f.closing = true
91
+		cancelIoEx(f.handle, nil)
92
+		f.wg.Wait()
93
+		// at this point, no new IO can start
94
+		syscall.Close(f.handle)
95
+		f.handle = 0
96
+	}
97
+}
98
+
99
+// Close closes a win32File.
100
+func (f *win32File) Close() error {
101
+	f.closeHandle()
102
+	runtime.SetFinalizer(f, nil)
103
+	return nil
104
+}
105
+
106
+// prepareIo prepares for a new IO operation
107
+func (f *win32File) prepareIo() (*ioOperation, error) {
108
+	f.wg.Add(1)
109
+	if f.closing {
110
+		return nil, ErrFileClosed
111
+	}
112
+	c := &ioOperation{}
113
+	c.ch = make(chan ioResult)
114
+	return c, nil
115
+}
116
+
117
+// ioCompletionProcessor processes completed async IOs forever
118
+func ioCompletionProcessor(h syscall.Handle) {
119
+	for {
120
+		var bytes uint32
121
+		var key uintptr
122
+		var op *ioOperation
123
+		err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
124
+		if op == nil {
125
+			panic(err)
126
+		}
127
+		op.ch <- ioResult{bytes, err}
128
+	}
129
+}
130
+
131
+// asyncIo processes the return value from ReadFile or WriteFile, blocking until
132
+// the operation has actually completed.
133
+func (f *win32File) asyncIo(c *ioOperation, deadline time.Time, bytes uint32, err error) (int, error) {
134
+	if err != syscall.ERROR_IO_PENDING {
135
+		f.wg.Done()
136
+		return int(bytes), err
137
+	} else {
138
+		var r ioResult
139
+		wait := true
140
+		timedout := false
141
+		if f.closing {
142
+			cancelIoEx(f.handle, &c.o)
143
+		} else if !deadline.IsZero() {
144
+			now := time.Now()
145
+			if !deadline.After(now) {
146
+				timedout = true
147
+			} else {
148
+				timeout := time.After(deadline.Sub(now))
149
+				select {
150
+				case r = <-c.ch:
151
+					wait = false
152
+				case <-timeout:
153
+					timedout = true
154
+				}
155
+			}
156
+		}
157
+		if timedout {
158
+			cancelIoEx(f.handle, &c.o)
159
+		}
160
+		if wait {
161
+			r = <-c.ch
162
+		}
163
+		err = r.err
164
+		if err == syscall.ERROR_OPERATION_ABORTED {
165
+			if f.closing {
166
+				err = ErrFileClosed
167
+			} else if timedout {
168
+				err = ErrTimeout
169
+			}
170
+		}
171
+		f.wg.Done()
172
+		return int(r.bytes), err
173
+	}
174
+}
175
+
176
+// Read reads from a file handle.
177
+func (f *win32File) Read(b []byte) (int, error) {
178
+	c, err := f.prepareIo()
179
+	if err != nil {
180
+		return 0, err
181
+	}
182
+	var bytes uint32
183
+	err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
184
+	n, err := f.asyncIo(c, f.readDeadline, bytes, err)
185
+
186
+	// Handle EOF conditions.
187
+	if err == nil && n == 0 && len(b) != 0 {
188
+		return 0, io.EOF
189
+	} else if err == syscall.ERROR_BROKEN_PIPE {
190
+		return 0, io.EOF
191
+	} else {
192
+		return n, err
193
+	}
194
+}
195
+
196
+// Write writes to a file handle.
197
+func (f *win32File) Write(b []byte) (int, error) {
198
+	c, err := f.prepareIo()
199
+	if err != nil {
200
+		return 0, err
201
+	}
202
+	var bytes uint32
203
+	err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
204
+	return f.asyncIo(c, f.writeDeadline, bytes, err)
205
+}
206
+
207
+func (f *win32File) SetReadDeadline(t time.Time) error {
208
+	f.readDeadline = t
209
+	return nil
210
+}
211
+
212
+func (f *win32File) SetWriteDeadline(t time.Time) error {
213
+	f.writeDeadline = t
214
+	return nil
215
+}
0 216
new file mode 100644
... ...
@@ -0,0 +1,797 @@
0
+// Copyright 2013 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build ignore
5
+
6
+/*
7
+mksyscall_windows generates windows system call bodies
8
+
9
+It parses all files specified on command line containing function
10
+prototypes (like syscall_windows.go) and prints system call bodies
11
+to standard output.
12
+
13
+The prototypes are marked by lines beginning with "//sys" and read
14
+like func declarations if //sys is replaced by func, but:
15
+
16
+* The parameter lists must give a name for each argument. This
17
+  includes return parameters.
18
+
19
+* The parameter lists must give a type for each argument:
20
+  the (x, y, z int) shorthand is not allowed.
21
+
22
+* If the return parameter is an error number, it must be named err.
23
+
24
+* If go func name needs to be different from it's winapi dll name,
25
+  the winapi name could be specified at the end, after "=" sign, like
26
+  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
27
+
28
+* Each function that returns err needs to supply a condition, that
29
+  return value of winapi will be tested against to detect failure.
30
+  This would set err to windows "last-error", otherwise it will be nil.
31
+  The value can be provided at end of //sys declaration, like
32
+  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
33
+  and is [failretval==0] by default.
34
+
35
+Usage:
36
+	mksyscall_windows [flags] [path ...]
37
+
38
+The flags are:
39
+	-output
40
+		Specify output file name (outputs to console if blank).
41
+	-trace
42
+		Generate print statement after every syscall.
43
+*/
44
+package main
45
+
46
+import (
47
+	"bufio"
48
+	"bytes"
49
+	"errors"
50
+	"flag"
51
+	"fmt"
52
+	"go/format"
53
+	"go/parser"
54
+	"go/token"
55
+	"io"
56
+	"io/ioutil"
57
+	"log"
58
+	"os"
59
+	"strconv"
60
+	"strings"
61
+	"text/template"
62
+)
63
+
64
+var (
65
+	filename       = flag.String("output", "", "output file name (standard output if omitted)")
66
+	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
67
+)
68
+
69
+func trim(s string) string {
70
+	return strings.Trim(s, " \t")
71
+}
72
+
73
+var packageName string
74
+
75
+func packagename() string {
76
+	return packageName
77
+}
78
+
79
+func syscalldot() string {
80
+	if packageName == "syscall" {
81
+		return ""
82
+	}
83
+	return "syscall."
84
+}
85
+
86
+// Param is function parameter
87
+type Param struct {
88
+	Name      string
89
+	Type      string
90
+	fn        *Fn
91
+	tmpVarIdx int
92
+}
93
+
94
+// tmpVar returns temp variable name that will be used to represent p during syscall.
95
+func (p *Param) tmpVar() string {
96
+	if p.tmpVarIdx < 0 {
97
+		p.tmpVarIdx = p.fn.curTmpVarIdx
98
+		p.fn.curTmpVarIdx++
99
+	}
100
+	return fmt.Sprintf("_p%d", p.tmpVarIdx)
101
+}
102
+
103
+// BoolTmpVarCode returns source code for bool temp variable.
104
+func (p *Param) BoolTmpVarCode() string {
105
+	const code = `var %s uint32
106
+	if %s {
107
+		%s = 1
108
+	} else {
109
+		%s = 0
110
+	}`
111
+	tmp := p.tmpVar()
112
+	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
113
+}
114
+
115
+// SliceTmpVarCode returns source code for slice temp variable.
116
+func (p *Param) SliceTmpVarCode() string {
117
+	const code = `var %s *%s
118
+	if len(%s) > 0 {
119
+		%s = &%s[0]
120
+	}`
121
+	tmp := p.tmpVar()
122
+	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
123
+}
124
+
125
+// StringTmpVarCode returns source code for string temp variable.
126
+func (p *Param) StringTmpVarCode() string {
127
+	errvar := p.fn.Rets.ErrorVarName()
128
+	if errvar == "" {
129
+		errvar = "_"
130
+	}
131
+	tmp := p.tmpVar()
132
+	const code = `var %s %s
133
+	%s, %s = %s(%s)`
134
+	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
135
+	if errvar == "-" {
136
+		return s
137
+	}
138
+	const morecode = `
139
+	if %s != nil {
140
+		return
141
+	}`
142
+	return s + fmt.Sprintf(morecode, errvar)
143
+}
144
+
145
+// TmpVarCode returns source code for temp variable.
146
+func (p *Param) TmpVarCode() string {
147
+	switch {
148
+	case p.Type == "bool":
149
+		return p.BoolTmpVarCode()
150
+	case strings.HasPrefix(p.Type, "[]"):
151
+		return p.SliceTmpVarCode()
152
+	default:
153
+		return ""
154
+	}
155
+}
156
+
157
+// TmpVarHelperCode returns source code for helper's temp variable.
158
+func (p *Param) TmpVarHelperCode() string {
159
+	if p.Type != "string" {
160
+		return ""
161
+	}
162
+	return p.StringTmpVarCode()
163
+}
164
+
165
+// SyscallArgList returns source code fragments representing p parameter
166
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
167
+// the first element and length.
168
+func (p *Param) SyscallArgList() []string {
169
+	t := p.HelperType()
170
+	var s string
171
+	switch {
172
+	case t[0] == '*':
173
+		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
174
+	case t == "bool":
175
+		s = p.tmpVar()
176
+	case strings.HasPrefix(t, "[]"):
177
+		return []string{
178
+			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
179
+			fmt.Sprintf("uintptr(len(%s))", p.Name),
180
+		}
181
+	default:
182
+		s = p.Name
183
+	}
184
+	return []string{fmt.Sprintf("uintptr(%s)", s)}
185
+}
186
+
187
+// IsError determines if p parameter is used to return error.
188
+func (p *Param) IsError() bool {
189
+	return p.Name == "err" && p.Type == "error"
190
+}
191
+
192
+// HelperType returns type of parameter p used in helper function.
193
+func (p *Param) HelperType() string {
194
+	if p.Type == "string" {
195
+		return p.fn.StrconvType()
196
+	}
197
+	return p.Type
198
+}
199
+
200
+// join concatenates parameters ps into a string with sep separator.
201
+// Each parameter is converted into string by applying fn to it
202
+// before conversion.
203
+func join(ps []*Param, fn func(*Param) string, sep string) string {
204
+	if len(ps) == 0 {
205
+		return ""
206
+	}
207
+	a := make([]string, 0)
208
+	for _, p := range ps {
209
+		a = append(a, fn(p))
210
+	}
211
+	return strings.Join(a, sep)
212
+}
213
+
214
+// Rets describes function return parameters.
215
+type Rets struct {
216
+	Name         string
217
+	Type         string
218
+	ReturnsError bool
219
+	FailCond     string
220
+}
221
+
222
+// ErrorVarName returns error variable name for r.
223
+func (r *Rets) ErrorVarName() string {
224
+	if r.ReturnsError {
225
+		return "err"
226
+	}
227
+	if r.Type == "error" {
228
+		return r.Name
229
+	}
230
+	return ""
231
+}
232
+
233
+// ToParams converts r into slice of *Param.
234
+func (r *Rets) ToParams() []*Param {
235
+	ps := make([]*Param, 0)
236
+	if len(r.Name) > 0 {
237
+		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
238
+	}
239
+	if r.ReturnsError {
240
+		ps = append(ps, &Param{Name: "err", Type: "error"})
241
+	}
242
+	return ps
243
+}
244
+
245
+// List returns source code of syscall return parameters.
246
+func (r *Rets) List() string {
247
+	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
248
+	if len(s) > 0 {
249
+		s = "(" + s + ")"
250
+	}
251
+	return s
252
+}
253
+
254
+// PrintList returns source code of trace printing part correspondent
255
+// to syscall return values.
256
+func (r *Rets) PrintList() string {
257
+	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
258
+}
259
+
260
+// SetReturnValuesCode returns source code that accepts syscall return values.
261
+func (r *Rets) SetReturnValuesCode() string {
262
+	if r.Name == "" && !r.ReturnsError {
263
+		return ""
264
+	}
265
+	retvar := "r0"
266
+	if r.Name == "" {
267
+		retvar = "r1"
268
+	}
269
+	errvar := "_"
270
+	if r.ReturnsError {
271
+		errvar = "e1"
272
+	}
273
+	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
274
+}
275
+
276
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
277
+	const code = `if %s {
278
+		if e1 != 0 {
279
+			err = error(e1)
280
+		} else {
281
+			err = %sEINVAL
282
+		}
283
+	}`
284
+	cond := retvar + " == 0"
285
+	if r.FailCond != "" {
286
+		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
287
+	}
288
+	return fmt.Sprintf(code, cond, syscalldot())
289
+}
290
+
291
+// SetErrorCode returns source code that sets return parameters.
292
+func (r *Rets) SetErrorCode() string {
293
+	const code = `if r0 != 0 {
294
+		%s = %sErrno(r0)
295
+	}`
296
+	if r.Name == "" && !r.ReturnsError {
297
+		return ""
298
+	}
299
+	if r.Name == "" {
300
+		return r.useLongHandleErrorCode("r1")
301
+	}
302
+	if r.Type == "error" {
303
+		return fmt.Sprintf(code, r.Name, syscalldot())
304
+	}
305
+	s := ""
306
+	switch {
307
+	case r.Type[0] == '*':
308
+		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
309
+	case r.Type == "bool":
310
+		s = fmt.Sprintf("%s = r0 != 0", r.Name)
311
+	default:
312
+		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
313
+	}
314
+	if !r.ReturnsError {
315
+		return s
316
+	}
317
+	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
318
+}
319
+
320
+// Fn describes syscall function.
321
+type Fn struct {
322
+	Name        string
323
+	Params      []*Param
324
+	Rets        *Rets
325
+	PrintTrace  bool
326
+	confirmproc bool
327
+	dllname     string
328
+	dllfuncname string
329
+	src         string
330
+	// TODO: get rid of this field and just use parameter index instead
331
+	curTmpVarIdx int // insure tmp variables have uniq names
332
+}
333
+
334
+// extractParams parses s to extract function parameters.
335
+func extractParams(s string, f *Fn) ([]*Param, error) {
336
+	s = trim(s)
337
+	if s == "" {
338
+		return nil, nil
339
+	}
340
+	a := strings.Split(s, ",")
341
+	ps := make([]*Param, len(a))
342
+	for i := range ps {
343
+		s2 := trim(a[i])
344
+		b := strings.Split(s2, " ")
345
+		if len(b) != 2 {
346
+			b = strings.Split(s2, "\t")
347
+			if len(b) != 2 {
348
+				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
349
+			}
350
+		}
351
+		ps[i] = &Param{
352
+			Name:      trim(b[0]),
353
+			Type:      trim(b[1]),
354
+			fn:        f,
355
+			tmpVarIdx: -1,
356
+		}
357
+	}
358
+	return ps, nil
359
+}
360
+
361
+// extractSection extracts text out of string s starting after start
362
+// and ending just before end. found return value will indicate success,
363
+// and prefix, body and suffix will contain correspondent parts of string s.
364
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
365
+	s = trim(s)
366
+	if strings.HasPrefix(s, string(start)) {
367
+		// no prefix
368
+		body = s[1:]
369
+	} else {
370
+		a := strings.SplitN(s, string(start), 2)
371
+		if len(a) != 2 {
372
+			return "", "", s, false
373
+		}
374
+		prefix = a[0]
375
+		body = a[1]
376
+	}
377
+	a := strings.SplitN(body, string(end), 2)
378
+	if len(a) != 2 {
379
+		return "", "", "", false
380
+	}
381
+	return prefix, a[0], a[1], true
382
+}
383
+
384
+// newFn parses string s and return created function Fn.
385
+func newFn(s string) (*Fn, error) {
386
+	s = trim(s)
387
+	f := &Fn{
388
+		Rets:       &Rets{},
389
+		src:        s,
390
+		PrintTrace: *printTraceFlag,
391
+	}
392
+	// function name and args
393
+	prefix, body, s, found := extractSection(s, '(', ')')
394
+	if !found || prefix == "" {
395
+		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
396
+	}
397
+	f.Name = prefix
398
+	var err error
399
+	f.Params, err = extractParams(body, f)
400
+	if err != nil {
401
+		return nil, err
402
+	}
403
+	// return values
404
+	_, body, s, found = extractSection(s, '(', ')')
405
+	if found {
406
+		r, err := extractParams(body, f)
407
+		if err != nil {
408
+			return nil, err
409
+		}
410
+		switch len(r) {
411
+		case 0:
412
+		case 1:
413
+			if r[0].IsError() {
414
+				f.Rets.ReturnsError = true
415
+			} else {
416
+				f.Rets.Name = r[0].Name
417
+				f.Rets.Type = r[0].Type
418
+			}
419
+		case 2:
420
+			if !r[1].IsError() {
421
+				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
422
+			}
423
+			f.Rets.ReturnsError = true
424
+			f.Rets.Name = r[0].Name
425
+			f.Rets.Type = r[0].Type
426
+		default:
427
+			return nil, errors.New("Too many return values in \"" + f.src + "\"")
428
+		}
429
+	}
430
+	// fail condition
431
+	_, body, s, found = extractSection(s, '[', ']')
432
+	if found {
433
+		f.Rets.FailCond = body
434
+	}
435
+	// dll and dll function names
436
+	s = trim(s)
437
+	if s == "" {
438
+		return f, nil
439
+	}
440
+	if !strings.HasPrefix(s, "=") {
441
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
442
+	}
443
+	s = trim(s[1:])
444
+	a := strings.Split(s, ".")
445
+	switch len(a) {
446
+	case 1:
447
+		f.dllfuncname = a[0]
448
+	case 2:
449
+		f.dllname = a[0]
450
+		f.dllfuncname = a[1]
451
+	default:
452
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
453
+	}
454
+	if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
455
+		f.confirmproc = true
456
+		f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
457
+	}
458
+	return f, nil
459
+}
460
+
461
+// DLLName returns DLL name for function f.
462
+func (f *Fn) DLLName() string {
463
+	if f.dllname == "" {
464
+		return "kernel32"
465
+	}
466
+	return f.dllname
467
+}
468
+
469
+// DLLName returns DLL function name for function f.
470
+func (f *Fn) DLLFuncName() string {
471
+	if f.dllfuncname == "" {
472
+		return f.Name
473
+	}
474
+	return f.dllfuncname
475
+}
476
+
477
+func (f *Fn) ConfirmProc() bool {
478
+	return f.confirmproc
479
+}
480
+
481
+// ParamList returns source code for function f parameters.
482
+func (f *Fn) ParamList() string {
483
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
484
+}
485
+
486
+// HelperParamList returns source code for helper function f parameters.
487
+func (f *Fn) HelperParamList() string {
488
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
489
+}
490
+
491
+// ParamPrintList returns source code of trace printing part correspondent
492
+// to syscall input parameters.
493
+func (f *Fn) ParamPrintList() string {
494
+	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
495
+}
496
+
497
+// ParamCount return number of syscall parameters for function f.
498
+func (f *Fn) ParamCount() int {
499
+	n := 0
500
+	for _, p := range f.Params {
501
+		n += len(p.SyscallArgList())
502
+	}
503
+	return n
504
+}
505
+
506
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
507
+// to use. It returns parameter count for correspondent SyscallX function.
508
+func (f *Fn) SyscallParamCount() int {
509
+	n := f.ParamCount()
510
+	switch {
511
+	case n <= 3:
512
+		return 3
513
+	case n <= 6:
514
+		return 6
515
+	case n <= 9:
516
+		return 9
517
+	case n <= 12:
518
+		return 12
519
+	case n <= 15:
520
+		return 15
521
+	default:
522
+		panic("too many arguments to system call")
523
+	}
524
+}
525
+
526
+// Syscall determines which SyscallX function to use for function f.
527
+func (f *Fn) Syscall() string {
528
+	c := f.SyscallParamCount()
529
+	if c == 3 {
530
+		return syscalldot() + "Syscall"
531
+	}
532
+	return syscalldot() + "Syscall" + strconv.Itoa(c)
533
+}
534
+
535
+// SyscallParamList returns source code for SyscallX parameters for function f.
536
+func (f *Fn) SyscallParamList() string {
537
+	a := make([]string, 0)
538
+	for _, p := range f.Params {
539
+		a = append(a, p.SyscallArgList()...)
540
+	}
541
+	for len(a) < f.SyscallParamCount() {
542
+		a = append(a, "0")
543
+	}
544
+	return strings.Join(a, ", ")
545
+}
546
+
547
+// HelperCallParamList returns source code of call into function f helper.
548
+func (f *Fn) HelperCallParamList() string {
549
+	a := make([]string, 0, len(f.Params))
550
+	for _, p := range f.Params {
551
+		s := p.Name
552
+		if p.Type == "string" {
553
+			s = p.tmpVar()
554
+		}
555
+		a = append(a, s)
556
+	}
557
+	return strings.Join(a, ", ")
558
+}
559
+
560
+// IsUTF16 is true, if f is W (utf16) function. It is false
561
+// for all A (ascii) functions.
562
+func (_ *Fn) IsUTF16() bool {
563
+	return true
564
+}
565
+
566
+// StrconvFunc returns name of Go string to OS string function for f.
567
+func (f *Fn) StrconvFunc() string {
568
+	if f.IsUTF16() {
569
+		return syscalldot() + "UTF16PtrFromString"
570
+	}
571
+	return syscalldot() + "BytePtrFromString"
572
+}
573
+
574
+// StrconvType returns Go type name used for OS string for f.
575
+func (f *Fn) StrconvType() string {
576
+	if f.IsUTF16() {
577
+		return "*uint16"
578
+	}
579
+	return "*byte"
580
+}
581
+
582
+// HasStringParam is true, if f has at least one string parameter.
583
+// Otherwise it is false.
584
+func (f *Fn) HasStringParam() bool {
585
+	for _, p := range f.Params {
586
+		if p.Type == "string" {
587
+			return true
588
+		}
589
+	}
590
+	return false
591
+}
592
+
593
+// HelperName returns name of function f helper.
594
+func (f *Fn) HelperName() string {
595
+	if !f.HasStringParam() {
596
+		return f.Name
597
+	}
598
+	return "_" + f.Name
599
+}
600
+
601
+// Source files and functions.
602
+type Source struct {
603
+	Funcs []*Fn
604
+	Files []string
605
+}
606
+
607
+// ParseFiles parses files listed in fs and extracts all syscall
608
+// functions listed in  sys comments. It returns source files
609
+// and functions collection *Source if successful.
610
+func ParseFiles(fs []string) (*Source, error) {
611
+	src := &Source{
612
+		Funcs: make([]*Fn, 0),
613
+		Files: make([]string, 0),
614
+	}
615
+	for _, file := range fs {
616
+		if err := src.ParseFile(file); err != nil {
617
+			return nil, err
618
+		}
619
+	}
620
+	return src, nil
621
+}
622
+
623
+// DLLs return dll names for a source set src.
624
+func (src *Source) DLLs() []string {
625
+	uniq := make(map[string]bool)
626
+	r := make([]string, 0)
627
+	for _, f := range src.Funcs {
628
+		name := f.DLLName()
629
+		if _, found := uniq[name]; !found {
630
+			uniq[name] = true
631
+			r = append(r, name)
632
+		}
633
+	}
634
+	return r
635
+}
636
+
637
+// ParseFile adds additional file path to a source set src.
638
+func (src *Source) ParseFile(path string) error {
639
+	file, err := os.Open(path)
640
+	if err != nil {
641
+		return err
642
+	}
643
+	defer file.Close()
644
+
645
+	s := bufio.NewScanner(file)
646
+	for s.Scan() {
647
+		t := trim(s.Text())
648
+		if len(t) < 7 {
649
+			continue
650
+		}
651
+		if !strings.HasPrefix(t, "//sys") {
652
+			continue
653
+		}
654
+		t = t[5:]
655
+		if !(t[0] == ' ' || t[0] == '\t') {
656
+			continue
657
+		}
658
+		f, err := newFn(t[1:])
659
+		if err != nil {
660
+			return err
661
+		}
662
+		src.Funcs = append(src.Funcs, f)
663
+	}
664
+	if err := s.Err(); err != nil {
665
+		return err
666
+	}
667
+	src.Files = append(src.Files, path)
668
+
669
+	// get package name
670
+	fset := token.NewFileSet()
671
+	_, err = file.Seek(0, 0)
672
+	if err != nil {
673
+		return err
674
+	}
675
+	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
676
+	if err != nil {
677
+		return err
678
+	}
679
+	packageName = pkg.Name.Name
680
+
681
+	return nil
682
+}
683
+
684
+// Generate output source file from a source set src.
685
+func (src *Source) Generate(w io.Writer) error {
686
+	funcMap := template.FuncMap{
687
+		"packagename": packagename,
688
+		"syscalldot":  syscalldot,
689
+	}
690
+	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
691
+	err := t.Execute(w, src)
692
+	if err != nil {
693
+		return errors.New("Failed to execute template: " + err.Error())
694
+	}
695
+	return nil
696
+}
697
+
698
+func usage() {
699
+	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
700
+	flag.PrintDefaults()
701
+	os.Exit(1)
702
+}
703
+
704
+func main() {
705
+	flag.Usage = usage
706
+	flag.Parse()
707
+	if len(flag.Args()) <= 0 {
708
+		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
709
+		usage()
710
+	}
711
+
712
+	src, err := ParseFiles(flag.Args())
713
+	if err != nil {
714
+		log.Fatal(err)
715
+	}
716
+
717
+	var buf bytes.Buffer
718
+	if err := src.Generate(&buf); err != nil {
719
+		log.Fatal(err)
720
+	}
721
+
722
+	data, err := format.Source(buf.Bytes())
723
+	if err != nil {
724
+		log.Fatal(err)
725
+	}
726
+	if *filename == "" {
727
+		_, err = os.Stdout.Write(data)
728
+	} else {
729
+		err = ioutil.WriteFile(*filename, data, 0644)
730
+	}
731
+	if err != nil {
732
+		log.Fatal(err)
733
+	}
734
+}
735
+
736
+// TODO: use println instead to print in the following template
737
+const srcTemplate = `
738
+
739
+{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
740
+
741
+package {{packagename}}
742
+
743
+import "unsafe"{{if syscalldot}}
744
+import "syscall"{{end}}
745
+
746
+var _ unsafe.Pointer
747
+
748
+var (
749
+{{template "dlls" .}}
750
+{{template "funcnames" .}})
751
+{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
752
+{{end}}
753
+
754
+{{/* help functions */}}
755
+
756
+{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
757
+{{end}}{{end}}
758
+
759
+{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
760
+{{end}}{{end}}
761
+
762
+{{define "helperbody"}}
763
+func {{.Name}}({{.ParamList}}) {{template "results" .}}{
764
+{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
765
+}
766
+{{end}}
767
+
768
+{{define "funcbody"}}
769
+func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
770
+{{template "tmpvars" .}}	{{template "syscallcheck" .}}{{template "syscall" .}}
771
+{{template "seterror" .}}{{template "printtrace" .}}	return
772
+}
773
+{{end}}
774
+
775
+{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
776
+{{end}}{{end}}{{end}}
777
+
778
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
779
+{{end}}{{end}}{{end}}
780
+
781
+{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
782
+
783
+{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
784
+    return
785
+}
786
+{{end}}{{end}}
787
+
788
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
789
+
790
+{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
791
+{{end}}{{end}}
792
+
793
+{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
794
+{{end}}{{end}}
795
+
796
+`
0 797
new file mode 100644
... ...
@@ -0,0 +1,280 @@
0
+package winio
1
+
2
+import (
3
+	"errors"
4
+	"net"
5
+	"os"
6
+	"syscall"
7
+	"time"
8
+	"unsafe"
9
+)
10
+
11
+//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
12
+//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
13
+//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
14
+//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
15
+
16
+type securityAttributes struct {
17
+	Length             uint32
18
+	SecurityDescriptor *byte
19
+	InheritHandle      uint32
20
+}
21
+
22
+const (
23
+	cERROR_PIPE_BUSY      = syscall.Errno(231)
24
+	cERROR_PIPE_CONNECTED = syscall.Errno(535)
25
+	cERROR_SEM_TIMEOUT    = syscall.Errno(121)
26
+
27
+	cPIPE_ACCESS_DUPLEX            = 0x3
28
+	cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
29
+	cSECURITY_SQOS_PRESENT         = 0x100000
30
+	cSECURITY_ANONYMOUS            = 0
31
+
32
+	cPIPE_REJECT_REMOTE_CLIENTS = 0x8
33
+
34
+	cPIPE_UNLIMITED_INSTANCES = 255
35
+
36
+	cNMPWAIT_USE_DEFAULT_WAIT = 0
37
+	cNMPWAIT_NOWAIT           = 1
38
+)
39
+
40
+var (
41
+	// This error should match net.errClosing since docker takes a dependency on its text
42
+	ErrPipeListenerClosed = errors.New("use of closed network connection")
43
+)
44
+
45
+type win32Pipe struct {
46
+	*win32File
47
+	path string
48
+}
49
+
50
+type pipeAddress string
51
+
52
+func (f *win32Pipe) LocalAddr() net.Addr {
53
+	return pipeAddress(f.path)
54
+}
55
+
56
+func (f *win32Pipe) RemoteAddr() net.Addr {
57
+	return pipeAddress(f.path)
58
+}
59
+
60
+func (f *win32Pipe) SetDeadline(t time.Time) error {
61
+	f.SetReadDeadline(t)
62
+	f.SetWriteDeadline(t)
63
+	return nil
64
+}
65
+
66
+func (s pipeAddress) Network() string {
67
+	return "pipe"
68
+}
69
+
70
+func (s pipeAddress) String() string {
71
+	return string(s)
72
+}
73
+
74
+func makeWin32Pipe(h syscall.Handle, path string) (*win32Pipe, error) {
75
+	f, err := makeWin32File(h)
76
+	if err != nil {
77
+		return nil, err
78
+	}
79
+	return &win32Pipe{f, path}, nil
80
+}
81
+
82
+// DialPipe connects to a named pipe by path, timing out if the connection
83
+// takes longer than the specified duration. If timeout is nil, then the timeout
84
+// is the default timeout established by the pipe server.
85
+func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
86
+	var absTimeout time.Time
87
+	if timeout != nil {
88
+		absTimeout = time.Now().Add(*timeout)
89
+	}
90
+	var err error
91
+	var h syscall.Handle
92
+	for {
93
+		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)
94
+		if err != cERROR_PIPE_BUSY {
95
+			break
96
+		}
97
+		now := time.Now()
98
+		var ms uint32
99
+		if absTimeout.IsZero() {
100
+			ms = cNMPWAIT_USE_DEFAULT_WAIT
101
+		} else if now.After(absTimeout) {
102
+			ms = cNMPWAIT_NOWAIT
103
+		} else {
104
+			ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
105
+		}
106
+		err = waitNamedPipe(path, ms)
107
+		if err != nil {
108
+			if err == cERROR_SEM_TIMEOUT {
109
+				return nil, ErrTimeout
110
+			}
111
+			break
112
+		}
113
+	}
114
+	if err != nil {
115
+		return nil, &os.PathError{"open", path, err}
116
+	}
117
+	p, err := makeWin32Pipe(h, path)
118
+	if err != nil {
119
+		syscall.Close(h)
120
+		return nil, err
121
+	}
122
+	return p, nil
123
+}
124
+
125
+type acceptResponse struct {
126
+	p   *win32Pipe
127
+	err error
128
+}
129
+
130
+type win32PipeListener struct {
131
+	firstHandle        syscall.Handle
132
+	path               string
133
+	securityDescriptor []byte
134
+	acceptCh           chan (chan acceptResponse)
135
+	closeCh            chan int
136
+	doneCh             chan int
137
+}
138
+
139
+func makeServerPipeHandle(path string, securityDescriptor []byte, first bool) (syscall.Handle, error) {
140
+	var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
141
+	if first {
142
+		flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
143
+	}
144
+	var sa securityAttributes
145
+	sa.Length = uint32(unsafe.Sizeof(sa))
146
+	if securityDescriptor != nil {
147
+		sa.SecurityDescriptor = &securityDescriptor[0]
148
+	}
149
+	h, err := createNamedPipe(path, flags, cPIPE_REJECT_REMOTE_CLIENTS, cPIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &sa)
150
+	if err != nil {
151
+		return 0, &os.PathError{"open", path, err}
152
+	}
153
+	return h, nil
154
+}
155
+
156
+func (l *win32PipeListener) makeServerPipe() (*win32Pipe, error) {
157
+	h, err := makeServerPipeHandle(l.path, l.securityDescriptor, false)
158
+	if err != nil {
159
+		return nil, err
160
+	}
161
+	p, err := makeWin32Pipe(h, l.path)
162
+	if err != nil {
163
+		syscall.Close(h)
164
+		return nil, err
165
+	}
166
+	return p, nil
167
+}
168
+
169
+func (l *win32PipeListener) listenerRoutine() {
170
+	closed := false
171
+	for !closed {
172
+		select {
173
+		case <-l.closeCh:
174
+			closed = true
175
+		case responseCh := <-l.acceptCh:
176
+			p, err := l.makeServerPipe()
177
+			if err == nil {
178
+				// Wait for the client to connect.
179
+				ch := make(chan error)
180
+				go func() {
181
+					ch <- connectPipe(p)
182
+				}()
183
+				select {
184
+				case err = <-ch:
185
+					if err != nil {
186
+						p.Close()
187
+						p = nil
188
+					}
189
+				case <-l.closeCh:
190
+					// Abort the connect request by closing the handle.
191
+					p.Close()
192
+					p = nil
193
+					err = <-ch
194
+					if err == nil || err == ErrFileClosed {
195
+						err = ErrPipeListenerClosed
196
+					}
197
+					closed = true
198
+				}
199
+			}
200
+			responseCh <- acceptResponse{p, err}
201
+		}
202
+	}
203
+	syscall.Close(l.firstHandle)
204
+	l.firstHandle = 0
205
+	// Notify Close() and Accept() callers that the handle has been closed.
206
+	close(l.doneCh)
207
+}
208
+
209
+func ListenPipe(path, sddl string) (net.Listener, error) {
210
+	var (
211
+		sd  []byte
212
+		err error
213
+	)
214
+	if sddl != "" {
215
+		sd, err = sddlToSecurityDescriptor(sddl)
216
+		if err != nil {
217
+			return nil, err
218
+		}
219
+	}
220
+	h, err := makeServerPipeHandle(path, sd, true)
221
+	if err != nil {
222
+		return nil, err
223
+	}
224
+	// Immediately open and then close a client handle so that the named pipe is
225
+	// created but not currently accepting connections.
226
+	h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
227
+	if err != nil {
228
+		syscall.Close(h)
229
+		return nil, err
230
+	}
231
+	syscall.Close(h2)
232
+	l := &win32PipeListener{
233
+		firstHandle:        h,
234
+		path:               path,
235
+		securityDescriptor: sd,
236
+		acceptCh:           make(chan (chan acceptResponse)),
237
+		closeCh:            make(chan int),
238
+		doneCh:             make(chan int),
239
+	}
240
+	go l.listenerRoutine()
241
+	return l, nil
242
+}
243
+
244
+func connectPipe(p *win32Pipe) error {
245
+	c, err := p.prepareIo()
246
+	if err != nil {
247
+		return err
248
+	}
249
+	err = connectNamedPipe(p.handle, &c.o)
250
+	_, err = p.asyncIo(c, time.Time{}, 0, err)
251
+	if err != nil && err != cERROR_PIPE_CONNECTED {
252
+		return err
253
+	}
254
+	return nil
255
+}
256
+
257
+func (l *win32PipeListener) Accept() (net.Conn, error) {
258
+	ch := make(chan acceptResponse)
259
+	select {
260
+	case l.acceptCh <- ch:
261
+		response := <-ch
262
+		return response.p, response.err
263
+	case <-l.doneCh:
264
+		return nil, ErrPipeListenerClosed
265
+	}
266
+}
267
+
268
+func (l *win32PipeListener) Close() error {
269
+	select {
270
+	case l.closeCh <- 1:
271
+		<-l.doneCh
272
+	case <-l.doneCh:
273
+	}
274
+	return nil
275
+}
276
+
277
+func (l *win32PipeListener) Addr() net.Addr {
278
+	return pipeAddress(l.path)
279
+}
0 280
new file mode 100644
... ...
@@ -0,0 +1,83 @@
0
+package winio
1
+
2
+import (
3
+	"syscall"
4
+	"unsafe"
5
+)
6
+
7
+//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
8
+//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
9
+//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
10
+//sys localFree(mem uintptr) = LocalFree
11
+//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
12
+
13
+const (
14
+	cERROR_NONE_MAPPED = syscall.Errno(1332)
15
+)
16
+
17
+type AccountLookupError struct {
18
+	Name string
19
+	Err  error
20
+}
21
+
22
+func (e *AccountLookupError) Error() string {
23
+	if e.Name == "" {
24
+		return "lookup account: empty account name specified"
25
+	}
26
+	var s string
27
+	switch e.Err {
28
+	case cERROR_NONE_MAPPED:
29
+		s = "not found"
30
+	default:
31
+		s = e.Err.Error()
32
+	}
33
+	return "lookup account " + e.Name + ": " + s
34
+}
35
+
36
+type SddlConversionError struct {
37
+	Sddl string
38
+	Err  error
39
+}
40
+
41
+func (e *SddlConversionError) Error() string {
42
+	return "convert " + e.Sddl + ": " + e.Err.Error()
43
+}
44
+
45
+// LookupSidByName looks up the SID of an account by name
46
+func LookupSidByName(name string) (sid string, err error) {
47
+	if name == "" {
48
+		return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
49
+	}
50
+
51
+	var sidSize, sidNameUse, refDomainSize uint32
52
+	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
53
+	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
54
+		return "", &AccountLookupError{name, err}
55
+	}
56
+	sidBuffer := make([]byte, sidSize)
57
+	refDomainBuffer := make([]uint16, refDomainSize)
58
+	err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
59
+	if err != nil {
60
+		return "", &AccountLookupError{name, err}
61
+	}
62
+	var strBuffer *uint16
63
+	err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
64
+	if err != nil {
65
+		return "", &AccountLookupError{name, err}
66
+	}
67
+	sid = syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(strBuffer))[:])
68
+	localFree(uintptr(unsafe.Pointer(strBuffer)))
69
+	return sid, nil
70
+}
71
+
72
+func sddlToSecurityDescriptor(sddl string) ([]byte, error) {
73
+	var sdBuffer uintptr
74
+	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
75
+	if err != nil {
76
+		return nil, &SddlConversionError{sddl, err}
77
+	}
78
+	defer localFree(sdBuffer)
79
+	sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
80
+	copy(sd, (*[1 << 30]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
81
+	return sd, nil
82
+}
0 83
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package winio
1
+
2
+//go:generate go run mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go
0 3
new file mode 100644
... ...
@@ -0,0 +1,218 @@
0
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
1
+
2
+package winio
3
+
4
+import "unsafe"
5
+import "syscall"
6
+
7
+var _ unsafe.Pointer
8
+
9
+var (
10
+	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
11
+	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
12
+
13
+	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx")
14
+	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort")
15
+	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus")
16
+	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes")
17
+	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe")
18
+	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW")
19
+	procCreateFileW                                          = modkernel32.NewProc("CreateFileW")
20
+	procWaitNamedPipeW                                       = modkernel32.NewProc("WaitNamedPipeW")
21
+	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
22
+	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
23
+	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
24
+	procLocalFree                                            = modkernel32.NewProc("LocalFree")
25
+	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength")
26
+)
27
+
28
+func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
29
+	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
30
+	if r1 == 0 {
31
+		if e1 != 0 {
32
+			err = error(e1)
33
+		} else {
34
+			err = syscall.EINVAL
35
+		}
36
+	}
37
+	return
38
+}
39
+
40
+func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
41
+	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
42
+	newport = syscall.Handle(r0)
43
+	if newport == 0 {
44
+		if e1 != 0 {
45
+			err = error(e1)
46
+		} else {
47
+			err = syscall.EINVAL
48
+		}
49
+	}
50
+	return
51
+}
52
+
53
+func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
54
+	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
55
+	if r1 == 0 {
56
+		if e1 != 0 {
57
+			err = error(e1)
58
+		} else {
59
+			err = syscall.EINVAL
60
+		}
61
+	}
62
+	return
63
+}
64
+
65
+func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
66
+	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
67
+	if r1 == 0 {
68
+		if e1 != 0 {
69
+			err = error(e1)
70
+		} else {
71
+			err = syscall.EINVAL
72
+		}
73
+	}
74
+	return
75
+}
76
+
77
+func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
78
+	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
79
+	if r1 == 0 {
80
+		if e1 != 0 {
81
+			err = error(e1)
82
+		} else {
83
+			err = syscall.EINVAL
84
+		}
85
+	}
86
+	return
87
+}
88
+
89
+func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
90
+	var _p0 *uint16
91
+	_p0, err = syscall.UTF16PtrFromString(name)
92
+	if err != nil {
93
+		return
94
+	}
95
+	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
96
+}
97
+
98
+func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
99
+	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)
100
+	handle = syscall.Handle(r0)
101
+	if handle == syscall.InvalidHandle {
102
+		if e1 != 0 {
103
+			err = error(e1)
104
+		} else {
105
+			err = syscall.EINVAL
106
+		}
107
+	}
108
+	return
109
+}
110
+
111
+func createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
112
+	var _p0 *uint16
113
+	_p0, err = syscall.UTF16PtrFromString(name)
114
+	if err != nil {
115
+		return
116
+	}
117
+	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
118
+}
119
+
120
+func _createFile(name *uint16, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
121
+	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)
122
+	handle = syscall.Handle(r0)
123
+	if handle == syscall.InvalidHandle {
124
+		if e1 != 0 {
125
+			err = error(e1)
126
+		} else {
127
+			err = syscall.EINVAL
128
+		}
129
+	}
130
+	return
131
+}
132
+
133
+func waitNamedPipe(name string, timeout uint32) (err error) {
134
+	var _p0 *uint16
135
+	_p0, err = syscall.UTF16PtrFromString(name)
136
+	if err != nil {
137
+		return
138
+	}
139
+	return _waitNamedPipe(_p0, timeout)
140
+}
141
+
142
+func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
143
+	r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
144
+	if r1 == 0 {
145
+		if e1 != 0 {
146
+			err = error(e1)
147
+		} else {
148
+			err = syscall.EINVAL
149
+		}
150
+	}
151
+	return
152
+}
153
+
154
+func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
155
+	var _p0 *uint16
156
+	_p0, err = syscall.UTF16PtrFromString(accountName)
157
+	if err != nil {
158
+		return
159
+	}
160
+	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
161
+}
162
+
163
+func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
164
+	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)
165
+	if r1 == 0 {
166
+		if e1 != 0 {
167
+			err = error(e1)
168
+		} else {
169
+			err = syscall.EINVAL
170
+		}
171
+	}
172
+	return
173
+}
174
+
175
+func convertSidToStringSid(sid *byte, str **uint16) (err error) {
176
+	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
177
+	if r1 == 0 {
178
+		if e1 != 0 {
179
+			err = error(e1)
180
+		} else {
181
+			err = syscall.EINVAL
182
+		}
183
+	}
184
+	return
185
+}
186
+
187
+func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
188
+	var _p0 *uint16
189
+	_p0, err = syscall.UTF16PtrFromString(str)
190
+	if err != nil {
191
+		return
192
+	}
193
+	return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
194
+}
195
+
196
+func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
197
+	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
198
+	if r1 == 0 {
199
+		if e1 != 0 {
200
+			err = error(e1)
201
+		} else {
202
+			err = syscall.EINVAL
203
+		}
204
+	}
205
+	return
206
+}
207
+
208
+func localFree(mem uintptr) {
209
+	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
210
+	return
211
+}
212
+
213
+func getSecurityDescriptorLength(sd uintptr) (len uint32) {
214
+	r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
215
+	len = uint32(r0)
216
+	return
217
+}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // ActivateLayer will find the layer with the given id and mount it's filesystem.
12 6
 // For a read/write layer, the mounted filesystem will appear as a volume on the
... ...
@@ -16,42 +10,15 @@ func ActivateLayer(info DriverInfo, id string) error {
16 16
 	title := "hcsshim::ActivateLayer "
17 17
 	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
18 18
 
19
-	// Load the DLL and get a handle to the procedure we need
20
-	dll, proc, err := loadAndFind(procActivateLayer)
21
-	if dll != nil {
22
-		defer dll.Release()
23
-	}
24
-	if err != nil {
25
-		return err
26
-	}
27
-
28
-	// Convert id to uint16 pointer for calling the procedure
29
-	idp, err := syscall.UTF16PtrFromString(id)
30
-	if err != nil {
31
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
32
-		logrus.Error(err)
33
-		return err
34
-	}
35
-
36
-	// Convert info to API calling convention
37 19
 	infop, err := convertDriverInfo(info)
38 20
 	if err != nil {
39
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", err)
40 21
 		logrus.Error(err)
41 22
 		return err
42 23
 	}
43 24
 
44
-	// Call the procedure itself.
45
-	r1, _, _ := proc.Call(
46
-		uintptr(unsafe.Pointer(&infop)),
47
-		uintptr(unsafe.Pointer(idp)))
48
-
49
-	use(unsafe.Pointer(&infop))
50
-	use(unsafe.Pointer(idp))
51
-
52
-	if r1 != 0 {
53
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s flavour=%d",
54
-			r1, syscall.Errno(r1), id, info.Flavour)
25
+	err = activateLayer(&infop, id)
26
+	if err != nil {
27
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
55 28
 		logrus.Error(err)
56 29
 		return err
57 30
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // CopyLayer performs a commit of the srcId (which is expected to be a read-write
12 6
 // layer) into a new read-only layer at dstId.  This requires the full list of
... ...
@@ -16,70 +10,21 @@ func CopyLayer(info DriverInfo, srcId, dstId string, parentLayerPaths []string)
16 16
 	title := "hcsshim::CopyLayer "
17 17
 	logrus.Debugf(title+"srcId %s dstId", srcId, dstId)
18 18
 
19
-	// Load the DLL and get a handle to the procedure we need
20
-	dll, proc, err := loadAndFind(procCopyLayer)
21
-	if dll != nil {
22
-		defer dll.Release()
23
-	}
24
-	if err != nil {
25
-		return err
26
-	}
27
-
28
-	// Convert srcId to uint16 pointer for calling the procedure
29
-	srcIdp, err := syscall.UTF16PtrFromString(srcId)
30
-	if err != nil {
31
-		err = fmt.Errorf(title+" - Failed conversion of srcId %s to pointer %s", srcId, err)
32
-		logrus.Error(err)
33
-		return err
34
-	}
35
-
36
-	// Convert dstId to uint16 pointer for calling the procedure
37
-	dstIdp, err := syscall.UTF16PtrFromString(dstId)
38
-	if err != nil {
39
-		err = fmt.Errorf(title+" - Failed conversion of dstId %s to pointer %s", dstId, err)
40
-		logrus.Error(err)
41
-		return err
42
-	}
43
-
44 19
 	// Generate layer descriptors
45 20
 	layers, err := layerPathsToDescriptors(parentLayerPaths)
46 21
 	if err != nil {
47
-		err = fmt.Errorf(title+" - Failed to generate layer descriptors %s", err)
48
-		logrus.Error(err)
49 22
 		return err
50 23
 	}
51 24
 
52 25
 	// Convert info to API calling convention
53 26
 	infop, err := convertDriverInfo(info)
54 27
 	if err != nil {
55
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", err)
56
-		logrus.Error(err)
57 28
 		return err
58 29
 	}
59 30
 
60
-	var layerDescriptorsp *WC_LAYER_DESCRIPTOR
61
-	if len(layers) > 0 {
62
-		layerDescriptorsp = &(layers[0])
63
-	} else {
64
-		layerDescriptorsp = nil
65
-	}
66
-
67
-	// Call the procedure itself.
68
-	r1, _, _ := proc.Call(
69
-		uintptr(unsafe.Pointer(&infop)),
70
-		uintptr(unsafe.Pointer(srcIdp)),
71
-		uintptr(unsafe.Pointer(dstIdp)),
72
-		uintptr(unsafe.Pointer(layerDescriptorsp)),
73
-		uintptr(len(layers)))
74
-
75
-	use(unsafe.Pointer(&infop))
76
-	use(unsafe.Pointer(srcIdp))
77
-	use(unsafe.Pointer(dstIdp))
78
-	use(unsafe.Pointer(layerDescriptorsp))
79
-
80
-	if r1 != 0 {
81
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s srcId=%s dstId=%d",
82
-			r1, syscall.Errno(r1), srcId, dstId)
31
+	err = copyLayer(&infop, srcId, dstId, layers)
32
+	if err != nil {
33
+		err = makeErrorf(err, title, "srcId=%s dstId=%d", srcId, dstId)
83 34
 		logrus.Error(err)
84 35
 		return err
85 36
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // CreateComputeSystem creates a container, initializing its configuration in
12 6
 // the Host Compute Service such that it can be started by a call to the
... ...
@@ -16,40 +10,9 @@ func CreateComputeSystem(id string, configuration string) error {
16 16
 	title := "HCSShim::CreateComputeSystem"
17 17
 	logrus.Debugln(title+" id=%s, configuration=%s", id, configuration)
18 18
 
19
-	// Load the DLL and get a handle to the procedure we need
20
-	dll, proc, err := loadAndFind(procCreateComputeSystem)
21
-	if dll != nil {
22
-		defer dll.Release()
23
-	}
19
+	err := createComputeSystem(id, configuration)
24 20
 	if err != nil {
25
-		return err
26
-	}
27
-
28
-	// Convert id to uint16 pointers for calling the procedure
29
-	idp, err := syscall.UTF16PtrFromString(id)
30
-	if err != nil {
31
-		err = fmt.Errorf(title+"- Failed conversion of id %s to pointer %s", id, err)
32
-		logrus.Error(err)
33
-		return err
34
-	}
35
-
36
-	// Convert configuration to uint16 pointers for calling the procedure
37
-	configurationp, err := syscall.UTF16PtrFromString(configuration)
38
-	if err != nil {
39
-		err = fmt.Errorf(title+" - Failed conversion of configuration %s to pointer %s", configuration, err)
40
-		logrus.Error(err)
41
-		return err
42
-	}
43
-
44
-	// Call the procedure itself.
45
-	r1, _, _ := proc.Call(
46
-		uintptr(unsafe.Pointer(idp)), uintptr(unsafe.Pointer(configurationp)))
47
-
48
-	use(unsafe.Pointer(idp))
49
-	use(unsafe.Pointer(configurationp))
50
-
51
-	if r1 != 0 {
52
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s configuration=%s", r1, syscall.Errno(r1), id, configuration)
21
+		err = makeErrorf(err, title, "id=%s configuration=%s", id, configuration)
53 22
 		logrus.Error(err)
54 23
 		return err
55 24
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // CreateLayer creates a new, empty, read-only layer on the filesystem based on
12 6
 // the parent layer provided.
... ...
@@ -14,52 +8,16 @@ func CreateLayer(info DriverInfo, id, parent string) error {
14 14
 	title := "hcsshim::CreateLayer "
15 15
 	logrus.Debugf(title+"Flavour %d ID %s parent %s", info.Flavour, id, parent)
16 16
 
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procCreateLayer)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return err
24
-	}
25
-
26
-	// Convert id to uint16 pointer for calling the procedure
27
-	idp, err := syscall.UTF16PtrFromString(id)
28
-	if err != nil {
29
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
30
-		logrus.Error(err)
31
-		return err
32
-	}
33
-
34
-	// Convert parent to uint16 pointer for calling the procedure
35
-	parentp, err := syscall.UTF16PtrFromString(parent)
36
-	if err != nil {
37
-		err = fmt.Errorf(title+" - Failed conversion of parent %s to pointer %s", parent, err)
38
-		logrus.Error(err)
39
-		return err
40
-	}
41
-
42 17
 	// Convert info to API calling convention
43 18
 	infop, err := convertDriverInfo(info)
44 19
 	if err != nil {
45
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", parent, err)
46 20
 		logrus.Error(err)
47 21
 		return err
48 22
 	}
49 23
 
50
-	// Call the procedure itself.
51
-	r1, _, _ := proc.Call(
52
-		uintptr(unsafe.Pointer(&infop)),
53
-		uintptr(unsafe.Pointer(idp)),
54
-		uintptr(unsafe.Pointer(parentp)))
55
-
56
-	use(unsafe.Pointer(&infop))
57
-	use(unsafe.Pointer(idp))
58
-	use(unsafe.Pointer(parentp))
59
-
60
-	if r1 != 0 {
61
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s parent=%s flavour=%d",
62
-			r1, syscall.Errno(r1), id, parent, info.Flavour)
24
+	err = createLayer(&infop, id, parent)
25
+	if err != nil {
26
+		err = makeErrorf(err, title, "id=%s parent=%s flavour=%d", id, parent, info.Flavour)
63 27
 		logrus.Error(err)
64 28
 		return err
65 29
 	}
... ...
@@ -2,12 +2,10 @@ package hcsshim
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
-	"fmt"
6 5
 	"io"
7
-	"runtime"
8 6
 	"syscall"
9
-	"unsafe"
10 7
 
8
+	"github.com/Microsoft/go-winio"
11 9
 	"github.com/Sirupsen/logrus"
12 10
 )
13 11
 
... ...
@@ -22,77 +20,38 @@ type CreateProcessParams struct {
22 22
 	ConsoleSize      [2]int
23 23
 }
24 24
 
25
-// pipe struct used for the stdin/stdout/stderr pipes
26
-type pipe struct {
27
-	handle syscall.Handle
28
-}
29
-
30
-func makePipe(h syscall.Handle) *pipe {
31
-	p := &pipe{h}
32
-	runtime.SetFinalizer(p, (*pipe).closeHandle)
33
-	return p
34
-}
35
-
36
-func (p *pipe) closeHandle() {
37
-	if p.handle != 0 {
38
-		syscall.CloseHandle(p.handle)
39
-		p.handle = 0
25
+// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
26
+// if there is an error.
27
+func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
28
+	fs := make([]io.ReadWriteCloser, len(hs))
29
+	for i, h := range hs {
30
+		if h != syscall.Handle(0) {
31
+			if err == nil {
32
+				fs[i], err = winio.MakeOpenFile(h)
33
+			}
34
+			if err != nil {
35
+				syscall.Close(h)
36
+			}
37
+		}
40 38
 	}
41
-}
42
-
43
-func (p *pipe) Close() error {
44
-	p.closeHandle()
45
-	runtime.SetFinalizer(p, nil)
46
-	return nil
47
-}
48
-
49
-func (p *pipe) Read(b []byte) (int, error) {
50
-	// syscall.Read returns 0, nil on ERROR_BROKEN_PIPE, but for
51
-	// our purposes this should indicate EOF. This may be a go bug.
52
-	var read uint32
53
-	err := syscall.ReadFile(p.handle, b, &read, nil)
54 39
 	if err != nil {
55
-		if err == syscall.ERROR_BROKEN_PIPE {
56
-			return 0, io.EOF
40
+		for _, f := range fs {
41
+			if f != nil {
42
+				f.Close()
43
+			}
57 44
 		}
58
-		return 0, err
45
+		return nil, err
59 46
 	}
60
-	return int(read), nil
61
-}
62
-
63
-func (p *pipe) Write(b []byte) (int, error) {
64
-	return syscall.Write(p.handle, b)
47
+	return fs, nil
65 48
 }
66 49
 
67 50
 // CreateProcessInComputeSystem starts a process in a container. This is invoked, for example,
68 51
 // as a result of docker run, docker exec, or RUN in Dockerfile. If successful,
69 52
 // it returns the PID of the process.
70
-func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useStderr bool, params CreateProcessParams) (uint32, io.WriteCloser, io.ReadCloser, io.ReadCloser, uint32, error) {
71
-
72
-	var (
73
-		stdin          io.WriteCloser
74
-		stdout, stderr io.ReadCloser
75
-	)
76
-
53
+func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useStderr bool, params CreateProcessParams) (_ uint32, _ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, hr uint32, err error) {
77 54
 	title := "HCSShim::CreateProcessInComputeSystem"
78 55
 	logrus.Debugf(title+" id=%s", id)
79
-
80
-	// Load the DLL and get a handle to the procedure we need
81
-	dll, proc, err := loadAndFind(procCreateProcessWithStdHandlesInComputeSystem)
82
-	if dll != nil {
83
-		defer dll.Release()
84
-	}
85
-	if err != nil {
86
-		return 0, nil, nil, nil, 0xFFFFFFFF, err
87
-	}
88
-
89
-	// Convert id to uint16 pointer for calling the procedure
90
-	idp, err := syscall.UTF16PtrFromString(id)
91
-	if err != nil {
92
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
93
-		logrus.Error(err)
94
-		return 0, nil, nil, nil, 0xFFFFFFFF, err
95
-	}
56
+	hr = 0xFFFFFFFF
96 57
 
97 58
 	// If we are not emulating a console, ignore any console size passed to us
98 59
 	if !params.EmulateConsole {
... ...
@@ -102,65 +61,43 @@ func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useS
102 102
 
103 103
 	paramsJson, err := json.Marshal(params)
104 104
 	if err != nil {
105
-		err = fmt.Errorf(title+" - Failed to marshall params %v %s", params, err)
106
-		return 0, nil, nil, nil, 0xFFFFFFFF, err
105
+		return
107 106
 	}
108 107
 
109
-	// Convert paramsJson to uint16 pointer for calling the procedure
110
-	paramsJsonp, err := syscall.UTF16PtrFromString(string(paramsJson))
111
-	if err != nil {
112
-		return 0, nil, nil, nil, 0xFFFFFFFF, err
113
-	}
114
-
115
-	// Get a POINTER to variable to take the pid outparm
116
-	pid := new(uint32)
117
-
118 108
 	logrus.Debugf(title+" - Calling Win32 %s %s", id, paramsJson)
119 109
 
120
-	var stdinHandle, stdoutHandle, stderrHandle syscall.Handle
121
-	var stdinParam, stdoutParam, stderrParam uintptr
110
+	var pid uint32
111
+
112
+	handles := make([]syscall.Handle, 3)
113
+	var stdinParam, stdoutParam, stderrParam *syscall.Handle
122 114
 	if useStdin {
123
-		stdinParam = uintptr(unsafe.Pointer(&stdinHandle))
115
+		stdinParam = &handles[0]
124 116
 	}
125 117
 	if useStdout {
126
-		stdoutParam = uintptr(unsafe.Pointer(&stdoutHandle))
118
+		stdoutParam = &handles[1]
127 119
 	}
128 120
 	if useStderr {
129
-		stderrParam = uintptr(unsafe.Pointer(&stderrHandle))
121
+		stderrParam = &handles[2]
130 122
 	}
131 123
 
132
-	// Call the procedure itself.
133
-	r1, _, _ := proc.Call(
134
-		uintptr(unsafe.Pointer(idp)),
135
-		uintptr(unsafe.Pointer(paramsJsonp)),
136
-		uintptr(unsafe.Pointer(pid)),
137
-		stdinParam,
138
-		stdoutParam,
139
-		stderrParam)
140
-
141
-	use(unsafe.Pointer(idp))
142
-	use(unsafe.Pointer(paramsJsonp))
143
-
144
-	if r1 != 0 {
145
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s params=%v", r1, syscall.Errno(r1), id, params)
124
+	err = createProcessWithStdHandlesInComputeSystem(id, string(paramsJson), &pid, stdinParam, stdoutParam, stderrParam)
125
+	if err != nil {
126
+		winerr := makeErrorf(err, title, "id=%s params=%v", id, params)
127
+		hr = winerr.HResult()
146 128
 		// Windows TP4: Hyper-V Containers may return this error with more than one
147 129
 		// concurrent exec. Do not log it as an error
148
-		if uint32(r1) != Win32InvalidArgument {
149
-			logrus.Error(err)
130
+		if hr != Win32InvalidArgument {
131
+			logrus.Error(winerr)
150 132
 		}
151
-		return 0, nil, nil, nil, uint32(r1), err
133
+		err = winerr
134
+		return
152 135
 	}
153 136
 
154
-	if useStdin {
155
-		stdin = makePipe(stdinHandle)
156
-	}
157
-	if useStdout {
158
-		stdout = makePipe(stdoutHandle)
159
-	}
160
-	if useStderr {
161
-		stderr = makePipe(stderrHandle)
137
+	pipes, err := makeOpenFiles(handles)
138
+	if err != nil {
139
+		return
162 140
 	}
163 141
 
164
-	logrus.Debugf(title+" - succeeded id=%s params=%s pid=%d", id, paramsJson, *pid)
165
-	return *pid, stdin, stdout, stderr, 0, nil
142
+	logrus.Debugf(title+" - succeeded id=%s params=%s pid=%d", id, paramsJson, pid)
143
+	return pid, pipes[0], pipes[1], pipes[2], 0, nil
166 144
 }
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // CreateSandboxLayer creates and populates new read-write layer for use by a container.
12 6
 // This requires both the id of the direct parent layer, as well as the full list
... ...
@@ -16,69 +10,22 @@ func CreateSandboxLayer(info DriverInfo, layerId, parentId string, parentLayerPa
16 16
 	title := "hcsshim::CreateSandboxLayer "
17 17
 	logrus.Debugf(title+"layerId %s parentId %s", layerId, parentId)
18 18
 
19
-	// Load the DLL and get a handle to the procedure we need
20
-	dll, proc, err := loadAndFind(procCreateSandboxLayer)
21
-	if dll != nil {
22
-		defer dll.Release()
23
-	}
24
-	if err != nil {
25
-		return err
26
-	}
27
-
28 19
 	// Generate layer descriptors
29 20
 	layers, err := layerPathsToDescriptors(parentLayerPaths)
30 21
 	if err != nil {
31
-		err = fmt.Errorf(title+"- Failed to generate layer descriptors ", err)
32
-		return err
33
-	}
34
-
35
-	// Convert layerId to uint16 pointer for calling the procedure
36
-	layerIdp, err := syscall.UTF16PtrFromString(layerId)
37
-	if err != nil {
38
-		err = fmt.Errorf(title+"- Failed conversion of layerId %s to pointer %s", layerId, err)
39
-		logrus.Error(err)
40
-		return err
41
-	}
42
-
43
-	// Convert parentId to uint16 pointer for calling the procedure
44
-	parentIdp, err := syscall.UTF16PtrFromString(parentId)
45
-	if err != nil {
46
-		err = fmt.Errorf(title+"- Failed conversion of parentId %s to pointer %s", parentId, err)
47
-		logrus.Error(err)
48 22
 		return err
49 23
 	}
50 24
 
51 25
 	// Convert info to API calling convention
52 26
 	infop, err := convertDriverInfo(info)
53 27
 	if err != nil {
54
-		err = fmt.Errorf(title+"- Failed conversion info struct %s", err)
55 28
 		logrus.Error(err)
56 29
 		return err
57 30
 	}
58 31
 
59
-	var layerDescriptorsp *WC_LAYER_DESCRIPTOR
60
-	if len(layers) > 0 {
61
-		layerDescriptorsp = &(layers[0])
62
-	} else {
63
-		layerDescriptorsp = nil
64
-	}
65
-
66
-	// Call the procedure itself.
67
-	r1, _, _ := proc.Call(
68
-		uintptr(unsafe.Pointer(&infop)),
69
-		uintptr(unsafe.Pointer(layerIdp)),
70
-		uintptr(unsafe.Pointer(parentIdp)),
71
-		uintptr(unsafe.Pointer(layerDescriptorsp)),
72
-		uintptr(len(layers)))
73
-
74
-	use(unsafe.Pointer(&infop))
75
-	use(unsafe.Pointer(layerIdp))
76
-	use(unsafe.Pointer(parentIdp))
77
-	use(unsafe.Pointer(layerDescriptorsp))
78
-
79
-	if r1 != 0 {
80
-		err = fmt.Errorf(title+"- Win32 API call returned error r1=%d err=%s layerId=%s parentId=%s",
81
-			r1, syscall.Errno(r1), layerId, parentId)
32
+	err = createSandboxLayer(&infop, layerId, parentId, layers)
33
+	if err != nil {
34
+		err = makeErrorf(err, title, "layerId=%s parentId=%s", layerId, parentId)
82 35
 		logrus.Error(err)
83 36
 		return err
84 37
 	}
... ...
@@ -1,54 +1,22 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
12 6
 func DeactivateLayer(info DriverInfo, id string) error {
13 7
 	title := "hcsshim::DeactivateLayer "
14 8
 	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
15 9
 
16
-	// Load the DLL and get a handle to the procedure we need
17
-	dll, proc, err := loadAndFind(procDeactivateLayer)
18
-	if dll != nil {
19
-		defer dll.Release()
20
-	}
21
-	if err != nil {
22
-		return err
23
-	}
24
-
25
-	// Convert id to uint16 pointer for calling the procedure
26
-	idp, err := syscall.UTF16PtrFromString(id)
27
-	if err != nil {
28
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
29
-		logrus.Error(err)
30
-		return err
31
-	}
32
-
33 10
 	// Convert info to API calling convention
34 11
 	infop, err := convertDriverInfo(info)
35 12
 	if err != nil {
36
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", err)
37 13
 		logrus.Error(err)
38 14
 		return err
39 15
 	}
40 16
 
41
-	// Call the procedure itself.
42
-	r1, _, _ := proc.Call(
43
-		uintptr(unsafe.Pointer(&infop)),
44
-		uintptr(unsafe.Pointer(idp)))
45
-
46
-	use(unsafe.Pointer(&infop))
47
-	use(unsafe.Pointer(idp))
48
-
49
-	if r1 != 0 {
50
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s flavour=%d",
51
-			r1, syscall.Errno(r1), id, info.Flavour)
17
+	err = deactivateLayer(&infop, id)
18
+	if err != nil {
19
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
52 20
 		logrus.Error(err)
53 21
 		return err
54 22
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // DestroyLayer will remove the on-disk files representing the layer with the given
12 6
 // id, including that layer's containing folder, if any.
... ...
@@ -14,42 +8,16 @@ func DestroyLayer(info DriverInfo, id string) error {
14 14
 	title := "hcsshim::DestroyLayer "
15 15
 	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
16 16
 
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procDestroyLayer)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return err
24
-	}
25
-
26
-	// Convert id to uint16 pointer for calling the procedure
27
-	idp, err := syscall.UTF16PtrFromString(id)
28
-	if err != nil {
29
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
30
-		logrus.Error(err)
31
-		return err
32
-	}
33
-
34 17
 	// Convert info to API calling convention
35 18
 	infop, err := convertDriverInfo(info)
36 19
 	if err != nil {
37
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", err)
38 20
 		logrus.Error(err)
39 21
 		return err
40 22
 	}
41 23
 
42
-	// Call the procedure itself.
43
-	r1, _, _ := proc.Call(
44
-		uintptr(unsafe.Pointer(&infop)),
45
-		uintptr(unsafe.Pointer(idp)))
46
-
47
-	use(unsafe.Pointer(&infop))
48
-	use(unsafe.Pointer(idp))
49
-
50
-	if r1 != 0 {
51
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s flavour=%d",
52
-			r1, syscall.Errno(r1), id, info.Flavour)
24
+	err = destroyLayer(&infop, id)
25
+	if err != nil {
26
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
53 27
 		logrus.Error(err)
54 28
 		return err
55 29
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // ExportLayer will create a folder at exportFolderPath and fill that folder with
12 6
 // the transport format version of the layer identified by layerId. This transport
... ...
@@ -17,68 +11,22 @@ func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, paren
17 17
 	title := "hcsshim::ExportLayer "
18 18
 	logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, exportFolderPath)
19 19
 
20
-	// Load the DLL and get a handle to the procedure we need
21
-	dll, proc, err := loadAndFind(procExportLayer)
22
-	if dll != nil {
23
-		defer dll.Release()
24
-	}
25
-	if err != nil {
26
-		return err
27
-	}
28
-
29 20
 	// Generate layer descriptors
30 21
 	layers, err := layerPathsToDescriptors(parentLayerPaths)
31 22
 	if err != nil {
32
-		err = fmt.Errorf(title+"- Failed to generate layer descriptors ", err)
33
-		return err
34
-	}
35
-
36
-	// Convert layerId to uint16 pointer for calling the procedure
37
-	layerIdp, err := syscall.UTF16PtrFromString(layerId)
38
-	if err != nil {
39
-		err = fmt.Errorf(title+"- Failed conversion of layerId %s to pointer %s", layerId, err)
40
-		logrus.Error(err)
41
-		return err
42
-	}
43
-
44
-	// Convert exportFolderPath to uint16 pointer for calling the procedure
45
-	exportFolderPathp, err := syscall.UTF16PtrFromString(exportFolderPath)
46
-	if err != nil {
47
-		err = fmt.Errorf(title+"- Failed conversion of exportFolderPath %s to pointer %s", exportFolderPath, err)
48
-		logrus.Error(err)
49 23
 		return err
50 24
 	}
51 25
 
52 26
 	// Convert info to API calling convention
53 27
 	infop, err := convertDriverInfo(info)
54 28
 	if err != nil {
55
-		err = fmt.Errorf(title+"- Failed conversion info struct %s", err)
56 29
 		logrus.Error(err)
57 30
 		return err
58 31
 	}
59 32
 
60
-	var layerDescriptorsp *WC_LAYER_DESCRIPTOR
61
-	if len(layers) > 0 {
62
-		layerDescriptorsp = &(layers[0])
63
-	} else {
64
-		layerDescriptorsp = nil
65
-	}
66
-
67
-	// Call the procedure itself.
68
-	r1, _, _ := proc.Call(
69
-		uintptr(unsafe.Pointer(&infop)),
70
-		uintptr(unsafe.Pointer(layerIdp)),
71
-		uintptr(unsafe.Pointer(exportFolderPathp)),
72
-		uintptr(unsafe.Pointer(layerDescriptorsp)),
73
-		uintptr(len(layers)))
74
-	use(unsafe.Pointer(&infop))
75
-	use(unsafe.Pointer(layerIdp))
76
-	use(unsafe.Pointer(exportFolderPathp))
77
-	use(unsafe.Pointer(layerDescriptorsp))
78
-
79
-	if r1 != 0 {
80
-		err = fmt.Errorf(title+"- Win32 API call returned error r1=%d err=%s layerId=%s flavour=%d folder=%s",
81
-			r1, syscall.Errno(r1), layerId, info.Flavour, exportFolderPath)
33
+	err = exportLayer(&infop, layerId, exportFolderPath, layers)
34
+	if err != nil {
35
+		err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, exportFolderPath)
82 36
 		logrus.Error(err)
83 37
 		return err
84 38
 	}
... ...
@@ -1,9 +1,7 @@
1 1
 package hcsshim
2 2
 
3 3
 import (
4
-	"fmt"
5 4
 	"syscall"
6
-	"unsafe"
7 5
 
8 6
 	"github.com/Sirupsen/logrus"
9 7
 )
... ...
@@ -16,45 +14,21 @@ func GetLayerMountPath(info DriverInfo, id string) (string, error) {
16 16
 	title := "hcsshim::GetLayerMountPath "
17 17
 	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
18 18
 
19
-	// Load the DLL and get a handle to the procedure we need
20
-	dll, proc, err := loadAndFind(procGetLayerMountPath)
21
-	if dll != nil {
22
-		defer dll.Release()
23
-	}
24
-	if err != nil {
25
-		return "", err
26
-	}
27
-
28
-	// Convert id to uint16 pointer for calling the procedure
29
-	idp, err := syscall.UTF16PtrFromString(id)
30
-	if err != nil {
31
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
32
-		logrus.Error(err)
33
-		return "", err
34
-	}
35
-
36 19
 	// Convert info to API calling convention
37 20
 	infop, err := convertDriverInfo(info)
38 21
 	if err != nil {
39
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", err)
40 22
 		logrus.Error(err)
41 23
 		return "", err
42 24
 	}
43 25
 
44
-	var mountPathLength uint64
26
+	var mountPathLength uintptr
45 27
 	mountPathLength = 0
46 28
 
47 29
 	// Call the procedure itself.
48 30
 	logrus.Debugf("Calling proc (1)")
49
-	r1, _, _ := proc.Call(
50
-		uintptr(unsafe.Pointer(&infop)),
51
-		uintptr(unsafe.Pointer(idp)),
52
-		uintptr(unsafe.Pointer(&mountPathLength)),
53
-		uintptr(unsafe.Pointer(nil)))
54
-
55
-	if r1 != 0 {
56
-		err = fmt.Errorf(title+" - First Win32 API call returned error r1=%d err=%s id=%s flavour=%d",
57
-			r1, syscall.Errno(r1), id, info.Flavour)
31
+	err = getLayerMountPath(&infop, id, &mountPathLength, nil)
32
+	if err != nil {
33
+		err = makeErrorf(err, title, "(first call) id=%s flavour=%d", id, info.Flavour)
58 34
 		logrus.Error(err)
59 35
 		return "", err
60 36
 	}
... ...
@@ -68,19 +42,9 @@ func GetLayerMountPath(info DriverInfo, id string) (string, error) {
68 68
 
69 69
 	// Call the procedure again
70 70
 	logrus.Debugf("Calling proc (2)")
71
-	r1, _, _ = proc.Call(
72
-		uintptr(unsafe.Pointer(&infop)),
73
-		uintptr(unsafe.Pointer(idp)),
74
-		uintptr(unsafe.Pointer(&mountPathLength)),
75
-		uintptr(unsafe.Pointer(&mountPathp[0])))
76
-
77
-	use(unsafe.Pointer(&mountPathLength))
78
-	use(unsafe.Pointer(&infop))
79
-	use(unsafe.Pointer(idp))
80
-
81
-	if r1 != 0 {
82
-		err = fmt.Errorf(title+" - Second Win32 API call returned error r1=%d err=%s id=%s flavour=%d",
83
-			r1, syscall.Errno(r1), id, info.Flavour)
71
+	err = getLayerMountPath(&infop, id, &mountPathLength, &mountPathp[0])
72
+	if err != nil {
73
+		err = makeErrorf(err, title, "(second call) id=%s flavour=%d", id, info.Flavour)
84 74
 		logrus.Error(err)
85 75
 		return "", err
86 76
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // GetSharedBaseImages will enumerate the images stored in the common central
12 6
 // image store and return descriptive info about those images for the purpose
... ...
@@ -14,43 +8,15 @@ import (
14 14
 func GetSharedBaseImages() (imageData string, err error) {
15 15
 	title := "hcsshim::GetSharedBaseImages "
16 16
 
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procGetSharedBaseImages)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return
24
-	}
25
-
26
-	// Load the OLE DLL and get a handle to the CoTaskMemFree procedure
27
-	dll2, proc2, err := loadAndFindFromDll(oleDLLName, procCoTaskMemFree)
28
-	if dll2 != nil {
29
-		defer dll2.Release()
30
-	}
31
-	if err != nil {
32
-		return
33
-	}
34
-
35
-	var output uintptr
36
-
37
-	// Call the procedure again
38 17
 	logrus.Debugf("Calling proc")
39
-	r1, _, _ := proc.Call(
40
-		uintptr(unsafe.Pointer(&output)))
41
-
42
-	if r1 != 0 {
43
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d errno=%s",
44
-			r1, syscall.Errno(r1))
18
+	var buffer *uint16
19
+	err = getBaseImages(&buffer)
20
+	if err != nil {
21
+		err = makeError(err, title, "")
45 22
 		logrus.Error(err)
46 23
 		return
47 24
 	}
48
-
49
-	// Defer the cleanup of the memory using CoTaskMemFree
50
-	defer proc2.Call(output)
51
-
52
-	imageData = syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(output))[:])
25
+	imageData = convertAndFreeCoTaskMemString(buffer)
53 26
 	logrus.Debugf(title+" - succeeded output=%s", imageData)
54
-
55 27
 	return
56 28
 }
... ...
@@ -7,46 +7,39 @@ import (
7 7
 	"fmt"
8 8
 	"syscall"
9 9
 	"unsafe"
10
-
11
-	"github.com/Sirupsen/logrus"
12 10
 )
13 11
 
14
-const (
15
-	// Name of the shim DLL for access to the HCS
16
-	shimDLLName = "vmcompute.dll"
17
-
18
-	// Container related functions in the shim DLL
19
-	procCreateComputeSystem                        = "CreateComputeSystem"
20
-	procStartComputeSystem                         = "StartComputeSystem"
21
-	procCreateProcessWithStdHandlesInComputeSystem = "CreateProcessWithStdHandlesInComputeSystem"
22
-	procWaitForProcessInComputeSystem              = "WaitForProcessInComputeSystem"
23
-	procShutdownComputeSystem                      = "ShutdownComputeSystem"
24
-	procTerminateComputeSystem                     = "TerminateComputeSystem"
25
-	procTerminateProcessInComputeSystem            = "TerminateProcessInComputeSystem"
26
-	procResizeConsoleInComputeSystem               = "ResizeConsoleInComputeSystem"
27
-
28
-	// Storage related functions in the shim DLL
29
-	procLayerExists         = "LayerExists"
30
-	procCreateLayer         = "CreateLayer"
31
-	procDestroyLayer        = "DestroyLayer"
32
-	procActivateLayer       = "ActivateLayer"
33
-	procDeactivateLayer     = "DeactivateLayer"
34
-	procGetLayerMountPath   = "GetLayerMountPath"
35
-	procCopyLayer           = "CopyLayer"
36
-	procCreateSandboxLayer  = "CreateSandboxLayer"
37
-	procPrepareLayer        = "PrepareLayer"
38
-	procUnprepareLayer      = "UnprepareLayer"
39
-	procExportLayer         = "ExportLayer"
40
-	procImportLayer         = "ImportLayer"
41
-	procGetSharedBaseImages = "GetBaseImages"
42
-	procNameToGuid          = "NameToGuid"
43
-
44
-	// Name of the standard OLE dll
45
-	oleDLLName = "Ole32.dll"
46
-
47
-	// Utility functions
48
-	procCoTaskMemFree = "CoTaskMemFree"
12
+//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go
13
+
14
+//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree
15
+
16
+//sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer?
17
+//sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer?
18
+//sys createLayer(info *driverInfo, id string, parent string) (hr error) = vmcompute.CreateLayer?
19
+//sys createSandboxLayer(info *driverInfo, id string, parent string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CreateSandboxLayer?
20
+//sys deactivateLayer(info *driverInfo, id string) (hr error) = vmcompute.DeactivateLayer?
21
+//sys destroyLayer(info *driverInfo, id string) (hr error) = vmcompute.DestroyLayer?
22
+//sys exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ExportLayer?
23
+//sys getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) = vmcompute.GetLayerMountPath?
24
+//sys getBaseImages(buffer **uint16) (hr error) = vmcompute.GetBaseImages?
25
+//sys importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ImportLayer?
26
+//sys layerExists(info *driverInfo, id string, exists *uint32) (hr error) = vmcompute.LayerExists?
27
+//sys nameToGuid(name string, guid *GUID) (hr error) = vmcompute.NameToGuid?
28
+//sys prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.PrepareLayer?
29
+//sys unprepareLayer(info *driverInfo, id string) (hr error) = vmcompute.UnprepareLayer?
30
+
31
+//sys createComputeSystem(id string, configuration string) (hr error) = vmcompute.CreateComputeSystem?
32
+//sys createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) = vmcompute.CreateProcessWithStdHandlesInComputeSystem?
33
+//sys resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) = vmcompute.ResizeConsoleInComputeSystem?
34
+//sys shutdownComputeSystem(id string, timeout uint32) (hr error) = vmcompute.ShutdownComputeSystem?
35
+//sys startComputeSystem(id string) (hr error) = vmcompute.StartComputeSystem?
36
+//sys terminateComputeSystem(id string) (hr error) = vmcompute.TerminateComputeSystem?
37
+//sys terminateProcessInComputeSystem(id string, pid uint32) (hr error) = vmcompute.TerminateProcessInComputeSystem?
38
+//sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem?
39
+
40
+//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
49 41
 
42
+const (
50 43
 	// Specific user-visible exit codes
51 44
 	WaitErrExecFailed = 32767
52 45
 
... ...
@@ -56,49 +49,45 @@ const (
56 56
 	Win32SpecifiedPathInvalid             = 0x800700A1 // ShutdownComputeSystem: The specified path is invalid
57 57
 	Win32SystemCannotFindThePathSpecified = 0x80070003 // ShutdownComputeSystem: The system cannot find the path specified
58 58
 	Win32InvalidArgument                  = 0x80072726 // CreateProcessInComputeSystem: An invalid argument was supplied
59
+	EFail                                 = 0x80004005
59 60
 
60 61
 	// Timeout on wait calls
61 62
 	TimeoutInfinite = 0xFFFFFFFF
62 63
 )
63 64
 
64
-// loadAndFindFromDll finds a procedure in the given DLL. Note we do NOT do lazy loading as
65
-// go is particularly unfriendly in the case of a mismatch. By that - it panics
66
-// if a function can't be found. By explicitly loading, we can control error
67
-// handling gracefully without the daemon terminating.
68
-func loadAndFindFromDll(dllName, procedure string) (dll *syscall.DLL, proc *syscall.Proc, err error) {
69
-	dll, err = syscall.LoadDLL(dllName)
70
-	if err != nil {
71
-		err = fmt.Errorf("Failed to load %s - error %s", dllName, err)
72
-		logrus.Error(err)
73
-		return
74
-	}
75
-
76
-	proc, err = dll.FindProc(procedure)
77
-	if err != nil {
78
-		err = fmt.Errorf("Failed to find %s in %s", procedure, dllName)
79
-		logrus.Error(err)
80
-		return
81
-	}
65
+type hcsError struct {
66
+	title string
67
+	rest  string
68
+	err   error
69
+}
82 70
 
83
-	return
71
+type Win32Error interface {
72
+	error
73
+	HResult() uint32
84 74
 }
85 75
 
86
-// loadAndFind finds a procedure in the shim DLL.
87
-func loadAndFind(procedure string) (*syscall.DLL, *syscall.Proc, error) {
76
+func makeError(err error, title, rest string) Win32Error {
77
+	return &hcsError{title, rest, err}
78
+}
88 79
 
89
-	return loadAndFindFromDll(shimDLLName, procedure)
80
+func makeErrorf(err error, title, format string, a ...interface{}) Win32Error {
81
+	return makeError(err, title, fmt.Sprintf(format, a...))
90 82
 }
91 83
 
92
-// use is a no-op, but the compiler cannot see that it is.
93
-// Calling use(p) ensures that p is kept live until that point.
94
-/*
95
-//go:noescape
96
-func use(p unsafe.Pointer)
97
-*/
84
+func (e *hcsError) HResult() uint32 {
85
+	if hr, ok := e.err.(syscall.Errno); ok {
86
+		return uint32(hr)
87
+	} else {
88
+		return EFail
89
+	}
90
+}
98 91
 
99
-// Alternate without using //go:noescape and asm.s
100
-var temp unsafe.Pointer
92
+func (e *hcsError) Error() string {
93
+	return fmt.Sprintf("%s- Win32 API call returned error r1=0x%x err=%s%s", e.title, e.HResult(), e.err, e.rest)
94
+}
101 95
 
102
-func use(p unsafe.Pointer) {
103
-	temp = p
96
+func convertAndFreeCoTaskMemString(buffer *uint16) string {
97
+	str := syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(buffer))[:])
98
+	coTaskMemFree(unsafe.Pointer(buffer))
99
+	return str
104 100
 }
105 101
new file mode 100644
... ...
@@ -0,0 +1,131 @@
0
+package hcsshim
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"net"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+)
9
+
10
+type NatPolicy struct {
11
+	Type         string
12
+	Protocol     string
13
+	InternalPort uint16
14
+	ExternalPort uint16
15
+}
16
+
17
+type QosPolicy struct {
18
+	Type                            string
19
+	MaximumOutgoingBandwidthInBytes uint64
20
+}
21
+
22
+// Subnet is assoicated with a network and represents a list
23
+// of subnets available to the network
24
+type Subnet struct {
25
+	AddressPrefix  string `json:",omitempty"`
26
+	GatewayAddress string `json:",omitempty"`
27
+}
28
+
29
+// MacPool is assoicated with a network and represents a list
30
+// of macaddresses available to the network
31
+type MacPool struct {
32
+	StartMacAddress string `json:",omitempty"`
33
+	EndMacAddress   string `json:",omitempty"`
34
+}
35
+
36
+// HNSNetwork represents a network in HNS
37
+type HNSNetwork struct {
38
+	Id       string            `json:",omitempty"`
39
+	Name     string            `json:",omitempty"`
40
+	Type     string            `json:",omitempty"`
41
+	Policies []json.RawMessage `json:",omitempty"`
42
+	MacPools []MacPool         `json:",omitempty"`
43
+	Subnets  []Subnet          `json:",omitempty"`
44
+}
45
+
46
+// HNSEndpoint represents a network endpoint in HNS
47
+type HNSEndpoint struct {
48
+	Id                 string            `json:",omitempty"`
49
+	Name               string            `json:",omitempty"`
50
+	VirtualNetwork     string            `json:",omitempty"`
51
+	VirtualNetworkName string            `json:",omitempty"`
52
+	Policies           []json.RawMessage `json:",omitempty"`
53
+	MacAddress         string            `json:",omitempty"`
54
+	IPAddress          net.IP            `json:",omitempty"`
55
+}
56
+
57
+type hnsNetworkResponse struct {
58
+	Success bool
59
+	Error   string
60
+	Output  HNSNetwork
61
+}
62
+
63
+type hnsResponse struct {
64
+	Success bool
65
+	Error   string
66
+	Output  json.RawMessage
67
+}
68
+
69
+func hnsCall(method, path, request string, returnResponse interface{}) error {
70
+	var responseBuffer *uint16
71
+	err := _hnsCall(method, path, request, &responseBuffer)
72
+	if err != nil {
73
+		return makeError(err, "hnsCall ", "")
74
+	}
75
+	response := convertAndFreeCoTaskMemString(responseBuffer)
76
+
77
+	hnsresponse := &hnsResponse{}
78
+	if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
79
+		return err
80
+	}
81
+
82
+	if !hnsresponse.Success {
83
+		return fmt.Errorf("HNS failed with error : %s", hnsresponse.Error)
84
+	}
85
+
86
+	if len(hnsresponse.Output) == 0 {
87
+		return nil
88
+	}
89
+
90
+	logrus.Debugf("Network Response : %s", hnsresponse.Output)
91
+	err = json.Unmarshal(hnsresponse.Output, returnResponse)
92
+	if err != nil {
93
+		return err
94
+	}
95
+
96
+	return nil
97
+}
98
+
99
+// HNSNetworkRequest makes a call into HNS to update/query a single network
100
+func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
101
+	var network HNSNetwork
102
+	err := hnsCall(method, "/networks/"+path, request, &network)
103
+	if err != nil {
104
+		return nil, err
105
+	}
106
+
107
+	return &network, nil
108
+}
109
+
110
+// HNSListNetworkRequest makes a HNS call to query the list of available networks
111
+func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
112
+	var network []HNSNetwork
113
+	err := hnsCall(method, "/networks/"+path, request, &network)
114
+	if err != nil {
115
+		return nil, err
116
+	}
117
+
118
+	return network, nil
119
+}
120
+
121
+// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
122
+func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
123
+	endpoint := &HNSEndpoint{}
124
+	err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
125
+	if err != nil {
126
+		return nil, err
127
+	}
128
+
129
+	return endpoint, nil
130
+}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // ImportLayer will take the contents of the folder at importFolderPath and import
12 6
 // that into a layer with the id layerId.  Note that in order to correctly populate
... ...
@@ -16,68 +10,22 @@ func ImportLayer(info DriverInfo, layerId string, importFolderPath string, paren
16 16
 	title := "hcsshim::ImportLayer "
17 17
 	logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, importFolderPath)
18 18
 
19
-	// Load the DLL and get a handle to the procedure we need
20
-	dll, proc, err := loadAndFind(procImportLayer)
21
-	if dll != nil {
22
-		defer dll.Release()
23
-	}
24
-	if err != nil {
25
-		return err
26
-	}
27
-
28 19
 	// Generate layer descriptors
29 20
 	layers, err := layerPathsToDescriptors(parentLayerPaths)
30 21
 	if err != nil {
31
-		err = fmt.Errorf(title+"- Failed to generate layer descriptors ", err)
32
-		return err
33
-	}
34
-
35
-	// Convert layerId to uint16 pointer for calling the procedure
36
-	layerIdp, err := syscall.UTF16PtrFromString(layerId)
37
-	if err != nil {
38
-		err = fmt.Errorf(title+"- Failed conversion of layerId %s to pointer %s", layerId, err)
39
-		logrus.Error(err)
40
-		return err
41
-	}
42
-
43
-	// Convert importFolderPath to uint16 pointer for calling the procedure
44
-	importFolderPathp, err := syscall.UTF16PtrFromString(importFolderPath)
45
-	if err != nil {
46
-		err = fmt.Errorf(title+"- Failed conversion of importFolderPath %s to pointer %s", importFolderPath, err)
47
-		logrus.Error(err)
48 22
 		return err
49 23
 	}
50 24
 
51 25
 	// Convert info to API calling convention
52 26
 	infop, err := convertDriverInfo(info)
53 27
 	if err != nil {
54
-		err = fmt.Errorf(title+"- Failed conversion info struct %s", err)
55 28
 		logrus.Error(err)
56 29
 		return err
57 30
 	}
58 31
 
59
-	var layerDescriptorsp *WC_LAYER_DESCRIPTOR
60
-	if len(layers) > 0 {
61
-		layerDescriptorsp = &(layers[0])
62
-	} else {
63
-		layerDescriptorsp = nil
64
-	}
65
-
66
-	// Call the procedure itself.
67
-	r1, _, _ := proc.Call(
68
-		uintptr(unsafe.Pointer(&infop)),
69
-		uintptr(unsafe.Pointer(layerIdp)),
70
-		uintptr(unsafe.Pointer(importFolderPathp)),
71
-		uintptr(unsafe.Pointer(layerDescriptorsp)),
72
-		uintptr(len(layers)))
73
-	use(unsafe.Pointer(&infop))
74
-	use(unsafe.Pointer(layerIdp))
75
-	use(unsafe.Pointer(importFolderPathp))
76
-	use(unsafe.Pointer(layerDescriptorsp))
77
-
78
-	if r1 != 0 {
79
-		err = fmt.Errorf(title+"- Win32 API call returned error r1=%d err=%s layerId=%s flavour=%d folder=%s",
80
-			r1, syscall.Errno(r1), layerId, info.Flavour, importFolderPath)
32
+	err = importLayer(&infop, layerId, importFolderPath, layers)
33
+	if err != nil {
34
+		err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, importFolderPath)
81 35
 		logrus.Error(err)
82 36
 		return err
83 37
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // LayerExists will return true if a layer with the given id exists and is known
12 6
 // to the system.
... ...
@@ -14,49 +8,23 @@ func LayerExists(info DriverInfo, id string) (bool, error) {
14 14
 	title := "hcsshim::LayerExists "
15 15
 	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
16 16
 
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procLayerExists)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return false, err
24
-	}
25
-
26
-	// Convert id to uint16 pointer for calling the procedure
27
-	idp, err := syscall.UTF16PtrFromString(id)
28
-	if err != nil {
29
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
30
-		logrus.Error(err)
31
-		return false, err
32
-	}
33
-
34 17
 	// Convert info to API calling convention
35 18
 	infop, err := convertDriverInfo(info)
36 19
 	if err != nil {
37
-		err = fmt.Errorf(title+" - Failed conversion info struct %s", err)
38 20
 		logrus.Error(err)
39 21
 		return false, err
40 22
 	}
41 23
 
42 24
 	// Call the procedure itself.
43
-	var exists bool // Outparam from Win32
25
+	var exists uint32
44 26
 
45
-	r1, _, _ := proc.Call(
46
-		uintptr(unsafe.Pointer(&infop)),
47
-		uintptr(unsafe.Pointer(idp)),
48
-		uintptr(unsafe.Pointer(&exists)))
49
-
50
-	use(unsafe.Pointer(&infop))
51
-	use(unsafe.Pointer(idp))
52
-
53
-	if r1 != 0 {
54
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s flavour=%d",
55
-			r1, syscall.Errno(r1), id, info.Flavour)
27
+	err = layerExists(&infop, id, &exists)
28
+	if err != nil {
29
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
56 30
 		logrus.Error(err)
57 31
 		return false, err
58 32
 	}
59 33
 
60 34
 	logrus.Debugf(title+"succeeded flavour=%d id=%s exists=%d", info.Flavour, id, exists)
61
-	return exists, nil
35
+	return exists != 0, nil
62 36
 }
63 37
new file mode 100644
... ...
@@ -0,0 +1,797 @@
0
+// Copyright 2013 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build ignore
5
+
6
+/*
7
+mksyscall_windows generates windows system call bodies
8
+
9
+It parses all files specified on command line containing function
10
+prototypes (like syscall_windows.go) and prints system call bodies
11
+to standard output.
12
+
13
+The prototypes are marked by lines beginning with "//sys" and read
14
+like func declarations if //sys is replaced by func, but:
15
+
16
+* The parameter lists must give a name for each argument. This
17
+  includes return parameters.
18
+
19
+* The parameter lists must give a type for each argument:
20
+  the (x, y, z int) shorthand is not allowed.
21
+
22
+* If the return parameter is an error number, it must be named err.
23
+
24
+* If go func name needs to be different from it's winapi dll name,
25
+  the winapi name could be specified at the end, after "=" sign, like
26
+  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
27
+
28
+* Each function that returns err needs to supply a condition, that
29
+  return value of winapi will be tested against to detect failure.
30
+  This would set err to windows "last-error", otherwise it will be nil.
31
+  The value can be provided at end of //sys declaration, like
32
+  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
33
+  and is [failretval==0] by default.
34
+
35
+Usage:
36
+	mksyscall_windows [flags] [path ...]
37
+
38
+The flags are:
39
+	-output
40
+		Specify output file name (outputs to console if blank).
41
+	-trace
42
+		Generate print statement after every syscall.
43
+*/
44
+package main
45
+
46
+import (
47
+	"bufio"
48
+	"bytes"
49
+	"errors"
50
+	"flag"
51
+	"fmt"
52
+	"go/format"
53
+	"go/parser"
54
+	"go/token"
55
+	"io"
56
+	"io/ioutil"
57
+	"log"
58
+	"os"
59
+	"strconv"
60
+	"strings"
61
+	"text/template"
62
+)
63
+
64
+var (
65
+	filename       = flag.String("output", "", "output file name (standard output if omitted)")
66
+	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
67
+)
68
+
69
+func trim(s string) string {
70
+	return strings.Trim(s, " \t")
71
+}
72
+
73
+var packageName string
74
+
75
+func packagename() string {
76
+	return packageName
77
+}
78
+
79
+func syscalldot() string {
80
+	if packageName == "syscall" {
81
+		return ""
82
+	}
83
+	return "syscall."
84
+}
85
+
86
+// Param is function parameter
87
+type Param struct {
88
+	Name      string
89
+	Type      string
90
+	fn        *Fn
91
+	tmpVarIdx int
92
+}
93
+
94
+// tmpVar returns temp variable name that will be used to represent p during syscall.
95
+func (p *Param) tmpVar() string {
96
+	if p.tmpVarIdx < 0 {
97
+		p.tmpVarIdx = p.fn.curTmpVarIdx
98
+		p.fn.curTmpVarIdx++
99
+	}
100
+	return fmt.Sprintf("_p%d", p.tmpVarIdx)
101
+}
102
+
103
+// BoolTmpVarCode returns source code for bool temp variable.
104
+func (p *Param) BoolTmpVarCode() string {
105
+	const code = `var %s uint32
106
+	if %s {
107
+		%s = 1
108
+	} else {
109
+		%s = 0
110
+	}`
111
+	tmp := p.tmpVar()
112
+	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
113
+}
114
+
115
+// SliceTmpVarCode returns source code for slice temp variable.
116
+func (p *Param) SliceTmpVarCode() string {
117
+	const code = `var %s *%s
118
+	if len(%s) > 0 {
119
+		%s = &%s[0]
120
+	}`
121
+	tmp := p.tmpVar()
122
+	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
123
+}
124
+
125
+// StringTmpVarCode returns source code for string temp variable.
126
+func (p *Param) StringTmpVarCode() string {
127
+	errvar := p.fn.Rets.ErrorVarName()
128
+	if errvar == "" {
129
+		errvar = "_"
130
+	}
131
+	tmp := p.tmpVar()
132
+	const code = `var %s %s
133
+	%s, %s = %s(%s)`
134
+	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
135
+	if errvar == "-" {
136
+		return s
137
+	}
138
+	const morecode = `
139
+	if %s != nil {
140
+		return
141
+	}`
142
+	return s + fmt.Sprintf(morecode, errvar)
143
+}
144
+
145
+// TmpVarCode returns source code for temp variable.
146
+func (p *Param) TmpVarCode() string {
147
+	switch {
148
+	case p.Type == "bool":
149
+		return p.BoolTmpVarCode()
150
+	case strings.HasPrefix(p.Type, "[]"):
151
+		return p.SliceTmpVarCode()
152
+	default:
153
+		return ""
154
+	}
155
+}
156
+
157
+// TmpVarHelperCode returns source code for helper's temp variable.
158
+func (p *Param) TmpVarHelperCode() string {
159
+	if p.Type != "string" {
160
+		return ""
161
+	}
162
+	return p.StringTmpVarCode()
163
+}
164
+
165
+// SyscallArgList returns source code fragments representing p parameter
166
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
167
+// the first element and length.
168
+func (p *Param) SyscallArgList() []string {
169
+	t := p.HelperType()
170
+	var s string
171
+	switch {
172
+	case t[0] == '*':
173
+		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
174
+	case t == "bool":
175
+		s = p.tmpVar()
176
+	case strings.HasPrefix(t, "[]"):
177
+		return []string{
178
+			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
179
+			fmt.Sprintf("uintptr(len(%s))", p.Name),
180
+		}
181
+	default:
182
+		s = p.Name
183
+	}
184
+	return []string{fmt.Sprintf("uintptr(%s)", s)}
185
+}
186
+
187
+// IsError determines if p parameter is used to return error.
188
+func (p *Param) IsError() bool {
189
+	return p.Name == "err" && p.Type == "error"
190
+}
191
+
192
+// HelperType returns type of parameter p used in helper function.
193
+func (p *Param) HelperType() string {
194
+	if p.Type == "string" {
195
+		return p.fn.StrconvType()
196
+	}
197
+	return p.Type
198
+}
199
+
200
+// join concatenates parameters ps into a string with sep separator.
201
+// Each parameter is converted into string by applying fn to it
202
+// before conversion.
203
+func join(ps []*Param, fn func(*Param) string, sep string) string {
204
+	if len(ps) == 0 {
205
+		return ""
206
+	}
207
+	a := make([]string, 0)
208
+	for _, p := range ps {
209
+		a = append(a, fn(p))
210
+	}
211
+	return strings.Join(a, sep)
212
+}
213
+
214
+// Rets describes function return parameters.
215
+type Rets struct {
216
+	Name         string
217
+	Type         string
218
+	ReturnsError bool
219
+	FailCond     string
220
+}
221
+
222
+// ErrorVarName returns error variable name for r.
223
+func (r *Rets) ErrorVarName() string {
224
+	if r.ReturnsError {
225
+		return "err"
226
+	}
227
+	if r.Type == "error" {
228
+		return r.Name
229
+	}
230
+	return ""
231
+}
232
+
233
+// ToParams converts r into slice of *Param.
234
+func (r *Rets) ToParams() []*Param {
235
+	ps := make([]*Param, 0)
236
+	if len(r.Name) > 0 {
237
+		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
238
+	}
239
+	if r.ReturnsError {
240
+		ps = append(ps, &Param{Name: "err", Type: "error"})
241
+	}
242
+	return ps
243
+}
244
+
245
+// List returns source code of syscall return parameters.
246
+func (r *Rets) List() string {
247
+	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
248
+	if len(s) > 0 {
249
+		s = "(" + s + ")"
250
+	}
251
+	return s
252
+}
253
+
254
+// PrintList returns source code of trace printing part correspondent
255
+// to syscall return values.
256
+func (r *Rets) PrintList() string {
257
+	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
258
+}
259
+
260
+// SetReturnValuesCode returns source code that accepts syscall return values.
261
+func (r *Rets) SetReturnValuesCode() string {
262
+	if r.Name == "" && !r.ReturnsError {
263
+		return ""
264
+	}
265
+	retvar := "r0"
266
+	if r.Name == "" {
267
+		retvar = "r1"
268
+	}
269
+	errvar := "_"
270
+	if r.ReturnsError {
271
+		errvar = "e1"
272
+	}
273
+	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
274
+}
275
+
276
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
277
+	const code = `if %s {
278
+		if e1 != 0 {
279
+			err = error(e1)
280
+		} else {
281
+			err = %sEINVAL
282
+		}
283
+	}`
284
+	cond := retvar + " == 0"
285
+	if r.FailCond != "" {
286
+		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
287
+	}
288
+	return fmt.Sprintf(code, cond, syscalldot())
289
+}
290
+
291
+// SetErrorCode returns source code that sets return parameters.
292
+func (r *Rets) SetErrorCode() string {
293
+	const code = `if r0 != 0 {
294
+		%s = %sErrno(r0)
295
+	}`
296
+	if r.Name == "" && !r.ReturnsError {
297
+		return ""
298
+	}
299
+	if r.Name == "" {
300
+		return r.useLongHandleErrorCode("r1")
301
+	}
302
+	if r.Type == "error" {
303
+		return fmt.Sprintf(code, r.Name, syscalldot())
304
+	}
305
+	s := ""
306
+	switch {
307
+	case r.Type[0] == '*':
308
+		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
309
+	case r.Type == "bool":
310
+		s = fmt.Sprintf("%s = r0 != 0", r.Name)
311
+	default:
312
+		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
313
+	}
314
+	if !r.ReturnsError {
315
+		return s
316
+	}
317
+	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
318
+}
319
+
320
+// Fn describes syscall function.
321
+type Fn struct {
322
+	Name        string
323
+	Params      []*Param
324
+	Rets        *Rets
325
+	PrintTrace  bool
326
+	confirmproc bool
327
+	dllname     string
328
+	dllfuncname string
329
+	src         string
330
+	// TODO: get rid of this field and just use parameter index instead
331
+	curTmpVarIdx int // insure tmp variables have uniq names
332
+}
333
+
334
+// extractParams parses s to extract function parameters.
335
+func extractParams(s string, f *Fn) ([]*Param, error) {
336
+	s = trim(s)
337
+	if s == "" {
338
+		return nil, nil
339
+	}
340
+	a := strings.Split(s, ",")
341
+	ps := make([]*Param, len(a))
342
+	for i := range ps {
343
+		s2 := trim(a[i])
344
+		b := strings.Split(s2, " ")
345
+		if len(b) != 2 {
346
+			b = strings.Split(s2, "\t")
347
+			if len(b) != 2 {
348
+				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
349
+			}
350
+		}
351
+		ps[i] = &Param{
352
+			Name:      trim(b[0]),
353
+			Type:      trim(b[1]),
354
+			fn:        f,
355
+			tmpVarIdx: -1,
356
+		}
357
+	}
358
+	return ps, nil
359
+}
360
+
361
+// extractSection extracts text out of string s starting after start
362
+// and ending just before end. found return value will indicate success,
363
+// and prefix, body and suffix will contain correspondent parts of string s.
364
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
365
+	s = trim(s)
366
+	if strings.HasPrefix(s, string(start)) {
367
+		// no prefix
368
+		body = s[1:]
369
+	} else {
370
+		a := strings.SplitN(s, string(start), 2)
371
+		if len(a) != 2 {
372
+			return "", "", s, false
373
+		}
374
+		prefix = a[0]
375
+		body = a[1]
376
+	}
377
+	a := strings.SplitN(body, string(end), 2)
378
+	if len(a) != 2 {
379
+		return "", "", "", false
380
+	}
381
+	return prefix, a[0], a[1], true
382
+}
383
+
384
+// newFn parses string s and return created function Fn.
385
+func newFn(s string) (*Fn, error) {
386
+	s = trim(s)
387
+	f := &Fn{
388
+		Rets:       &Rets{},
389
+		src:        s,
390
+		PrintTrace: *printTraceFlag,
391
+	}
392
+	// function name and args
393
+	prefix, body, s, found := extractSection(s, '(', ')')
394
+	if !found || prefix == "" {
395
+		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
396
+	}
397
+	f.Name = prefix
398
+	var err error
399
+	f.Params, err = extractParams(body, f)
400
+	if err != nil {
401
+		return nil, err
402
+	}
403
+	// return values
404
+	_, body, s, found = extractSection(s, '(', ')')
405
+	if found {
406
+		r, err := extractParams(body, f)
407
+		if err != nil {
408
+			return nil, err
409
+		}
410
+		switch len(r) {
411
+		case 0:
412
+		case 1:
413
+			if r[0].IsError() {
414
+				f.Rets.ReturnsError = true
415
+			} else {
416
+				f.Rets.Name = r[0].Name
417
+				f.Rets.Type = r[0].Type
418
+			}
419
+		case 2:
420
+			if !r[1].IsError() {
421
+				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
422
+			}
423
+			f.Rets.ReturnsError = true
424
+			f.Rets.Name = r[0].Name
425
+			f.Rets.Type = r[0].Type
426
+		default:
427
+			return nil, errors.New("Too many return values in \"" + f.src + "\"")
428
+		}
429
+	}
430
+	// fail condition
431
+	_, body, s, found = extractSection(s, '[', ']')
432
+	if found {
433
+		f.Rets.FailCond = body
434
+	}
435
+	// dll and dll function names
436
+	s = trim(s)
437
+	if s == "" {
438
+		return f, nil
439
+	}
440
+	if !strings.HasPrefix(s, "=") {
441
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
442
+	}
443
+	s = trim(s[1:])
444
+	a := strings.Split(s, ".")
445
+	switch len(a) {
446
+	case 1:
447
+		f.dllfuncname = a[0]
448
+	case 2:
449
+		f.dllname = a[0]
450
+		f.dllfuncname = a[1]
451
+	default:
452
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
453
+	}
454
+	if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
455
+		f.confirmproc = true
456
+		f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
457
+	}
458
+	return f, nil
459
+}
460
+
461
+// DLLName returns DLL name for function f.
462
+func (f *Fn) DLLName() string {
463
+	if f.dllname == "" {
464
+		return "kernel32"
465
+	}
466
+	return f.dllname
467
+}
468
+
469
+// DLLName returns DLL function name for function f.
470
+func (f *Fn) DLLFuncName() string {
471
+	if f.dllfuncname == "" {
472
+		return f.Name
473
+	}
474
+	return f.dllfuncname
475
+}
476
+
477
+func (f *Fn) ConfirmProc() bool {
478
+	return f.confirmproc
479
+}
480
+
481
+// ParamList returns source code for function f parameters.
482
+func (f *Fn) ParamList() string {
483
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
484
+}
485
+
486
+// HelperParamList returns source code for helper function f parameters.
487
+func (f *Fn) HelperParamList() string {
488
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
489
+}
490
+
491
+// ParamPrintList returns source code of trace printing part correspondent
492
+// to syscall input parameters.
493
+func (f *Fn) ParamPrintList() string {
494
+	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
495
+}
496
+
497
+// ParamCount return number of syscall parameters for function f.
498
+func (f *Fn) ParamCount() int {
499
+	n := 0
500
+	for _, p := range f.Params {
501
+		n += len(p.SyscallArgList())
502
+	}
503
+	return n
504
+}
505
+
506
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
507
+// to use. It returns parameter count for correspondent SyscallX function.
508
+func (f *Fn) SyscallParamCount() int {
509
+	n := f.ParamCount()
510
+	switch {
511
+	case n <= 3:
512
+		return 3
513
+	case n <= 6:
514
+		return 6
515
+	case n <= 9:
516
+		return 9
517
+	case n <= 12:
518
+		return 12
519
+	case n <= 15:
520
+		return 15
521
+	default:
522
+		panic("too many arguments to system call")
523
+	}
524
+}
525
+
526
+// Syscall determines which SyscallX function to use for function f.
527
+func (f *Fn) Syscall() string {
528
+	c := f.SyscallParamCount()
529
+	if c == 3 {
530
+		return syscalldot() + "Syscall"
531
+	}
532
+	return syscalldot() + "Syscall" + strconv.Itoa(c)
533
+}
534
+
535
+// SyscallParamList returns source code for SyscallX parameters for function f.
536
+func (f *Fn) SyscallParamList() string {
537
+	a := make([]string, 0)
538
+	for _, p := range f.Params {
539
+		a = append(a, p.SyscallArgList()...)
540
+	}
541
+	for len(a) < f.SyscallParamCount() {
542
+		a = append(a, "0")
543
+	}
544
+	return strings.Join(a, ", ")
545
+}
546
+
547
+// HelperCallParamList returns source code of call into function f helper.
548
+func (f *Fn) HelperCallParamList() string {
549
+	a := make([]string, 0, len(f.Params))
550
+	for _, p := range f.Params {
551
+		s := p.Name
552
+		if p.Type == "string" {
553
+			s = p.tmpVar()
554
+		}
555
+		a = append(a, s)
556
+	}
557
+	return strings.Join(a, ", ")
558
+}
559
+
560
+// IsUTF16 is true, if f is W (utf16) function. It is false
561
+// for all A (ascii) functions.
562
+func (_ *Fn) IsUTF16() bool {
563
+	return true
564
+}
565
+
566
+// StrconvFunc returns name of Go string to OS string function for f.
567
+func (f *Fn) StrconvFunc() string {
568
+	if f.IsUTF16() {
569
+		return syscalldot() + "UTF16PtrFromString"
570
+	}
571
+	return syscalldot() + "BytePtrFromString"
572
+}
573
+
574
+// StrconvType returns Go type name used for OS string for f.
575
+func (f *Fn) StrconvType() string {
576
+	if f.IsUTF16() {
577
+		return "*uint16"
578
+	}
579
+	return "*byte"
580
+}
581
+
582
+// HasStringParam is true, if f has at least one string parameter.
583
+// Otherwise it is false.
584
+func (f *Fn) HasStringParam() bool {
585
+	for _, p := range f.Params {
586
+		if p.Type == "string" {
587
+			return true
588
+		}
589
+	}
590
+	return false
591
+}
592
+
593
+// HelperName returns name of function f helper.
594
+func (f *Fn) HelperName() string {
595
+	if !f.HasStringParam() {
596
+		return f.Name
597
+	}
598
+	return "_" + f.Name
599
+}
600
+
601
+// Source files and functions.
602
+type Source struct {
603
+	Funcs []*Fn
604
+	Files []string
605
+}
606
+
607
+// ParseFiles parses files listed in fs and extracts all syscall
608
+// functions listed in  sys comments. It returns source files
609
+// and functions collection *Source if successful.
610
+func ParseFiles(fs []string) (*Source, error) {
611
+	src := &Source{
612
+		Funcs: make([]*Fn, 0),
613
+		Files: make([]string, 0),
614
+	}
615
+	for _, file := range fs {
616
+		if err := src.ParseFile(file); err != nil {
617
+			return nil, err
618
+		}
619
+	}
620
+	return src, nil
621
+}
622
+
623
+// DLLs return dll names for a source set src.
624
+func (src *Source) DLLs() []string {
625
+	uniq := make(map[string]bool)
626
+	r := make([]string, 0)
627
+	for _, f := range src.Funcs {
628
+		name := f.DLLName()
629
+		if _, found := uniq[name]; !found {
630
+			uniq[name] = true
631
+			r = append(r, name)
632
+		}
633
+	}
634
+	return r
635
+}
636
+
637
+// ParseFile adds additional file path to a source set src.
638
+func (src *Source) ParseFile(path string) error {
639
+	file, err := os.Open(path)
640
+	if err != nil {
641
+		return err
642
+	}
643
+	defer file.Close()
644
+
645
+	s := bufio.NewScanner(file)
646
+	for s.Scan() {
647
+		t := trim(s.Text())
648
+		if len(t) < 7 {
649
+			continue
650
+		}
651
+		if !strings.HasPrefix(t, "//sys") {
652
+			continue
653
+		}
654
+		t = t[5:]
655
+		if !(t[0] == ' ' || t[0] == '\t') {
656
+			continue
657
+		}
658
+		f, err := newFn(t[1:])
659
+		if err != nil {
660
+			return err
661
+		}
662
+		src.Funcs = append(src.Funcs, f)
663
+	}
664
+	if err := s.Err(); err != nil {
665
+		return err
666
+	}
667
+	src.Files = append(src.Files, path)
668
+
669
+	// get package name
670
+	fset := token.NewFileSet()
671
+	_, err = file.Seek(0, 0)
672
+	if err != nil {
673
+		return err
674
+	}
675
+	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
676
+	if err != nil {
677
+		return err
678
+	}
679
+	packageName = pkg.Name.Name
680
+
681
+	return nil
682
+}
683
+
684
+// Generate output source file from a source set src.
685
+func (src *Source) Generate(w io.Writer) error {
686
+	funcMap := template.FuncMap{
687
+		"packagename": packagename,
688
+		"syscalldot":  syscalldot,
689
+	}
690
+	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
691
+	err := t.Execute(w, src)
692
+	if err != nil {
693
+		return errors.New("Failed to execute template: " + err.Error())
694
+	}
695
+	return nil
696
+}
697
+
698
+func usage() {
699
+	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
700
+	flag.PrintDefaults()
701
+	os.Exit(1)
702
+}
703
+
704
+func main() {
705
+	flag.Usage = usage
706
+	flag.Parse()
707
+	if len(flag.Args()) <= 0 {
708
+		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
709
+		usage()
710
+	}
711
+
712
+	src, err := ParseFiles(flag.Args())
713
+	if err != nil {
714
+		log.Fatal(err)
715
+	}
716
+
717
+	var buf bytes.Buffer
718
+	if err := src.Generate(&buf); err != nil {
719
+		log.Fatal(err)
720
+	}
721
+
722
+	data, err := format.Source(buf.Bytes())
723
+	if err != nil {
724
+		log.Fatal(err)
725
+	}
726
+	if *filename == "" {
727
+		_, err = os.Stdout.Write(data)
728
+	} else {
729
+		err = ioutil.WriteFile(*filename, data, 0644)
730
+	}
731
+	if err != nil {
732
+		log.Fatal(err)
733
+	}
734
+}
735
+
736
+// TODO: use println instead to print in the following template
737
+const srcTemplate = `
738
+
739
+{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
740
+
741
+package {{packagename}}
742
+
743
+import "unsafe"{{if syscalldot}}
744
+import "syscall"{{end}}
745
+
746
+var _ unsafe.Pointer
747
+
748
+var (
749
+{{template "dlls" .}}
750
+{{template "funcnames" .}})
751
+{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
752
+{{end}}
753
+
754
+{{/* help functions */}}
755
+
756
+{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
757
+{{end}}{{end}}
758
+
759
+{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
760
+{{end}}{{end}}
761
+
762
+{{define "helperbody"}}
763
+func {{.Name}}({{.ParamList}}) {{template "results" .}}{
764
+{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
765
+}
766
+{{end}}
767
+
768
+{{define "funcbody"}}
769
+func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
770
+{{template "tmpvars" .}}	{{template "syscallcheck" .}}{{template "syscall" .}}
771
+{{template "seterror" .}}{{template "printtrace" .}}	return
772
+}
773
+{{end}}
774
+
775
+{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
776
+{{end}}{{end}}{{end}}
777
+
778
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
779
+{{end}}{{end}}{{end}}
780
+
781
+{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
782
+
783
+{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
784
+    return
785
+}
786
+{{end}}{{end}}
787
+
788
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
789
+
790
+{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
791
+{{end}}{{end}}
792
+
793
+{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
794
+{{end}}{{end}}
795
+
796
+`
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // NameToGuid converts the given string into a GUID using the algorithm in the
12 6
 // Host Compute Service, ensuring GUIDs generated with the same string are common
... ...
@@ -15,32 +9,9 @@ func NameToGuid(name string) (id GUID, err error) {
15 15
 	title := "hcsshim::NameToGuid "
16 16
 	logrus.Debugf(title+"Name %s", name)
17 17
 
18
-	// Load the DLL and get a handle to the procedure we need
19
-	dll, proc, err := loadAndFind(procNameToGuid)
20
-	if dll != nil {
21
-		defer dll.Release()
22
-	}
23
-	if err != nil {
24
-		return
25
-	}
26
-
27
-	// Convert name to uint16 pointer for calling the procedure
28
-	namep, err := syscall.UTF16PtrFromString(name)
18
+	err = nameToGuid(name, &id)
29 19
 	if err != nil {
30
-		err = fmt.Errorf(title+" - Failed conversion of name %s to pointer %s", name, err)
31
-		logrus.Error(err)
32
-		return
33
-	}
34
-
35
-	// Call the procedure itself.
36
-	logrus.Debugf("Calling proc")
37
-	r1, _, _ := proc.Call(
38
-		uintptr(unsafe.Pointer(namep)),
39
-		uintptr(unsafe.Pointer(&id)))
40
-
41
-	if r1 != 0 {
42
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s name=%s",
43
-			r1, syscall.Errno(r1), name)
20
+		err = makeErrorf(err, title, "name=%s", name)
44 21
 		logrus.Error(err)
45 22
 		return
46 23
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // PrepareLayer finds a mounted read-write layer matching layerId and enables the
12 6
 // the filesystem filter for use on that layer.  This requires the paths to all
... ...
@@ -17,58 +11,22 @@ func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) er
17 17
 	title := "hcsshim::PrepareLayer "
18 18
 	logrus.Debugf(title+"flavour %d layerId %s", info.Flavour, layerId)
19 19
 
20
-	// Load the DLL and get a handle to the procedure we need
21
-	dll, proc, err := loadAndFind(procPrepareLayer)
22
-	if dll != nil {
23
-		defer dll.Release()
24
-	}
25
-	if err != nil {
26
-		return err
27
-	}
28
-
29 20
 	// Generate layer descriptors
30 21
 	layers, err := layerPathsToDescriptors(parentLayerPaths)
31 22
 	if err != nil {
32
-		err = fmt.Errorf(title+"- Failed to generate layer descriptors ", err)
33
-		return err
34
-	}
35
-
36
-	// Convert layerId to uint16 pointer for calling the procedure
37
-	layerIdp, err := syscall.UTF16PtrFromString(layerId)
38
-	if err != nil {
39
-		err = fmt.Errorf(title+"- Failed conversion of layerId %s to pointer %s", layerId, err)
40
-		logrus.Error(err)
41 23
 		return err
42 24
 	}
43 25
 
44 26
 	// Convert info to API calling convention
45 27
 	infop, err := convertDriverInfo(info)
46 28
 	if err != nil {
47
-		err = fmt.Errorf(title+"- Failed conversion info struct %s", err)
48 29
 		logrus.Error(err)
49 30
 		return err
50 31
 	}
51 32
 
52
-	var layerDescriptorsp *WC_LAYER_DESCRIPTOR
53
-	if len(layers) > 0 {
54
-		layerDescriptorsp = &(layers[0])
55
-	} else {
56
-		layerDescriptorsp = nil
57
-	}
58
-
59
-	// Call the procedure itself.
60
-	r1, _, _ := proc.Call(
61
-		uintptr(unsafe.Pointer(&infop)),
62
-		uintptr(unsafe.Pointer(layerIdp)),
63
-		uintptr(unsafe.Pointer(layerDescriptorsp)),
64
-		uintptr(len(layers)))
65
-	use(unsafe.Pointer(&infop))
66
-	use(unsafe.Pointer(layerIdp))
67
-	use(unsafe.Pointer(layerDescriptorsp))
68
-
69
-	if r1 != 0 {
70
-		err = fmt.Errorf(title+"- Win32 API call returned error r1=%d err=%s layerId=%s flavour=%d",
71
-			r1, syscall.Errno(r1), layerId, info.Flavour)
33
+	err = prepareLayer(&infop, layerId, layers)
34
+	if err != nil {
35
+		err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)
72 36
 		logrus.Error(err)
73 37
 		return err
74 38
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // ResizeConsoleInComputeSystem updates the height and width of the console
12 6
 // session for the process with the given id in the container with the given id.
... ...
@@ -15,29 +9,9 @@ func ResizeConsoleInComputeSystem(id string, processid uint32, h, w int) error {
15 15
 	title := "HCSShim::ResizeConsoleInComputeSystem"
16 16
 	logrus.Debugf(title+" id=%s processid=%d (%d,%d)", id, processid, h, w)
17 17
 
18
-	// Load the DLL and get a handle to the procedure we need
19
-	dll, proc, err := loadAndFind(procResizeConsoleInComputeSystem)
20
-	if dll != nil {
21
-		defer dll.Release()
22
-	}
23
-	if err != nil {
24
-		return err
25
-	}
26
-
27
-	// Convert id to uint16 pointer for calling the procedure
28
-	idp, err := syscall.UTF16PtrFromString(id)
18
+	err := resizeConsoleInComputeSystem(id, processid, uint16(h), uint16(w), 0)
29 19
 	if err != nil {
30
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
31
-		logrus.Error(err)
32
-		return err
33
-	}
34
-
35
-	h16 := uint16(h)
36
-	w16 := uint16(w)
37
-
38
-	r1, _, _ := proc.Call(uintptr(unsafe.Pointer(idp)), uintptr(processid), uintptr(h16), uintptr(w16), uintptr(0))
39
-	if r1 != 0 {
40
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s, id=%s pid=%d", r1, syscall.Errno(r1), id, processid)
20
+		err = makeErrorf(err, title, "id=%s pid=%d", id, processid)
41 21
 		logrus.Error(err)
42 22
 		return err
43 23
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // TerminateComputeSystem force terminates a container.
12 6
 func TerminateComputeSystem(id string, timeout uint32, context string) (uint32, error) {
... ...
@@ -24,44 +18,25 @@ func ShutdownComputeSystem(id string, timeout uint32, context string) (uint32, e
24 24
 func shutdownTerminate(shutdown bool, id string, timeout uint32, context string) (uint32, error) {
25 25
 
26 26
 	var (
27
-		title    = "HCSShim::"
28
-		procName string
27
+		title = "HCSShim::"
29 28
 	)
30 29
 	if shutdown {
31 30
 		title = title + "ShutdownComputeSystem"
32
-		procName = procShutdownComputeSystem
33 31
 	} else {
34 32
 		title = title + "TerminateComputeSystem"
35
-		procName = procTerminateComputeSystem
36 33
 	}
37 34
 	logrus.Debugf(title+" id=%s context=%s", id, context)
38 35
 
39
-	// Load the DLL and get a handle to the procedure we need
40
-	dll, proc, err := loadAndFind(procName)
41
-	if dll != nil {
42
-		defer dll.Release()
43
-	}
44
-	if err != nil {
45
-		return 0xffffffff, err
36
+	var err error
37
+	if shutdown {
38
+		err = shutdownComputeSystem(id, timeout)
39
+	} else {
40
+		err = terminateComputeSystem(id)
46 41
 	}
47 42
 
48
-	// Convert id to uint16 pointers for calling the procedure
49
-	idp, err := syscall.UTF16PtrFromString(id)
50 43
 	if err != nil {
51
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
52
-		logrus.Error(err)
53
-		return 0xffffffff, err
54
-	}
55
-
56
-	// Call the procedure itself.
57
-	r1, _, err := proc.Call(
58
-		uintptr(unsafe.Pointer(idp)), uintptr(timeout))
59
-
60
-	use(unsafe.Pointer(idp))
61
-
62
-	if r1 != 0 {
63
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=0x%X err=%s id=%s context=%s", r1, syscall.Errno(r1), id, context)
64
-		return uint32(r1), err
44
+		err := makeErrorf(err, title, "id=%s context=%s", id, context)
45
+		return err.HResult(), err
65 46
 	}
66 47
 
67 48
 	logrus.Debugf(title+" succeeded id=%s context=%s", id, context)
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // StartComputeSystem starts a container that has previously been created via
12 6
 // CreateComputeSystem.
... ...
@@ -15,30 +9,9 @@ func StartComputeSystem(id string) error {
15 15
 	title := "HCSShim::StartComputeSystem"
16 16
 	logrus.Debugf(title+" id=%s", id)
17 17
 
18
-	// Load the DLL and get a handle to the procedure we need
19
-	dll, proc, err := loadAndFind(procStartComputeSystem)
20
-	if dll != nil {
21
-		defer dll.Release()
22
-	}
23
-	if err != nil {
24
-		return err
25
-	}
26
-
27
-	// Convert ID to uint16 pointers for calling the procedure
28
-	idp, err := syscall.UTF16PtrFromString(id)
18
+	err := startComputeSystem(id)
29 19
 	if err != nil {
30
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
31
-		logrus.Error(err)
32
-		return err
33
-	}
34
-
35
-	// Call the procedure itself.
36
-	r1, _, _ := proc.Call(uintptr(unsafe.Pointer(idp)))
37
-
38
-	use(unsafe.Pointer(idp))
39
-
40
-	if r1 != 0 {
41
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s", r1, syscall.Errno(r1), id)
20
+		err = makeErrorf(err, title, "id=%s", id)
42 21
 		logrus.Error(err)
43 22
 		return err
44 23
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // TerminateProcessInComputeSystem kills a process in a running container.
12 6
 func TerminateProcessInComputeSystem(id string, processid uint32) (err error) {
... ...
@@ -14,32 +8,9 @@ func TerminateProcessInComputeSystem(id string, processid uint32) (err error) {
14 14
 	title := "HCSShim::TerminateProcessInComputeSystem"
15 15
 	logrus.Debugf(title+" id=%s processid=%d", id, processid)
16 16
 
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procTerminateProcessInComputeSystem)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return err
24
-	}
25
-
26
-	// Convert ID to uint16 pointer for calling the procedure
27
-	idp, err := syscall.UTF16PtrFromString(id)
17
+	err = terminateProcessInComputeSystem(id, processid)
28 18
 	if err != nil {
29
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
30
-		logrus.Error(err)
31
-		return err
32
-	}
33
-
34
-	// Call the procedure itself.
35
-	r1, _, err := proc.Call(
36
-		uintptr(unsafe.Pointer(idp)),
37
-		uintptr(processid))
38
-
39
-	use(unsafe.Pointer(idp))
40
-
41
-	if r1 != 0 {
42
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s", r1, syscall.Errno(r1), id)
19
+		err = makeErrorf(err, title, "err=%s id=%s", id)
43 20
 		logrus.Error(err)
44 21
 		return err
45 22
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // UnprepareLayer disables the filesystem filter for the read-write layer with
12 6
 // the given id.
... ...
@@ -14,42 +8,16 @@ func UnprepareLayer(info DriverInfo, layerId string) error {
14 14
 	title := "hcsshim::UnprepareLayer "
15 15
 	logrus.Debugf(title+"flavour %d layerId %s", info.Flavour, layerId)
16 16
 
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procUnprepareLayer)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return err
24
-	}
25
-
26
-	// Convert layerId to uint16 pointer for calling the procedure
27
-	layerIdp, err := syscall.UTF16PtrFromString(layerId)
28
-	if err != nil {
29
-		err = fmt.Errorf(title+"- Failed conversion of layerId %s to pointer %s", layerId, err)
30
-		logrus.Error(err)
31
-		return err
32
-	}
33
-
34 17
 	// Convert info to API calling convention
35 18
 	infop, err := convertDriverInfo(info)
36 19
 	if err != nil {
37
-		err = fmt.Errorf(title+"- Failed conversion info struct %s", err)
38 20
 		logrus.Error(err)
39 21
 		return err
40 22
 	}
41 23
 
42
-	// Call the procedure itself.
43
-	r1, _, _ := proc.Call(
44
-		uintptr(unsafe.Pointer(&infop)),
45
-		uintptr(unsafe.Pointer(layerIdp)))
46
-
47
-	use(unsafe.Pointer(&infop))
48
-	use(unsafe.Pointer(layerIdp))
49
-
50
-	if r1 != 0 {
51
-		err = fmt.Errorf(title+"- Win32 API call returned error r1=%d err=%s layerId=%s flavour=%d",
52
-			r1, syscall.Errno(r1), layerId, info.Flavour)
24
+	err = unprepareLayer(&infop, layerId)
25
+	if err != nil {
26
+		err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)
53 27
 		logrus.Error(err)
54 28
 		return err
55 29
 	}
... ...
@@ -1,12 +1,6 @@
1 1
 package hcsshim
2 2
 
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
3
+import "github.com/Sirupsen/logrus"
10 4
 
11 5
 // WaitForProcessInComputeSystem waits for a process ID to terminate and returns
12 6
 // the exit code. Returns exitcode, errno, error
... ...
@@ -15,40 +9,13 @@ func WaitForProcessInComputeSystem(id string, processid uint32, timeout uint32)
15 15
 	title := "HCSShim::WaitForProcessInComputeSystem"
16 16
 	logrus.Debugf(title+" id=%s processid=%d", id, processid)
17 17
 
18
-	// Load the DLL and get a handle to the procedure we need
19
-	dll, proc, err := loadAndFind(procWaitForProcessInComputeSystem)
20
-	if dll != nil {
21
-		defer dll.Release()
22
-	}
23
-	if err != nil {
24
-		return 0, 0, err
25
-	}
26
-
27
-	// Convert id to uint16 pointer for calling the procedure
28
-	idp, err := syscall.UTF16PtrFromString(id)
18
+	var exitCode uint32
19
+	err := waitForProcessInComputeSystem(id, processid, timeout, &exitCode)
29 20
 	if err != nil {
30
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
31
-		logrus.Error(err)
32
-		return 0, 0, err
33
-	}
34
-
35
-	// To get a POINTER to the ExitCode
36
-	ec := new(int32)
37
-
38
-	// Call the procedure itself.
39
-	r1, _, err := proc.Call(
40
-		uintptr(unsafe.Pointer(idp)),
41
-		uintptr(processid),
42
-		uintptr(timeout),
43
-		uintptr(unsafe.Pointer(ec)))
44
-
45
-	use(unsafe.Pointer(idp))
46
-
47
-	if r1 != 0 {
48
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=0x%X err=%s id=%s", r1, syscall.Errno(r1), id)
49
-		return 0, uint32(r1), err
21
+		err := makeErrorf(err, title, "id=%s", id)
22
+		return 0, err.HResult(), err
50 23
 	}
51 24
 
52
-	logrus.Debugf(title+" succeeded id=%s processid=%d exitcode=%d", id, processid, *ec)
53
-	return *ec, 0, nil
25
+	logrus.Debugf(title+" succeeded id=%s processid=%d exitcode=%d", id, processid, exitCode)
26
+	return int32(exitCode), 0, nil
54 27
 }
55 28
new file mode 100644
... ...
@@ -0,0 +1,559 @@
0
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
1
+
2
+package hcsshim
3
+
4
+import "unsafe"
5
+import "syscall"
6
+
7
+var _ unsafe.Pointer
8
+
9
+var (
10
+	modole32     = syscall.NewLazyDLL("ole32.dll")
11
+	modvmcompute = syscall.NewLazyDLL("vmcompute.dll")
12
+
13
+	procCoTaskMemFree                              = modole32.NewProc("CoTaskMemFree")
14
+	procActivateLayer                              = modvmcompute.NewProc("ActivateLayer")
15
+	procCopyLayer                                  = modvmcompute.NewProc("CopyLayer")
16
+	procCreateLayer                                = modvmcompute.NewProc("CreateLayer")
17
+	procCreateSandboxLayer                         = modvmcompute.NewProc("CreateSandboxLayer")
18
+	procDeactivateLayer                            = modvmcompute.NewProc("DeactivateLayer")
19
+	procDestroyLayer                               = modvmcompute.NewProc("DestroyLayer")
20
+	procExportLayer                                = modvmcompute.NewProc("ExportLayer")
21
+	procGetLayerMountPath                          = modvmcompute.NewProc("GetLayerMountPath")
22
+	procGetBaseImages                              = modvmcompute.NewProc("GetBaseImages")
23
+	procImportLayer                                = modvmcompute.NewProc("ImportLayer")
24
+	procLayerExists                                = modvmcompute.NewProc("LayerExists")
25
+	procNameToGuid                                 = modvmcompute.NewProc("NameToGuid")
26
+	procPrepareLayer                               = modvmcompute.NewProc("PrepareLayer")
27
+	procUnprepareLayer                             = modvmcompute.NewProc("UnprepareLayer")
28
+	procCreateComputeSystem                        = modvmcompute.NewProc("CreateComputeSystem")
29
+	procCreateProcessWithStdHandlesInComputeSystem = modvmcompute.NewProc("CreateProcessWithStdHandlesInComputeSystem")
30
+	procResizeConsoleInComputeSystem               = modvmcompute.NewProc("ResizeConsoleInComputeSystem")
31
+	procShutdownComputeSystem                      = modvmcompute.NewProc("ShutdownComputeSystem")
32
+	procStartComputeSystem                         = modvmcompute.NewProc("StartComputeSystem")
33
+	procTerminateComputeSystem                     = modvmcompute.NewProc("TerminateComputeSystem")
34
+	procTerminateProcessInComputeSystem            = modvmcompute.NewProc("TerminateProcessInComputeSystem")
35
+	procWaitForProcessInComputeSystem              = modvmcompute.NewProc("WaitForProcessInComputeSystem")
36
+	procHNSCall                                    = modvmcompute.NewProc("HNSCall")
37
+)
38
+
39
+func coTaskMemFree(buffer unsafe.Pointer) {
40
+	syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(buffer), 0, 0)
41
+	return
42
+}
43
+
44
+func activateLayer(info *driverInfo, id string) (hr error) {
45
+	var _p0 *uint16
46
+	_p0, hr = syscall.UTF16PtrFromString(id)
47
+	if hr != nil {
48
+		return
49
+	}
50
+	return _activateLayer(info, _p0)
51
+}
52
+
53
+func _activateLayer(info *driverInfo, id *uint16) (hr error) {
54
+	if hr = procActivateLayer.Find(); hr != nil {
55
+		return
56
+	}
57
+	r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
58
+	if r0 != 0 {
59
+		hr = syscall.Errno(r0)
60
+	}
61
+	return
62
+}
63
+
64
+func copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
65
+	var _p0 *uint16
66
+	_p0, hr = syscall.UTF16PtrFromString(srcId)
67
+	if hr != nil {
68
+		return
69
+	}
70
+	var _p1 *uint16
71
+	_p1, hr = syscall.UTF16PtrFromString(dstId)
72
+	if hr != nil {
73
+		return
74
+	}
75
+	return _copyLayer(info, _p0, _p1, descriptors)
76
+}
77
+
78
+func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
79
+	var _p2 *WC_LAYER_DESCRIPTOR
80
+	if len(descriptors) > 0 {
81
+		_p2 = &descriptors[0]
82
+	}
83
+	if hr = procCopyLayer.Find(); hr != nil {
84
+		return
85
+	}
86
+	r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
87
+	if r0 != 0 {
88
+		hr = syscall.Errno(r0)
89
+	}
90
+	return
91
+}
92
+
93
+func createLayer(info *driverInfo, id string, parent string) (hr error) {
94
+	var _p0 *uint16
95
+	_p0, hr = syscall.UTF16PtrFromString(id)
96
+	if hr != nil {
97
+		return
98
+	}
99
+	var _p1 *uint16
100
+	_p1, hr = syscall.UTF16PtrFromString(parent)
101
+	if hr != nil {
102
+		return
103
+	}
104
+	return _createLayer(info, _p0, _p1)
105
+}
106
+
107
+func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
108
+	if hr = procCreateLayer.Find(); hr != nil {
109
+		return
110
+	}
111
+	r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
112
+	if r0 != 0 {
113
+		hr = syscall.Errno(r0)
114
+	}
115
+	return
116
+}
117
+
118
+func createSandboxLayer(info *driverInfo, id string, parent string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
119
+	var _p0 *uint16
120
+	_p0, hr = syscall.UTF16PtrFromString(id)
121
+	if hr != nil {
122
+		return
123
+	}
124
+	var _p1 *uint16
125
+	_p1, hr = syscall.UTF16PtrFromString(parent)
126
+	if hr != nil {
127
+		return
128
+	}
129
+	return _createSandboxLayer(info, _p0, _p1, descriptors)
130
+}
131
+
132
+func _createSandboxLayer(info *driverInfo, id *uint16, parent *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
133
+	var _p2 *WC_LAYER_DESCRIPTOR
134
+	if len(descriptors) > 0 {
135
+		_p2 = &descriptors[0]
136
+	}
137
+	if hr = procCreateSandboxLayer.Find(); hr != nil {
138
+		return
139
+	}
140
+	r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
141
+	if r0 != 0 {
142
+		hr = syscall.Errno(r0)
143
+	}
144
+	return
145
+}
146
+
147
+func deactivateLayer(info *driverInfo, id string) (hr error) {
148
+	var _p0 *uint16
149
+	_p0, hr = syscall.UTF16PtrFromString(id)
150
+	if hr != nil {
151
+		return
152
+	}
153
+	return _deactivateLayer(info, _p0)
154
+}
155
+
156
+func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
157
+	if hr = procDeactivateLayer.Find(); hr != nil {
158
+		return
159
+	}
160
+	r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
161
+	if r0 != 0 {
162
+		hr = syscall.Errno(r0)
163
+	}
164
+	return
165
+}
166
+
167
+func destroyLayer(info *driverInfo, id string) (hr error) {
168
+	var _p0 *uint16
169
+	_p0, hr = syscall.UTF16PtrFromString(id)
170
+	if hr != nil {
171
+		return
172
+	}
173
+	return _destroyLayer(info, _p0)
174
+}
175
+
176
+func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
177
+	if hr = procDestroyLayer.Find(); hr != nil {
178
+		return
179
+	}
180
+	r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
181
+	if r0 != 0 {
182
+		hr = syscall.Errno(r0)
183
+	}
184
+	return
185
+}
186
+
187
+func exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
188
+	var _p0 *uint16
189
+	_p0, hr = syscall.UTF16PtrFromString(id)
190
+	if hr != nil {
191
+		return
192
+	}
193
+	var _p1 *uint16
194
+	_p1, hr = syscall.UTF16PtrFromString(path)
195
+	if hr != nil {
196
+		return
197
+	}
198
+	return _exportLayer(info, _p0, _p1, descriptors)
199
+}
200
+
201
+func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
202
+	var _p2 *WC_LAYER_DESCRIPTOR
203
+	if len(descriptors) > 0 {
204
+		_p2 = &descriptors[0]
205
+	}
206
+	if hr = procExportLayer.Find(); hr != nil {
207
+		return
208
+	}
209
+	r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
210
+	if r0 != 0 {
211
+		hr = syscall.Errno(r0)
212
+	}
213
+	return
214
+}
215
+
216
+func getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) {
217
+	var _p0 *uint16
218
+	_p0, hr = syscall.UTF16PtrFromString(id)
219
+	if hr != nil {
220
+		return
221
+	}
222
+	return _getLayerMountPath(info, _p0, length, buffer)
223
+}
224
+
225
+func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *uint16) (hr error) {
226
+	if hr = procGetLayerMountPath.Find(); hr != nil {
227
+		return
228
+	}
229
+	r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0)
230
+	if r0 != 0 {
231
+		hr = syscall.Errno(r0)
232
+	}
233
+	return
234
+}
235
+
236
+func getBaseImages(buffer **uint16) (hr error) {
237
+	if hr = procGetBaseImages.Find(); hr != nil {
238
+		return
239
+	}
240
+	r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0)
241
+	if r0 != 0 {
242
+		hr = syscall.Errno(r0)
243
+	}
244
+	return
245
+}
246
+
247
+func importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
248
+	var _p0 *uint16
249
+	_p0, hr = syscall.UTF16PtrFromString(id)
250
+	if hr != nil {
251
+		return
252
+	}
253
+	var _p1 *uint16
254
+	_p1, hr = syscall.UTF16PtrFromString(path)
255
+	if hr != nil {
256
+		return
257
+	}
258
+	return _importLayer(info, _p0, _p1, descriptors)
259
+}
260
+
261
+func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
262
+	var _p2 *WC_LAYER_DESCRIPTOR
263
+	if len(descriptors) > 0 {
264
+		_p2 = &descriptors[0]
265
+	}
266
+	if hr = procImportLayer.Find(); hr != nil {
267
+		return
268
+	}
269
+	r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
270
+	if r0 != 0 {
271
+		hr = syscall.Errno(r0)
272
+	}
273
+	return
274
+}
275
+
276
+func layerExists(info *driverInfo, id string, exists *uint32) (hr error) {
277
+	var _p0 *uint16
278
+	_p0, hr = syscall.UTF16PtrFromString(id)
279
+	if hr != nil {
280
+		return
281
+	}
282
+	return _layerExists(info, _p0, exists)
283
+}
284
+
285
+func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
286
+	if hr = procLayerExists.Find(); hr != nil {
287
+		return
288
+	}
289
+	r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
290
+	if r0 != 0 {
291
+		hr = syscall.Errno(r0)
292
+	}
293
+	return
294
+}
295
+
296
+func nameToGuid(name string, guid *GUID) (hr error) {
297
+	var _p0 *uint16
298
+	_p0, hr = syscall.UTF16PtrFromString(name)
299
+	if hr != nil {
300
+		return
301
+	}
302
+	return _nameToGuid(_p0, guid)
303
+}
304
+
305
+func _nameToGuid(name *uint16, guid *GUID) (hr error) {
306
+	if hr = procNameToGuid.Find(); hr != nil {
307
+		return
308
+	}
309
+	r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0)
310
+	if r0 != 0 {
311
+		hr = syscall.Errno(r0)
312
+	}
313
+	return
314
+}
315
+
316
+func prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
317
+	var _p0 *uint16
318
+	_p0, hr = syscall.UTF16PtrFromString(id)
319
+	if hr != nil {
320
+		return
321
+	}
322
+	return _prepareLayer(info, _p0, descriptors)
323
+}
324
+
325
+func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
326
+	var _p1 *WC_LAYER_DESCRIPTOR
327
+	if len(descriptors) > 0 {
328
+		_p1 = &descriptors[0]
329
+	}
330
+	if hr = procPrepareLayer.Find(); hr != nil {
331
+		return
332
+	}
333
+	r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0)
334
+	if r0 != 0 {
335
+		hr = syscall.Errno(r0)
336
+	}
337
+	return
338
+}
339
+
340
+func unprepareLayer(info *driverInfo, id string) (hr error) {
341
+	var _p0 *uint16
342
+	_p0, hr = syscall.UTF16PtrFromString(id)
343
+	if hr != nil {
344
+		return
345
+	}
346
+	return _unprepareLayer(info, _p0)
347
+}
348
+
349
+func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
350
+	if hr = procUnprepareLayer.Find(); hr != nil {
351
+		return
352
+	}
353
+	r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
354
+	if r0 != 0 {
355
+		hr = syscall.Errno(r0)
356
+	}
357
+	return
358
+}
359
+
360
+func createComputeSystem(id string, configuration string) (hr error) {
361
+	var _p0 *uint16
362
+	_p0, hr = syscall.UTF16PtrFromString(id)
363
+	if hr != nil {
364
+		return
365
+	}
366
+	var _p1 *uint16
367
+	_p1, hr = syscall.UTF16PtrFromString(configuration)
368
+	if hr != nil {
369
+		return
370
+	}
371
+	return _createComputeSystem(_p0, _p1)
372
+}
373
+
374
+func _createComputeSystem(id *uint16, configuration *uint16) (hr error) {
375
+	if hr = procCreateComputeSystem.Find(); hr != nil {
376
+		return
377
+	}
378
+	r0, _, _ := syscall.Syscall(procCreateComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), 0)
379
+	if r0 != 0 {
380
+		hr = syscall.Errno(r0)
381
+	}
382
+	return
383
+}
384
+
385
+func createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) {
386
+	var _p0 *uint16
387
+	_p0, hr = syscall.UTF16PtrFromString(id)
388
+	if hr != nil {
389
+		return
390
+	}
391
+	var _p1 *uint16
392
+	_p1, hr = syscall.UTF16PtrFromString(paramsJson)
393
+	if hr != nil {
394
+		return
395
+	}
396
+	return _createProcessWithStdHandlesInComputeSystem(_p0, _p1, pid, stdin, stdout, stderr)
397
+}
398
+
399
+func _createProcessWithStdHandlesInComputeSystem(id *uint16, paramsJson *uint16, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) {
400
+	if hr = procCreateProcessWithStdHandlesInComputeSystem.Find(); hr != nil {
401
+		return
402
+	}
403
+	r0, _, _ := syscall.Syscall6(procCreateProcessWithStdHandlesInComputeSystem.Addr(), 6, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(paramsJson)), uintptr(unsafe.Pointer(pid)), uintptr(unsafe.Pointer(stdin)), uintptr(unsafe.Pointer(stdout)), uintptr(unsafe.Pointer(stderr)))
404
+	if r0 != 0 {
405
+		hr = syscall.Errno(r0)
406
+	}
407
+	return
408
+}
409
+
410
+func resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) {
411
+	var _p0 *uint16
412
+	_p0, hr = syscall.UTF16PtrFromString(id)
413
+	if hr != nil {
414
+		return
415
+	}
416
+	return _resizeConsoleInComputeSystem(_p0, pid, height, width, flags)
417
+}
418
+
419
+func _resizeConsoleInComputeSystem(id *uint16, pid uint32, height uint16, width uint16, flags uint32) (hr error) {
420
+	if hr = procResizeConsoleInComputeSystem.Find(); hr != nil {
421
+		return
422
+	}
423
+	r0, _, _ := syscall.Syscall6(procResizeConsoleInComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(height), uintptr(width), uintptr(flags), 0)
424
+	if r0 != 0 {
425
+		hr = syscall.Errno(r0)
426
+	}
427
+	return
428
+}
429
+
430
+func shutdownComputeSystem(id string, timeout uint32) (hr error) {
431
+	var _p0 *uint16
432
+	_p0, hr = syscall.UTF16PtrFromString(id)
433
+	if hr != nil {
434
+		return
435
+	}
436
+	return _shutdownComputeSystem(_p0, timeout)
437
+}
438
+
439
+func _shutdownComputeSystem(id *uint16, timeout uint32) (hr error) {
440
+	if hr = procShutdownComputeSystem.Find(); hr != nil {
441
+		return
442
+	}
443
+	r0, _, _ := syscall.Syscall(procShutdownComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(timeout), 0)
444
+	if r0 != 0 {
445
+		hr = syscall.Errno(r0)
446
+	}
447
+	return
448
+}
449
+
450
+func startComputeSystem(id string) (hr error) {
451
+	var _p0 *uint16
452
+	_p0, hr = syscall.UTF16PtrFromString(id)
453
+	if hr != nil {
454
+		return
455
+	}
456
+	return _startComputeSystem(_p0)
457
+}
458
+
459
+func _startComputeSystem(id *uint16) (hr error) {
460
+	if hr = procStartComputeSystem.Find(); hr != nil {
461
+		return
462
+	}
463
+	r0, _, _ := syscall.Syscall(procStartComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
464
+	if r0 != 0 {
465
+		hr = syscall.Errno(r0)
466
+	}
467
+	return
468
+}
469
+
470
+func terminateComputeSystem(id string) (hr error) {
471
+	var _p0 *uint16
472
+	_p0, hr = syscall.UTF16PtrFromString(id)
473
+	if hr != nil {
474
+		return
475
+	}
476
+	return _terminateComputeSystem(_p0)
477
+}
478
+
479
+func _terminateComputeSystem(id *uint16) (hr error) {
480
+	if hr = procTerminateComputeSystem.Find(); hr != nil {
481
+		return
482
+	}
483
+	r0, _, _ := syscall.Syscall(procTerminateComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
484
+	if r0 != 0 {
485
+		hr = syscall.Errno(r0)
486
+	}
487
+	return
488
+}
489
+
490
+func terminateProcessInComputeSystem(id string, pid uint32) (hr error) {
491
+	var _p0 *uint16
492
+	_p0, hr = syscall.UTF16PtrFromString(id)
493
+	if hr != nil {
494
+		return
495
+	}
496
+	return _terminateProcessInComputeSystem(_p0, pid)
497
+}
498
+
499
+func _terminateProcessInComputeSystem(id *uint16, pid uint32) (hr error) {
500
+	if hr = procTerminateProcessInComputeSystem.Find(); hr != nil {
501
+		return
502
+	}
503
+	r0, _, _ := syscall.Syscall(procTerminateProcessInComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(pid), 0)
504
+	if r0 != 0 {
505
+		hr = syscall.Errno(r0)
506
+	}
507
+	return
508
+}
509
+
510
+func waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) {
511
+	var _p0 *uint16
512
+	_p0, hr = syscall.UTF16PtrFromString(id)
513
+	if hr != nil {
514
+		return
515
+	}
516
+	return _waitForProcessInComputeSystem(_p0, pid, timeout, exitCode)
517
+}
518
+
519
+func _waitForProcessInComputeSystem(id *uint16, pid uint32, timeout uint32, exitCode *uint32) (hr error) {
520
+	if hr = procWaitForProcessInComputeSystem.Find(); hr != nil {
521
+		return
522
+	}
523
+	r0, _, _ := syscall.Syscall6(procWaitForProcessInComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(timeout), uintptr(unsafe.Pointer(exitCode)), 0, 0)
524
+	if r0 != 0 {
525
+		hr = syscall.Errno(r0)
526
+	}
527
+	return
528
+}
529
+
530
+func _hnsCall(method string, path string, object string, response **uint16) (hr error) {
531
+	var _p0 *uint16
532
+	_p0, hr = syscall.UTF16PtrFromString(method)
533
+	if hr != nil {
534
+		return
535
+	}
536
+	var _p1 *uint16
537
+	_p1, hr = syscall.UTF16PtrFromString(path)
538
+	if hr != nil {
539
+		return
540
+	}
541
+	var _p2 *uint16
542
+	_p2, hr = syscall.UTF16PtrFromString(object)
543
+	if hr != nil {
544
+		return
545
+	}
546
+	return __hnsCall(_p0, _p1, _p2, response)
547
+}
548
+
549
+func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) (hr error) {
550
+	if hr = procHNSCall.Find(); hr != nil {
551
+		return
552
+	}
553
+	r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
554
+	if r0 != 0 {
555
+		hr = syscall.Errno(r0)
556
+	}
557
+	return
558
+}