Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
# the following lines are in sorted order, FYI |
| 2 | 2 |
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 |
| 3 | 3 |
github.com/Microsoft/hcsshim 44c060121b68e8bdc40b411beba551f3b4ee9e55 |
| 4 |
-github.com/Microsoft/go-winio v0.4.10 |
|
| 4 |
+github.com/Microsoft/go-winio v0.4.11 |
|
| 5 | 5 |
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a |
| 6 | 6 |
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git |
| 7 | 7 |
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a |
| ... | ... |
@@ -1,137 +1,137 @@ |
| 1 |
-package winio |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "bytes" |
|
| 5 |
- "encoding/binary" |
|
| 6 |
- "errors" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-type fileFullEaInformation struct {
|
|
| 10 |
- NextEntryOffset uint32 |
|
| 11 |
- Flags uint8 |
|
| 12 |
- NameLength uint8 |
|
| 13 |
- ValueLength uint16 |
|
| 14 |
-} |
|
| 15 |
- |
|
| 16 |
-var ( |
|
| 17 |
- fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
|
|
| 18 |
- |
|
| 19 |
- errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
|
|
| 20 |
- errEaNameTooLarge = errors.New("extended attribute name too large")
|
|
| 21 |
- errEaValueTooLarge = errors.New("extended attribute value too large")
|
|
| 22 |
-) |
|
| 23 |
- |
|
| 24 |
-// ExtendedAttribute represents a single Windows EA. |
|
| 25 |
-type ExtendedAttribute struct {
|
|
| 26 |
- Name string |
|
| 27 |
- Value []byte |
|
| 28 |
- Flags uint8 |
|
| 29 |
-} |
|
| 30 |
- |
|
| 31 |
-func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
|
| 32 |
- var info fileFullEaInformation |
|
| 33 |
- err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) |
|
| 34 |
- if err != nil {
|
|
| 35 |
- err = errInvalidEaBuffer |
|
| 36 |
- return |
|
| 37 |
- } |
|
| 38 |
- |
|
| 39 |
- nameOffset := fileFullEaInformationSize |
|
| 40 |
- nameLen := int(info.NameLength) |
|
| 41 |
- valueOffset := nameOffset + int(info.NameLength) + 1 |
|
| 42 |
- valueLen := int(info.ValueLength) |
|
| 43 |
- nextOffset := int(info.NextEntryOffset) |
|
| 44 |
- if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
|
| 45 |
- err = errInvalidEaBuffer |
|
| 46 |
- return |
|
| 47 |
- } |
|
| 48 |
- |
|
| 49 |
- ea.Name = string(b[nameOffset : nameOffset+nameLen]) |
|
| 50 |
- ea.Value = b[valueOffset : valueOffset+valueLen] |
|
| 51 |
- ea.Flags = info.Flags |
|
| 52 |
- if info.NextEntryOffset != 0 {
|
|
| 53 |
- nb = b[info.NextEntryOffset:] |
|
| 54 |
- } |
|
| 55 |
- return |
|
| 56 |
-} |
|
| 57 |
- |
|
| 58 |
-// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION |
|
| 59 |
-// buffer retrieved from BackupRead, ZwQueryEaFile, etc. |
|
| 60 |
-func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
|
|
| 61 |
- for len(b) != 0 {
|
|
| 62 |
- ea, nb, err := parseEa(b) |
|
| 63 |
- if err != nil {
|
|
| 64 |
- return nil, err |
|
| 65 |
- } |
|
| 66 |
- |
|
| 67 |
- eas = append(eas, ea) |
|
| 68 |
- b = nb |
|
| 69 |
- } |
|
| 70 |
- return |
|
| 71 |
-} |
|
| 72 |
- |
|
| 73 |
-func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
|
| 74 |
- if int(uint8(len(ea.Name))) != len(ea.Name) {
|
|
| 75 |
- return errEaNameTooLarge |
|
| 76 |
- } |
|
| 77 |
- if int(uint16(len(ea.Value))) != len(ea.Value) {
|
|
| 78 |
- return errEaValueTooLarge |
|
| 79 |
- } |
|
| 80 |
- entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) |
|
| 81 |
- withPadding := (entrySize + 3) &^ 3 |
|
| 82 |
- nextOffset := uint32(0) |
|
| 83 |
- if !last {
|
|
| 84 |
- nextOffset = withPadding |
|
| 85 |
- } |
|
| 86 |
- info := fileFullEaInformation{
|
|
| 87 |
- NextEntryOffset: nextOffset, |
|
| 88 |
- Flags: ea.Flags, |
|
| 89 |
- NameLength: uint8(len(ea.Name)), |
|
| 90 |
- ValueLength: uint16(len(ea.Value)), |
|
| 91 |
- } |
|
| 92 |
- |
|
| 93 |
- err := binary.Write(buf, binary.LittleEndian, &info) |
|
| 94 |
- if err != nil {
|
|
| 95 |
- return err |
|
| 96 |
- } |
|
| 97 |
- |
|
| 98 |
- _, err = buf.Write([]byte(ea.Name)) |
|
| 99 |
- if err != nil {
|
|
| 100 |
- return err |
|
| 101 |
- } |
|
| 102 |
- |
|
| 103 |
- err = buf.WriteByte(0) |
|
| 104 |
- if err != nil {
|
|
| 105 |
- return err |
|
| 106 |
- } |
|
| 107 |
- |
|
| 108 |
- _, err = buf.Write(ea.Value) |
|
| 109 |
- if err != nil {
|
|
| 110 |
- return err |
|
| 111 |
- } |
|
| 112 |
- |
|
| 113 |
- _, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
|
|
| 114 |
- if err != nil {
|
|
| 115 |
- return err |
|
| 116 |
- } |
|
| 117 |
- |
|
| 118 |
- return nil |
|
| 119 |
-} |
|
| 120 |
- |
|
| 121 |
-// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION |
|
| 122 |
-// buffer for use with BackupWrite, ZwSetEaFile, etc. |
|
| 123 |
-func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
|
|
| 124 |
- var buf bytes.Buffer |
|
| 125 |
- for i := range eas {
|
|
| 126 |
- last := false |
|
| 127 |
- if i == len(eas)-1 {
|
|
| 128 |
- last = true |
|
| 129 |
- } |
|
| 130 |
- |
|
| 131 |
- err := writeEa(&buf, &eas[i], last) |
|
| 132 |
- if err != nil {
|
|
| 133 |
- return nil, err |
|
| 134 |
- } |
|
| 135 |
- } |
|
| 136 |
- return buf.Bytes(), nil |
|
| 137 |
-} |
|
| 1 |
+package winio |
|
| 2 |
+ |
|
| 3 |
+import ( |
|
| 4 |
+ "bytes" |
|
| 5 |
+ "encoding/binary" |
|
| 6 |
+ "errors" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+type fileFullEaInformation struct {
|
|
| 10 |
+ NextEntryOffset uint32 |
|
| 11 |
+ Flags uint8 |
|
| 12 |
+ NameLength uint8 |
|
| 13 |
+ ValueLength uint16 |
|
| 14 |
+} |
|
| 15 |
+ |
|
| 16 |
+var ( |
|
| 17 |
+ fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
|
|
| 18 |
+ |
|
| 19 |
+ errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
|
|
| 20 |
+ errEaNameTooLarge = errors.New("extended attribute name too large")
|
|
| 21 |
+ errEaValueTooLarge = errors.New("extended attribute value too large")
|
|
| 22 |
+) |
|
| 23 |
+ |
|
| 24 |
+// ExtendedAttribute represents a single Windows EA. |
|
| 25 |
+type ExtendedAttribute struct {
|
|
| 26 |
+ Name string |
|
| 27 |
+ Value []byte |
|
| 28 |
+ Flags uint8 |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
|
| 32 |
+ var info fileFullEaInformation |
|
| 33 |
+ err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) |
|
| 34 |
+ if err != nil {
|
|
| 35 |
+ err = errInvalidEaBuffer |
|
| 36 |
+ return |
|
| 37 |
+ } |
|
| 38 |
+ |
|
| 39 |
+ nameOffset := fileFullEaInformationSize |
|
| 40 |
+ nameLen := int(info.NameLength) |
|
| 41 |
+ valueOffset := nameOffset + int(info.NameLength) + 1 |
|
| 42 |
+ valueLen := int(info.ValueLength) |
|
| 43 |
+ nextOffset := int(info.NextEntryOffset) |
|
| 44 |
+ if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
|
| 45 |
+ err = errInvalidEaBuffer |
|
| 46 |
+ return |
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ ea.Name = string(b[nameOffset : nameOffset+nameLen]) |
|
| 50 |
+ ea.Value = b[valueOffset : valueOffset+valueLen] |
|
| 51 |
+ ea.Flags = info.Flags |
|
| 52 |
+ if info.NextEntryOffset != 0 {
|
|
| 53 |
+ nb = b[info.NextEntryOffset:] |
|
| 54 |
+ } |
|
| 55 |
+ return |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION |
|
| 59 |
+// buffer retrieved from BackupRead, ZwQueryEaFile, etc. |
|
| 60 |
+func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
|
|
| 61 |
+ for len(b) != 0 {
|
|
| 62 |
+ ea, nb, err := parseEa(b) |
|
| 63 |
+ if err != nil {
|
|
| 64 |
+ return nil, err |
|
| 65 |
+ } |
|
| 66 |
+ |
|
| 67 |
+ eas = append(eas, ea) |
|
| 68 |
+ b = nb |
|
| 69 |
+ } |
|
| 70 |
+ return |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
|
| 74 |
+ if int(uint8(len(ea.Name))) != len(ea.Name) {
|
|
| 75 |
+ return errEaNameTooLarge |
|
| 76 |
+ } |
|
| 77 |
+ if int(uint16(len(ea.Value))) != len(ea.Value) {
|
|
| 78 |
+ return errEaValueTooLarge |
|
| 79 |
+ } |
|
| 80 |
+ entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) |
|
| 81 |
+ withPadding := (entrySize + 3) &^ 3 |
|
| 82 |
+ nextOffset := uint32(0) |
|
| 83 |
+ if !last {
|
|
| 84 |
+ nextOffset = withPadding |
|
| 85 |
+ } |
|
| 86 |
+ info := fileFullEaInformation{
|
|
| 87 |
+ NextEntryOffset: nextOffset, |
|
| 88 |
+ Flags: ea.Flags, |
|
| 89 |
+ NameLength: uint8(len(ea.Name)), |
|
| 90 |
+ ValueLength: uint16(len(ea.Value)), |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ err := binary.Write(buf, binary.LittleEndian, &info) |
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ return err |
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ _, err = buf.Write([]byte(ea.Name)) |
|
| 99 |
+ if err != nil {
|
|
| 100 |
+ return err |
|
| 101 |
+ } |
|
| 102 |
+ |
|
| 103 |
+ err = buf.WriteByte(0) |
|
| 104 |
+ if err != nil {
|
|
| 105 |
+ return err |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ _, err = buf.Write(ea.Value) |
|
| 109 |
+ if err != nil {
|
|
| 110 |
+ return err |
|
| 111 |
+ } |
|
| 112 |
+ |
|
| 113 |
+ _, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
|
|
| 114 |
+ if err != nil {
|
|
| 115 |
+ return err |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ return nil |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION |
|
| 122 |
+// buffer for use with BackupWrite, ZwSetEaFile, etc. |
|
| 123 |
+func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
|
|
| 124 |
+ var buf bytes.Buffer |
|
| 125 |
+ for i := range eas {
|
|
| 126 |
+ last := false |
|
| 127 |
+ if i == len(eas)-1 {
|
|
| 128 |
+ last = true |
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 131 |
+ err := writeEa(&buf, &eas[i], last) |
|
| 132 |
+ if err != nil {
|
|
| 133 |
+ return nil, err |
|
| 134 |
+ } |
|
| 135 |
+ } |
|
| 136 |
+ return buf.Bytes(), nil |
|
| 137 |
+} |
| ... | ... |
@@ -1,82 +1,108 @@ |
| 1 |
-// +build windows |
|
| 2 |
- |
|
| 3 |
-package vhd |
|
| 4 |
- |
|
| 5 |
-import "syscall" |
|
| 6 |
- |
|
| 7 |
-//go:generate go run mksyscall_windows.go -output zvhd.go vhd.go |
|
| 8 |
- |
|
| 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 |
- |
|
| 11 |
-type virtualStorageType struct {
|
|
| 12 |
- DeviceID uint32 |
|
| 13 |
- VendorID [16]byte |
|
| 14 |
-} |
|
| 15 |
- |
|
| 16 |
-const virtualDiskAccessNONE uint32 = 0 |
|
| 17 |
-const virtualDiskAccessATTACHRO uint32 = 65536 |
|
| 18 |
-const virtualDiskAccessATTACHRW uint32 = 131072 |
|
| 19 |
-const virtualDiskAccessDETACH uint32 = 262144 |
|
| 20 |
-const virtualDiskAccessGETINFO uint32 = 524288 |
|
| 21 |
-const virtualDiskAccessCREATE uint32 = 1048576 |
|
| 22 |
-const virtualDiskAccessMETAOPS uint32 = 2097152 |
|
| 23 |
-const virtualDiskAccessREAD uint32 = 851968 |
|
| 24 |
-const virtualDiskAccessALL uint32 = 4128768 |
|
| 25 |
-const virtualDiskAccessWRITABLE uint32 = 3276800 |
|
| 26 |
- |
|
| 27 |
-const createVirtualDiskFlagNone uint32 = 0 |
|
| 28 |
-const createVirtualDiskFlagFullPhysicalAllocation uint32 = 1 |
|
| 29 |
-const createVirtualDiskFlagPreventWritesToSourceDisk uint32 = 2 |
|
| 30 |
-const createVirtualDiskFlagDoNotCopyMetadataFromParent uint32 = 4 |
|
| 31 |
- |
|
| 32 |
-type version2 struct {
|
|
| 33 |
- UniqueID [16]byte // GUID |
|
| 34 |
- MaximumSize uint64 |
|
| 35 |
- BlockSizeInBytes uint32 |
|
| 36 |
- SectorSizeInBytes uint32 |
|
| 37 |
- ParentPath *uint16 // string |
|
| 38 |
- SourcePath *uint16 // string |
|
| 39 |
- OpenFlags uint32 |
|
| 40 |
- ParentVirtualStorageType virtualStorageType |
|
| 41 |
- SourceVirtualStorageType virtualStorageType |
|
| 42 |
- ResiliencyGUID [16]byte // GUID |
|
| 43 |
-} |
|
| 44 |
- |
|
| 45 |
-type createVirtualDiskParameters struct {
|
|
| 46 |
- Version uint32 // Must always be set to 2 |
|
| 47 |
- Version2 version2 |
|
| 48 |
-} |
|
| 49 |
- |
|
| 50 |
-// CreateVhdx will create a simple vhdx file at the given path using default values. |
|
| 51 |
-func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
|
| 52 |
- var defaultType virtualStorageType |
|
| 53 |
- |
|
| 54 |
- parameters := createVirtualDiskParameters{
|
|
| 55 |
- Version: 2, |
|
| 56 |
- Version2: version2{
|
|
| 57 |
- MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024, |
|
| 58 |
- BlockSizeInBytes: blockSizeInMb * 1024 * 1024, |
|
| 59 |
- }, |
|
| 60 |
- } |
|
| 61 |
- |
|
| 62 |
- var handle syscall.Handle |
|
| 63 |
- |
|
| 64 |
- if err := createVirtualDisk( |
|
| 65 |
- &defaultType, |
|
| 66 |
- path, |
|
| 67 |
- virtualDiskAccessNONE, |
|
| 68 |
- nil, |
|
| 69 |
- createVirtualDiskFlagNone, |
|
| 70 |
- 0, |
|
| 71 |
- ¶meters, |
|
| 72 |
- nil, |
|
| 73 |
- &handle); err != nil {
|
|
| 74 |
- return err |
|
| 75 |
- } |
|
| 76 |
- |
|
| 77 |
- if err := syscall.CloseHandle(handle); err != nil {
|
|
| 78 |
- return err |
|
| 79 |
- } |
|
| 80 |
- |
|
| 81 |
- return nil |
|
| 82 |
-} |
|
| 1 |
+// +build windows |
|
| 2 |
+ |
|
| 3 |
+package vhd |
|
| 4 |
+ |
|
| 5 |
+import "syscall" |
|
| 6 |
+ |
|
| 7 |
+//go:generate go run mksyscall_windows.go -output zvhd.go vhd.go |
|
| 8 |
+ |
|
| 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 *uintptr, 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 |
+} |
|
| 17 |
+ |
|
| 18 |
+const virtualDiskAccessNONE uint32 = 0 |
|
| 19 |
+const virtualDiskAccessATTACHRO uint32 = 65536 |
|
| 20 |
+const virtualDiskAccessATTACHRW uint32 = 131072 |
|
| 21 |
+const virtualDiskAccessDETACH uint32 = 262144 |
|
| 22 |
+const virtualDiskAccessGETINFO uint32 = 524288 |
|
| 23 |
+const virtualDiskAccessCREATE uint32 = 1048576 |
|
| 24 |
+const virtualDiskAccessMETAOPS uint32 = 2097152 |
|
| 25 |
+const virtualDiskAccessREAD uint32 = 851968 |
|
| 26 |
+const virtualDiskAccessALL uint32 = 4128768 |
|
| 27 |
+const virtualDiskAccessWRITABLE uint32 = 3276800 |
|
| 28 |
+ |
|
| 29 |
+const createVirtualDiskFlagNone uint32 = 0 |
|
| 30 |
+const createVirtualDiskFlagFullPhysicalAllocation uint32 = 1 |
|
| 31 |
+const createVirtualDiskFlagPreventWritesToSourceDisk uint32 = 2 |
|
| 32 |
+const createVirtualDiskFlagDoNotCopyMetadataFromParent uint32 = 4 |
|
| 33 |
+ |
|
| 34 |
+type version2 struct {
|
|
| 35 |
+ UniqueID [16]byte // GUID |
|
| 36 |
+ MaximumSize uint64 |
|
| 37 |
+ BlockSizeInBytes uint32 |
|
| 38 |
+ SectorSizeInBytes uint32 |
|
| 39 |
+ ParentPath *uint16 // string |
|
| 40 |
+ SourcePath *uint16 // string |
|
| 41 |
+ OpenFlags uint32 |
|
| 42 |
+ ParentVirtualStorageType virtualStorageType |
|
| 43 |
+ SourceVirtualStorageType virtualStorageType |
|
| 44 |
+ ResiliencyGUID [16]byte // GUID |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+type createVirtualDiskParameters struct {
|
|
| 48 |
+ Version uint32 // Must always be set to 2 |
|
| 49 |
+ Version2 version2 |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+// CreateVhdx will create a simple vhdx file at the given path using default values. |
|
| 53 |
+func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
|
| 54 |
+ var defaultType virtualStorageType |
|
| 55 |
+ |
|
| 56 |
+ parameters := createVirtualDiskParameters{
|
|
| 57 |
+ Version: 2, |
|
| 58 |
+ Version2: version2{
|
|
| 59 |
+ MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024, |
|
| 60 |
+ BlockSizeInBytes: blockSizeInMb * 1024 * 1024, |
|
| 61 |
+ }, |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ var handle syscall.Handle |
|
| 65 |
+ |
|
| 66 |
+ if err := createVirtualDisk( |
|
| 67 |
+ &defaultType, |
|
| 68 |
+ path, |
|
| 69 |
+ virtualDiskAccessNONE, |
|
| 70 |
+ nil, |
|
| 71 |
+ createVirtualDiskFlagNone, |
|
| 72 |
+ 0, |
|
| 73 |
+ ¶meters, |
|
| 74 |
+ nil, |
|
| 75 |
+ &handle); err != nil {
|
|
| 76 |
+ return err |
|
| 77 |
+ } |
|
| 78 |
+ |
|
| 79 |
+ if err := syscall.CloseHandle(handle); err != nil {
|
|
| 80 |
+ return err |
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ return nil |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+// DetachVhd detaches a VHD attached at the given path. |
|
| 87 |
+func DetachVhd(path string) error {
|
|
| 88 |
+ var ( |
|
| 89 |
+ defaultType virtualStorageType |
|
| 90 |
+ handle syscall.Handle |
|
| 91 |
+ ) |
|
| 92 |
+ |
|
| 93 |
+ if err := openVirtualDisk( |
|
| 94 |
+ &defaultType, |
|
| 95 |
+ path, |
|
| 96 |
+ virtualDiskAccessDETACH, |
|
| 97 |
+ 0, |
|
| 98 |
+ nil, |
|
| 99 |
+ &handle); err != nil {
|
|
| 100 |
+ return err |
|
| 101 |
+ } |
|
| 102 |
+ defer syscall.CloseHandle(handle) |
|
| 103 |
+ |
|
| 104 |
+ if err := detachVirtualDisk(handle, 0, 0); err != nil {
|
|
| 105 |
+ return err |
|
| 106 |
+ } |
|
| 107 |
+ return nil |
|
| 108 |
+} |
| ... | ... |
@@ -40,6 +40,8 @@ var ( |
| 40 | 40 |
modVirtDisk = windows.NewLazySystemDLL("VirtDisk.dll")
|
| 41 | 41 |
|
| 42 | 42 |
procCreateVirtualDisk = modVirtDisk.NewProc("CreateVirtualDisk")
|
| 43 |
+ procOpenVirtualDisk = modVirtDisk.NewProc("OpenVirtualDisk")
|
|
| 44 |
+ procDetachVirtualDisk = modVirtDisk.NewProc("DetachVirtualDisk")
|
|
| 43 | 45 |
) |
| 44 | 46 |
|
| 45 | 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) {
|
| ... | ... |
@@ -62,3 +64,36 @@ func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, vi |
| 62 | 62 |
} |
| 63 | 63 |
return |
| 64 | 64 |
} |
| 65 |
+ |
|
| 66 |
+func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) {
|
|
| 67 |
+ var _p0 *uint16 |
|
| 68 |
+ _p0, err = syscall.UTF16PtrFromString(path) |
|
| 69 |
+ if err != nil {
|
|
| 70 |
+ return |
|
| 71 |
+ } |
|
| 72 |
+ return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, flags, parameters, handle) |
|
| 73 |
+} |
|
| 74 |
+ |
|
| 75 |
+func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) {
|
|
| 76 |
+ 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 |
+ if r1 != 0 {
|
|
| 78 |
+ if e1 != 0 {
|
|
| 79 |
+ err = errnoErr(e1) |
|
| 80 |
+ } else {
|
|
| 81 |
+ err = syscall.EINVAL |
|
| 82 |
+ } |
|
| 83 |
+ } |
|
| 84 |
+ return |
|
| 85 |
+} |
|
| 86 |
+ |
|
| 87 |
+func detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) {
|
|
| 88 |
+ r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(flags), uintptr(providerSpecificFlags)) |
|
| 89 |
+ if r1 != 0 {
|
|
| 90 |
+ if e1 != 0 {
|
|
| 91 |
+ err = errnoErr(e1) |
|
| 92 |
+ } else {
|
|
| 93 |
+ err = syscall.EINVAL |
|
| 94 |
+ } |
|
| 95 |
+ } |
|
| 96 |
+ return |
|
| 97 |
+} |