Browse code

Bump hcsshim to get some fixes.

This also requires bumping winio.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2021/04/08 07:45:33
Showing 85 changed files
... ...
@@ -1,6 +1,6 @@
1 1
 github.com/Azure/go-ansiterm                        d6e3b3328b783f23731bc4d058875b0371ff8109
2
-github.com/Microsoft/hcsshim                        380508768ed2619a4777f268c6443017bb76b04e # v0.8.10
3
-github.com/Microsoft/go-winio                       5b44b70ab3ab4d291a7c1d28afe7b4afeced0ed4 # v0.4.15
2
+github.com/Microsoft/hcsshim                        e811ee705ec77df2ae28857ade553043fb564d91 # v0.8.16
3
+github.com/Microsoft/go-winio                       d1ffc52c73318019ce58aaa5282588c52df029b7 # v0.4.16
4 4
 github.com/docker/libtrust                          9cbd2a1374f46905c68a4eb3694a130610adc62a
5 5
 github.com/golang/gddo                              72a348e765d293ed6d1ded7b699591f14d6cd921
6 6
 github.com/google/uuid                              0cd6bf5da1e1c83f8b45653022c74f71af0538a4 # v1.1.1
... ...
@@ -3,7 +3,7 @@ module github.com/Microsoft/go-winio
3 3
 go 1.12
4 4
 
5 5
 require (
6
-	github.com/pkg/errors v0.8.1
6
+	github.com/pkg/errors v0.9.1
7 7
 	github.com/sirupsen/logrus v1.4.1
8 8
 	golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3
9 9
 )
... ...
@@ -429,10 +429,10 @@ type PipeConfig struct {
429 429
 	// when the pipe is in message mode.
430 430
 	MessageMode bool
431 431
 
432
-	// InputBufferSize specifies the size the input buffer, in bytes.
432
+	// InputBufferSize specifies the size of the input buffer, in bytes.
433 433
 	InputBufferSize int32
434 434
 
435
-	// OutputBufferSize specifies the size the input buffer, in bytes.
435
+	// OutputBufferSize specifies the size of the output buffer, in bytes.
436 436
 	OutputBufferSize int32
437 437
 }
438 438
 
... ...
@@ -2,150 +2,323 @@
2 2
 
3 3
 package vhd
4 4
 
5
-import "syscall"
5
+import (
6
+	"fmt"
7
+	"syscall"
8
+
9
+	"github.com/Microsoft/go-winio/pkg/guid"
10
+	"github.com/pkg/errors"
11
+	"golang.org/x/sys/windows"
12
+)
6 13
 
7 14
 //go:generate go run mksyscall_windows.go -output zvhd.go vhd.go
8 15
 
9
-//sys createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.CreateVirtualDisk
10
-//sys openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.OpenVirtualDisk
11
-//sys detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = VirtDisk.DetachVirtualDisk
12
-
13
-type virtualStorageType struct {
14
-	DeviceID uint32
15
-	VendorID [16]byte
16
-}
16
+//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk
17
+//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk
18
+//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk
19
+//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = virtdisk.DetachVirtualDisk
20
+//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) [failretval != 0] = virtdisk.GetVirtualDiskPhysicalPath
17 21
 
18 22
 type (
19
-	createVirtualDiskFlag uint32
20
-	VirtualDiskAccessMask uint32
23
+	CreateVirtualDiskFlag uint32
21 24
 	VirtualDiskFlag       uint32
25
+	AttachVirtualDiskFlag uint32
26
+	DetachVirtualDiskFlag uint32
27
+	VirtualDiskAccessMask uint32
22 28
 )
23 29
 
24
-const (
25
-	// Flags for creating a VHD (not exported)
26
-	createVirtualDiskFlagNone                        createVirtualDiskFlag = 0
27
-	createVirtualDiskFlagFullPhysicalAllocation      createVirtualDiskFlag = 1
28
-	createVirtualDiskFlagPreventWritesToSourceDisk   createVirtualDiskFlag = 2
29
-	createVirtualDiskFlagDoNotCopyMetadataFromParent createVirtualDiskFlag = 4
30
-
31
-	// Access Mask for opening a VHD
32
-	VirtualDiskAccessNone     VirtualDiskAccessMask = 0
33
-	VirtualDiskAccessAttachRO VirtualDiskAccessMask = 65536
34
-	VirtualDiskAccessAttachRW VirtualDiskAccessMask = 131072
35
-	VirtualDiskAccessDetach   VirtualDiskAccessMask = 262144
36
-	VirtualDiskAccessGetInfo  VirtualDiskAccessMask = 524288
37
-	VirtualDiskAccessCreate   VirtualDiskAccessMask = 1048576
38
-	VirtualDiskAccessMetaOps  VirtualDiskAccessMask = 2097152
39
-	VirtualDiskAccessRead     VirtualDiskAccessMask = 851968
40
-	VirtualDiskAccessAll      VirtualDiskAccessMask = 4128768
41
-	VirtualDiskAccessWritable VirtualDiskAccessMask = 3276800
42
-
43
-	// Flags for opening a VHD
44
-	OpenVirtualDiskFlagNone                        VirtualDiskFlag = 0
45
-	OpenVirtualDiskFlagNoParents                   VirtualDiskFlag = 0x1
46
-	OpenVirtualDiskFlagBlankFile                   VirtualDiskFlag = 0x2
47
-	OpenVirtualDiskFlagBootDrive                   VirtualDiskFlag = 0x4
48
-	OpenVirtualDiskFlagCachedIO                    VirtualDiskFlag = 0x8
49
-	OpenVirtualDiskFlagCustomDiffChain             VirtualDiskFlag = 0x10
50
-	OpenVirtualDiskFlagParentCachedIO              VirtualDiskFlag = 0x20
51
-	OpenVirtualDiskFlagVhdSetFileOnly              VirtualDiskFlag = 0x40
52
-	OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x80
53
-	OpenVirtualDiskFlagNoWriteHardening            VirtualDiskFlag = 0x100
54
-)
30
+type VirtualStorageType struct {
31
+	DeviceID uint32
32
+	VendorID guid.GUID
33
+}
55 34
 
56
-type createVersion2 struct {
57
-	UniqueID                 [16]byte // GUID
35
+type CreateVersion2 struct {
36
+	UniqueID                 guid.GUID
58 37
 	MaximumSize              uint64
59 38
 	BlockSizeInBytes         uint32
60 39
 	SectorSizeInBytes        uint32
40
+	PhysicalSectorSizeInByte uint32
61 41
 	ParentPath               *uint16 // string
62 42
 	SourcePath               *uint16 // string
63 43
 	OpenFlags                uint32
64
-	ParentVirtualStorageType virtualStorageType
65
-	SourceVirtualStorageType virtualStorageType
66
-	ResiliencyGUID           [16]byte // GUID
44
+	ParentVirtualStorageType VirtualStorageType
45
+	SourceVirtualStorageType VirtualStorageType
46
+	ResiliencyGUID           guid.GUID
67 47
 }
68 48
 
69
-type createVirtualDiskParameters struct {
49
+type CreateVirtualDiskParameters struct {
70 50
 	Version  uint32 // Must always be set to 2
71
-	Version2 createVersion2
51
+	Version2 CreateVersion2
72 52
 }
73 53
 
74
-type openVersion2 struct {
75
-	GetInfoOnly    int32    // bool but 4-byte aligned
76
-	ReadOnly       int32    // bool but 4-byte aligned
77
-	ResiliencyGUID [16]byte // GUID
54
+type OpenVersion2 struct {
55
+	GetInfoOnly    bool
56
+	ReadOnly       bool
57
+	ResiliencyGUID guid.GUID
78 58
 }
79 59
 
80
-type openVirtualDiskParameters struct {
60
+type OpenVirtualDiskParameters struct {
81 61
 	Version  uint32 // Must always be set to 2
82
-	Version2 openVersion2
62
+	Version2 OpenVersion2
83 63
 }
84 64
 
85
-// CreateVhdx will create a simple vhdx file at the given path using default values.
86
-func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
87
-	var (
88
-		defaultType virtualStorageType
89
-		handle      syscall.Handle
90
-	)
65
+type AttachVersion2 struct {
66
+	RestrictedOffset uint64
67
+	RestrictedLength uint64
68
+}
69
+
70
+type AttachVirtualDiskParameters struct {
71
+	Version  uint32 // Must always be set to 2
72
+	Version2 AttachVersion2
73
+}
74
+
75
+const (
76
+	VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
77
+
78
+	// Access Mask for opening a VHD
79
+	VirtualDiskAccessNone     VirtualDiskAccessMask = 0x00000000
80
+	VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
81
+	VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
82
+	VirtualDiskAccessDetach   VirtualDiskAccessMask = 0x00040000
83
+	VirtualDiskAccessGetInfo  VirtualDiskAccessMask = 0x00080000
84
+	VirtualDiskAccessCreate   VirtualDiskAccessMask = 0x00100000
85
+	VirtualDiskAccessMetaOps  VirtualDiskAccessMask = 0x00200000
86
+	VirtualDiskAccessRead     VirtualDiskAccessMask = 0x000d0000
87
+	VirtualDiskAccessAll      VirtualDiskAccessMask = 0x003f0000
88
+	VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
91 89
 
92
-	parameters := createVirtualDiskParameters{
90
+	// Flags for creating a VHD
91
+	CreateVirtualDiskFlagNone                              CreateVirtualDiskFlag = 0x0
92
+	CreateVirtualDiskFlagFullPhysicalAllocation            CreateVirtualDiskFlag = 0x1
93
+	CreateVirtualDiskFlagPreventWritesToSourceDisk         CreateVirtualDiskFlag = 0x2
94
+	CreateVirtualDiskFlagDoNotCopyMetadataFromParent       CreateVirtualDiskFlag = 0x4
95
+	CreateVirtualDiskFlagCreateBackingStorage              CreateVirtualDiskFlag = 0x8
96
+	CreateVirtualDiskFlagUseChangeTrackingSourceLimit      CreateVirtualDiskFlag = 0x10
97
+	CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
98
+	CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage   CreateVirtualDiskFlag = 0x40
99
+	CreateVirtualDiskFlagSparseFile                        CreateVirtualDiskFlag = 0x80
100
+	CreateVirtualDiskFlagPmemCompatible                    CreateVirtualDiskFlag = 0x100
101
+	CreateVirtualDiskFlagSupportCompressedVolumes          CreateVirtualDiskFlag = 0x200
102
+
103
+	// Flags for opening a VHD
104
+	OpenVirtualDiskFlagNone                        VirtualDiskFlag = 0x00000000
105
+	OpenVirtualDiskFlagNoParents                   VirtualDiskFlag = 0x00000001
106
+	OpenVirtualDiskFlagBlankFile                   VirtualDiskFlag = 0x00000002
107
+	OpenVirtualDiskFlagBootDrive                   VirtualDiskFlag = 0x00000004
108
+	OpenVirtualDiskFlagCachedIO                    VirtualDiskFlag = 0x00000008
109
+	OpenVirtualDiskFlagCustomDiffChain             VirtualDiskFlag = 0x00000010
110
+	OpenVirtualDiskFlagParentCachedIO              VirtualDiskFlag = 0x00000020
111
+	OpenVirtualDiskFlagVhdsetFileOnly              VirtualDiskFlag = 0x00000040
112
+	OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x00000080
113
+	OpenVirtualDiskFlagNoWriteHardening            VirtualDiskFlag = 0x00000100
114
+	OpenVirtualDiskFlagSupportCompressedVolumes    VirtualDiskFlag = 0x00000200
115
+
116
+	// Flags for attaching a VHD
117
+	AttachVirtualDiskFlagNone                          AttachVirtualDiskFlag = 0x00000000
118
+	AttachVirtualDiskFlagReadOnly                      AttachVirtualDiskFlag = 0x00000001
119
+	AttachVirtualDiskFlagNoDriveLetter                 AttachVirtualDiskFlag = 0x00000002
120
+	AttachVirtualDiskFlagPermanentLifetime             AttachVirtualDiskFlag = 0x00000004
121
+	AttachVirtualDiskFlagNoLocalHost                   AttachVirtualDiskFlag = 0x00000008
122
+	AttachVirtualDiskFlagNoSecurityDescriptor          AttachVirtualDiskFlag = 0x00000010
123
+	AttachVirtualDiskFlagBypassDefaultEncryptionPolicy AttachVirtualDiskFlag = 0x00000020
124
+	AttachVirtualDiskFlagNonPnp                        AttachVirtualDiskFlag = 0x00000040
125
+	AttachVirtualDiskFlagRestrictedRange               AttachVirtualDiskFlag = 0x00000080
126
+	AttachVirtualDiskFlagSinglePartition               AttachVirtualDiskFlag = 0x00000100
127
+	AttachVirtualDiskFlagRegisterVolume                AttachVirtualDiskFlag = 0x00000200
128
+
129
+	// Flags for detaching a VHD
130
+	DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
131
+)
132
+
133
+// CreateVhdx is a helper function to create a simple vhdx file at the given path using
134
+// default values.
135
+func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
136
+	params := CreateVirtualDiskParameters{
93 137
 		Version: 2,
94
-		Version2: createVersion2{
138
+		Version2: CreateVersion2{
95 139
 			MaximumSize:      uint64(maxSizeInGb) * 1024 * 1024 * 1024,
96 140
 			BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
97 141
 		},
98 142
 	}
99 143
 
100
-	if err := createVirtualDisk(
101
-		&defaultType,
102
-		path,
103
-		uint32(VirtualDiskAccessNone),
104
-		nil,
105
-		uint32(createVirtualDiskFlagNone),
106
-		0,
107
-		&parameters,
108
-		nil,
109
-		&handle); err != nil {
144
+	handle, err := CreateVirtualDisk(path, VirtualDiskAccessNone, CreateVirtualDiskFlagNone, &params)
145
+	if err != nil {
110 146
 		return err
111 147
 	}
112 148
 
113 149
 	if err := syscall.CloseHandle(handle); err != nil {
114 150
 		return err
115 151
 	}
152
+	return nil
153
+}
116 154
 
155
+// DetachVirtualDisk detaches a virtual hard disk by handle.
156
+func DetachVirtualDisk(handle syscall.Handle) (err error) {
157
+	if err := detachVirtualDisk(handle, 0, 0); err != nil {
158
+		return errors.Wrap(err, "failed to detach virtual disk")
159
+	}
117 160
 	return nil
118 161
 }
119 162
 
120
-// DetachVhd detaches a mounted container layer vhd found at `path`.
163
+// DetachVhd detaches a vhd found at `path`.
121 164
 func DetachVhd(path string) error {
122 165
 	handle, err := OpenVirtualDisk(
123 166
 		path,
124 167
 		VirtualDiskAccessNone,
125
-		OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator)
168
+		OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
169
+	)
170
+	if err != nil {
171
+		return err
172
+	}
173
+	defer syscall.CloseHandle(handle)
174
+	return DetachVirtualDisk(handle)
175
+}
176
+
177
+// AttachVirtualDisk attaches a virtual hard disk for use.
178
+func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtualDiskFlag, parameters *AttachVirtualDiskParameters) (err error) {
179
+	if parameters.Version != 2 {
180
+		return fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
181
+	}
182
+	if err := attachVirtualDisk(
183
+		handle,
184
+		nil,
185
+		uint32(attachVirtualDiskFlag),
186
+		0,
187
+		parameters,
188
+		nil,
189
+	); err != nil {
190
+		return errors.Wrap(err, "failed to attach virtual disk")
191
+	}
192
+	return nil
193
+}
126 194
 
195
+// AttachVhd attaches a virtual hard disk at `path` for use.
196
+func AttachVhd(path string) (err error) {
197
+	handle, err := OpenVirtualDisk(
198
+		path,
199
+		VirtualDiskAccessNone,
200
+		OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
201
+	)
127 202
 	if err != nil {
128 203
 		return err
129 204
 	}
205
+
130 206
 	defer syscall.CloseHandle(handle)
131
-	return detachVirtualDisk(handle, 0, 0)
207
+	params := AttachVirtualDiskParameters{Version: 2}
208
+	if err := AttachVirtualDisk(
209
+		handle,
210
+		AttachVirtualDiskFlagNone,
211
+		&params,
212
+	); err != nil {
213
+		return errors.Wrap(err, "failed to attach virtual disk")
214
+	}
215
+	return nil
132 216
 }
133 217
 
134 218
 // OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
135
-func OpenVirtualDisk(path string, accessMask VirtualDiskAccessMask, flag VirtualDiskFlag) (syscall.Handle, error) {
219
+func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag) (syscall.Handle, error) {
220
+	parameters := OpenVirtualDiskParameters{Version: 2}
221
+	handle, err := OpenVirtualDiskWithParameters(
222
+		vhdPath,
223
+		virtualDiskAccessMask,
224
+		openVirtualDiskFlags,
225
+		&parameters,
226
+	)
227
+	if err != nil {
228
+		return 0, err
229
+	}
230
+	return handle, nil
231
+}
232
+
233
+// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
234
+func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag, parameters *OpenVirtualDiskParameters) (syscall.Handle, error) {
136 235
 	var (
137
-		defaultType virtualStorageType
138 236
 		handle      syscall.Handle
237
+		defaultType VirtualStorageType
139 238
 	)
140
-	parameters := openVirtualDiskParameters{Version: 2}
239
+	if parameters.Version != 2 {
240
+		return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
241
+	}
141 242
 	if err := openVirtualDisk(
142 243
 		&defaultType,
244
+		vhdPath,
245
+		uint32(virtualDiskAccessMask),
246
+		uint32(openVirtualDiskFlags),
247
+		parameters,
248
+		&handle,
249
+	); err != nil {
250
+		return 0, errors.Wrap(err, "failed to open virtual disk")
251
+	}
252
+	return handle, nil
253
+}
254
+
255
+// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
256
+func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask, createVirtualDiskFlags CreateVirtualDiskFlag, parameters *CreateVirtualDiskParameters) (syscall.Handle, error) {
257
+	var (
258
+		handle      syscall.Handle
259
+		defaultType VirtualStorageType
260
+	)
261
+	if parameters.Version != 2 {
262
+		return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
263
+	}
264
+
265
+	if err := createVirtualDisk(
266
+		&defaultType,
143 267
 		path,
144
-		uint32(accessMask),
145
-		uint32(flag),
146
-		&parameters,
147
-		&handle); err != nil {
148
-		return 0, err
268
+		uint32(virtualDiskAccessMask),
269
+		nil,
270
+		uint32(createVirtualDiskFlags),
271
+		0,
272
+		parameters,
273
+		nil,
274
+		&handle,
275
+	); err != nil {
276
+		return handle, errors.Wrap(err, "failed to create virtual disk")
149 277
 	}
150 278
 	return handle, nil
151 279
 }
280
+
281
+// GetVirtualDiskPhysicalPath takes a handle to a virtual hard disk and returns the physical
282
+// path of the disk on the machine. This path is in the form \\.\PhysicalDriveX where X is an integer
283
+// that represents the particular enumeration of the physical disk on the caller's system.
284
+func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
285
+	var (
286
+		diskPathSizeInBytes uint32 = 256 * 2 // max path length 256 wide chars
287
+		diskPhysicalPathBuf [256]uint16
288
+	)
289
+	if err := getVirtualDiskPhysicalPath(
290
+		handle,
291
+		&diskPathSizeInBytes,
292
+		&diskPhysicalPathBuf[0],
293
+	); err != nil {
294
+		return "", errors.Wrap(err, "failed to get disk physical path")
295
+	}
296
+	return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
297
+}
298
+
299
+// CreateDiffVhd is a helper function to create a differencing virtual disk.
300
+func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
301
+	// Setting `ParentPath` is how to signal to create a differencing disk.
302
+	createParams := &CreateVirtualDiskParameters{
303
+		Version: 2,
304
+		Version2: CreateVersion2{
305
+			ParentPath:       windows.StringToUTF16Ptr(baseVhdPath),
306
+			BlockSizeInBytes: blockSizeInMB * 1024 * 1024,
307
+			OpenFlags:        uint32(OpenVirtualDiskFlagCachedIO),
308
+		},
309
+	}
310
+
311
+	vhdHandle, err := CreateVirtualDisk(
312
+		diffVhdPath,
313
+		VirtualDiskAccessNone,
314
+		CreateVirtualDiskFlagNone,
315
+		createParams,
316
+	)
317
+	if err != nil {
318
+		return fmt.Errorf("failed to create differencing vhd: %s", err)
319
+	}
320
+	if err := syscall.CloseHandle(vhdHandle); err != nil {
321
+		return fmt.Errorf("failed to close differencing vhd handle: %s", err)
322
+	}
323
+	return nil
324
+}
... ...
@@ -37,24 +37,26 @@ func errnoErr(e syscall.Errno) error {
37 37
 }
38 38
 
39 39
 var (
40
-	modVirtDisk = windows.NewLazySystemDLL("VirtDisk.dll")
40
+	modvirtdisk = windows.NewLazySystemDLL("virtdisk.dll")
41 41
 
42
-	procCreateVirtualDisk = modVirtDisk.NewProc("CreateVirtualDisk")
43
-	procOpenVirtualDisk   = modVirtDisk.NewProc("OpenVirtualDisk")
44
-	procDetachVirtualDisk = modVirtDisk.NewProc("DetachVirtualDisk")
42
+	procCreateVirtualDisk          = modvirtdisk.NewProc("CreateVirtualDisk")
43
+	procOpenVirtualDisk            = modvirtdisk.NewProc("OpenVirtualDisk")
44
+	procAttachVirtualDisk          = modvirtdisk.NewProc("AttachVirtualDisk")
45
+	procDetachVirtualDisk          = modvirtdisk.NewProc("DetachVirtualDisk")
46
+	procGetVirtualDiskPhysicalPath = modvirtdisk.NewProc("GetVirtualDiskPhysicalPath")
45 47
 )
46 48
 
47
-func createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) {
49
+func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
48 50
 	var _p0 *uint16
49 51
 	_p0, err = syscall.UTF16PtrFromString(path)
50 52
 	if err != nil {
51 53
 		return
52 54
 	}
53
-	return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, flags, providerSpecificFlags, parameters, o, handle)
55
+	return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle)
54 56
 }
55 57
 
56
-func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) {
57
-	r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(flags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(handle)))
58
+func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
59
+	r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
58 60
 	if r1 != 0 {
59 61
 		if e1 != 0 {
60 62
 			err = errnoErr(e1)
... ...
@@ -65,17 +67,17 @@ func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, vi
65 65
 	return
66 66
 }
67 67
 
68
-func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
68
+func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
69 69
 	var _p0 *uint16
70 70
 	_p0, err = syscall.UTF16PtrFromString(path)
71 71
 	if err != nil {
72 72
 		return
73 73
 	}
74
-	return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, flags, parameters, handle)
74
+	return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, openVirtualDiskFlags, parameters, handle)
75 75
 }
76 76
 
77
-func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
78
-	r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
77
+func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
78
+	r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
79 79
 	if r1 != 0 {
80 80
 		if e1 != 0 {
81 81
 			err = errnoErr(e1)
... ...
@@ -86,8 +88,32 @@ func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virt
86 86
 	return
87 87
 }
88 88
 
89
-func detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) {
90
-	r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(flags), uintptr(providerSpecificFlags))
89
+func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) {
90
+	r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
91
+	if r1 != 0 {
92
+		if e1 != 0 {
93
+			err = errnoErr(e1)
94
+		} else {
95
+			err = syscall.EINVAL
96
+		}
97
+	}
98
+	return
99
+}
100
+
101
+func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) {
102
+	r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
103
+	if r1 != 0 {
104
+		if e1 != 0 {
105
+			err = errnoErr(e1)
106
+		} else {
107
+			err = syscall.EINVAL
108
+		}
109
+	}
110
+	return
111
+}
112
+
113
+func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) {
114
+	r1, _, e1 := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
91 115
 	if r1 != 0 {
92 116
 		if e1 != 0 {
93 117
 			err = errnoErr(e1)
... ...
@@ -1,6 +1,6 @@
1 1
 # hcsshim
2 2
 
3
-[![Build status](https://ci.appveyor.com/api/projects/status/nbcw28mnkqml0loa/branch/master?svg=true)](https://ci.appveyor.com/project/WindowsVirtualization/hcsshim/branch/master)
3
+[![Build status](https://github.com/microsoft/hcsshim/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/microsoft/hcsshim/actions?query=branch%3Amaster)
4 4
 
5 5
 This package contains the Golang interface for using the Windows [Host Compute Service](https://techcommunity.microsoft.com/t5/containers/introducing-the-host-compute-service-hcs/ba-p/382332) (HCS) to launch and manage [Windows Containers](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/). It also contains other helpers and functions for managing Windows Containers such as the Golang interface for the Host Network Service (HNS).
6 6
 
... ...
@@ -5,14 +5,15 @@ package options
5 5
 
6 6
 import (
7 7
 	fmt "fmt"
8
-	proto "github.com/gogo/protobuf/proto"
9
-	_ "github.com/gogo/protobuf/types"
10
-	github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
11 8
 	io "io"
12 9
 	math "math"
13 10
 	reflect "reflect"
14 11
 	strings "strings"
15 12
 	time "time"
13
+
14
+	proto "github.com/gogo/protobuf/proto"
15
+	_ "github.com/gogo/protobuf/types"
16
+	github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
16 17
 )
17 18
 
18 19
 // Reference imports to suppress errors if they are not otherwise used.
... ...
@@ -115,7 +116,26 @@ type Options struct {
115 115
 	VmMemorySizeInMb int32 `protobuf:"varint,9,opt,name=vm_memory_size_in_mb,json=vmMemorySizeInMb,proto3" json:"vm_memory_size_in_mb,omitempty"`
116 116
 	// GPUVHDPath is the path to the gpu vhd to add to the uvm
117 117
 	// when a container requests a gpu
118
-	GPUVHDPath           string   `protobuf:"bytes,10,opt,name=GPUVHDPath,proto3" json:"GPUVHDPath,omitempty"`
118
+	GPUVHDPath string `protobuf:"bytes,10,opt,name=GPUVHDPath,proto3" json:"GPUVHDPath,omitempty"`
119
+	// scale_cpu_limits_to_sandbox indicates that container CPU limits should
120
+	// be adjusted to account for the difference in number of cores between the
121
+	// host and UVM.
122
+	ScaleCpuLimitsToSandbox bool `protobuf:"varint,11,opt,name=scale_cpu_limits_to_sandbox,json=scaleCpuLimitsToSandbox,proto3" json:"scale_cpu_limits_to_sandbox,omitempty"`
123
+	// default_container_scratch_size_in_gb is the default scratch size (sandbox.vhdx)
124
+	// to be used for containers. Every container will get a sandbox of `size_in_gb` assigned
125
+	// instead of the default of 20GB.
126
+	DefaultContainerScratchSizeInGb int32 `protobuf:"varint,12,opt,name=default_container_scratch_size_in_gb,json=defaultContainerScratchSizeInGb,proto3" json:"default_container_scratch_size_in_gb,omitempty"`
127
+	// default_vm_scratch_size_in_gb is the default scratch size (sandbox.vhdx)
128
+	// to be used for the UVM. This only applies to WCOW as LCOW doesn't mount a scratch
129
+	// specifically for the UVM.
130
+	DefaultVmScratchSizeInGb int32 `protobuf:"varint,13,opt,name=default_vm_scratch_size_in_gb,json=defaultVmScratchSizeInGb,proto3" json:"default_vm_scratch_size_in_gb,omitempty"`
131
+	// share_scratch specifies if we'd like to reuse scratch space between multiple containers.
132
+	// This currently only affects LCOW. The sandbox containers scratch space is re-used for all
133
+	// subsequent containers launched in the pod.
134
+	ShareScratch bool `protobuf:"varint,14,opt,name=share_scratch,json=shareScratch,proto3" json:"share_scratch,omitempty"`
135
+	//NCProxyAddr is the address of the network configuration proxy service. If omitted
136
+	// the network is setup locally.
137
+	NCProxyAddr          string   `protobuf:"bytes,15,opt,name=NCProxyAddr,proto3" json:"NCProxyAddr,omitempty"`
119 138
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
120 139
 	XXX_unrecognized     []byte   `json:"-"`
121 140
 	XXX_sizecache        int32    `json:"-"`
... ...
@@ -214,56 +234,64 @@ func init() {
214 214
 }
215 215
 
216 216
 var fileDescriptor_b643df6839c75082 = []byte{
217
-	// 775 bytes of a gzipped FileDescriptorProto
218
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x6f, 0xdb, 0x36,
219
-	0x1c, 0xb5, 0x1a, 0x7f, 0xe9, 0xd7, 0x25, 0x75, 0x38, 0x1f, 0x84, 0x6c, 0xb3, 0x8d, 0xf4, 0xd0,
220
-	0x14, 0x6b, 0xa4, 0xa4, 0x3b, 0xee, 0x34, 0xc7, 0xce, 0xaa, 0x61, 0x49, 0x04, 0x39, 0x6b, 0xf7,
221
-	0x71, 0x20, 0xf4, 0xc1, 0xc8, 0x44, 0x4d, 0x51, 0x20, 0x69, 0x2f, 0xee, 0x69, 0x7f, 0xc2, 0xfe,
222
-	0xa8, 0x1d, 0x72, 0xdc, 0x71, 0xc0, 0x80, 0x6c, 0xf5, 0x5f, 0x32, 0x90, 0x92, 0xd2, 0xad, 0x08,
223
-	0x76, 0xe9, 0xc9, 0xd4, 0x7b, 0x8f, 0xef, 0xf7, 0xc1, 0x07, 0xc3, 0x45, 0x46, 0xd5, 0x7c, 0x19,
224
-	0xbb, 0x09, 0x67, 0xde, 0x19, 0x4d, 0x04, 0x97, 0xfc, 0x4a, 0x79, 0xf3, 0x44, 0xca, 0x39, 0x65,
225
-	0x5e, 0xc2, 0x52, 0x2f, 0xe1, 0xb9, 0x8a, 0x68, 0x4e, 0x44, 0x7a, 0xa8, 0xb1, 0x43, 0xb1, 0xcc,
226
-	0xe7, 0x89, 0x3c, 0x5c, 0x1d, 0x7b, 0xbc, 0x50, 0x94, 0xe7, 0xd2, 0x2b, 0x11, 0xb7, 0x10, 0x5c,
227
-	0x71, 0xd4, 0x7f, 0xa7, 0x77, 0x2b, 0x62, 0x75, 0xbc, 0xd7, 0xcf, 0x78, 0xc6, 0x8d, 0xc0, 0xd3,
228
-	0xa7, 0x52, 0xbb, 0x37, 0xcc, 0x38, 0xcf, 0x16, 0xc4, 0x33, 0x5f, 0xf1, 0xf2, 0xca, 0x53, 0x94,
229
-	0x11, 0xa9, 0x22, 0x56, 0x94, 0x82, 0xfd, 0xdf, 0x9a, 0xd0, 0xb9, 0x28, 0xab, 0xa0, 0x3e, 0xb4,
230
-	0x52, 0x12, 0x2f, 0x33, 0xc7, 0x1a, 0x59, 0x07, 0xdd, 0xb0, 0xfc, 0x40, 0xa7, 0x00, 0xe6, 0x80,
231
-	0xd5, 0xba, 0x20, 0xce, 0x83, 0x91, 0x75, 0xb0, 0xf3, 0xfc, 0x89, 0x7b, 0x5f, 0x0f, 0x6e, 0x65,
232
-	0xe4, 0x4e, 0xb4, 0xfe, 0x72, 0x5d, 0x90, 0xd0, 0x4e, 0xeb, 0x23, 0x7a, 0x0c, 0xdb, 0x82, 0x64,
233
-	0x54, 0x2a, 0xb1, 0xc6, 0x82, 0x73, 0xe5, 0x6c, 0x8d, 0xac, 0x03, 0x3b, 0xfc, 0xa8, 0x06, 0x43,
234
-	0xce, 0x95, 0x16, 0xc9, 0x28, 0x4f, 0x63, 0x7e, 0x8d, 0x29, 0x8b, 0x32, 0xe2, 0x34, 0x4b, 0x51,
235
-	0x05, 0xfa, 0x1a, 0x43, 0x4f, 0xa1, 0x57, 0x8b, 0x8a, 0x45, 0xa4, 0xae, 0xb8, 0x60, 0x4e, 0xcb,
236
-	0xe8, 0x1e, 0x55, 0x78, 0x50, 0xc1, 0xe8, 0x27, 0xd8, 0xbd, 0xf3, 0x93, 0x7c, 0x11, 0xe9, 0xfe,
237
-	0x9c, 0xb6, 0x99, 0xc1, 0xfd, 0xff, 0x19, 0x66, 0x55, 0xc5, 0xfa, 0x56, 0x58, 0xd7, 0xbc, 0x43,
238
-	0x90, 0x07, 0xfd, 0x98, 0x73, 0x85, 0xaf, 0xe8, 0x82, 0x48, 0x33, 0x13, 0x2e, 0x22, 0x35, 0x77,
239
-	0x3a, 0xa6, 0x97, 0x5d, 0xcd, 0x9d, 0x6a, 0x4a, 0x4f, 0x16, 0x44, 0x6a, 0x8e, 0x9e, 0x01, 0x5a,
240
-	0x31, 0x5c, 0x08, 0x9e, 0x10, 0x29, 0xb9, 0xc0, 0x09, 0x5f, 0xe6, 0xca, 0xe9, 0x8e, 0xac, 0x83,
241
-	0x56, 0xd8, 0x5b, 0xb1, 0xa0, 0x26, 0x4e, 0x34, 0x8e, 0x5c, 0xe8, 0xaf, 0x18, 0x66, 0x84, 0x71,
242
-	0xb1, 0xc6, 0x92, 0xbe, 0x21, 0x98, 0xe6, 0x98, 0xc5, 0x8e, 0x5d, 0xeb, 0xcf, 0x0c, 0x35, 0xa3,
243
-	0x6f, 0x88, 0x9f, 0x9f, 0xc5, 0x68, 0x00, 0xf0, 0x75, 0xf0, 0xdd, 0xcb, 0x17, 0x13, 0x5d, 0xcb,
244
-	0x01, 0xd3, 0xc4, 0xbf, 0x90, 0xfd, 0xa7, 0x60, 0xdf, 0x3d, 0x0c, 0xb2, 0xa1, 0x75, 0x1e, 0xf8,
245
-	0xc1, 0xb4, 0xd7, 0x40, 0x5d, 0x68, 0x9e, 0xfa, 0xdf, 0x4e, 0x7b, 0x16, 0xea, 0xc0, 0xd6, 0xf4,
246
-	0xf2, 0x55, 0xef, 0xc1, 0xbe, 0x07, 0xbd, 0xf7, 0xe7, 0x47, 0x0f, 0xa1, 0x13, 0x84, 0x17, 0x27,
247
-	0xd3, 0xd9, 0xac, 0xd7, 0x40, 0x3b, 0x00, 0x2f, 0x7e, 0x08, 0xa6, 0xe1, 0x4b, 0x7f, 0x76, 0x11,
248
-	0xf6, 0xac, 0xfd, 0x3f, 0xb7, 0x60, 0xa7, 0x6a, 0x7f, 0x42, 0x54, 0x44, 0x17, 0x12, 0x7d, 0x06,
249
-	0x60, 0x9e, 0x10, 0xe7, 0x11, 0x23, 0x26, 0x52, 0x76, 0x68, 0x1b, 0xe4, 0x3c, 0x62, 0x04, 0x9d,
250
-	0x00, 0x24, 0x82, 0x44, 0x8a, 0xa4, 0x38, 0x52, 0x26, 0x56, 0x0f, 0x9f, 0xef, 0xb9, 0x65, 0x5c,
251
-	0xdd, 0x3a, 0xae, 0xee, 0x65, 0x1d, 0xd7, 0x71, 0xf7, 0xe6, 0x76, 0xd8, 0xf8, 0xf5, 0xaf, 0xa1,
252
-	0x15, 0xda, 0xd5, 0xbd, 0xaf, 0x14, 0xfa, 0x1c, 0xd0, 0x6b, 0x22, 0x72, 0xb2, 0xc0, 0x3a, 0xd7,
253
-	0xf8, 0xf8, 0xe8, 0x08, 0xe7, 0xd2, 0x04, 0xab, 0x19, 0x3e, 0x2a, 0x19, 0xed, 0x70, 0x7c, 0x74,
254
-	0x74, 0x2e, 0x91, 0x0b, 0x1f, 0x57, 0xcb, 0x4c, 0x38, 0x63, 0x54, 0xe1, 0x78, 0xad, 0x88, 0x34,
255
-	0x09, 0x6b, 0x86, 0xbb, 0x25, 0x75, 0x62, 0x98, 0xb1, 0x26, 0xd0, 0x29, 0x8c, 0x2a, 0xfd, 0xcf,
256
-	0x5c, 0xbc, 0xa6, 0x79, 0x86, 0x25, 0x51, 0xb8, 0x10, 0x74, 0x15, 0x29, 0x52, 0x5d, 0x6e, 0x99,
257
-	0xcb, 0x9f, 0x96, 0xba, 0x57, 0xa5, 0x6c, 0x46, 0x54, 0x50, 0x8a, 0x4a, 0x9f, 0x09, 0x0c, 0xef,
258
-	0xf1, 0x91, 0xf3, 0x48, 0x90, 0xb4, 0xb2, 0x69, 0x1b, 0x9b, 0x4f, 0xde, 0xb7, 0x99, 0x19, 0x4d,
259
-	0xe9, 0xf2, 0x0c, 0xa0, 0x0a, 0x0e, 0xa6, 0xa9, 0x89, 0xd8, 0xf6, 0x78, 0x7b, 0x73, 0x3b, 0xb4,
260
-	0xab, 0xb5, 0xfb, 0x93, 0xd0, 0xae, 0x04, 0x7e, 0x8a, 0x9e, 0x40, 0x6f, 0x29, 0x89, 0xf8, 0xcf,
261
-	0x5a, 0xba, 0xa6, 0xc8, 0xb6, 0xc6, 0xdf, 0x2d, 0xe5, 0x31, 0x74, 0xc8, 0x35, 0x49, 0xb4, 0xa7,
262
-	0xce, 0x95, 0x3d, 0x86, 0xcd, 0xed, 0xb0, 0x3d, 0xbd, 0x26, 0x89, 0x3f, 0x09, 0xdb, 0x9a, 0xf2,
263
-	0xd3, 0x71, 0x7a, 0xf3, 0x76, 0xd0, 0xf8, 0xe3, 0xed, 0xa0, 0xf1, 0xcb, 0x66, 0x60, 0xdd, 0x6c,
264
-	0x06, 0xd6, 0xef, 0x9b, 0x81, 0xf5, 0xf7, 0x66, 0x60, 0xfd, 0xf8, 0xcd, 0x87, 0xff, 0xb9, 0x7d,
265
-	0x59, 0xfd, 0x7e, 0xdf, 0x88, 0xdb, 0xe6, 0xdd, 0xbf, 0xf8, 0x27, 0x00, 0x00, 0xff, 0xff, 0x75,
266
-	0x1f, 0x14, 0xf4, 0x33, 0x05, 0x00, 0x00,
217
+	// 899 bytes of a gzipped FileDescriptorProto
218
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x5b, 0x6f, 0xdb, 0x36,
219
+	0x18, 0x86, 0xad, 0x26, 0x71, 0xac, 0x2f, 0x71, 0xe2, 0x70, 0x06, 0x26, 0xa4, 0xab, 0x6d, 0xa4,
220
+	0x03, 0x9a, 0x62, 0x8d, 0x94, 0x74, 0x97, 0x1b, 0x30, 0xd4, 0x87, 0xb4, 0x1e, 0x9a, 0x44, 0x90,
221
+	0xb3, 0x74, 0x87, 0x0b, 0x42, 0x07, 0x5a, 0x16, 0x6a, 0x8a, 0x02, 0x49, 0x7b, 0x71, 0xaf, 0xf6,
222
+	0x13, 0xf6, 0xb3, 0x72, 0xb9, 0xcb, 0x0d, 0x03, 0xb2, 0xd5, 0xbf, 0x64, 0x10, 0x45, 0xb9, 0x5d,
223
+	0x10, 0xec, 0x66, 0x57, 0xa6, 0xde, 0xef, 0xe1, 0xcb, 0x8f, 0x87, 0xd7, 0x70, 0x11, 0x27, 0x72,
224
+	0x32, 0x0b, 0xec, 0x90, 0x51, 0xe7, 0x2c, 0x09, 0x39, 0x13, 0x6c, 0x2c, 0x9d, 0x49, 0x28, 0xc4,
225
+	0x24, 0xa1, 0x4e, 0x48, 0x23, 0x27, 0x64, 0xa9, 0xf4, 0x93, 0x94, 0xf0, 0xe8, 0x28, 0xd7, 0x8e,
226
+	0xf8, 0x2c, 0x9d, 0x84, 0xe2, 0x68, 0x7e, 0xe2, 0xb0, 0x4c, 0x26, 0x2c, 0x15, 0x4e, 0xa1, 0xd8,
227
+	0x19, 0x67, 0x92, 0xa1, 0xe6, 0x07, 0xde, 0xd6, 0x85, 0xf9, 0xc9, 0x7e, 0x33, 0x66, 0x31, 0x53,
228
+	0x80, 0x93, 0x8f, 0x0a, 0x76, 0xbf, 0x1d, 0x33, 0x16, 0x4f, 0x89, 0xa3, 0xbe, 0x82, 0xd9, 0xd8,
229
+	0x91, 0x09, 0x25, 0x42, 0xfa, 0x34, 0x2b, 0x80, 0x83, 0x3f, 0xaa, 0xb0, 0x79, 0x51, 0xac, 0x82,
230
+	0x9a, 0xb0, 0x11, 0x91, 0x60, 0x16, 0x5b, 0x46, 0xc7, 0x38, 0xac, 0x79, 0xc5, 0x07, 0x3a, 0x05,
231
+	0x50, 0x03, 0x2c, 0x17, 0x19, 0xb1, 0x1e, 0x74, 0x8c, 0xc3, 0x9d, 0xe7, 0x4f, 0xec, 0xfb, 0x7a,
232
+	0xb0, 0xb5, 0x91, 0xdd, 0xcf, 0xf9, 0xcb, 0x45, 0x46, 0x3c, 0x33, 0x2a, 0x87, 0xe8, 0x31, 0xd4,
233
+	0x39, 0x89, 0x13, 0x21, 0xf9, 0x02, 0x73, 0xc6, 0xa4, 0xb5, 0xd6, 0x31, 0x0e, 0x4d, 0x6f, 0xbb,
234
+	0x14, 0x3d, 0xc6, 0x64, 0x0e, 0x09, 0x3f, 0x8d, 0x02, 0x76, 0x8d, 0x13, 0xea, 0xc7, 0xc4, 0x5a,
235
+	0x2f, 0x20, 0x2d, 0x0e, 0x73, 0x0d, 0x3d, 0x85, 0x46, 0x09, 0x65, 0x53, 0x5f, 0x8e, 0x19, 0xa7,
236
+	0xd6, 0x86, 0xe2, 0x76, 0xb5, 0xee, 0x6a, 0x19, 0xfd, 0x04, 0x7b, 0x2b, 0x3f, 0xc1, 0xa6, 0x7e,
237
+	0xde, 0x9f, 0x55, 0x55, 0x7b, 0xb0, 0xff, 0x7b, 0x0f, 0x23, 0xbd, 0x62, 0x39, 0xcb, 0x2b, 0xd7,
238
+	0x5c, 0x29, 0xc8, 0x81, 0x66, 0xc0, 0x98, 0xc4, 0xe3, 0x64, 0x4a, 0x84, 0xda, 0x13, 0xce, 0x7c,
239
+	0x39, 0xb1, 0x36, 0x55, 0x2f, 0x7b, 0x79, 0xed, 0x34, 0x2f, 0xe5, 0x3b, 0x73, 0x7d, 0x39, 0x41,
240
+	0xcf, 0x00, 0xcd, 0x29, 0xce, 0x38, 0x0b, 0x89, 0x10, 0x8c, 0xe3, 0x90, 0xcd, 0x52, 0x69, 0xd5,
241
+	0x3a, 0xc6, 0xe1, 0x86, 0xd7, 0x98, 0x53, 0xb7, 0x2c, 0xf4, 0x72, 0x1d, 0xd9, 0xd0, 0x9c, 0x53,
242
+	0x4c, 0x09, 0x65, 0x7c, 0x81, 0x45, 0xf2, 0x8e, 0xe0, 0x24, 0xc5, 0x34, 0xb0, 0xcc, 0x92, 0x3f,
243
+	0x53, 0xa5, 0x51, 0xf2, 0x8e, 0x0c, 0xd3, 0xb3, 0x00, 0xb5, 0x00, 0x5e, 0xba, 0xdf, 0x5d, 0xbd,
244
+	0xea, 0xe7, 0x6b, 0x59, 0xa0, 0x9a, 0xf8, 0x48, 0x41, 0x5f, 0xc3, 0x43, 0x11, 0xfa, 0x53, 0x82,
245
+	0xc3, 0x6c, 0x86, 0xa7, 0x09, 0x4d, 0xa4, 0xc0, 0x92, 0x61, 0xbd, 0x2d, 0x6b, 0x4b, 0x5d, 0xfa,
246
+	0xa7, 0x0a, 0xe9, 0x65, 0xb3, 0xd7, 0x0a, 0xb8, 0x64, 0xfa, 0x1c, 0xd0, 0x19, 0x7c, 0x1e, 0x91,
247
+	0xb1, 0x3f, 0x9b, 0x4a, 0xbc, 0x3a, 0x37, 0x2c, 0x42, 0xee, 0xcb, 0x70, 0xb2, 0xea, 0x2e, 0x0e,
248
+	0xac, 0x6d, 0xd5, 0x5d, 0x5b, 0xb3, 0xbd, 0x12, 0x1d, 0x15, 0x64, 0xd1, 0xec, 0xcb, 0x00, 0x7d,
249
+	0x03, 0x8f, 0x4a, 0xbb, 0x39, 0xbd, 0xcf, 0xa7, 0xae, 0x7c, 0x2c, 0x0d, 0x5d, 0xd1, 0xbb, 0x06,
250
+	0xf9, 0x4b, 0x99, 0xf8, 0x9c, 0x94, 0x73, 0xad, 0x1d, 0xd5, 0xff, 0xb6, 0x12, 0x35, 0x8c, 0x3a,
251
+	0xb0, 0x75, 0xde, 0x73, 0x39, 0xbb, 0x5e, 0xbc, 0x88, 0x22, 0x6e, 0xed, 0xaa, 0x33, 0xf9, 0x58,
252
+	0x3a, 0x78, 0x0a, 0xe6, 0xea, 0xb5, 0x22, 0x13, 0x36, 0xce, 0xdd, 0xa1, 0x3b, 0x68, 0x54, 0x50,
253
+	0x0d, 0xd6, 0x4f, 0x87, 0xaf, 0x07, 0x0d, 0x03, 0x6d, 0xc2, 0xda, 0xe0, 0xf2, 0x4d, 0xe3, 0xc1,
254
+	0x81, 0x03, 0x8d, 0xbb, 0x8f, 0x02, 0x6d, 0xc1, 0xa6, 0xeb, 0x5d, 0xf4, 0x06, 0xa3, 0x51, 0xa3,
255
+	0x82, 0x76, 0x00, 0x5e, 0xfd, 0xe0, 0x0e, 0xbc, 0xab, 0xe1, 0xe8, 0xc2, 0x6b, 0x18, 0x07, 0x7f,
256
+	0xae, 0xc1, 0x8e, 0xbe, 0xd3, 0x3e, 0x91, 0x7e, 0x32, 0x15, 0xe8, 0x11, 0x80, 0x7a, 0xd7, 0x38,
257
+	0xf5, 0x29, 0x51, 0x39, 0x33, 0x3d, 0x53, 0x29, 0xe7, 0x3e, 0x25, 0xa8, 0x07, 0x10, 0x72, 0xe2,
258
+	0x4b, 0x12, 0x61, 0x5f, 0xaa, 0xac, 0x6d, 0x3d, 0xdf, 0xb7, 0x8b, 0x0c, 0xdb, 0x65, 0x86, 0xed,
259
+	0xcb, 0x32, 0xc3, 0xdd, 0xda, 0xcd, 0x6d, 0xbb, 0xf2, 0xeb, 0x5f, 0x6d, 0xc3, 0x33, 0xf5, 0xbc,
260
+	0x17, 0x12, 0x7d, 0x01, 0xe8, 0x2d, 0xe1, 0x29, 0x99, 0xe2, 0x3c, 0xec, 0xf8, 0xe4, 0xf8, 0x18,
261
+	0xa7, 0x42, 0xa5, 0x6d, 0xdd, 0xdb, 0x2d, 0x2a, 0xb9, 0xc3, 0xc9, 0xf1, 0xf1, 0xb9, 0x40, 0x36,
262
+	0x7c, 0xa2, 0x5f, 0x58, 0xc8, 0x28, 0x4d, 0x24, 0x0e, 0x16, 0x92, 0x08, 0x15, 0xbb, 0x75, 0x6f,
263
+	0xaf, 0x28, 0xf5, 0x54, 0xa5, 0x9b, 0x17, 0xd0, 0x29, 0x74, 0x34, 0xff, 0x33, 0xe3, 0x6f, 0x93,
264
+	0x34, 0xc6, 0x82, 0x48, 0x9c, 0xf1, 0x64, 0xee, 0x4b, 0xa2, 0x27, 0x6f, 0xa8, 0xc9, 0x9f, 0x15,
265
+	0xdc, 0x9b, 0x02, 0x1b, 0x11, 0xe9, 0x16, 0x50, 0xe1, 0xd3, 0x87, 0xf6, 0x3d, 0x3e, 0xea, 0xf2,
266
+	0x22, 0x6d, 0x53, 0x55, 0x36, 0x0f, 0xef, 0xda, 0x8c, 0x14, 0x53, 0xb8, 0x3c, 0x03, 0xd0, 0x69,
267
+	0xc2, 0x49, 0xa4, 0x72, 0x57, 0xef, 0xd6, 0x97, 0xb7, 0x6d, 0x53, 0x1f, 0xfb, 0xb0, 0xef, 0x99,
268
+	0x1a, 0x18, 0x46, 0xe8, 0x09, 0x34, 0x66, 0x82, 0xf0, 0x7f, 0x1d, 0x4b, 0x4d, 0x2d, 0x52, 0xcf,
269
+	0xf5, 0x0f, 0x87, 0xf2, 0x18, 0x36, 0xc9, 0x35, 0x09, 0x73, 0xcf, 0x3c, 0x6c, 0x66, 0x17, 0x96,
270
+	0xb7, 0xed, 0xea, 0xe0, 0x9a, 0x84, 0xc3, 0xbe, 0x57, 0xcd, 0x4b, 0xc3, 0xa8, 0x1b, 0xdd, 0xbc,
271
+	0x6f, 0x55, 0x7e, 0x7f, 0xdf, 0xaa, 0xfc, 0xb2, 0x6c, 0x19, 0x37, 0xcb, 0x96, 0xf1, 0xdb, 0xb2,
272
+	0x65, 0xfc, 0xbd, 0x6c, 0x19, 0x3f, 0x7e, 0xfb, 0xff, 0xff, 0xf1, 0xbf, 0xd2, 0xbf, 0xdf, 0x57,
273
+	0x82, 0xaa, 0xba, 0xf7, 0x2f, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x0d, 0x33, 0xad, 0x48,
274
+	0x06, 0x00, 0x00,
267 275
 }
268 276
 
269 277
 func (m *Options) Marshal() (dAtA []byte, err error) {
... ...
@@ -341,6 +369,42 @@ func (m *Options) MarshalTo(dAtA []byte) (int, error) {
341 341
 		i = encodeVarintRunhcs(dAtA, i, uint64(len(m.GPUVHDPath)))
342 342
 		i += copy(dAtA[i:], m.GPUVHDPath)
343 343
 	}
344
+	if m.ScaleCpuLimitsToSandbox {
345
+		dAtA[i] = 0x58
346
+		i++
347
+		if m.ScaleCpuLimitsToSandbox {
348
+			dAtA[i] = 1
349
+		} else {
350
+			dAtA[i] = 0
351
+		}
352
+		i++
353
+	}
354
+	if m.DefaultContainerScratchSizeInGb != 0 {
355
+		dAtA[i] = 0x60
356
+		i++
357
+		i = encodeVarintRunhcs(dAtA, i, uint64(m.DefaultContainerScratchSizeInGb))
358
+	}
359
+	if m.DefaultVmScratchSizeInGb != 0 {
360
+		dAtA[i] = 0x68
361
+		i++
362
+		i = encodeVarintRunhcs(dAtA, i, uint64(m.DefaultVmScratchSizeInGb))
363
+	}
364
+	if m.ShareScratch {
365
+		dAtA[i] = 0x70
366
+		i++
367
+		if m.ShareScratch {
368
+			dAtA[i] = 1
369
+		} else {
370
+			dAtA[i] = 0
371
+		}
372
+		i++
373
+	}
374
+	if len(m.NCProxyAddr) > 0 {
375
+		dAtA[i] = 0x7a
376
+		i++
377
+		i = encodeVarintRunhcs(dAtA, i, uint64(len(m.NCProxyAddr)))
378
+		i += copy(dAtA[i:], m.NCProxyAddr)
379
+	}
344 380
 	if m.XXX_unrecognized != nil {
345 381
 		i += copy(dAtA[i:], m.XXX_unrecognized)
346 382
 	}
... ...
@@ -468,6 +532,22 @@ func (m *Options) Size() (n int) {
468 468
 	if l > 0 {
469 469
 		n += 1 + l + sovRunhcs(uint64(l))
470 470
 	}
471
+	if m.ScaleCpuLimitsToSandbox {
472
+		n += 2
473
+	}
474
+	if m.DefaultContainerScratchSizeInGb != 0 {
475
+		n += 1 + sovRunhcs(uint64(m.DefaultContainerScratchSizeInGb))
476
+	}
477
+	if m.DefaultVmScratchSizeInGb != 0 {
478
+		n += 1 + sovRunhcs(uint64(m.DefaultVmScratchSizeInGb))
479
+	}
480
+	if m.ShareScratch {
481
+		n += 2
482
+	}
483
+	l = len(m.NCProxyAddr)
484
+	if l > 0 {
485
+		n += 1 + l + sovRunhcs(uint64(l))
486
+	}
471 487
 	if m.XXX_unrecognized != nil {
472 488
 		n += len(m.XXX_unrecognized)
473 489
 	}
... ...
@@ -542,6 +622,11 @@ func (this *Options) String() string {
542 542
 		`VmProcessorCount:` + fmt.Sprintf("%v", this.VmProcessorCount) + `,`,
543 543
 		`VmMemorySizeInMb:` + fmt.Sprintf("%v", this.VmMemorySizeInMb) + `,`,
544 544
 		`GPUVHDPath:` + fmt.Sprintf("%v", this.GPUVHDPath) + `,`,
545
+		`ScaleCpuLimitsToSandbox:` + fmt.Sprintf("%v", this.ScaleCpuLimitsToSandbox) + `,`,
546
+		`DefaultContainerScratchSizeInGb:` + fmt.Sprintf("%v", this.DefaultContainerScratchSizeInGb) + `,`,
547
+		`DefaultVmScratchSizeInGb:` + fmt.Sprintf("%v", this.DefaultVmScratchSizeInGb) + `,`,
548
+		`ShareScratch:` + fmt.Sprintf("%v", this.ShareScratch) + `,`,
549
+		`NCProxyAddr:` + fmt.Sprintf("%v", this.NCProxyAddr) + `,`,
545 550
 		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
546 551
 		`}`,
547 552
 	}, "")
... ...
@@ -859,6 +944,116 @@ func (m *Options) Unmarshal(dAtA []byte) error {
859 859
 			}
860 860
 			m.GPUVHDPath = string(dAtA[iNdEx:postIndex])
861 861
 			iNdEx = postIndex
862
+		case 11:
863
+			if wireType != 0 {
864
+				return fmt.Errorf("proto: wrong wireType = %d for field ScaleCpuLimitsToSandbox", wireType)
865
+			}
866
+			var v int
867
+			for shift := uint(0); ; shift += 7 {
868
+				if shift >= 64 {
869
+					return ErrIntOverflowRunhcs
870
+				}
871
+				if iNdEx >= l {
872
+					return io.ErrUnexpectedEOF
873
+				}
874
+				b := dAtA[iNdEx]
875
+				iNdEx++
876
+				v |= int(b&0x7F) << shift
877
+				if b < 0x80 {
878
+					break
879
+				}
880
+			}
881
+			m.ScaleCpuLimitsToSandbox = bool(v != 0)
882
+		case 12:
883
+			if wireType != 0 {
884
+				return fmt.Errorf("proto: wrong wireType = %d for field DefaultContainerScratchSizeInGb", wireType)
885
+			}
886
+			m.DefaultContainerScratchSizeInGb = 0
887
+			for shift := uint(0); ; shift += 7 {
888
+				if shift >= 64 {
889
+					return ErrIntOverflowRunhcs
890
+				}
891
+				if iNdEx >= l {
892
+					return io.ErrUnexpectedEOF
893
+				}
894
+				b := dAtA[iNdEx]
895
+				iNdEx++
896
+				m.DefaultContainerScratchSizeInGb |= int32(b&0x7F) << shift
897
+				if b < 0x80 {
898
+					break
899
+				}
900
+			}
901
+		case 13:
902
+			if wireType != 0 {
903
+				return fmt.Errorf("proto: wrong wireType = %d for field DefaultVmScratchSizeInGb", wireType)
904
+			}
905
+			m.DefaultVmScratchSizeInGb = 0
906
+			for shift := uint(0); ; shift += 7 {
907
+				if shift >= 64 {
908
+					return ErrIntOverflowRunhcs
909
+				}
910
+				if iNdEx >= l {
911
+					return io.ErrUnexpectedEOF
912
+				}
913
+				b := dAtA[iNdEx]
914
+				iNdEx++
915
+				m.DefaultVmScratchSizeInGb |= int32(b&0x7F) << shift
916
+				if b < 0x80 {
917
+					break
918
+				}
919
+			}
920
+		case 14:
921
+			if wireType != 0 {
922
+				return fmt.Errorf("proto: wrong wireType = %d for field ShareScratch", wireType)
923
+			}
924
+			var v int
925
+			for shift := uint(0); ; shift += 7 {
926
+				if shift >= 64 {
927
+					return ErrIntOverflowRunhcs
928
+				}
929
+				if iNdEx >= l {
930
+					return io.ErrUnexpectedEOF
931
+				}
932
+				b := dAtA[iNdEx]
933
+				iNdEx++
934
+				v |= int(b&0x7F) << shift
935
+				if b < 0x80 {
936
+					break
937
+				}
938
+			}
939
+			m.ShareScratch = bool(v != 0)
940
+		case 15:
941
+			if wireType != 2 {
942
+				return fmt.Errorf("proto: wrong wireType = %d for field NCProxyAddr", wireType)
943
+			}
944
+			var stringLen uint64
945
+			for shift := uint(0); ; shift += 7 {
946
+				if shift >= 64 {
947
+					return ErrIntOverflowRunhcs
948
+				}
949
+				if iNdEx >= l {
950
+					return io.ErrUnexpectedEOF
951
+				}
952
+				b := dAtA[iNdEx]
953
+				iNdEx++
954
+				stringLen |= uint64(b&0x7F) << shift
955
+				if b < 0x80 {
956
+					break
957
+				}
958
+			}
959
+			intStringLen := int(stringLen)
960
+			if intStringLen < 0 {
961
+				return ErrInvalidLengthRunhcs
962
+			}
963
+			postIndex := iNdEx + intStringLen
964
+			if postIndex < 0 {
965
+				return ErrInvalidLengthRunhcs
966
+			}
967
+			if postIndex > l {
968
+				return io.ErrUnexpectedEOF
969
+			}
970
+			m.NCProxyAddr = string(dAtA[iNdEx:postIndex])
971
+			iNdEx = postIndex
862 972
 		default:
863 973
 			iNdEx = preIndex
864 974
 			skippy, err := skipRunhcs(dAtA[iNdEx:])
... ...
@@ -62,7 +62,30 @@ message Options {
62 62
 
63 63
 	// GPUVHDPath is the path to the gpu vhd to add to the uvm
64 64
 	// when a container requests a gpu
65
-	string GPUVHDPath = 10; 
65
+	string GPUVHDPath = 10;
66
+
67
+	// scale_cpu_limits_to_sandbox indicates that container CPU limits should
68
+	// be adjusted to account for the difference in number of cores between the
69
+	// host and UVM.
70
+	bool scale_cpu_limits_to_sandbox = 11;
71
+
72
+	// default_container_scratch_size_in_gb is the default scratch size (sandbox.vhdx) 
73
+	// to be used for containers. Every container will get a sandbox of `size_in_gb` assigned
74
+	// instead of the default of 20GB. 
75
+	int32 default_container_scratch_size_in_gb = 12;
76
+
77
+	// default_vm_scratch_size_in_gb is the default scratch size (sandbox.vhdx) 
78
+	// to be used for the UVM. This only applies to WCOW as LCOW doesn't mount a scratch 
79
+	// specifically for the UVM.
80
+	int32 default_vm_scratch_size_in_gb = 13;
81
+
82
+	// share_scratch specifies if we'd like to reuse scratch space between multiple containers. 
83
+	// This currently only affects LCOW. The sandbox containers scratch space is re-used for all
84
+	// subsequent containers launched in the pod.  
85
+	bool share_scratch = 14;
86
+	//NCProxyAddr is the address of the network configuration proxy service. If omitted 
87
+	// the network is setup locally. 
88
+	string NCProxyAddr = 15; 
66 89
 }
67 90
 
68 91
 // ProcessDetails contains additional information about a process. This is the additional
69 92
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+
6
+	"github.com/Microsoft/hcsshim/internal/oc"
7
+	"github.com/pkg/errors"
8
+	"go.opencensus.io/trace"
9
+)
10
+
11
+// AttachLayerStorageFilter sets up the layer storage filter on a writable
12
+// container layer.
13
+//
14
+// `layerPath` is a path to a directory the writable layer is mounted. If the
15
+// path does not end in a `\` the platform will append it automatically.
16
+//
17
+// `layerData` is the parent read-only layer data.
18
+func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
19
+	title := "hcsshim.AttachLayerStorageFilter"
20
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
21
+	defer span.End()
22
+	defer func() { oc.SetSpanStatus(span, err) }()
23
+	span.AddAttributes(
24
+		trace.StringAttribute("layerPath", layerPath),
25
+	)
26
+
27
+	bytes, err := json.Marshal(layerData)
28
+	if err != nil {
29
+		return err
30
+	}
31
+
32
+	err = hcsAttachLayerStorageFilter(layerPath, string(bytes))
33
+	if err != nil {
34
+		return errors.Wrap(err, "failed to attach layer storage filter")
35
+	}
36
+	return nil
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/Microsoft/hcsshim/internal/oc"
6
+	"github.com/pkg/errors"
7
+	"go.opencensus.io/trace"
8
+)
9
+
10
+// DestroyLayer deletes a container layer.
11
+//
12
+// `layerPath` is a path to a directory containing the layer to export.
13
+func DestroyLayer(ctx context.Context, layerPath string) (err error) {
14
+	title := "hcsshim.DestroyLayer"
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16
+	defer span.End()
17
+	defer func() { oc.SetSpanStatus(span, err) }()
18
+	span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
19
+
20
+	err = hcsDestroyLayer(layerPath)
21
+	if err != nil {
22
+		return errors.Wrap(err, "failed to destroy layer")
23
+	}
24
+	return nil
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/Microsoft/hcsshim/internal/oc"
6
+	"github.com/pkg/errors"
7
+	"go.opencensus.io/trace"
8
+)
9
+
10
+// DetachLayerStorageFilter detaches the layer storage filter on a writable container layer.
11
+//
12
+// `layerPath` is a path to a directory containing the layer to export.
13
+func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
14
+	title := "hcsshim.DetachLayerStorageFilter"
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16
+	defer span.End()
17
+	defer func() { oc.SetSpanStatus(span, err) }()
18
+	span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
19
+
20
+	err = hcsDetachLayerStorageFilter(layerPath)
21
+	if err != nil {
22
+		return errors.Wrap(err, "failed to detach layer storage filter")
23
+	}
24
+	return nil
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+
6
+	"github.com/Microsoft/hcsshim/internal/oc"
7
+	"github.com/pkg/errors"
8
+	"go.opencensus.io/trace"
9
+)
10
+
11
+// ExportLayer exports a container layer.
12
+//
13
+// `layerPath` is a path to a directory containing the layer to export.
14
+//
15
+// `exportFolderPath` is a pre-existing folder to export the layer to.
16
+//
17
+// `layerData` is the parent layer data.
18
+//
19
+// `options` are the export options applied to the exported layer.
20
+func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
21
+	title := "hcsshim.ExportLayer"
22
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
23
+	defer span.End()
24
+	defer func() { oc.SetSpanStatus(span, err) }()
25
+	span.AddAttributes(
26
+		trace.StringAttribute("layerPath", layerPath),
27
+		trace.StringAttribute("exportFolderPath", exportFolderPath),
28
+	)
29
+
30
+	ldbytes, err := json.Marshal(layerData)
31
+	if err != nil {
32
+		return err
33
+	}
34
+
35
+	obytes, err := json.Marshal(options)
36
+	if err != nil {
37
+		return err
38
+	}
39
+
40
+	err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes))
41
+	if err != nil {
42
+		return errors.Wrap(err, "failed to export layer")
43
+	}
44
+	return nil
45
+}
0 46
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/Microsoft/hcsshim/internal/oc"
6
+	"github.com/pkg/errors"
7
+	"go.opencensus.io/trace"
8
+	"golang.org/x/sys/windows"
9
+)
10
+
11
+// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
12
+//
13
+// If the VHD is not mounted it will be temporarily mounted.
14
+func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
15
+	title := "hcsshim.FormatWritableLayerVhd"
16
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
17
+	defer span.End()
18
+	defer func() { oc.SetSpanStatus(span, err) }()
19
+
20
+	err = hcsFormatWritableLayerVhd(vhdHandle)
21
+	if err != nil {
22
+		return errors.Wrap(err, "failed to format writable layer vhd")
23
+	}
24
+	return nil
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,193 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+	"os"
5
+	"path/filepath"
6
+	"syscall"
7
+
8
+	"github.com/Microsoft/go-winio/pkg/security"
9
+	"github.com/Microsoft/go-winio/vhd"
10
+	"github.com/pkg/errors"
11
+	"golang.org/x/sys/windows"
12
+)
13
+
14
+const defaultVHDXBlockSizeInMB = 1
15
+
16
+// SetupContainerBaseLayer is a helper to setup a containers scratch. It
17
+// will create and format the vhdx's inside and the size is configurable with the sizeInGB
18
+// parameter.
19
+//
20
+// `layerPath` is the path to the base container layer on disk.
21
+//
22
+// `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
23
+//
24
+// `diffVhdPath` is the path where the differencing disk for the base layer should be created.
25
+//
26
+// `sizeInGB` is the size in gigabytes to make the base vhdx.
27
+func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
28
+	var (
29
+		hivesPath  = filepath.Join(layerPath, "Hives")
30
+		layoutPath = filepath.Join(layerPath, "Layout")
31
+	)
32
+
33
+	// We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
34
+	// already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
35
+	// differencing disks if they exist in case we're asking for a different size.
36
+	if _, err := os.Stat(hivesPath); err == nil {
37
+		if err := os.RemoveAll(hivesPath); err != nil {
38
+			return errors.Wrap(err, "failed to remove prexisting hives directory")
39
+		}
40
+	}
41
+	if _, err := os.Stat(layoutPath); err == nil {
42
+		if err := os.RemoveAll(layoutPath); err != nil {
43
+			return errors.Wrap(err, "failed to remove prexisting layout file")
44
+		}
45
+	}
46
+
47
+	if _, err := os.Stat(baseVhdPath); err == nil {
48
+		if err := os.RemoveAll(baseVhdPath); err != nil {
49
+			return errors.Wrap(err, "failed to remove base vhdx path")
50
+		}
51
+	}
52
+	if _, err := os.Stat(diffVhdPath); err == nil {
53
+		if err := os.RemoveAll(diffVhdPath); err != nil {
54
+			return errors.Wrap(err, "failed to remove differencing vhdx")
55
+		}
56
+	}
57
+
58
+	createParams := &vhd.CreateVirtualDiskParameters{
59
+		Version: 2,
60
+		Version2: vhd.CreateVersion2{
61
+			MaximumSize:      sizeInGB * 1024 * 1024 * 1024,
62
+			BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
63
+		},
64
+	}
65
+	handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
66
+	if err != nil {
67
+		return errors.Wrap(err, "failed to create vhdx")
68
+	}
69
+
70
+	defer func() {
71
+		if err != nil {
72
+			_ = syscall.CloseHandle(handle)
73
+			os.RemoveAll(baseVhdPath)
74
+			os.RemoveAll(diffVhdPath)
75
+		}
76
+	}()
77
+
78
+	if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
79
+		return err
80
+	}
81
+	// Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
82
+	if err = syscall.CloseHandle(handle); err != nil {
83
+		return errors.Wrap(err, "failed to close vhdx handle")
84
+	}
85
+
86
+	options := OsLayerOptions{
87
+		Type: OsLayerTypeContainer,
88
+	}
89
+
90
+	// SetupBaseOSLayer expects an empty vhd handle for a container layer and will
91
+	// error out otherwise.
92
+	if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
93
+		return err
94
+	}
95
+	// Create the differencing disk that will be what's copied for the final rw layer
96
+	// for a container.
97
+	if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
98
+		return errors.Wrap(err, "failed to create differencing disk")
99
+	}
100
+
101
+	if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
102
+		return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
103
+	}
104
+	if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
105
+		return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
106
+	}
107
+	return nil
108
+}
109
+
110
+// SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
111
+// the vhdx inside and the size is configurable by the sizeInGB parameter.
112
+//
113
+// `uvmPath` is the path to the UtilityVM filesystem.
114
+//
115
+// `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
116
+//
117
+// `diffVhdPath` is the path where the differencing disk for the UVM should be created.
118
+//
119
+// `sizeInGB` specifies the size in gigabytes to make the base vhdx.
120
+func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
121
+	// Remove the base and differencing disks if they exist in case we're asking for a different size.
122
+	if _, err := os.Stat(baseVhdPath); err == nil {
123
+		if err := os.RemoveAll(baseVhdPath); err != nil {
124
+			return errors.Wrap(err, "failed to remove base vhdx")
125
+		}
126
+	}
127
+	if _, err := os.Stat(diffVhdPath); err == nil {
128
+		if err := os.RemoveAll(diffVhdPath); err != nil {
129
+			return errors.Wrap(err, "failed to remove differencing vhdx")
130
+		}
131
+	}
132
+
133
+	// Just create the vhdx for utilityVM layer, no need to format it.
134
+	createParams := &vhd.CreateVirtualDiskParameters{
135
+		Version: 2,
136
+		Version2: vhd.CreateVersion2{
137
+			MaximumSize:      sizeInGB * 1024 * 1024 * 1024,
138
+			BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
139
+		},
140
+	}
141
+	handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
142
+	if err != nil {
143
+		return errors.Wrap(err, "failed to create vhdx")
144
+	}
145
+
146
+	defer func() {
147
+		if err != nil {
148
+			_ = syscall.CloseHandle(handle)
149
+			os.RemoveAll(baseVhdPath)
150
+			os.RemoveAll(diffVhdPath)
151
+		}
152
+	}()
153
+
154
+	// If it is a UtilityVM layer then the base vhdx must be attached when calling
155
+	// `SetupBaseOSLayer`
156
+	attachParams := &vhd.AttachVirtualDiskParameters{
157
+		Version: 2,
158
+	}
159
+	if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
160
+		return errors.Wrapf(err, "failed to attach virtual disk")
161
+	}
162
+
163
+	options := OsLayerOptions{
164
+		Type: OsLayerTypeVM,
165
+	}
166
+	if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
167
+		return err
168
+	}
169
+
170
+	// Detach and close the handle after setting up the layer as we don't need the handle
171
+	// for anything else and we no longer need to be attached either.
172
+	if err = vhd.DetachVirtualDisk(handle); err != nil {
173
+		return errors.Wrap(err, "failed to detach vhdx")
174
+	}
175
+	if err = syscall.CloseHandle(handle); err != nil {
176
+		return errors.Wrap(err, "failed to close vhdx handle")
177
+	}
178
+
179
+	// Create the differencing disk that will be what's copied for the final rw layer
180
+	// for a container.
181
+	if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
182
+		return errors.Wrap(err, "failed to create differencing disk")
183
+	}
184
+
185
+	if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
186
+		return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
187
+	}
188
+	if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
189
+		return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
190
+	}
191
+	return nil
192
+}
0 193
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+
6
+	"github.com/Microsoft/hcsshim/internal/oc"
7
+	"github.com/pkg/errors"
8
+	"go.opencensus.io/trace"
9
+)
10
+
11
+// ImportLayer imports a container layer.
12
+//
13
+// `layerPath` is a path to a directory to import the layer to. If the directory
14
+// does not exist it will be automatically created.
15
+//
16
+// `sourceFolderpath` is a pre-existing folder that contains the layer to
17
+// import.
18
+//
19
+// `layerData` is the parent layer data.
20
+func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
21
+	title := "hcsshim.ImportLayer"
22
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
23
+	defer span.End()
24
+	defer func() { oc.SetSpanStatus(span, err) }()
25
+	span.AddAttributes(
26
+		trace.StringAttribute("layerPath", layerPath),
27
+		trace.StringAttribute("sourceFolderPath", sourceFolderPath),
28
+	)
29
+
30
+	bytes, err := json.Marshal(layerData)
31
+	if err != nil {
32
+		return err
33
+	}
34
+
35
+	err = hcsImportLayer(layerPath, sourceFolderPath, string(bytes))
36
+	if err != nil {
37
+		return errors.Wrap(err, "failed to import layer")
38
+	}
39
+	return nil
40
+}
0 41
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+
6
+	"github.com/Microsoft/hcsshim/internal/oc"
7
+	"github.com/pkg/errors"
8
+	"go.opencensus.io/trace"
9
+)
10
+
11
+// InitializeWritableLayer initializes a writable layer for a container.
12
+//
13
+// `layerPath` is a path to a directory the layer is mounted. If the
14
+// path does not end in a `\` the platform will append it automatically.
15
+//
16
+// `layerData` is the parent read-only layer data.
17
+func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
18
+	title := "hcsshim.InitializeWritableLayer"
19
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
20
+	defer span.End()
21
+	defer func() { oc.SetSpanStatus(span, err) }()
22
+	span.AddAttributes(
23
+		trace.StringAttribute("layerPath", layerPath),
24
+	)
25
+
26
+	bytes, err := json.Marshal(layerData)
27
+	if err != nil {
28
+		return err
29
+	}
30
+
31
+	// Options are not used in the platform as of RS5
32
+	err = hcsInitializeWritableLayer(layerPath, string(bytes), "")
33
+	if err != nil {
34
+		return errors.Wrap(err, "failed to intitialize container layer")
35
+	}
36
+	return nil
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/Microsoft/hcsshim/internal/interop"
6
+	"github.com/Microsoft/hcsshim/internal/oc"
7
+	"github.com/pkg/errors"
8
+	"go.opencensus.io/trace"
9
+	"golang.org/x/sys/windows"
10
+)
11
+
12
+// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer.
13
+func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
14
+	title := "hcsshim.GetLayerVhdMountPath"
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16
+	defer span.End()
17
+	defer func() { oc.SetSpanStatus(span, err) }()
18
+
19
+	var mountPath *uint16
20
+	err = hcsGetLayerVhdMountPath(vhdHandle, &mountPath)
21
+	if err != nil {
22
+		return "", errors.Wrap(err, "failed to get vhd mount path")
23
+	}
24
+	path = interop.ConvertAndFreeCoTaskMemString(mountPath)
25
+	return path, nil
26
+}
0 27
new file mode 100644
... ...
@@ -0,0 +1,74 @@
0
+package computestorage
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+
6
+	"github.com/Microsoft/hcsshim/internal/oc"
7
+	"github.com/Microsoft/hcsshim/osversion"
8
+	"github.com/pkg/errors"
9
+	"go.opencensus.io/trace"
10
+	"golang.org/x/sys/windows"
11
+)
12
+
13
+// SetupBaseOSLayer sets up a layer that contains a base OS for a container.
14
+//
15
+// `layerPath` is a path to a directory containing the layer.
16
+//
17
+// `vhdHandle` is an empty file handle of `options.Type == OsLayerTypeContainer`
18
+// or else it is a file handle to the 'SystemTemplateBase.vhdx' if `options.Type
19
+// == OsLayerTypeVm`.
20
+//
21
+// `options` are the options applied while processing the layer.
22
+func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
23
+	title := "hcsshim.SetupBaseOSLayer"
24
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
25
+	defer span.End()
26
+	defer func() { oc.SetSpanStatus(span, err) }()
27
+	span.AddAttributes(
28
+		trace.StringAttribute("layerPath", layerPath),
29
+	)
30
+
31
+	bytes, err := json.Marshal(options)
32
+	if err != nil {
33
+		return err
34
+	}
35
+
36
+	err = hcsSetupBaseOSLayer(layerPath, vhdHandle, string(bytes))
37
+	if err != nil {
38
+		return errors.Wrap(err, "failed to setup base OS layer")
39
+	}
40
+	return nil
41
+}
42
+
43
+// SetupBaseOSVolume sets up a volume that contains a base OS for a container.
44
+//
45
+// `layerPath` is a path to a directory containing the layer.
46
+//
47
+// `volumePath` is the path to the volume to be used for setup.
48
+//
49
+// `options` are the options applied while processing the layer.
50
+func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
51
+	if osversion.Get().Build < 19645 {
52
+		return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
53
+	}
54
+	title := "hcsshim.SetupBaseOSVolume"
55
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
56
+	defer span.End()
57
+	defer func() { oc.SetSpanStatus(span, err) }()
58
+	span.AddAttributes(
59
+		trace.StringAttribute("layerPath", layerPath),
60
+		trace.StringAttribute("volumePath", volumePath),
61
+	)
62
+
63
+	bytes, err := json.Marshal(options)
64
+	if err != nil {
65
+		return err
66
+	}
67
+
68
+	err = hcsSetupBaseOSVolume(layerPath, volumePath, string(bytes))
69
+	if err != nil {
70
+		return errors.Wrap(err, "failed to setup base OS layer")
71
+	}
72
+	return nil
73
+}
0 74
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+// Package computestorage is a wrapper around the HCS storage APIs. These are new storage APIs introduced
1
+// separate from the original graphdriver calls intended to give more freedom around creating
2
+// and managing container layers and scratch spaces.
3
+package computestorage
4
+
5
+import (
6
+	hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
7
+)
8
+
9
+//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go storage.go
10
+
11
+//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer?
12
+//sys hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
13
+//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestoryLayer?
14
+//sys hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) = computestorage.HcsSetupBaseOSLayer?
15
+//sys hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
16
+//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter?
17
+//sys hcsDetachLayerStorageFilter(layerPath string) (hr error) = computestorage.HcsDetachLayerStorageFilter?
18
+//sys hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
19
+//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
20
+//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
21
+
22
+// LayerData is the data used to describe parent layer information.
23
+type LayerData struct {
24
+	SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"`
25
+	Layers        []hcsschema.Layer `json:"Layers,omitempty"`
26
+}
27
+
28
+// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.
29
+type ExportLayerOptions struct {
30
+	IsWritableLayer bool `json:"IsWritableLayer,omitempty"`
31
+}
32
+
33
+// OsLayerType is the type of layer being operated on.
34
+type OsLayerType string
35
+
36
+const (
37
+	// OsLayerTypeContainer is a container layer.
38
+	OsLayerTypeContainer OsLayerType = "Container"
39
+	// OsLayerTypeVM is a virtual machine layer.
40
+	OsLayerTypeVM OsLayerType = "Vm"
41
+)
42
+
43
+// OsLayerOptions are the set of options that are used with the `SetupBaseOSLayer` and
44
+// `SetupBaseOSVolume` calls.
45
+type OsLayerOptions struct {
46
+	Type                       OsLayerType `json:"Type,omitempty"`
47
+	DisableCiCacheOptimization bool        `json:"DisableCiCacheOptimization,omitempty"`
48
+	SkipUpdateBcdForBoot       bool        `json:"SkipUpdateBcdForBoot,omitempty"`
49
+}
0 50
new file mode 100644
... ...
@@ -0,0 +1,319 @@
0
+// Code generated mksyscall_windows.exe DO NOT EDIT
1
+
2
+package computestorage
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+
8
+	"golang.org/x/sys/windows"
9
+)
10
+
11
+var _ unsafe.Pointer
12
+
13
+// Do the interface allocations only once for common
14
+// Errno values.
15
+const (
16
+	errnoERROR_IO_PENDING = 997
17
+)
18
+
19
+var (
20
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
21
+)
22
+
23
+// errnoErr returns common boxed Errno values, to prevent
24
+// allocations at runtime.
25
+func errnoErr(e syscall.Errno) error {
26
+	switch e {
27
+	case 0:
28
+		return nil
29
+	case errnoERROR_IO_PENDING:
30
+		return errERROR_IO_PENDING
31
+	}
32
+	// TODO: add more here, after collecting data on the common
33
+	// error values see on Windows. (perhaps when running
34
+	// all.bat?)
35
+	return e
36
+}
37
+
38
+var (
39
+	modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
40
+
41
+	procHcsImportLayer              = modcomputestorage.NewProc("HcsImportLayer")
42
+	procHcsExportLayer              = modcomputestorage.NewProc("HcsExportLayer")
43
+	procHcsDestoryLayer             = modcomputestorage.NewProc("HcsDestoryLayer")
44
+	procHcsSetupBaseOSLayer         = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
45
+	procHcsInitializeWritableLayer  = modcomputestorage.NewProc("HcsInitializeWritableLayer")
46
+	procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
47
+	procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
48
+	procHcsFormatWritableLayerVhd   = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
49
+	procHcsGetLayerVhdMountPath     = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
50
+	procHcsSetupBaseOSVolume        = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
51
+)
52
+
53
+func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
54
+	var _p0 *uint16
55
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
56
+	if hr != nil {
57
+		return
58
+	}
59
+	var _p1 *uint16
60
+	_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
61
+	if hr != nil {
62
+		return
63
+	}
64
+	var _p2 *uint16
65
+	_p2, hr = syscall.UTF16PtrFromString(layerData)
66
+	if hr != nil {
67
+		return
68
+	}
69
+	return _hcsImportLayer(_p0, _p1, _p2)
70
+}
71
+
72
+func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
73
+	if hr = procHcsImportLayer.Find(); hr != nil {
74
+		return
75
+	}
76
+	r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
77
+	if int32(r0) < 0 {
78
+		if r0&0x1fff0000 == 0x00070000 {
79
+			r0 &= 0xffff
80
+		}
81
+		hr = syscall.Errno(r0)
82
+	}
83
+	return
84
+}
85
+
86
+func hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) {
87
+	var _p0 *uint16
88
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
89
+	if hr != nil {
90
+		return
91
+	}
92
+	var _p1 *uint16
93
+	_p1, hr = syscall.UTF16PtrFromString(exportFolderPath)
94
+	if hr != nil {
95
+		return
96
+	}
97
+	var _p2 *uint16
98
+	_p2, hr = syscall.UTF16PtrFromString(layerData)
99
+	if hr != nil {
100
+		return
101
+	}
102
+	var _p3 *uint16
103
+	_p3, hr = syscall.UTF16PtrFromString(options)
104
+	if hr != nil {
105
+		return
106
+	}
107
+	return _hcsExportLayer(_p0, _p1, _p2, _p3)
108
+}
109
+
110
+func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
111
+	if hr = procHcsExportLayer.Find(); hr != nil {
112
+		return
113
+	}
114
+	r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
115
+	if int32(r0) < 0 {
116
+		if r0&0x1fff0000 == 0x00070000 {
117
+			r0 &= 0xffff
118
+		}
119
+		hr = syscall.Errno(r0)
120
+	}
121
+	return
122
+}
123
+
124
+func hcsDestroyLayer(layerPath string) (hr error) {
125
+	var _p0 *uint16
126
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
127
+	if hr != nil {
128
+		return
129
+	}
130
+	return _hcsDestroyLayer(_p0)
131
+}
132
+
133
+func _hcsDestroyLayer(layerPath *uint16) (hr error) {
134
+	if hr = procHcsDestoryLayer.Find(); hr != nil {
135
+		return
136
+	}
137
+	r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
138
+	if int32(r0) < 0 {
139
+		if r0&0x1fff0000 == 0x00070000 {
140
+			r0 &= 0xffff
141
+		}
142
+		hr = syscall.Errno(r0)
143
+	}
144
+	return
145
+}
146
+
147
+func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
148
+	var _p0 *uint16
149
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
150
+	if hr != nil {
151
+		return
152
+	}
153
+	var _p1 *uint16
154
+	_p1, hr = syscall.UTF16PtrFromString(options)
155
+	if hr != nil {
156
+		return
157
+	}
158
+	return _hcsSetupBaseOSLayer(_p0, handle, _p1)
159
+}
160
+
161
+func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
162
+	if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
163
+		return
164
+	}
165
+	r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
166
+	if int32(r0) < 0 {
167
+		if r0&0x1fff0000 == 0x00070000 {
168
+			r0 &= 0xffff
169
+		}
170
+		hr = syscall.Errno(r0)
171
+	}
172
+	return
173
+}
174
+
175
+func hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) {
176
+	var _p0 *uint16
177
+	_p0, hr = syscall.UTF16PtrFromString(writableLayerPath)
178
+	if hr != nil {
179
+		return
180
+	}
181
+	var _p1 *uint16
182
+	_p1, hr = syscall.UTF16PtrFromString(layerData)
183
+	if hr != nil {
184
+		return
185
+	}
186
+	var _p2 *uint16
187
+	_p2, hr = syscall.UTF16PtrFromString(options)
188
+	if hr != nil {
189
+		return
190
+	}
191
+	return _hcsInitializeWritableLayer(_p0, _p1, _p2)
192
+}
193
+
194
+func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
195
+	if hr = procHcsInitializeWritableLayer.Find(); hr != nil {
196
+		return
197
+	}
198
+	r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
199
+	if int32(r0) < 0 {
200
+		if r0&0x1fff0000 == 0x00070000 {
201
+			r0 &= 0xffff
202
+		}
203
+		hr = syscall.Errno(r0)
204
+	}
205
+	return
206
+}
207
+
208
+func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
209
+	var _p0 *uint16
210
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
211
+	if hr != nil {
212
+		return
213
+	}
214
+	var _p1 *uint16
215
+	_p1, hr = syscall.UTF16PtrFromString(layerData)
216
+	if hr != nil {
217
+		return
218
+	}
219
+	return _hcsAttachLayerStorageFilter(_p0, _p1)
220
+}
221
+
222
+func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
223
+	if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil {
224
+		return
225
+	}
226
+	r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0)
227
+	if int32(r0) < 0 {
228
+		if r0&0x1fff0000 == 0x00070000 {
229
+			r0 &= 0xffff
230
+		}
231
+		hr = syscall.Errno(r0)
232
+	}
233
+	return
234
+}
235
+
236
+func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
237
+	var _p0 *uint16
238
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
239
+	if hr != nil {
240
+		return
241
+	}
242
+	return _hcsDetachLayerStorageFilter(_p0)
243
+}
244
+
245
+func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
246
+	if hr = procHcsDetachLayerStorageFilter.Find(); hr != nil {
247
+		return
248
+	}
249
+	r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
250
+	if int32(r0) < 0 {
251
+		if r0&0x1fff0000 == 0x00070000 {
252
+			r0 &= 0xffff
253
+		}
254
+		hr = syscall.Errno(r0)
255
+	}
256
+	return
257
+}
258
+
259
+func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
260
+	if hr = procHcsFormatWritableLayerVhd.Find(); hr != nil {
261
+		return
262
+	}
263
+	r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
264
+	if int32(r0) < 0 {
265
+		if r0&0x1fff0000 == 0x00070000 {
266
+			r0 &= 0xffff
267
+		}
268
+		hr = syscall.Errno(r0)
269
+	}
270
+	return
271
+}
272
+
273
+func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
274
+	if hr = procHcsGetLayerVhdMountPath.Find(); hr != nil {
275
+		return
276
+	}
277
+	r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
278
+	if int32(r0) < 0 {
279
+		if r0&0x1fff0000 == 0x00070000 {
280
+			r0 &= 0xffff
281
+		}
282
+		hr = syscall.Errno(r0)
283
+	}
284
+	return
285
+}
286
+
287
+func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) {
288
+	var _p0 *uint16
289
+	_p0, hr = syscall.UTF16PtrFromString(layerPath)
290
+	if hr != nil {
291
+		return
292
+	}
293
+	var _p1 *uint16
294
+	_p1, hr = syscall.UTF16PtrFromString(volumePath)
295
+	if hr != nil {
296
+		return
297
+	}
298
+	var _p2 *uint16
299
+	_p2, hr = syscall.UTF16PtrFromString(options)
300
+	if hr != nil {
301
+		return
302
+	}
303
+	return _hcsSetupBaseOSVolume(_p0, _p1, _p2)
304
+}
305
+
306
+func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
307
+	if hr = procHcsSetupBaseOSVolume.Find(); hr != nil {
308
+		return
309
+	}
310
+	r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
311
+	if int32(r0) < 0 {
312
+		if r0&0x1fff0000 == 0x00070000 {
313
+			r0 &= 0xffff
314
+		}
315
+		hr = syscall.Errno(r0)
316
+	}
317
+	return
318
+}
... ...
@@ -83,7 +83,6 @@ type NetworkNotFoundError = hns.NetworkNotFoundError
83 83
 type ProcessError struct {
84 84
 	Process   *process
85 85
 	Operation string
86
-	ExtraInfo string
87 86
 	Err       error
88 87
 	Events    []hcs.ErrorEvent
89 88
 }
... ...
@@ -92,7 +91,6 @@ type ProcessError struct {
92 92
 type ContainerError struct {
93 93
 	Container *container
94 94
 	Operation string
95
-	ExtraInfo string
96 95
 	Err       error
97 96
 	Events    []hcs.ErrorEvent
98 97
 }
... ...
@@ -125,22 +123,9 @@ func (e *ContainerError) Error() string {
125 125
 		s += "\n" + ev.String()
126 126
 	}
127 127
 
128
-	if e.ExtraInfo != "" {
129
-		s += " extra info: " + e.ExtraInfo
130
-	}
131
-
132 128
 	return s
133 129
 }
134 130
 
135
-func makeContainerError(container *container, operation string, extraInfo string, err error) error {
136
-	// Don't double wrap errors
137
-	if _, ok := err.(*ContainerError); ok {
138
-		return err
139
-	}
140
-	containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
141
-	return containerError
142
-}
143
-
144 131
 func (e *ProcessError) Error() string {
145 132
 	if e == nil {
146 133
 		return "<nil>"
... ...
@@ -171,15 +156,6 @@ func (e *ProcessError) Error() string {
171 171
 	return s
172 172
 }
173 173
 
174
-func makeProcessError(process *process, operation string, extraInfo string, err error) error {
175
-	// Don't double wrap errors
176
-	if _, ok := err.(*ProcessError); ok {
177
-		return err
178
-	}
179
-	processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
180
-	return processError
181
-}
182
-
183 174
 // IsNotExist checks if an error is caused by the Container or Process not existing.
184 175
 // Note: Currently, ErrElementNotFound can mean that a Process has either
185 176
 // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
... ...
@@ -230,6 +206,18 @@ func IsNotSupported(err error) bool {
230 230
 	return hcs.IsNotSupported(getInnerError(err))
231 231
 }
232 232
 
233
+// IsOperationInvalidState returns true when err is caused by
234
+// `ErrVmcomputeOperationInvalidState`.
235
+func IsOperationInvalidState(err error) bool {
236
+	return hcs.IsOperationInvalidState(getInnerError(err))
237
+}
238
+
239
+// IsAccessIsDenied returns true when err is caused by
240
+// `ErrVmcomputeOperationAccessIsDenied`.
241
+func IsAccessIsDenied(err error) bool {
242
+	return hcs.IsAccessIsDenied(getInnerError(err))
243
+}
244
+
233 245
 func getInnerError(err error) error {
234 246
 	switch pe := err.(type) {
235 247
 	case nil:
... ...
@@ -244,7 +232,7 @@ func getInnerError(err error) error {
244 244
 
245 245
 func convertSystemError(err error, c *container) error {
246 246
 	if serr, ok := err.(*hcs.SystemError); ok {
247
-		return &ContainerError{Container: c, Operation: serr.Op, ExtraInfo: serr.Extra, Err: serr.Err, Events: serr.Events}
247
+		return &ContainerError{Container: c, Operation: serr.Op, Err: serr.Err, Events: serr.Events}
248 248
 	}
249 249
 	return err
250 250
 }
... ...
@@ -514,6 +514,45 @@ func (w *Writer) lookup(name string, mustExist bool) (*inode, *inode, string, er
514 514
 	return dir, child, childname, nil
515 515
 }
516 516
 
517
+// CreateWithParents adds a file to the file system creating the parent directories in the path if
518
+// they don't exist (like `mkdir -p`). These non existing parent directories are created
519
+// with the same permissions as that of it's parent directory. It is expected that the a
520
+// call to make these parent directories will be made at a later point with the correct
521
+// permissions, at that time the permissions of these directories will be updated.
522
+func (w *Writer) CreateWithParents(name string, f *File) error {
523
+	// go through the directories in the path one by one and create the
524
+	// parent directories if they don't exist.
525
+	cleanname := path.Clean("/" + name)[1:]
526
+	parentDirs, _ := path.Split(cleanname)
527
+	currentPath := ""
528
+	root := w.root()
529
+	dirname := ""
530
+	for parentDirs != "" {
531
+		dirname, parentDirs = splitFirst(parentDirs)
532
+		currentPath += "/" + dirname
533
+		if _, ok := root.Children[dirname]; !ok {
534
+			f := &File{
535
+				Mode:     root.Mode,
536
+				Atime:    time.Now(),
537
+				Mtime:    time.Now(),
538
+				Ctime:    time.Now(),
539
+				Crtime:   time.Now(),
540
+				Size:     0,
541
+				Uid:      root.Uid,
542
+				Gid:      root.Gid,
543
+				Devmajor: root.Devmajor,
544
+				Devminor: root.Devminor,
545
+				Xattrs:   make(map[string][]byte),
546
+			}
547
+			if err := w.Create(currentPath, f); err != nil {
548
+				return fmt.Errorf("failed while creating parent directories: %w", err)
549
+			}
550
+		}
551
+		root = root.Children[dirname]
552
+	}
553
+	return w.Create(name, f)
554
+}
555
+
517 556
 // Create adds a file to the file system.
518 557
 func (w *Writer) Create(name string, f *File) error {
519 558
 	if err := w.finishInode(); err != nil {
... ...
@@ -693,7 +732,7 @@ func (w *Writer) seekBlock(block uint32) {
693 693
 func (w *Writer) nextBlock() {
694 694
 	if w.pos%blockSize != 0 {
695 695
 		// Simplify callers; w.err is updated on failure.
696
-		w.zero(blockSize - w.pos%blockSize)
696
+		_, _ = w.zero(blockSize - w.pos%blockSize)
697 697
 	}
698 698
 }
699 699
 
... ...
@@ -743,7 +782,7 @@ func (w *Writer) writeExtents(inode *inode) error {
743 743
 			extents [4]format.ExtentLeafNode
744 744
 		}
745 745
 		fillExtents(&root.hdr, root.extents[:extents], startBlock, 0, blocks)
746
-		binary.Write(&b, binary.LittleEndian, root)
746
+		_ = binary.Write(&b, binary.LittleEndian, root)
747 747
 	} else if extents <= 4*extentsPerBlock {
748 748
 		const extentsPerBlock = blockSize/extentNodeSize - 1
749 749
 		extentBlocks := extents/extentsPerBlock + 1
... ...
@@ -778,12 +817,12 @@ func (w *Writer) writeExtents(inode *inode) error {
778 778
 
779 779
 			offset := i * extentsPerBlock * maxBlocksPerExtent
780 780
 			fillExtents(&node.hdr, node.extents[:extentsInBlock], startBlock+offset, offset, blocks)
781
-			binary.Write(&b2, binary.LittleEndian, node)
781
+			_ = binary.Write(&b2, binary.LittleEndian, node)
782 782
 			if _, err := w.write(b2.Next(blockSize)); err != nil {
783 783
 				return err
784 784
 			}
785 785
 		}
786
-		binary.Write(&b, binary.LittleEndian, root)
786
+		_ = binary.Write(&b, binary.LittleEndian, root)
787 787
 	} else {
788 788
 		panic("file too big")
789 789
 	}
... ...
@@ -924,7 +963,13 @@ func (w *Writer) writeDirectory(dir, parent *inode) error {
924 924
 		children = append(children, name)
925 925
 	}
926 926
 	sort.Slice(children, func(i, j int) bool {
927
-		return dir.Children[children[i]].Number < dir.Children[children[j]].Number
927
+		left_num := dir.Children[children[i]].Number
928
+		right_num := dir.Children[children[j]].Number
929
+
930
+		if left_num == right_num {
931
+			return children[i] < children[j]
932
+		}
933
+		return left_num < right_num
928 934
 	})
929 935
 
930 936
 	for _, name := range children {
... ...
@@ -945,7 +990,24 @@ func (w *Writer) writeDirectoryRecursive(dir, parent *inode) error {
945 945
 	if err := w.writeDirectory(dir, parent); err != nil {
946 946
 		return err
947 947
 	}
948
-	for _, child := range dir.Children {
948
+
949
+	// Follow e2fsck's convention and sort the children by inode number.
950
+	var children []string
951
+	for name := range dir.Children {
952
+		children = append(children, name)
953
+	}
954
+	sort.Slice(children, func(i, j int) bool {
955
+		left_num := dir.Children[children[i]].Number
956
+		right_num := dir.Children[children[j]].Number
957
+
958
+		if left_num == right_num {
959
+			return children[i] < children[j]
960
+		}
961
+		return left_num < right_num
962
+	})
963
+
964
+	for _, name := range children {
965
+		child := dir.Children[name]
949 966
 		if child.IsDir() {
950 967
 			if err := w.writeDirectoryRecursive(child, dir); err != nil {
951 968
 				return err
... ...
@@ -998,12 +1060,12 @@ func (w *Writer) writeInodeTable(tableSize uint32) error {
998 998
 				binary.LittleEndian.PutUint32(binode.Block[4:], dev)
999 999
 			}
1000 1000
 
1001
-			binary.Write(&b, binary.LittleEndian, binode)
1001
+			_ = binary.Write(&b, binary.LittleEndian, binode)
1002 1002
 			b.Truncate(inodeUsedSize)
1003 1003
 			n, _ := b.Write(inode.XattrInline)
1004
-			io.CopyN(&b, zero, int64(inodeExtraSize-n))
1004
+			_, _ = io.CopyN(&b, zero, int64(inodeExtraSize-n))
1005 1005
 		} else {
1006
-			io.CopyN(&b, zero, inodeSize)
1006
+			_, _ = io.CopyN(&b, zero, inodeSize)
1007 1007
 		}
1008 1008
 		if _, err := w.write(b.Next(inodeSize)); err != nil {
1009 1009
 			return err
... ...
@@ -1136,7 +1198,7 @@ func (w *Writer) Close() error {
1136 1136
 		diskSize = minSize
1137 1137
 	}
1138 1138
 
1139
-	usedGdBlocks := (groups-1)/groupDescriptorSize + 1
1139
+	usedGdBlocks := (groups-1)/groupsPerDescriptorBlock + 1
1140 1140
 	if usedGdBlocks > w.gdBlocks {
1141 1141
 		return exceededMaxSizeError{w.maxDiskSize}
1142 1142
 	}
... ...
@@ -1253,7 +1315,7 @@ func (w *Writer) Close() error {
1253 1253
 	if w.supportInlineData {
1254 1254
 		sb.FeatureIncompat |= format.IncompatInlineData
1255 1255
 	}
1256
-	binary.Write(b, binary.LittleEndian, sb)
1256
+	_ = binary.Write(b, binary.LittleEndian, sb)
1257 1257
 	w.seekBlock(0)
1258 1258
 	if _, err := w.write(blk[:]); err != nil {
1259 1259
 		return err
... ...
@@ -5,10 +5,12 @@ import (
5 5
 	"bufio"
6 6
 	"encoding/binary"
7 7
 	"io"
8
+	"os"
8 9
 	"path"
9 10
 	"strings"
10 11
 
11 12
 	"github.com/Microsoft/hcsshim/ext4/internal/compactext4"
13
+	"github.com/Microsoft/hcsshim/ext4/internal/format"
12 14
 )
13 15
 
14 16
 type params struct {
... ...
@@ -146,7 +148,7 @@ func Convert(r io.Reader, w io.ReadWriteSeeker, options ...Option) error {
146 146
 			}
147 147
 			f.Mode &= ^compactext4.TypeMask
148 148
 			f.Mode |= typ
149
-			err = fs.Create(hdr.Name, f)
149
+			err = fs.CreateWithParents(hdr.Name, f)
150 150
 			if err != nil {
151 151
 				return err
152 152
 			}
... ...
@@ -172,3 +174,36 @@ func Convert(r io.Reader, w io.ReadWriteSeeker, options ...Option) error {
172 172
 	}
173 173
 	return nil
174 174
 }
175
+
176
+// ReadExt4SuperBlock reads and returns ext4 super block from VHD
177
+//
178
+// The layout on disk is as follows:
179
+// | Group 0 padding     | - 1024 bytes
180
+// | ext4 SuperBlock     | - 1 block
181
+// | Group Descriptors   | - many blocks
182
+// | Reserved GDT Blocks | - many blocks
183
+// | Data Block Bitmap   | - 1 block
184
+// | inode Bitmap        | - 1 block
185
+// | inode Table         | - many blocks
186
+// | Data Blocks         | - many blocks
187
+//
188
+// More details can be found here https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
189
+//
190
+// Our goal is to skip the Group 0 padding, read and return the ext4 SuperBlock
191
+func ReadExt4SuperBlock(vhdPath string) (*format.SuperBlock, error) {
192
+	vhd, err := os.OpenFile(vhdPath, os.O_RDONLY, 0)
193
+	if err != nil {
194
+		return nil, err
195
+	}
196
+	defer vhd.Close()
197
+
198
+	// Skip padding at the start
199
+	if _, err := vhd.Seek(1024, io.SeekStart); err != nil {
200
+		return nil, err
201
+	}
202
+	var sb format.SuperBlock
203
+	if err := binary.Read(vhd, binary.LittleEndian, &sb); err != nil {
204
+		return nil, err
205
+	}
206
+	return &sb, nil
207
+}
... ...
@@ -56,7 +56,7 @@ func calculateCheckSum(footer *vhdFooter) uint32 {
56 56
 	footer.Checksum = 0
57 57
 
58 58
 	buf := &bytes.Buffer{}
59
-	binary.Write(buf, binary.BigEndian, footer)
59
+	_ = binary.Write(buf, binary.BigEndian, footer)
60 60
 
61 61
 	var chk uint32
62 62
 	bufBytes := buf.Bytes()
... ...
@@ -3,33 +3,20 @@ module github.com/Microsoft/hcsshim
3 3
 go 1.13
4 4
 
5 5
 require (
6
-	github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab
7
-	github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59
8
-	github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1
9
-	github.com/containerd/containerd v1.3.2
10
-	github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
11
-	github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448 // indirect
12
-	github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3
13
-	github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de
14
-	github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd
15
-	github.com/gogo/protobuf v1.3.1
16
-	github.com/golang/protobuf v1.3.2 // indirect
17
-	github.com/kr/pretty v0.1.0 // indirect
18
-	github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2 // indirect
19
-	github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f // indirect
20
-	github.com/opencontainers/runtime-spec v1.0.2
6
+	github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3
7
+	github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68
8
+	github.com/containerd/console v1.0.1
9
+	github.com/containerd/containerd v1.5.0-beta.4
10
+	github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0
11
+	github.com/containerd/ttrpc v1.0.2
12
+	github.com/containerd/typeurl v1.0.1
13
+	github.com/gogo/protobuf v1.3.2
14
+	github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d
21 15
 	github.com/pkg/errors v0.9.1
22
-	github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7 // indirect
23
-	github.com/sirupsen/logrus v1.4.2
24
-	github.com/stretchr/testify v1.4.0 // indirect
16
+	github.com/sirupsen/logrus v1.7.0
25 17
 	github.com/urfave/cli v1.22.2
26
-	go.opencensus.io v0.22.0
27
-	golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect
28
-	golang.org/x/sync v0.0.0-20190423024810-112230192c58
29
-	golang.org/x/sys v0.0.0-20200120151820-655fe14d7479
30
-	google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 // indirect
31
-	google.golang.org/grpc v1.23.1
32
-	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
33
-	gopkg.in/yaml.v2 v2.2.8 // indirect
34
-	gotest.tools v2.2.0+incompatible // indirect
18
+	go.opencensus.io v0.22.3
19
+	golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
20
+	golang.org/x/sys v0.0.0-20210324051608-47abb6519492
21
+	google.golang.org/grpc v1.33.2
35 22
 )
... ...
@@ -40,6 +40,9 @@ func HNSListEndpointRequest() ([]HNSEndpoint, error) {
40 40
 // HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
41 41
 func HotAttachEndpoint(containerID string, endpointID string) error {
42 42
 	endpoint, err := GetHNSEndpointByID(endpointID)
43
+	if err != nil {
44
+		return err
45
+	}
43 46
 	isAttached, err := endpoint.IsAttached(containerID)
44 47
 	if isAttached {
45 48
 		return err
... ...
@@ -50,6 +53,9 @@ func HotAttachEndpoint(containerID string, endpointID string) error {
50 50
 // HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
51 51
 func HotDetachEndpoint(containerID string, endpointID string) error {
52 52
 	endpoint, err := GetHNSEndpointByID(endpointID)
53
+	if err != nil {
54
+		return err
55
+	}
53 56
 	isAttached, err := endpoint.IsAttached(containerID)
54 57
 	if !isAttached {
55 58
 		return err
... ...
@@ -80,4 +80,6 @@ type Container interface {
80 80
 	// container to be terminated by some error condition (including calling
81 81
 	// Close).
82 82
 	Wait() error
83
+	// Modify sends a request to modify container resources
84
+	Modify(ctx context.Context, config interface{}) error
83 85
 }
... ...
@@ -106,6 +106,7 @@ func newSystemChannels() notificationChannels {
106 106
 		hcsNotificationSystemStartCompleted,
107 107
 		hcsNotificationSystemPauseCompleted,
108 108
 		hcsNotificationSystemResumeCompleted,
109
+		hcsNotificationSystemSaveCompleted,
109 110
 	} {
110 111
 		channels[notif] = make(notificationChannel, 1)
111 112
 	}
... ...
@@ -171,7 +171,6 @@ type SystemError struct {
171 171
 	ID     string
172 172
 	Op     string
173 173
 	Err    error
174
-	Extra  string
175 174
 	Events []ErrorEvent
176 175
 }
177 176
 
... ...
@@ -182,9 +181,6 @@ func (e *SystemError) Error() string {
182 182
 	for _, ev := range e.Events {
183 183
 		s += "\n" + ev.String()
184 184
 	}
185
-	if e.Extra != "" {
186
-		s += "\n(extra info: " + e.Extra + ")"
187
-	}
188 185
 	return s
189 186
 }
190 187
 
... ...
@@ -198,7 +194,7 @@ func (e *SystemError) Timeout() bool {
198 198
 	return ok && err.Timeout()
199 199
 }
200 200
 
201
-func makeSystemError(system *System, op string, extra string, err error, events []ErrorEvent) error {
201
+func makeSystemError(system *System, op string, err error, events []ErrorEvent) error {
202 202
 	// Don't double wrap errors
203 203
 	if _, ok := err.(*SystemError); ok {
204 204
 		return err
... ...
@@ -206,7 +202,6 @@ func makeSystemError(system *System, op string, extra string, err error, events
206 206
 	return &SystemError{
207 207
 		ID:     system.ID(),
208 208
 		Op:     op,
209
-		Extra:  extra,
210 209
 		Err:    err,
211 210
 		Events: events,
212 211
 	}
... ...
@@ -312,6 +307,13 @@ func IsOperationInvalidState(err error) bool {
312 312
 	return err == ErrVmcomputeOperationInvalidState
313 313
 }
314 314
 
315
+// IsAccessIsDenied returns true when err is caused by
316
+// `ErrVmcomputeOperationAccessIsDenied`.
317
+func IsAccessIsDenied(err error) bool {
318
+	err = getInnerError(err)
319
+	return err == ErrVmcomputeOperationAccessIsDenied
320
+}
321
+
315 322
 func getInnerError(err error) error {
316 323
 	switch pe := err.(type) {
317 324
 	case nil:
... ...
@@ -325,12 +327,3 @@ func getInnerError(err error) error {
325 325
 	}
326 326
 	return err
327 327
 }
328
-
329
-func getOperationLogResult(err error) (string, error) {
330
-	switch err {
331
-	case nil:
332
-		return "Success", nil
333
-	default:
334
-		return "Error", err
335
-	}
336
-}
... ...
@@ -64,11 +64,7 @@ type processStatus struct {
64 64
 	LastWaitResult int32
65 65
 }
66 66
 
67
-const (
68
-	stdIn  string = "StdIn"
69
-	stdOut string = "StdOut"
70
-	stdErr string = "StdErr"
71
-)
67
+const stdIn string = "StdIn"
72 68
 
73 69
 const (
74 70
 	modifyConsoleSize string = "ConsoleSize"
... ...
@@ -176,8 +172,10 @@ func (process *Process) waitBackground() {
176 176
 		trace.Int64Attribute("pid", int64(process.processID)))
177 177
 
178 178
 	var (
179
-		err      error
180
-		exitCode = -1
179
+		err            error
180
+		exitCode       = -1
181
+		propertiesJSON string
182
+		resultJSON     string
181 183
 	)
182 184
 
183 185
 	err = waitForNotification(ctx, process.callbackNumber, hcsNotificationProcessExited, nil)
... ...
@@ -190,15 +188,15 @@ func (process *Process) waitBackground() {
190 190
 
191 191
 		// Make sure we didnt race with Close() here
192 192
 		if process.handle != 0 {
193
-			propertiesJSON, resultJSON, err := vmcompute.HcsGetProcessProperties(ctx, process.handle)
193
+			propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle)
194 194
 			events := processHcsResult(ctx, resultJSON)
195 195
 			if err != nil {
196
-				err = makeProcessError(process, operation, err, events)
196
+				err = makeProcessError(process, operation, err, events) //nolint:ineffassign
197 197
 			} else {
198 198
 				properties := &processStatus{}
199 199
 				err = json.Unmarshal([]byte(propertiesJSON), properties)
200 200
 				if err != nil {
201
-					err = makeProcessError(process, operation, err, nil)
201
+					err = makeProcessError(process, operation, err, nil) //nolint:ineffassign
202 202
 				} else {
203 203
 					if properties.LastWaitResult != 0 {
204 204
 						log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result")
... ...
@@ -468,7 +466,7 @@ func (process *Process) unregisterCallback(ctx context.Context) error {
468 468
 	delete(callbackMap, callbackNumber)
469 469
 	callbackMapLock.Unlock()
470 470
 
471
-	handle = 0
471
+	handle = 0 //nolint:ineffassign
472 472
 
473 473
 	return nil
474 474
 }
475 475
deleted file mode 100644
... ...
@@ -1,5 +0,0 @@
1
-package hcs
2
-
3
-//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go syscall.go
4
-
5
-//sys hcsFormatWritableLayerVhd(handle uintptr) (hr error) = computestorage.HcsFormatWritableLayerVhd
... ...
@@ -73,8 +73,8 @@ func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface in
73 73
 		if err = computeSystem.registerCallback(ctx); err != nil {
74 74
 			// Terminate the compute system if it still exists. We're okay to
75 75
 			// ignore a failure here.
76
-			computeSystem.Terminate(ctx)
77
-			return nil, makeSystemError(computeSystem, operation, "", err, nil)
76
+			_ = computeSystem.Terminate(ctx)
77
+			return nil, makeSystemError(computeSystem, operation, err, nil)
78 78
 		}
79 79
 	}
80 80
 
... ...
@@ -83,9 +83,9 @@ func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface in
83 83
 		if err == ErrTimeout {
84 84
 			// Terminate the compute system if it still exists. We're okay to
85 85
 			// ignore a failure here.
86
-			computeSystem.Terminate(ctx)
86
+			_ = computeSystem.Terminate(ctx)
87 87
 		}
88
-		return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events)
88
+		return nil, makeSystemError(computeSystem, operation, err, events)
89 89
 	}
90 90
 	go computeSystem.waitBackground()
91 91
 	if err = computeSystem.getCachedProperties(ctx); err != nil {
... ...
@@ -102,7 +102,7 @@ func OpenComputeSystem(ctx context.Context, id string) (*System, error) {
102 102
 	handle, resultJSON, err := vmcompute.HcsOpenComputeSystem(ctx, id)
103 103
 	events := processHcsResult(ctx, resultJSON)
104 104
 	if err != nil {
105
-		return nil, makeSystemError(computeSystem, operation, "", err, events)
105
+		return nil, makeSystemError(computeSystem, operation, err, events)
106 106
 	}
107 107
 	computeSystem.handle = handle
108 108
 	defer func() {
... ...
@@ -111,7 +111,7 @@ func OpenComputeSystem(ctx context.Context, id string) (*System, error) {
111 111
 		}
112 112
 	}()
113 113
 	if err = computeSystem.registerCallback(ctx); err != nil {
114
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
114
+		return nil, makeSystemError(computeSystem, operation, err, nil)
115 115
 	}
116 116
 	go computeSystem.waitBackground()
117 117
 	if err = computeSystem.getCachedProperties(ctx); err != nil {
... ...
@@ -187,13 +187,13 @@ func (computeSystem *System) Start(ctx context.Context) (err error) {
187 187
 	defer computeSystem.handleLock.RUnlock()
188 188
 
189 189
 	if computeSystem.handle == 0 {
190
-		return makeSystemError(computeSystem, operation, "", ErrAlreadyClosed, nil)
190
+		return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
191 191
 	}
192 192
 
193 193
 	resultJSON, err := vmcompute.HcsStartComputeSystem(ctx, computeSystem.handle, "")
194 194
 	events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart)
195 195
 	if err != nil {
196
-		return makeSystemError(computeSystem, operation, "", err, events)
196
+		return makeSystemError(computeSystem, operation, err, events)
197 197
 	}
198 198
 
199 199
 	return nil
... ...
@@ -220,7 +220,7 @@ func (computeSystem *System) Shutdown(ctx context.Context) error {
220 220
 	switch err {
221 221
 	case nil, ErrVmcomputeAlreadyStopped, ErrComputeSystemDoesNotExist, ErrVmcomputeOperationPending:
222 222
 	default:
223
-		return makeSystemError(computeSystem, operation, "", err, events)
223
+		return makeSystemError(computeSystem, operation, err, events)
224 224
 	}
225 225
 	return nil
226 226
 }
... ...
@@ -241,7 +241,7 @@ func (computeSystem *System) Terminate(ctx context.Context) error {
241 241
 	switch err {
242 242
 	case nil, ErrVmcomputeAlreadyStopped, ErrComputeSystemDoesNotExist, ErrVmcomputeOperationPending:
243 243
 	default:
244
-		return makeSystemError(computeSystem, operation, "", err, events)
244
+		return makeSystemError(computeSystem, operation, err, events)
245 245
 	}
246 246
 	return nil
247 247
 }
... ...
@@ -263,10 +263,10 @@ func (computeSystem *System) waitBackground() {
263 263
 		log.G(ctx).Debug("system exited")
264 264
 	case ErrVmcomputeUnexpectedExit:
265 265
 		log.G(ctx).Debug("unexpected system exit")
266
-		computeSystem.exitError = makeSystemError(computeSystem, operation, "", err, nil)
266
+		computeSystem.exitError = makeSystemError(computeSystem, operation, err, nil)
267 267
 		err = nil
268 268
 	default:
269
-		err = makeSystemError(computeSystem, operation, "", err, nil)
269
+		err = makeSystemError(computeSystem, operation, err, nil)
270 270
 	}
271 271
 	computeSystem.closedWaitOnce.Do(func() {
272 272
 		computeSystem.waitError = err
... ...
@@ -304,13 +304,13 @@ func (computeSystem *System) Properties(ctx context.Context, types ...schema1.Pr
304 304
 
305 305
 	queryBytes, err := json.Marshal(schema1.PropertyQuery{PropertyTypes: types})
306 306
 	if err != nil {
307
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
307
+		return nil, makeSystemError(computeSystem, operation, err, nil)
308 308
 	}
309 309
 
310 310
 	propertiesJSON, resultJSON, err := vmcompute.HcsGetComputeSystemProperties(ctx, computeSystem.handle, string(queryBytes))
311 311
 	events := processHcsResult(ctx, resultJSON)
312 312
 	if err != nil {
313
-		return nil, makeSystemError(computeSystem, operation, "", err, events)
313
+		return nil, makeSystemError(computeSystem, operation, err, events)
314 314
 	}
315 315
 
316 316
 	if propertiesJSON == "" {
... ...
@@ -318,7 +318,7 @@ func (computeSystem *System) Properties(ctx context.Context, types ...schema1.Pr
318 318
 	}
319 319
 	properties := &schema1.ContainerProperties{}
320 320
 	if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
321
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
321
+		return nil, makeSystemError(computeSystem, operation, err, nil)
322 322
 	}
323 323
 
324 324
 	return properties, nil
... ...
@@ -333,13 +333,13 @@ func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschem
333 333
 
334 334
 	queryBytes, err := json.Marshal(hcsschema.PropertyQuery{PropertyTypes: types})
335 335
 	if err != nil {
336
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
336
+		return nil, makeSystemError(computeSystem, operation, err, nil)
337 337
 	}
338 338
 
339 339
 	propertiesJSON, resultJSON, err := vmcompute.HcsGetComputeSystemProperties(ctx, computeSystem.handle, string(queryBytes))
340 340
 	events := processHcsResult(ctx, resultJSON)
341 341
 	if err != nil {
342
-		return nil, makeSystemError(computeSystem, operation, "", err, events)
342
+		return nil, makeSystemError(computeSystem, operation, err, events)
343 343
 	}
344 344
 
345 345
 	if propertiesJSON == "" {
... ...
@@ -347,7 +347,7 @@ func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschem
347 347
 	}
348 348
 	properties := &hcsschema.Properties{}
349 349
 	if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
350
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
350
+		return nil, makeSystemError(computeSystem, operation, err, nil)
351 351
 	}
352 352
 
353 353
 	return properties, nil
... ...
@@ -368,13 +368,13 @@ func (computeSystem *System) Pause(ctx context.Context) (err error) {
368 368
 	defer computeSystem.handleLock.RUnlock()
369 369
 
370 370
 	if computeSystem.handle == 0 {
371
-		return makeSystemError(computeSystem, operation, "", ErrAlreadyClosed, nil)
371
+		return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
372 372
 	}
373 373
 
374 374
 	resultJSON, err := vmcompute.HcsPauseComputeSystem(ctx, computeSystem.handle, "")
375 375
 	events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause)
376 376
 	if err != nil {
377
-		return makeSystemError(computeSystem, operation, "", err, events)
377
+		return makeSystemError(computeSystem, operation, err, events)
378 378
 	}
379 379
 
380 380
 	return nil
... ...
@@ -395,13 +395,45 @@ func (computeSystem *System) Resume(ctx context.Context) (err error) {
395 395
 	defer computeSystem.handleLock.RUnlock()
396 396
 
397 397
 	if computeSystem.handle == 0 {
398
-		return makeSystemError(computeSystem, operation, "", ErrAlreadyClosed, nil)
398
+		return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
399 399
 	}
400 400
 
401 401
 	resultJSON, err := vmcompute.HcsResumeComputeSystem(ctx, computeSystem.handle, "")
402 402
 	events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume)
403 403
 	if err != nil {
404
-		return makeSystemError(computeSystem, operation, "", err, events)
404
+		return makeSystemError(computeSystem, operation, err, events)
405
+	}
406
+
407
+	return nil
408
+}
409
+
410
+// Save the compute system
411
+func (computeSystem *System) Save(ctx context.Context, options interface{}) (err error) {
412
+	operation := "hcsshim::System::Save"
413
+
414
+	// hcsSaveComputeSystemContext is an async peration. Start the outer span
415
+	// here to measure the full save time.
416
+	ctx, span := trace.StartSpan(ctx, operation)
417
+	defer span.End()
418
+	defer func() { oc.SetSpanStatus(span, err) }()
419
+	span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
420
+
421
+	saveOptions, err := json.Marshal(options)
422
+	if err != nil {
423
+		return err
424
+	}
425
+
426
+	computeSystem.handleLock.RLock()
427
+	defer computeSystem.handleLock.RUnlock()
428
+
429
+	if computeSystem.handle == 0 {
430
+		return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
431
+	}
432
+
433
+	result, err := vmcompute.HcsSaveComputeSystem(ctx, computeSystem.handle, string(saveOptions))
434
+	events, err := processAsyncHcsResult(ctx, err, result, computeSystem.callbackNumber, hcsNotificationSystemSaveCompleted, &timeout.SystemSave)
435
+	if err != nil {
436
+		return makeSystemError(computeSystem, operation, err, events)
405 437
 	}
406 438
 
407 439
 	return nil
... ...
@@ -412,19 +444,19 @@ func (computeSystem *System) createProcess(ctx context.Context, operation string
412 412
 	defer computeSystem.handleLock.RUnlock()
413 413
 
414 414
 	if computeSystem.handle == 0 {
415
-		return nil, nil, makeSystemError(computeSystem, operation, "", ErrAlreadyClosed, nil)
415
+		return nil, nil, makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
416 416
 	}
417 417
 
418 418
 	configurationb, err := json.Marshal(c)
419 419
 	if err != nil {
420
-		return nil, nil, makeSystemError(computeSystem, operation, "", err, nil)
420
+		return nil, nil, makeSystemError(computeSystem, operation, err, nil)
421 421
 	}
422 422
 
423 423
 	configuration := string(configurationb)
424 424
 	processInfo, processHandle, resultJSON, err := vmcompute.HcsCreateProcess(ctx, computeSystem.handle, configuration)
425 425
 	events := processHcsResult(ctx, resultJSON)
426 426
 	if err != nil {
427
-		return nil, nil, makeSystemError(computeSystem, operation, configuration, err, events)
427
+		return nil, nil, makeSystemError(computeSystem, operation, err, events)
428 428
 	}
429 429
 
430 430
 	log.G(ctx).WithField("pid", processInfo.ProcessId).Debug("created process pid")
... ...
@@ -446,7 +478,7 @@ func (computeSystem *System) CreateProcess(ctx context.Context, c interface{}) (
446 446
 
447 447
 	pipes, err := makeOpenFiles([]syscall.Handle{processInfo.StdInput, processInfo.StdOutput, processInfo.StdError})
448 448
 	if err != nil {
449
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
449
+		return nil, makeSystemError(computeSystem, operation, err, nil)
450 450
 	}
451 451
 	process.stdin = pipes[0]
452 452
 	process.stdout = pipes[1]
... ...
@@ -454,7 +486,7 @@ func (computeSystem *System) CreateProcess(ctx context.Context, c interface{}) (
454 454
 	process.hasCachedStdio = true
455 455
 
456 456
 	if err = process.registerCallback(ctx); err != nil {
457
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
457
+		return nil, makeSystemError(computeSystem, operation, err, nil)
458 458
 	}
459 459
 	go process.waitBackground()
460 460
 
... ...
@@ -469,18 +501,18 @@ func (computeSystem *System) OpenProcess(ctx context.Context, pid int) (*Process
469 469
 	operation := "hcsshim::System::OpenProcess"
470 470
 
471 471
 	if computeSystem.handle == 0 {
472
-		return nil, makeSystemError(computeSystem, operation, "", ErrAlreadyClosed, nil)
472
+		return nil, makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
473 473
 	}
474 474
 
475 475
 	processHandle, resultJSON, err := vmcompute.HcsOpenProcess(ctx, computeSystem.handle, uint32(pid))
476 476
 	events := processHcsResult(ctx, resultJSON)
477 477
 	if err != nil {
478
-		return nil, makeSystemError(computeSystem, operation, "", err, events)
478
+		return nil, makeSystemError(computeSystem, operation, err, events)
479 479
 	}
480 480
 
481 481
 	process := newProcess(processHandle, pid, computeSystem)
482 482
 	if err = process.registerCallback(ctx); err != nil {
483
-		return nil, makeSystemError(computeSystem, operation, "", err, nil)
483
+		return nil, makeSystemError(computeSystem, operation, err, nil)
484 484
 	}
485 485
 	go process.waitBackground()
486 486
 
... ...
@@ -504,12 +536,12 @@ func (computeSystem *System) Close() (err error) {
504 504
 	}
505 505
 
506 506
 	if err = computeSystem.unregisterCallback(ctx); err != nil {
507
-		return makeSystemError(computeSystem, operation, "", err, nil)
507
+		return makeSystemError(computeSystem, operation, err, nil)
508 508
 	}
509 509
 
510 510
 	err = vmcompute.HcsCloseComputeSystem(ctx, computeSystem.handle)
511 511
 	if err != nil {
512
-		return makeSystemError(computeSystem, operation, "", err, nil)
512
+		return makeSystemError(computeSystem, operation, err, nil)
513 513
 	}
514 514
 
515 515
 	computeSystem.handle = 0
... ...
@@ -573,7 +605,7 @@ func (computeSystem *System) unregisterCallback(ctx context.Context) error {
573 573
 	delete(callbackMap, callbackNumber)
574 574
 	callbackMapLock.Unlock()
575 575
 
576
-	handle = 0
576
+	handle = 0 //nolint:ineffassign
577 577
 
578 578
 	return nil
579 579
 }
... ...
@@ -586,7 +618,7 @@ func (computeSystem *System) Modify(ctx context.Context, config interface{}) err
586 586
 	operation := "hcsshim::System::Modify"
587 587
 
588 588
 	if computeSystem.handle == 0 {
589
-		return makeSystemError(computeSystem, operation, "", ErrAlreadyClosed, nil)
589
+		return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
590 590
 	}
591 591
 
592 592
 	requestBytes, err := json.Marshal(config)
... ...
@@ -598,7 +630,7 @@ func (computeSystem *System) Modify(ctx context.Context, config interface{}) err
598 598
 	resultJSON, err := vmcompute.HcsModifyComputeSystem(ctx, computeSystem.handle, requestJSON)
599 599
 	events := processHcsResult(ctx, resultJSON)
600 600
 	if err != nil {
601
-		return makeSystemError(computeSystem, operation, requestJSON, err, events)
601
+		return makeSystemError(computeSystem, operation, err, events)
602 602
 	}
603 603
 
604 604
 	return nil
... ...
@@ -7,6 +7,7 @@ import (
7 7
 
8 8
 	"github.com/Microsoft/go-winio"
9 9
 	diskutil "github.com/Microsoft/go-winio/vhd"
10
+	"github.com/Microsoft/hcsshim/computestorage"
10 11
 	"github.com/pkg/errors"
11 12
 	"golang.org/x/sys/windows"
12 13
 )
... ...
@@ -36,7 +37,7 @@ func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
36 36
 	return fs, nil
37 37
 }
38 38
 
39
-// creates a VHD formatted with NTFS of size `sizeGB` at the given `vhdPath`.
39
+// CreateNTFSVHD creates a VHD formatted with NTFS of size `sizeGB` at the given `vhdPath`.
40 40
 func CreateNTFSVHD(ctx context.Context, vhdPath string, sizeGB uint32) (err error) {
41 41
 	if err := diskutil.CreateVhdx(vhdPath, sizeGB, 1); err != nil {
42 42
 		return errors.Wrap(err, "failed to create VHD")
... ...
@@ -53,7 +54,7 @@ func CreateNTFSVHD(ctx context.Context, vhdPath string, sizeGB uint32) (err erro
53 53
 		}
54 54
 	}()
55 55
 
56
-	if err := hcsFormatWritableLayerVhd(uintptr(vhd)); err != nil {
56
+	if err := computestorage.FormatWritableLayerVhd(ctx, windows.Handle(vhd)); err != nil {
57 57
 		return errors.Wrap(err, "failed to format VHD")
58 58
 	}
59 59
 
... ...
@@ -65,5 +65,4 @@ func waitForNotification(ctx context.Context, callbackNumber uintptr, expectedNo
65 65
 	case <-c:
66 66
 		return ErrTimeout
67 67
 	}
68
-	return nil
69 68
 }
70 69
deleted file mode 100644
... ...
@@ -1,54 +0,0 @@
1
-// Code generated mksyscall_windows.exe DO NOT EDIT
2
-
3
-package hcs
4
-
5
-import (
6
-	"syscall"
7
-	"unsafe"
8
-
9
-	"golang.org/x/sys/windows"
10
-)
11
-
12
-var _ unsafe.Pointer
13
-
14
-// Do the interface allocations only once for common
15
-// Errno values.
16
-const (
17
-	errnoERROR_IO_PENDING = 997
18
-)
19
-
20
-var (
21
-	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
22
-)
23
-
24
-// errnoErr returns common boxed Errno values, to prevent
25
-// allocations at runtime.
26
-func errnoErr(e syscall.Errno) error {
27
-	switch e {
28
-	case 0:
29
-		return nil
30
-	case errnoERROR_IO_PENDING:
31
-		return errERROR_IO_PENDING
32
-	}
33
-	// TODO: add more here, after collecting data on the common
34
-	// error values see on Windows. (perhaps when running
35
-	// all.bat?)
36
-	return e
37
-}
38
-
39
-var (
40
-	modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
41
-
42
-	procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
43
-)
44
-
45
-func hcsFormatWritableLayerVhd(handle uintptr) (hr error) {
46
-	r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
47
-	if int32(r0) < 0 {
48
-		if r0&0x1fff0000 == 0x00070000 {
49
-			r0 &= 0xffff
50
-		}
51
-		hr = syscall.Errno(r0)
52
-	}
53
-	return
54
-}
... ...
@@ -39,12 +39,6 @@ type HNSNetwork struct {
39 39
 	AutomaticDNS         bool              `json:",omitempty"`
40 40
 }
41 41
 
42
-type hnsNetworkResponse struct {
43
-	Success bool
44
-	Error   string
45
-	Output  HNSNetwork
46
-}
47
-
48 42
 type hnsResponse struct {
49 43
 	Success bool
50 44
 	Error   string
... ...
@@ -27,9 +27,10 @@ type namespaceResourceRequest struct {
27 27
 }
28 28
 
29 29
 type Namespace struct {
30
-	ID           string
31
-	IsDefault    bool                `json:",omitempty"`
32
-	ResourceList []NamespaceResource `json:",omitempty"`
30
+	ID            string
31
+	IsDefault     bool                `json:",omitempty"`
32
+	ResourceList  []NamespaceResource `json:",omitempty"`
33
+	CompartmentId uint32              `json:",omitempty"`
33 34
 }
34 35
 
35 36
 func issueNamespaceRequest(id *string, method, subpath string, request interface{}) (*Namespace, error) {
... ...
@@ -76,7 +76,7 @@ func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFl
76 76
 	}
77 77
 
78 78
 	oa.Length = unsafe.Sizeof(oa)
79
-	oa.ObjectName = uintptr(unsafe.Pointer(pathUnicode))
79
+	oa.ObjectName = pathUnicode
80 80
 	oa.RootDirectory = uintptr(root.Fd())
81 81
 	oa.Attributes = winapi.OBJ_DONT_REPARSE
82 82
 	status := winapi.NtCreateFile(
... ...
@@ -177,7 +177,7 @@ func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
177 177
 	linkinfo := (*winapi.FileLinkInformation)(unsafe.Pointer(linkinfoBuffer))
178 178
 	linkinfo.RootDirectory = parent.Fd()
179 179
 	linkinfo.FileNameLength = uint32(len(newbase16) * 2)
180
-	copy((*[32768]uint16)(unsafe.Pointer(&linkinfo.FileName[0]))[:], newbase16)
180
+	copy(winapi.Uint16BufferToSlice(&linkinfo.FileName[0], len(newbase16)), newbase16)
181 181
 
182 182
 	var iosb winapi.IOStatusBlock
183 183
 	status := winapi.NtSetInformationFile(
... ...
@@ -244,7 +244,7 @@ func RemoveRelative(path string, root *os.File) error {
244 244
 		err = deleteOnClose(f)
245 245
 		if err == syscall.ERROR_ACCESS_DENIED {
246 246
 			// Maybe the file is marked readonly. Clear the bit and retry.
247
-			clearReadOnly(f)
247
+			_ = clearReadOnly(f)
248 248
 			err = deleteOnClose(f)
249 249
 		}
250 250
 	}
... ...
@@ -119,9 +119,9 @@ type PropertyType string
119 119
 
120 120
 const (
121 121
 	PropertyTypeStatistics        PropertyType = "Statistics"        // V1 and V2
122
-	PropertyTypeProcessList                    = "ProcessList"       // V1 and V2
123
-	PropertyTypeMappedVirtualDisk              = "MappedVirtualDisk" // Not supported in V2 schema call
124
-	PropertyTypeGuestConnection                = "GuestConnection"   // V1 and V2. Nil return from HCS before RS5
122
+	PropertyTypeProcessList       PropertyType = "ProcessList"       // V1 and V2
123
+	PropertyTypeMappedVirtualDisk PropertyType = "MappedVirtualDisk" // Not supported in V2 schema call
124
+	PropertyTypeGuestConnection   PropertyType = "GuestConnection"   // V1 and V2. Nil return from HCS before RS5
125 125
 )
126 126
 
127 127
 type PropertyQuery struct {
... ...
@@ -218,6 +218,7 @@ type GuestDefinedCapabilities struct {
218 218
 	SignalProcessSupported        bool `json:",omitempty"`
219 219
 	DumpStacksSupported           bool `json:",omitempty"`
220 220
 	DeleteContainerStateSupported bool `json:",omitempty"`
221
+	UpdateContainerSupported      bool `json:",omitempty"`
221 222
 }
222 223
 
223 224
 // GuestConnectionInfo is the structure of an iterm return by a GuestConnection call on a utility VM
224 225
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+// CPU groups allow Hyper-V administrators to better manage and allocate the host's CPU resources across guest virtual machines
12
+type CpuGroup struct {
13
+	Id string `json:"Id,omitempty"`
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+type CpuGroupAffinity struct {
12
+	LogicalProcessorCount int32   `json:"LogicalProcessorCount,omitempty"`
13
+	LogicalProcessors     []int32 `json:"LogicalProcessors,omitempty"`
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+type CpuGroupConfig struct {
12
+	GroupId         string             `json:"GroupId,omitempty"`
13
+	Affinity        *CpuGroupAffinity  `json:"Affinity,omitempty"`
14
+	GroupProperties []CpuGroupProperty `json:"GroupProperties,omitempty"`
15
+	// Hypervisor CPU group IDs exposed to clients
16
+	HypervisorGroupId int32 `json:"HypervisorGroupId,omitempty"`
17
+}
0 18
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+// Structure used to return cpu groups for a Service property query
12
+type CpuGroupConfigurations struct {
13
+	CpuGroups []CpuGroupConfig `json:"CpuGroups,omitempty"`
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+type CPUGroupOperation string
12
+
13
+const (
14
+	CreateGroup CPUGroupOperation = "CreateGroup"
15
+	DeleteGroup CPUGroupOperation = "DeleteGroup"
16
+	SetProperty CPUGroupOperation = "SetProperty"
17
+)
0 18
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+type CpuGroupProperty struct {
12
+	PropertyCode  uint32 `json:"PropertyCode,omitempty"`
13
+	PropertyValue uint32 `json:"PropertyValue,omitempty"`
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+// Create group operation settings
12
+type CreateGroupOperation struct {
13
+	GroupId               string   `json:"GroupId,omitempty"`
14
+	LogicalProcessorCount uint32   `json:"LogicalProcessorCount,omitempty"`
15
+	LogicalProcessors     []uint32 `json:"LogicalProcessors,omitempty"`
16
+}
0 17
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+// Delete group operation settings
12
+type DeleteGroupOperation struct {
13
+	GroupId string `json:"GroupId,omitempty"`
14
+}
... ...
@@ -13,8 +13,8 @@ type DeviceType string
13 13
 
14 14
 const (
15 15
 	ClassGUID      DeviceType = "ClassGuid"
16
-	DeviceInstance            = "DeviceInstance"
17
-	GPUMirror                 = "GpuMirror"
16
+	DeviceInstance DeviceType = "DeviceInstance"
17
+	GPUMirror      DeviceType = "GpuMirror"
18 18
 )
19 19
 
20 20
 type Device struct {
21 21
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+// Structure used to request a service processor modification
12
+type HostProcessorModificationRequest struct {
13
+	Operation        CPUGroupOperation `json:"Operation,omitempty"`
14
+	OperationDetails interface{}       `json:"OperationDetails,omitempty"`
15
+}
... ...
@@ -19,4 +19,10 @@ type HvSocketServiceConfig struct {
19 19
 
20 20
 	//  If true, HvSocket will process wildcard binds for this service/system combination.  Wildcard binds are secured in the registry at  SOFTWARE/Microsoft/Windows NT/CurrentVersion/Virtualization/HvSocket/WildcardDescriptors
21 21
 	AllowWildcardBinds bool `json:"AllowWildcardBinds,omitempty"`
22
+
23
+	// Disabled controls whether the HvSocket service is accepting connection requests.
24
+	// This set to true will make the service refuse all incoming connections as well as cancel
25
+	// any connections already established. The service itself will still be active however
26
+	// and can be re-enabled at a future time.
27
+	Disabled bool `json:"Disabled,omitempty"`
22 28
 }
23 29
new file mode 100644
... ...
@@ -0,0 +1,42 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+type InterruptModerationName string
12
+
13
+// The valid interrupt moderation modes for I/O virtualization (IOV) offloading.
14
+const (
15
+	DefaultName  InterruptModerationName = "Default"
16
+	AdaptiveName InterruptModerationName = "Adaptive"
17
+	OffName      InterruptModerationName = "Off"
18
+	LowName      InterruptModerationName = "Low"
19
+	MediumName   InterruptModerationName = "Medium"
20
+	HighName     InterruptModerationName = "High"
21
+)
22
+
23
+type InterruptModerationValue uint32
24
+
25
+const (
26
+	DefaultValue InterruptModerationValue = iota
27
+	AdaptiveValue
28
+	OffValue
29
+	LowValue    InterruptModerationValue = 100
30
+	MediumValue InterruptModerationValue = 200
31
+	HighValue   InterruptModerationValue = 300
32
+)
33
+
34
+var InterruptModerationValueToName = map[InterruptModerationValue]InterruptModerationName{
35
+	DefaultValue:  DefaultName,
36
+	AdaptiveValue: AdaptiveName,
37
+	OffValue:      OffName,
38
+	LowValue:      LowName,
39
+	MediumValue:   MediumName,
40
+	HighValue:     HighName,
41
+}
0 42
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+type IovSettings struct {
12
+	// The weight assigned to this port for I/O virtualization (IOV) offloading.
13
+	// Setting this to 0 disables IOV offloading.
14
+	OffloadWeight *uint32 `json:"OffloadWeight,omitempty"`
15
+
16
+	// The number of queue pairs requested for this port for I/O virtualization (IOV) offloading.
17
+	QueuePairsRequested *uint32 `json:"QueuePairsRequested,omitempty"`
18
+
19
+	// The interrupt moderation mode for I/O virtualization (IOV) offloading.
20
+	InterruptModeration *InterruptModerationName `json:"InterruptModeration,omitempty"`
21
+}
... ...
@@ -11,8 +11,8 @@ package hcsschema
11 11
 
12 12
 type LogicalProcessor struct {
13 13
 	LpIndex     uint32 `json:"LpIndex,omitempty"`
14
-	NodeNumber  uint8  `json:"NodeNumber, omitempty"`
15
-	PackageId   uint32 `json:"PackageId, omitempty"`
16
-	CoreId      uint32 `json:"CoreId, omitempty"`
17
-	RootVpIndex int32  `json:"RootVpIndex, omitempty"`
14
+	NodeNumber  uint8  `json:"NodeNumber,omitempty"`
15
+	PackageId   uint32 `json:"PackageId,omitempty"`
16
+	CoreId      uint32 `json:"CoreId,omitempty"`
17
+	RootVpIndex int32  `json:"RootVpIndex,omitempty"`
18 18
 }
... ...
@@ -11,6 +11,7 @@ package hcsschema
11 11
 
12 12
 type NetworkAdapter struct {
13 13
 	EndpointId string `json:"EndpointId,omitempty"`
14
-
15 14
 	MacAddress string `json:"MacAddress,omitempty"`
15
+	// The I/O virtualization (IOV) offloading configuration.
16
+	IovSettings *IovSettings `json:"IovSettings,omitempty"`
16 17
 }
... ...
@@ -22,4 +22,5 @@ const (
22 22
 	PTGuestConnection             PropertyType = "GuestConnection"
23 23
 	PTICHeartbeatStatus           PropertyType = "ICHeartbeatStatus"
24 24
 	PTProcessorTopology           PropertyType = "ProcessorTopology"
25
+	PTCPUGroup                    PropertyType = "CpuGroup"
25 26
 )
26 27
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+/*
1
+ * HCS API
2
+ *
3
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
4
+ *
5
+ * API version: 2.4
6
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
7
+ */
8
+
9
+package hcsschema
10
+
11
+// ProcessorLimits is used when modifying processor scheduling limits of a virtual machine.
12
+type ProcessorLimits struct {
13
+	// Maximum amount of host CPU resources that the virtual machine can use.
14
+	Limit uint64 `json:"Limit,omitempty"`
15
+	// Value describing the relative priority of this virtual machine compared to other virtual machines.
16
+	Weight uint64 `json:"Weight,omitempty"`
17
+	// Minimum amount of host CPU resources that the virtual machine is guaranteed.
18
+	Reservation uint64 `json:"Reservation,omitempty"`
19
+	// Provides the target maximum CPU frequency, in MHz, for a virtual machine.
20
+	MaximumFrequencyMHz uint32 `json:"MaximumFrequencyMHz,omitempty"`
21
+}
... ...
@@ -29,6 +29,9 @@ var (
29 29
 	// SystemResume is the timeout for resuming a compute system
30 30
 	SystemResume time.Duration = defaultTimeout
31 31
 
32
+	// SystemSave is the timeout for saving a compute system
33
+	SystemSave time.Duration = defaultTimeout
34
+
32 35
 	// SyscallWatcher is the timeout before warning of a potential stuck platform syscall.
33 36
 	SyscallWatcher time.Duration = defaultTimeout
34 37
 
... ...
@@ -51,6 +54,7 @@ func init() {
51 51
 	SystemStart = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMSTART", SystemStart)
52 52
 	SystemPause = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMPAUSE", SystemPause)
53 53
 	SystemResume = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMRESUME", SystemResume)
54
+	SystemSave = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMSAVE", SystemSave)
54 55
 	SyscallWatcher = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSCALLWATCHER", SyscallWatcher)
55 56
 	Tar2VHD = durationFromEnvironment("HCSSHIM_TIMEOUT_TAR2VHD", Tar2VHD)
56 57
 	ExternalCommandToStart = durationFromEnvironment("HCSSHIM_TIMEOUT_EXTERNALCOMMANDSTART", ExternalCommandToStart)
... ...
@@ -29,6 +29,7 @@ import (
29 29
 //sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings?
30 30
 //sys hcsRegisterComputeSystemCallback(computeSystem HcsSystem, callback uintptr, context uintptr, callbackHandle *HcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
31 31
 //sys hcsUnregisterComputeSystemCallback(callbackHandle HcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
32
+//sys hcsSaveComputeSystem(computeSystem HcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsSaveComputeSystem?
32 33
 
33 34
 //sys hcsCreateProcess(computeSystem HcsSystem, processParameters string, processInformation *HcsProcessInformation, process *HcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess?
34 35
 //sys hcsOpenProcess(computeSystem HcsSystem, pid uint32, process *HcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess?
... ...
@@ -61,7 +62,7 @@ type HcsCallback syscall.Handle
61 61
 type HcsProcessInformation struct {
62 62
 	// ProcessId is the pid of the created process.
63 63
 	ProcessId uint32
64
-	reserved  uint32
64
+	reserved  uint32 //nolint:structcheck
65 65
 	// StdInput is the handle associated with the stdin of the process.
66 66
 	StdInput syscall.Handle
67 67
 	// StdOutput is the handle associated with the stdout of the process.
... ...
@@ -585,3 +586,25 @@ func HcsUnregisterProcessCallback(ctx gcontext.Context, callbackHandle HcsCallba
585 585
 		return hcsUnregisterProcessCallback(callbackHandle)
586 586
 	})
587 587
 }
588
+
589
+func HcsSaveComputeSystem(ctx gcontext.Context, computeSystem HcsSystem, options string) (result string, hr error) {
590
+	ctx, span := trace.StartSpan(ctx, "HcsSaveComputeSystem")
591
+	defer span.End()
592
+	defer func() {
593
+		if result != "" {
594
+			span.AddAttributes(trace.StringAttribute("result", result))
595
+		}
596
+		if hr != errVmcomputeOperationPending {
597
+			oc.SetSpanStatus(span, hr)
598
+		}
599
+	}()
600
+
601
+	return result, execute(ctx, timeout.SyscallWatcher, func() error {
602
+		var resultp *uint16
603
+		err := hcsSaveComputeSystem(computeSystem, options, &resultp)
604
+		if resultp != nil {
605
+			result = interop.ConvertAndFreeCoTaskMemString(resultp)
606
+		}
607
+		return err
608
+	})
609
+}
... ...
@@ -53,6 +53,7 @@ var (
53 53
 	procHcsModifyServiceSettings           = modvmcompute.NewProc("HcsModifyServiceSettings")
54 54
 	procHcsRegisterComputeSystemCallback   = modvmcompute.NewProc("HcsRegisterComputeSystemCallback")
55 55
 	procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback")
56
+	procHcsSaveComputeSystem               = modvmcompute.NewProc("HcsSaveComputeSystem")
56 57
 	procHcsCreateProcess                   = modvmcompute.NewProc("HcsCreateProcess")
57 58
 	procHcsOpenProcess                     = modvmcompute.NewProc("HcsOpenProcess")
58 59
 	procHcsCloseProcess                    = modvmcompute.NewProc("HcsCloseProcess")
... ...
@@ -366,6 +367,29 @@ func hcsUnregisterComputeSystemCallback(callbackHandle HcsCallback) (hr error) {
366 366
 	return
367 367
 }
368 368
 
369
+func hcsSaveComputeSystem(computeSystem HcsSystem, options string, result **uint16) (hr error) {
370
+	var _p0 *uint16
371
+	_p0, hr = syscall.UTF16PtrFromString(options)
372
+	if hr != nil {
373
+		return
374
+	}
375
+	return _hcsSaveComputeSystem(computeSystem, _p0, result)
376
+}
377
+
378
+func _hcsSaveComputeSystem(computeSystem HcsSystem, options *uint16, result **uint16) (hr error) {
379
+	if hr = procHcsSaveComputeSystem.Find(); hr != nil {
380
+		return
381
+	}
382
+	r0, _, _ := syscall.Syscall(procHcsSaveComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
383
+	if int32(r0) < 0 {
384
+		if r0&0x1fff0000 == 0x00070000 {
385
+			r0 &= 0xffff
386
+		}
387
+		hr = syscall.Errno(r0)
388
+	}
389
+	return
390
+}
391
+
369 392
 func hcsCreateProcess(computeSystem HcsSystem, processParameters string, processInformation *HcsProcessInformation, process *HcsProcess, result **uint16) (hr error) {
370 393
 	var _p0 *uint16
371 394
 	_p0, hr = syscall.UTF16PtrFromString(processParameters)
... ...
@@ -14,7 +14,7 @@ import (
14 14
 // An activated layer must later be deactivated via DeactivateLayer.
15 15
 func ActivateLayer(ctx context.Context, path string) (err error) {
16 16
 	title := "hcsshim::ActivateLayer"
17
-	ctx, span := trace.StartSpan(ctx, title)
17
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
18 18
 	defer span.End()
19 19
 	defer func() { oc.SetSpanStatus(span, err) }()
20 20
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // the parent layer provided.
13 13
 func CreateLayer(ctx context.Context, path, parent string) (err error) {
14 14
 	title := "hcsshim::CreateLayer"
15
-	ctx, span := trace.StartSpan(ctx, title)
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16 16
 	defer span.End()
17 17
 	defer func() { oc.SetSpanStatus(span, err) }()
18 18
 	span.AddAttributes(
... ...
@@ -11,7 +11,7 @@ import (
11 11
 // DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
12 12
 func DeactivateLayer(ctx context.Context, path string) (err error) {
13 13
 	title := "hcsshim::DeactivateLayer"
14
-	ctx, span := trace.StartSpan(ctx, title)
14
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
15 15
 	defer span.End()
16 16
 	defer func() { oc.SetSpanStatus(span, err) }()
17 17
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // path, including that layer's containing folder, if any.
13 13
 func DestroyLayer(ctx context.Context, path string) (err error) {
14 14
 	title := "hcsshim::DestroyLayer"
15
-	ctx, span := trace.StartSpan(ctx, title)
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16 16
 	defer span.End()
17 17
 	defer func() { oc.SetSpanStatus(span, err) }()
18 18
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -21,8 +21,7 @@ func GetLayerMountPath(ctx context.Context, path string) (_ string, err error) {
21 21
 	defer func() { oc.SetSpanStatus(span, err) }()
22 22
 	span.AddAttributes(trace.StringAttribute("path", path))
23 23
 
24
-	var mountPathLength uintptr
25
-	mountPathLength = 0
24
+	var mountPathLength uintptr = 0
26 25
 
27 26
 	// Call the procedure itself.
28 27
 	log.G(ctx).Debug("Calling proc (1)")
... ...
@@ -14,7 +14,7 @@ import (
14 14
 // of registering them with the graphdriver, graph, and tagstore.
15 15
 func GetSharedBaseImages(ctx context.Context) (_ string, err error) {
16 16
 	title := "hcsshim::GetSharedBaseImages"
17
-	ctx, span := trace.StartSpan(ctx, title)
17
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
18 18
 	defer span.End()
19 19
 	defer func() { oc.SetSpanStatus(span, err) }()
20 20
 
... ...
@@ -11,7 +11,7 @@ import (
11 11
 // GrantVmAccess adds access to a file for a given VM
12 12
 func GrantVmAccess(ctx context.Context, vmid string, filepath string) (err error) {
13 13
 	title := "hcsshim::GrantVmAccess"
14
-	ctx, span := trace.StartSpan(ctx, title)
14
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
15 15
 	defer span.End()
16 16
 	defer func() { oc.SetSpanStatus(span, err) }()
17 17
 	span.AddAttributes(
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // to the system.
13 13
 func LayerExists(ctx context.Context, path string) (_ bool, err error) {
14 14
 	title := "hcsshim::LayerExists"
15
-	ctx, span := trace.StartSpan(ctx, title)
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16 16
 	defer span.End()
17 17
 	defer func() { oc.SetSpanStatus(span, err) }()
18 18
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -390,7 +390,7 @@ func (w *legacyLayerWriter) CloseRoots() {
390 390
 		w.destRoot = nil
391 391
 	}
392 392
 	for i := range w.parentRoots {
393
-		w.parentRoots[i].Close()
393
+		_ = w.parentRoots[i].Close()
394 394
 	}
395 395
 	w.parentRoots = nil
396 396
 }
... ...
@@ -640,7 +640,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
640 640
 		defer func() {
641 641
 			if f != nil {
642 642
 				f.Close()
643
-				safefile.RemoveRelative(name, w.destRoot)
643
+				_ = safefile.RemoveRelative(name, w.destRoot)
644 644
 			}
645 645
 		}()
646 646
 
... ...
@@ -676,7 +676,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
676 676
 	defer func() {
677 677
 		if f != nil {
678 678
 			f.Close()
679
-			safefile.RemoveRelative(fname, w.root)
679
+			_ = safefile.RemoveRelative(fname, w.root)
680 680
 		}
681 681
 	}()
682 682
 
... ...
@@ -14,7 +14,7 @@ import (
14 14
 // across all clients.
15 15
 func NameToGuid(ctx context.Context, name string) (_ guid.GUID, err error) {
16 16
 	title := "hcsshim::NameToGuid"
17
-	ctx, span := trace.StartSpan(ctx, title)
17
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
18 18
 	defer span.End()
19 19
 	defer func() { oc.SetSpanStatus(span, err) }()
20 20
 	span.AddAttributes(trace.StringAttribute("name", name))
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // The files should have been extracted to <path>\Files.
13 13
 func ProcessBaseLayer(ctx context.Context, path string) (err error) {
14 14
 	title := "hcsshim::ProcessBaseLayer"
15
-	ctx, span := trace.StartSpan(ctx, title)
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16 16
 	defer span.End()
17 17
 	defer func() { oc.SetSpanStatus(span, err) }()
18 18
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -28,7 +28,7 @@ func ProcessBaseLayer(ctx context.Context, path string) (err error) {
28 28
 // The files should have been extracted to <path>\Files.
29 29
 func ProcessUtilityVMImage(ctx context.Context, path string) (err error) {
30 30
 	title := "hcsshim::ProcessUtilityVMImage"
31
-	ctx, span := trace.StartSpan(ctx, title)
31
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
32 32
 	defer span.End()
33 33
 	defer func() { oc.SetSpanStatus(span, err) }()
34 34
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // the given id.
13 13
 func UnprepareLayer(ctx context.Context, path string) (err error) {
14 14
 	title := "hcsshim::UnprepareLayer"
15
-	ctx, span := trace.StartSpan(ctx, title)
15
+	ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
16 16
 	defer span.End()
17 17
 	defer func() { oc.SetSpanStatus(span, err) }()
18 18
 	span.AddAttributes(trace.StringAttribute("path", path))
... ...
@@ -31,6 +31,43 @@ const (
31 31
 	STATUS_NO_MORE_ENTRIES = 0x8000001a
32 32
 )
33 33
 
34
+// Select entries from FILE_INFO_BY_HANDLE_CLASS.
35
+//
36
+// C declaration:
37
+//   typedef enum _FILE_INFO_BY_HANDLE_CLASS {
38
+//       FileBasicInfo,
39
+//       FileStandardInfo,
40
+//       FileNameInfo,
41
+//       FileRenameInfo,
42
+//       FileDispositionInfo,
43
+//       FileAllocationInfo,
44
+//       FileEndOfFileInfo,
45
+//       FileStreamInfo,
46
+//       FileCompressionInfo,
47
+//       FileAttributeTagInfo,
48
+//       FileIdBothDirectoryInfo,
49
+//       FileIdBothDirectoryRestartInfo,
50
+//       FileIoPriorityHintInfo,
51
+//       FileRemoteProtocolInfo,
52
+//       FileFullDirectoryInfo,
53
+//       FileFullDirectoryRestartInfo,
54
+//       FileStorageInfo,
55
+//       FileAlignmentInfo,
56
+//       FileIdInfo,
57
+//       FileIdExtdDirectoryInfo,
58
+//       FileIdExtdDirectoryRestartInfo,
59
+//       FileDispositionInfoEx,
60
+//       FileRenameInfoEx,
61
+//       FileCaseSensitiveInfo,
62
+//       FileNormalizedNameInfo,
63
+//       MaximumFileInfoByHandleClass
64
+//   } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;
65
+//
66
+// Documentation: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ne-minwinbase-file_info_by_handle_class
67
+const (
68
+	FileIdInfo = 18
69
+)
70
+
34 71
 type FileDispositionInformationEx struct {
35 72
 	Flags uintptr
36 73
 }
... ...
@@ -42,7 +79,7 @@ type IOStatusBlock struct {
42 42
 type ObjectAttributes struct {
43 43
 	Length             uintptr
44 44
 	RootDirectory      uintptr
45
-	ObjectName         uintptr
45
+	ObjectName         *UnicodeString
46 46
 	Attributes         uintptr
47 47
 	SecurityDescriptor uintptr
48 48
 	SecurityQoS        uintptr
... ...
@@ -59,3 +96,15 @@ type FileLinkInformation struct {
59 59
 	FileNameLength  uint32
60 60
 	FileName        [1]uint16
61 61
 }
62
+
63
+// C declaration:
64
+//   typedef struct _FILE_ID_INFO {
65
+//       ULONGLONG   VolumeSerialNumber;
66
+//       FILE_ID_128 FileId;
67
+//   } FILE_ID_INFO, *PFILE_ID_INFO;
68
+//
69
+// Documentation: https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_info
70
+type FILE_ID_INFO struct {
71
+	VolumeSerialNumber uint64
72
+	FileID             [16]byte
73
+}
62 74
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package winapi
1
+
2
+//sys GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error)
... ...
@@ -1,32 +1,41 @@
1 1
 package winapi
2 2
 
3 3
 import (
4
+	"unsafe"
5
+
4 6
 	"golang.org/x/sys/windows"
5 7
 )
6 8
 
7 9
 // Messages that can be received from an assigned io completion port.
8 10
 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_associate_completion_port
9 11
 const (
10
-	JOB_OBJECT_MSG_END_OF_JOB_TIME       = 1
11
-	JOB_OBJECT_MSG_END_OF_PROCESS_TIME   = 2
12
-	JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT  = 3
13
-	JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO   = 4
14
-	JOB_OBJECT_MSG_NEW_PROCESS           = 6
15
-	JOB_OBJECT_MSG_EXIT_PROCESS          = 7
16
-	JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8
17
-	JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT  = 9
18
-	JOB_OBJECT_MSG_JOB_MEMORY_LIMIT      = 10
19
-	JOB_OBJECT_MSG_NOTIFICATION_LIMIT    = 11
12
+	JOB_OBJECT_MSG_END_OF_JOB_TIME       uint32 = 1
13
+	JOB_OBJECT_MSG_END_OF_PROCESS_TIME   uint32 = 2
14
+	JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT  uint32 = 3
15
+	JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO   uint32 = 4
16
+	JOB_OBJECT_MSG_NEW_PROCESS           uint32 = 6
17
+	JOB_OBJECT_MSG_EXIT_PROCESS          uint32 = 7
18
+	JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS uint32 = 8
19
+	JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT  uint32 = 9
20
+	JOB_OBJECT_MSG_JOB_MEMORY_LIMIT      uint32 = 10
21
+	JOB_OBJECT_MSG_NOTIFICATION_LIMIT    uint32 = 11
20 22
 )
21 23
 
24
+// Access rights for creating or opening job objects.
25
+//
26
+// https://docs.microsoft.com/en-us/windows/win32/procthread/job-object-security-and-access-rights
27
+const JOB_OBJECT_ALL_ACCESS = 0x1F001F
28
+
22 29
 // IO limit flags
23 30
 //
24 31
 // https://docs.microsoft.com/en-us/windows/win32/api/jobapi2/ns-jobapi2-jobobject_io_rate_control_information
25 32
 const JOB_OBJECT_IO_RATE_CONTROL_ENABLE = 0x1
26 33
 
34
+const JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE uint32 = 0x1
35
+
27 36
 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
28 37
 const (
29
-	JOB_OBJECT_CPU_RATE_CONTROL_ENABLE = 1 << iota
38
+	JOB_OBJECT_CPU_RATE_CONTROL_ENABLE uint32 = 1 << iota
30 39
 	JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED
31 40
 	JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP
32 41
 	JOB_OBJECT_CPU_RATE_CONTROL_NOTIFY
... ...
@@ -41,7 +50,9 @@ const (
41 41
 	JobObjectBasicProcessIdList              uint32 = 3
42 42
 	JobObjectBasicAndIoAccountingInformation uint32 = 8
43 43
 	JobObjectLimitViolationInformation       uint32 = 13
44
+	JobObjectMemoryUsageInformation          uint32 = 28
44 45
 	JobObjectNotificationLimitInformation2   uint32 = 33
46
+	JobObjectIoAttribution                   uint32 = 42
45 47
 )
46 48
 
47 49
 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_limit_information
... ...
@@ -60,7 +71,7 @@ type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
60 60
 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information
61 61
 type JOBOBJECT_CPU_RATE_CONTROL_INFORMATION struct {
62 62
 	ControlFlags uint32
63
-	Rate         uint32
63
+	Value        uint32
64 64
 }
65 65
 
66 66
 // https://docs.microsoft.com/en-us/windows/win32/api/jobapi2/ns-jobapi2-jobobject_io_rate_control_information
... ...
@@ -80,9 +91,68 @@ type JOBOBJECT_BASIC_PROCESS_ID_LIST struct {
80 80
 	ProcessIdList             [1]uintptr
81 81
 }
82 82
 
83
+// AllPids returns all the process Ids in the job object.
84
+func (p *JOBOBJECT_BASIC_PROCESS_ID_LIST) AllPids() []uintptr {
85
+	return (*[(1 << 27) - 1]uintptr)(unsafe.Pointer(&p.ProcessIdList[0]))[:p.NumberOfProcessIdsInList]
86
+}
87
+
88
+// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_accounting_information
89
+type JOBOBJECT_BASIC_ACCOUNTING_INFORMATION struct {
90
+	TotalUserTime             int64
91
+	TotalKernelTime           int64
92
+	ThisPeriodTotalUserTime   int64
93
+	ThisPeriodTotalKernelTime int64
94
+	TotalPageFaultCount       uint32
95
+	TotalProcesses            uint32
96
+	ActiveProcesses           uint32
97
+	TotalTerminateProcesses   uint32
98
+}
99
+
100
+//https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_and_io_accounting_information
101
+type JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION struct {
102
+	BasicInfo JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
103
+	IoInfo    windows.IO_COUNTERS
104
+}
105
+
106
+// typedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION {
107
+//     ULONG64 JobMemory;
108
+//     ULONG64 PeakJobMemoryUsed;
109
+// } JOBOBJECT_MEMORY_USAGE_INFORMATION, *PJOBOBJECT_MEMORY_USAGE_INFORMATION;
110
+//
111
+type JOBOBJECT_MEMORY_USAGE_INFORMATION struct {
112
+	JobMemory         uint64
113
+	PeakJobMemoryUsed uint64
114
+}
115
+
116
+// typedef struct _JOBOBJECT_IO_ATTRIBUTION_STATS {
117
+//     ULONG_PTR IoCount;
118
+//     ULONGLONG TotalNonOverlappedQueueTime;
119
+//     ULONGLONG TotalNonOverlappedServiceTime;
120
+//     ULONGLONG TotalSize;
121
+// } JOBOBJECT_IO_ATTRIBUTION_STATS, *PJOBOBJECT_IO_ATTRIBUTION_STATS;
122
+//
123
+type JOBOBJECT_IO_ATTRIBUTION_STATS struct {
124
+	IoCount                       uintptr
125
+	TotalNonOverlappedQueueTime   uint64
126
+	TotalNonOverlappedServiceTime uint64
127
+	TotalSize                     uint64
128
+}
129
+
130
+// typedef struct _JOBOBJECT_IO_ATTRIBUTION_INFORMATION {
131
+//     ULONG ControlFlags;
132
+//     JOBOBJECT_IO_ATTRIBUTION_STATS ReadStats;
133
+//     JOBOBJECT_IO_ATTRIBUTION_STATS WriteStats;
134
+// } JOBOBJECT_IO_ATTRIBUTION_INFORMATION, *PJOBOBJECT_IO_ATTRIBUTION_INFORMATION;
135
+//
136
+type JOBOBJECT_IO_ATTRIBUTION_INFORMATION struct {
137
+	ControlFlags uint32
138
+	ReadStats    JOBOBJECT_IO_ATTRIBUTION_STATS
139
+	WriteStats   JOBOBJECT_IO_ATTRIBUTION_STATS
140
+}
141
+
83 142
 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_associate_completion_port
84 143
 type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
85
-	CompletionKey  uintptr
144
+	CompletionKey  windows.Handle
86 145
 	CompletionPort windows.Handle
87 146
 }
88 147
 
... ...
@@ -118,3 +188,28 @@ type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
118 118
 // );
119 119
 //
120 120
 //sys SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateControlInfo *JOBOBJECT_IO_RATE_CONTROL_INFORMATION) (ret uint32, err error) = kernel32.SetIoRateControlInformationJobObject
121
+
122
+// DWORD QueryIoRateControlInformationJobObject(
123
+// 		HANDLE                                hJob,
124
+// 		PCWSTR                                VolumeName,
125
+//		JOBOBJECT_IO_RATE_CONTROL_INFORMATION **InfoBlocks,
126
+// 		ULONG                                 *InfoBlockCount
127
+// );
128
+//sys QueryIoRateControlInformationJobObject(jobHandle windows.Handle, volumeName *uint16, ioRateControlInfo **JOBOBJECT_IO_RATE_CONTROL_INFORMATION, infoBlockCount *uint32) (ret uint32, err error) = kernel32.QueryIoRateControlInformationJobObject
129
+
130
+// NTSTATUS
131
+// NtOpenJobObject (
132
+//     _Out_ PHANDLE JobHandle,
133
+//     _In_ ACCESS_MASK DesiredAccess,
134
+//     _In_ POBJECT_ATTRIBUTES ObjectAttributes
135
+// );
136
+//sys NtOpenJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) = ntdll.NtOpenJobObject
137
+
138
+// NTSTATUS
139
+// NTAPI
140
+// NtCreateJobObject (
141
+//     _Out_ PHANDLE JobHandle,
142
+//     _In_ ACCESS_MASK DesiredAccess,
143
+//     _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
144
+// );
145
+//sys NtCreateJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) = ntdll.NtCreateJobObject
... ...
@@ -9,3 +9,19 @@ package winapi
9 9
 
10 10
 //sys LocalAlloc(flags uint32, size int) (ptr uintptr) = kernel32.LocalAlloc
11 11
 //sys LocalFree(ptr uintptr) = kernel32.LocalFree
12
+
13
+// BOOL QueryWorkingSet(
14
+//	HANDLE hProcess,
15
+//	PVOID  pv,
16
+//	DWORD  cb
17
+// );
18
+//sys QueryWorkingSet(handle windows.Handle, pv uintptr, cb uint32) (err error) = psapi.QueryWorkingSet
19
+
20
+type PSAPI_WORKING_SET_INFORMATION struct {
21
+	NumberOfEntries uintptr
22
+	WorkingSetInfo  [1]PSAPI_WORKING_SET_BLOCK
23
+}
24
+
25
+type PSAPI_WORKING_SET_BLOCK struct {
26
+	Flags uintptr
27
+}
12 28
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package winapi
1
+
2
+//sys SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err error) = iphlpapi.SetJobCompartmentId
... ...
@@ -8,4 +8,4 @@ package winapi
8 8
 // 	LPWSTR  lpBuffer,
9 9
 // 	LPWSTR  *lpFilePart
10 10
 // );
11
-//sys SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath **uint16) (size uint32, err error) = kernel32.SearchPathW
11
+//sys SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath *uint16) (size uint32, err error) = kernel32.SearchPathW
... ...
@@ -1,3 +1,10 @@
1 1
 package winapi
2 2
 
3 3
 const PROCESS_ALL_ACCESS uint32 = 2097151
4
+
5
+// DWORD GetProcessImageFileNameW(
6
+//	HANDLE hProcess,
7
+//	LPWSTR lpImageFileName,
8
+//	DWORD  nSize
9
+// );
10
+//sys GetProcessImageFileName(hProcess windows.Handle, imageFileName *uint16, nSize uint32) (size uint32, err error) = kernel32.GetProcessImageFileNameW
4 11
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+package winapi
1
+
2
+import "golang.org/x/sys/windows"
3
+
4
+const SystemProcessInformation = 5
5
+
6
+const STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
7
+
8
+// __kernel_entry NTSTATUS NtQuerySystemInformation(
9
+// 	SYSTEM_INFORMATION_CLASS SystemInformationClass,
10
+// 	PVOID                    SystemInformation,
11
+// 	ULONG                    SystemInformationLength,
12
+// 	PULONG                   ReturnLength
13
+// );
14
+//sys NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQuerySystemInformation
15
+
16
+type SYSTEM_PROCESS_INFORMATION struct {
17
+	NextEntryOffset              uint32         // ULONG
18
+	NumberOfThreads              uint32         // ULONG
19
+	WorkingSetPrivateSize        int64          // LARGE_INTEGER
20
+	HardFaultCount               uint32         // ULONG
21
+	NumberOfThreadsHighWatermark uint32         // ULONG
22
+	CycleTime                    uint64         // ULONGLONG
23
+	CreateTime                   int64          // LARGE_INTEGER
24
+	UserTime                     int64          // LARGE_INTEGER
25
+	KernelTime                   int64          // LARGE_INTEGER
26
+	ImageName                    UnicodeString  // UNICODE_STRING
27
+	BasePriority                 int32          // KPRIORITY
28
+	UniqueProcessID              windows.Handle // HANDLE
29
+	InheritedFromUniqueProcessID windows.Handle // HANDLE
30
+	HandleCount                  uint32         // ULONG
31
+	SessionID                    uint32         // ULONG
32
+	UniqueProcessKey             *uint32        // ULONG_PTR
33
+	PeakVirtualSize              uintptr        // SIZE_T
34
+	VirtualSize                  uintptr        // SIZE_T
35
+	PageFaultCount               uint32         // ULONG
36
+	PeakWorkingSetSize           uintptr        // SIZE_T
37
+	WorkingSetSize               uintptr        // SIZE_T
38
+	QuotaPeakPagedPoolUsage      uintptr        // SIZE_T
39
+	QuotaPagedPoolUsage          uintptr        // SIZE_T
40
+	QuotaPeakNonPagedPoolUsage   uintptr        // SIZE_T
41
+	QuotaNonPagedPoolUsage       uintptr        // SIZE_T
42
+	PagefileUsage                uintptr        // SIZE_T
43
+	PeakPagefileUsage            uintptr        // SIZE_T
44
+	PrivatePageCount             uintptr        // SIZE_T
45
+	ReadOperationCount           int64          // LARGE_INTEGER
46
+	WriteOperationCount          int64          // LARGE_INTEGER
47
+	OtherOperationCount          int64          // LARGE_INTEGER
48
+	ReadTransferCount            int64          // LARGE_INTEGER
49
+	WriteTransferCount           int64          // LARGE_INTEGER
50
+	OtherTransferCount           int64          // LARGE_INTEGER
51
+}
0 52
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+package winapi
1
+
2
+// HANDLE CreateRemoteThread(
3
+// 	HANDLE                 hProcess,
4
+// 	LPSECURITY_ATTRIBUTES  lpThreadAttributes,
5
+// 	SIZE_T                 dwStackSize,
6
+// 	LPTHREAD_START_ROUTINE lpStartAddress,
7
+// 	LPVOID                 lpParameter,
8
+// 	DWORD                  dwCreationFlags,
9
+// 	LPDWORD                lpThreadId
10
+// );
11
+//sys CreateRemoteThread(process windows.Handle, sa *windows.SecurityAttributes, stackSize uint32, startAddr uintptr, parameter uintptr, creationFlags uint32, threadID *uint32) (handle windows.Handle, err error) = kernel32.CreateRemoteThread
... ...
@@ -2,11 +2,24 @@ package winapi
2 2
 
3 3
 import (
4 4
 	"errors"
5
+	"reflect"
5 6
 	"syscall"
6
-	"unicode/utf16"
7 7
 	"unsafe"
8
+
9
+	"golang.org/x/sys/windows"
8 10
 )
9 11
 
12
+// Uint16BufferToSlice wraps a uint16 pointer-and-length into a slice
13
+// for easier interop with Go APIs
14
+func Uint16BufferToSlice(buffer *uint16, bufferLength int) (result []uint16) {
15
+	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&result))
16
+	hdr.Data = uintptr(unsafe.Pointer(buffer))
17
+	hdr.Cap = bufferLength
18
+	hdr.Len = bufferLength
19
+
20
+	return
21
+}
22
+
10 23
 type UnicodeString struct {
11 24
 	Length        uint16
12 25
 	MaximumLength uint16
... ...
@@ -15,28 +28,30 @@ type UnicodeString struct {
15 15
 
16 16
 //String converts a UnicodeString to a golang string
17 17
 func (uni UnicodeString) String() string {
18
-	p := (*[0xffff]uint16)(unsafe.Pointer(uni.Buffer))
19
-
20 18
 	// UnicodeString is not guaranteed to be null terminated, therefore
21 19
 	// use the UnicodeString's Length field
22
-	lengthInChars := uni.Length / 2
23
-	return syscall.UTF16ToString(p[:lengthInChars])
20
+	return syscall.UTF16ToString(Uint16BufferToSlice(uni.Buffer, int(uni.Length/2)))
24 21
 }
25 22
 
26 23
 // NewUnicodeString allocates a new UnicodeString and copies `s` into
27 24
 // the buffer of the new UnicodeString.
28 25
 func NewUnicodeString(s string) (*UnicodeString, error) {
29
-	ws := utf16.Encode(([]rune)(s))
30
-	if len(ws) > 32767 {
26
+	// Get length of original `s` to use in the UnicodeString since the `buf`
27
+	// created later will have an additional trailing null character
28
+	length := len(s)
29
+	if length > 32767 {
31 30
 		return nil, syscall.ENAMETOOLONG
32 31
 	}
33 32
 
33
+	buf, err := windows.UTF16FromString(s)
34
+	if err != nil {
35
+		return nil, err
36
+	}
34 37
 	uni := &UnicodeString{
35
-		Length:        uint16(len(ws) * 2),
36
-		MaximumLength: uint16(len(ws) * 2),
37
-		Buffer:        &make([]uint16, len(ws))[0],
38
+		Length:        uint16(length * 2),
39
+		MaximumLength: uint16(length * 2),
40
+		Buffer:        &buf[0],
38 41
 	}
39
-	copy((*[32768]uint16)(unsafe.Pointer(uni.Buffer))[:], ws)
40 42
 	return uni, nil
41 43
 }
42 44
 
... ...
@@ -2,4 +2,4 @@
2 2
 // be thought of as an extension to golang.org/x/sys/windows.
3 3
 package winapi
4 4
 
5
-//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go jobobject.go path.go logon.go memory.go processor.go devices.go filesystem.go errors.go
5
+//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go system.go net.go path.go thread.go iocp.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go
... ...
@@ -37,32 +37,95 @@ func errnoErr(e syscall.Errno) error {
37 37
 }
38 38
 
39 39
 var (
40
+	modntdll    = windows.NewLazySystemDLL("ntdll.dll")
41
+	modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
40 42
 	modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
41 43
 	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
44
+	modpsapi    = windows.NewLazySystemDLL("psapi.dll")
42 45
 	modcfgmgr32 = windows.NewLazySystemDLL("cfgmgr32.dll")
43
-	modntdll    = windows.NewLazySystemDLL("ntdll.dll")
44 46
 
45
-	procIsProcessInJob                       = modkernel32.NewProc("IsProcessInJob")
46
-	procQueryInformationJobObject            = modkernel32.NewProc("QueryInformationJobObject")
47
-	procOpenJobObjectW                       = modkernel32.NewProc("OpenJobObjectW")
48
-	procSetIoRateControlInformationJobObject = modkernel32.NewProc("SetIoRateControlInformationJobObject")
49
-	procSearchPathW                          = modkernel32.NewProc("SearchPathW")
50
-	procLogonUserW                           = modadvapi32.NewProc("LogonUserW")
51
-	procRtlMoveMemory                        = modkernel32.NewProc("RtlMoveMemory")
52
-	procLocalAlloc                           = modkernel32.NewProc("LocalAlloc")
53
-	procLocalFree                            = modkernel32.NewProc("LocalFree")
54
-	procGetActiveProcessorCount              = modkernel32.NewProc("GetActiveProcessorCount")
55
-	procCM_Get_Device_ID_List_SizeA          = modcfgmgr32.NewProc("CM_Get_Device_ID_List_SizeA")
56
-	procCM_Get_Device_ID_ListA               = modcfgmgr32.NewProc("CM_Get_Device_ID_ListA")
57
-	procCM_Locate_DevNodeW                   = modcfgmgr32.NewProc("CM_Locate_DevNodeW")
58
-	procCM_Get_DevNode_PropertyW             = modcfgmgr32.NewProc("CM_Get_DevNode_PropertyW")
59
-	procNtCreateFile                         = modntdll.NewProc("NtCreateFile")
60
-	procNtSetInformationFile                 = modntdll.NewProc("NtSetInformationFile")
61
-	procNtOpenDirectoryObject                = modntdll.NewProc("NtOpenDirectoryObject")
62
-	procNtQueryDirectoryObject               = modntdll.NewProc("NtQueryDirectoryObject")
63
-	procRtlNtStatusToDosError                = modntdll.NewProc("RtlNtStatusToDosError")
47
+	procNtQuerySystemInformation               = modntdll.NewProc("NtQuerySystemInformation")
48
+	procSetJobCompartmentId                    = modiphlpapi.NewProc("SetJobCompartmentId")
49
+	procSearchPathW                            = modkernel32.NewProc("SearchPathW")
50
+	procCreateRemoteThread                     = modkernel32.NewProc("CreateRemoteThread")
51
+	procGetQueuedCompletionStatus              = modkernel32.NewProc("GetQueuedCompletionStatus")
52
+	procIsProcessInJob                         = modkernel32.NewProc("IsProcessInJob")
53
+	procQueryInformationJobObject              = modkernel32.NewProc("QueryInformationJobObject")
54
+	procOpenJobObjectW                         = modkernel32.NewProc("OpenJobObjectW")
55
+	procSetIoRateControlInformationJobObject   = modkernel32.NewProc("SetIoRateControlInformationJobObject")
56
+	procQueryIoRateControlInformationJobObject = modkernel32.NewProc("QueryIoRateControlInformationJobObject")
57
+	procNtOpenJobObject                        = modntdll.NewProc("NtOpenJobObject")
58
+	procNtCreateJobObject                      = modntdll.NewProc("NtCreateJobObject")
59
+	procLogonUserW                             = modadvapi32.NewProc("LogonUserW")
60
+	procRtlMoveMemory                          = modkernel32.NewProc("RtlMoveMemory")
61
+	procLocalAlloc                             = modkernel32.NewProc("LocalAlloc")
62
+	procLocalFree                              = modkernel32.NewProc("LocalFree")
63
+	procQueryWorkingSet                        = modpsapi.NewProc("QueryWorkingSet")
64
+	procGetProcessImageFileNameW               = modkernel32.NewProc("GetProcessImageFileNameW")
65
+	procGetActiveProcessorCount                = modkernel32.NewProc("GetActiveProcessorCount")
66
+	procCM_Get_Device_ID_List_SizeA            = modcfgmgr32.NewProc("CM_Get_Device_ID_List_SizeA")
67
+	procCM_Get_Device_ID_ListA                 = modcfgmgr32.NewProc("CM_Get_Device_ID_ListA")
68
+	procCM_Locate_DevNodeW                     = modcfgmgr32.NewProc("CM_Locate_DevNodeW")
69
+	procCM_Get_DevNode_PropertyW               = modcfgmgr32.NewProc("CM_Get_DevNode_PropertyW")
70
+	procNtCreateFile                           = modntdll.NewProc("NtCreateFile")
71
+	procNtSetInformationFile                   = modntdll.NewProc("NtSetInformationFile")
72
+	procNtOpenDirectoryObject                  = modntdll.NewProc("NtOpenDirectoryObject")
73
+	procNtQueryDirectoryObject                 = modntdll.NewProc("NtQueryDirectoryObject")
74
+	procRtlNtStatusToDosError                  = modntdll.NewProc("RtlNtStatusToDosError")
64 75
 )
65 76
 
77
+func NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) {
78
+	r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)), 0, 0)
79
+	status = uint32(r0)
80
+	return
81
+}
82
+
83
+func SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err error) {
84
+	r0, _, _ := syscall.Syscall(procSetJobCompartmentId.Addr(), 2, uintptr(handle), uintptr(compartmentId), 0)
85
+	if r0 != 0 {
86
+		win32Err = syscall.Errno(r0)
87
+	}
88
+	return
89
+}
90
+
91
+func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath *uint16) (size uint32, err error) {
92
+	r0, _, e1 := syscall.Syscall6(procSearchPathW.Addr(), 6, uintptr(unsafe.Pointer(lpPath)), uintptr(unsafe.Pointer(lpFileName)), uintptr(unsafe.Pointer(lpExtension)), uintptr(nBufferLength), uintptr(unsafe.Pointer(lpBuffer)), uintptr(unsafe.Pointer(lpFilePath)))
93
+	size = uint32(r0)
94
+	if size == 0 {
95
+		if e1 != 0 {
96
+			err = errnoErr(e1)
97
+		} else {
98
+			err = syscall.EINVAL
99
+		}
100
+	}
101
+	return
102
+}
103
+
104
+func CreateRemoteThread(process windows.Handle, sa *windows.SecurityAttributes, stackSize uint32, startAddr uintptr, parameter uintptr, creationFlags uint32, threadID *uint32) (handle windows.Handle, err error) {
105
+	r0, _, e1 := syscall.Syscall9(procCreateRemoteThread.Addr(), 7, uintptr(process), uintptr(unsafe.Pointer(sa)), uintptr(stackSize), uintptr(startAddr), uintptr(parameter), uintptr(creationFlags), uintptr(unsafe.Pointer(threadID)), 0, 0)
106
+	handle = windows.Handle(r0)
107
+	if handle == 0 {
108
+		if e1 != 0 {
109
+			err = errnoErr(e1)
110
+		} else {
111
+			err = syscall.EINVAL
112
+		}
113
+	}
114
+	return
115
+}
116
+
117
+func GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error) {
118
+	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
119
+	if r1 == 0 {
120
+		if e1 != 0 {
121
+			err = errnoErr(e1)
122
+		} else {
123
+			err = syscall.EINVAL
124
+		}
125
+	}
126
+	return
127
+}
128
+
66 129
 func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *bool) (err error) {
67 130
 	r1, _, e1 := syscall.Syscall(procIsProcessInJob.Addr(), 3, uintptr(procHandle), uintptr(jobHandle), uintptr(unsafe.Pointer(result)))
68 131
 	if r1 == 0 {
... ...
@@ -119,10 +182,10 @@ func SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateContro
119 119
 	return
120 120
 }
121 121
 
122
-func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath **uint16) (size uint32, err error) {
123
-	r0, _, e1 := syscall.Syscall6(procSearchPathW.Addr(), 6, uintptr(unsafe.Pointer(lpPath)), uintptr(unsafe.Pointer(lpFileName)), uintptr(unsafe.Pointer(lpExtension)), uintptr(nBufferLength), uintptr(unsafe.Pointer(lpBuffer)), uintptr(unsafe.Pointer(lpFilePath)))
124
-	size = uint32(r0)
125
-	if size == 0 {
122
+func QueryIoRateControlInformationJobObject(jobHandle windows.Handle, volumeName *uint16, ioRateControlInfo **JOBOBJECT_IO_RATE_CONTROL_INFORMATION, infoBlockCount *uint32) (ret uint32, err error) {
123
+	r0, _, e1 := syscall.Syscall6(procQueryIoRateControlInformationJobObject.Addr(), 4, uintptr(jobHandle), uintptr(unsafe.Pointer(volumeName)), uintptr(unsafe.Pointer(ioRateControlInfo)), uintptr(unsafe.Pointer(infoBlockCount)), 0, 0)
124
+	ret = uint32(r0)
125
+	if ret == 0 {
126 126
 		if e1 != 0 {
127 127
 			err = errnoErr(e1)
128 128
 		} else {
... ...
@@ -132,6 +195,18 @@ func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBuffer
132 132
 	return
133 133
 }
134 134
 
135
+func NtOpenJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) {
136
+	r0, _, _ := syscall.Syscall(procNtOpenJobObject.Addr(), 3, uintptr(unsafe.Pointer(jobHandle)), uintptr(desiredAccess), uintptr(unsafe.Pointer(objAttributes)))
137
+	status = uint32(r0)
138
+	return
139
+}
140
+
141
+func NtCreateJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) {
142
+	r0, _, _ := syscall.Syscall(procNtCreateJobObject.Addr(), 3, uintptr(unsafe.Pointer(jobHandle)), uintptr(desiredAccess), uintptr(unsafe.Pointer(objAttributes)))
143
+	status = uint32(r0)
144
+	return
145
+}
146
+
135 147
 func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) {
136 148
 	r1, _, e1 := syscall.Syscall6(procLogonUserW.Addr(), 6, uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(domain)), uintptr(unsafe.Pointer(password)), uintptr(logonType), uintptr(logonProvider), uintptr(unsafe.Pointer(token)))
137 149
 	if r1 == 0 {
... ...
@@ -167,6 +242,31 @@ func LocalFree(ptr uintptr) {
167 167
 	return
168 168
 }
169 169
 
170
+func QueryWorkingSet(handle windows.Handle, pv uintptr, cb uint32) (err error) {
171
+	r1, _, e1 := syscall.Syscall(procQueryWorkingSet.Addr(), 3, uintptr(handle), uintptr(pv), uintptr(cb))
172
+	if r1 == 0 {
173
+		if e1 != 0 {
174
+			err = errnoErr(e1)
175
+		} else {
176
+			err = syscall.EINVAL
177
+		}
178
+	}
179
+	return
180
+}
181
+
182
+func GetProcessImageFileName(hProcess windows.Handle, imageFileName *uint16, nSize uint32) (size uint32, err error) {
183
+	r0, _, e1 := syscall.Syscall(procGetProcessImageFileNameW.Addr(), 3, uintptr(hProcess), uintptr(unsafe.Pointer(imageFileName)), uintptr(nSize))
184
+	size = uint32(r0)
185
+	if size == 0 {
186
+		if e1 != 0 {
187
+			err = errnoErr(e1)
188
+		} else {
189
+			err = syscall.EINVAL
190
+		}
191
+	}
192
+	return
193
+}
194
+
170 195
 func GetActiveProcessorCount(groupNumber uint16) (amount uint32) {
171 196
 	r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0)
172 197
 	amount = uint32(r0)
... ...
@@ -15,21 +15,6 @@ type OSVersion struct {
15 15
 	Build        uint16
16 16
 }
17 17
 
18
-// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
19
-type osVersionInfoEx struct {
20
-	OSVersionInfoSize uint32
21
-	MajorVersion      uint32
22
-	MinorVersion      uint32
23
-	BuildNumber       uint32
24
-	PlatformID        uint32
25
-	CSDVersion        [128]uint16
26
-	ServicePackMajor  uint16
27
-	ServicePackMinor  uint16
28
-	SuiteMask         uint16
29
-	ProductType       byte
30
-	Reserve           byte
31
-}
32
-
33 18
 // Get gets the operating system version on Windows.
34 19
 // The calling application must be manifested to get the correct version information.
35 20
 func Get() OSVersion {
... ...
@@ -32,4 +32,7 @@ const (
32 32
 	// V20H1 (version 2004) corresponds to Windows Server 2004 (semi-annual
33 33
 	// channel).
34 34
 	V20H1 = 19041
35
+
36
+	// V20H2 corresponds to Windows Server 20H2 (semi-annual channel).
37
+	V20H2 = 19042
35 38
 )