Skip to content

Commit 794e186

Browse files
authored
Merge pull request #52 from ksubrmnn/disknumber
GetDiskNumberWithID API
2 parents f72dab1 + 9fcc30f commit 794e186

File tree

2 files changed

+205
-5
lines changed

2 files changed

+205
-5
lines changed

internal/os/disk/api.go

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1+
// +build windows
2+
13
package disk
24

35
import (
46
"encoding/json"
57
"fmt"
68
"os/exec"
9+
"strconv"
710
"strings"
11+
"syscall"
12+
"unsafe"
813

914
shared "github.com/kubernetes-csi/csi-proxy/internal/shared/disk"
1015
"k8s.io/klog"
1116
)
1217

18+
var (
19+
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
20+
)
21+
22+
const (
23+
IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080
24+
IOCTL_STORAGE_QUERY_PROPERTY = 0x002d1400
25+
)
26+
1327
// Implements the OS API calls related to Disk Devices. All code here should be very simple
1428
// pass-through to the OS APIs or cmdlets. Any logic around the APIs/cmdlet invocation
1529
// should go in internal/server/filesystem/disk.go so that logic can be easily unit-tested
@@ -123,11 +137,83 @@ func (APIImplementor) CreatePartition(diskID string) error {
123137
return nil
124138
}
125139

126-
func (APIImplementor) GetDiskNumberByName(diskName string) (string, error) {
127-
out, err := exec.Command("DiskUtil.exe", "-GetDiskNumberWithId", diskName).CombinedOutput()
128-
outString := string(out)
140+
func (imp APIImplementor) GetDiskNumberByName(diskName string) (string, error) {
141+
diskNumber, err := imp.GetDiskNumberWithID(diskName)
142+
return strconv.FormatUint(uint64(diskNumber), 10), err
143+
}
144+
145+
func (APIImplementor) DiskNumber(disk syscall.Handle) (uint32, error) {
146+
var bytes uint32
147+
devNum := StorageDeviceNumber{}
148+
buflen := uint32(unsafe.Sizeof(devNum.DeviceType)) + uint32(unsafe.Sizeof(devNum.DeviceNumber)) + uint32(unsafe.Sizeof(devNum.PartitionNumber))
149+
150+
err := syscall.DeviceIoControl(disk, IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, (*byte)(unsafe.Pointer(&devNum)), buflen, &bytes, nil)
151+
152+
return devNum.DeviceNumber, err
153+
}
154+
155+
func (APIImplementor) DiskHasPage83ID(disk syscall.Handle, matchID string) (bool, error) {
156+
query := StoragePropertyQuery{}
157+
158+
bufferSize := uint32(4 * 1024)
159+
buffer := make([]byte, 4*1024)
160+
var size uint32
161+
var n uint32
162+
var m uint16
163+
164+
query.QueryType = PropertyStandardQuery
165+
query.PropertyID = StorageDeviceIDProperty
166+
167+
querySize := uint32(unsafe.Sizeof(query.PropertyID)) + uint32(unsafe.Sizeof(query.QueryType)) + uint32(unsafe.Sizeof(query.Byte))
168+
querySize = uint32(unsafe.Sizeof(query))
169+
err := syscall.DeviceIoControl(disk, IOCTL_STORAGE_QUERY_PROPERTY, (*byte)(unsafe.Pointer(&query)), querySize, (*byte)(unsafe.Pointer(&buffer[0])), bufferSize, &size, nil)
170+
if err != nil {
171+
return false, fmt.Errorf("IOCTL_STORAGE_QUERY_PROPERTY failed: %v", err)
172+
}
173+
174+
devIDDesc := (*StorageDeviceIDDescriptor)(unsafe.Pointer(&buffer[0]))
175+
176+
pID := (*StorageIdentifier)(unsafe.Pointer(&devIDDesc.Identifiers[0]))
177+
178+
page83ID := []byte{}
179+
byteSize := unsafe.Sizeof(byte(0))
180+
for n = 0; n < devIDDesc.NumberOfIdentifiers; n++ {
181+
if pID.CodeSet == StorageIDCodeSetASCII && pID.Association == StorageIDAssocDevice {
182+
for m = 0; m < pID.IdentifierSize; m++ {
183+
page83ID = append(page83ID, *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pID.Identifier[0])) + byteSize*uintptr(m))))
184+
}
185+
186+
page83IDString := string(page83ID)
187+
if strings.Contains(page83IDString, matchID) {
188+
return true, nil
189+
}
190+
}
191+
pID = (*StorageIdentifier)(unsafe.Pointer(uintptr(unsafe.Pointer(pID)) + byteSize*uintptr(pID.NextOffset)))
192+
}
193+
return false, nil
194+
}
195+
196+
func (imp APIImplementor) GetDiskNumberWithID(page83ID string) (uint32, error) {
197+
out, err := exec.Command("powershell.exe", "(get-disk | select Path) | ConvertTo-Json").CombinedOutput()
129198
if err != nil {
130-
return "", fmt.Errorf("error getting disk number by name %s: %v, output %v", diskName, err, out)
199+
return 0, fmt.Errorf("Could not query disk paths")
131200
}
132-
return strings.TrimSpace(outString), nil
201+
202+
outString := string(out)
203+
diskPaths := []DiskPath{}
204+
json.Unmarshal([]byte(outString), &diskPaths)
205+
206+
for i := range diskPaths {
207+
h, err := syscall.Open(diskPaths[i].Path, syscall.O_RDONLY, 0)
208+
if err != nil {
209+
return 0, err
210+
}
211+
212+
found, err := imp.DiskHasPage83ID(h, page83ID)
213+
if found {
214+
return imp.DiskNumber(h)
215+
}
216+
}
217+
218+
return 0, fmt.Errorf("Could not find disk with Page83 ID %s", page83ID)
133219
}

internal/os/disk/types.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package disk
2+
3+
type StorageDeviceNumber struct {
4+
DeviceType DeviceType
5+
DeviceNumber uint32
6+
PartitionNumber uint32
7+
}
8+
type DeviceType uint32
9+
10+
type StoragePropertyID uint32
11+
12+
const (
13+
StorageDeviceProperty StoragePropertyID = 0
14+
StorageAdapterProperty = 1
15+
StorageDeviceIDProperty = 2
16+
StorageDeviceUniqueIDProperty = 3
17+
StorageDeviceWriteCacheProperty = 4
18+
StorageMiniportProperty = 5
19+
StorageAccessAlignmentProperty = 6
20+
StorageDeviceSeekPenaltyProperty = 7
21+
StorageDeviceTrimProperty = 8
22+
StorageDeviceWriteAggregationProperty = 9
23+
StorageDeviceDeviceTelemetryProperty = 10
24+
StorageDeviceLBProvisioningProperty = 11
25+
StorageDevicePowerProperty = 12
26+
StorageDeviceCopyOffloadProperty = 13
27+
StorageDeviceResiliencyProperty = 14
28+
StorageDeviceMediumProductType = 15
29+
StorageAdapterRpmbProperty = 16
30+
StorageAdapterCryptoProperty = 17
31+
StorageDeviceIoCapabilityProperty = 18
32+
StorageAdapterProtocolSpecificProperty = 19
33+
StorageDeviceProtocolSpecificProperty = 20
34+
StorageAdapterTemperatureProperty = 21
35+
StorageDeviceTemperatureProperty = 22
36+
StorageAdapterPhysicalTopologyProperty = 23
37+
StorageDevicePhysicalTopologyProperty = 24
38+
StorageDeviceAttributesProperty = 25
39+
StorageDeviceManagementStatus = 26
40+
StorageAdapterSerialNumberProperty = 27
41+
StorageDeviceLocationProperty = 28
42+
StorageDeviceNumaProperty = 29
43+
StorageDeviceZonedDeviceProperty = 30
44+
StorageDeviceUnsafeShutdownCount = 31
45+
StorageDeviceEnduranceProperty = 32
46+
)
47+
48+
type StorageQueryType uint32
49+
50+
const (
51+
PropertyStandardQuery StorageQueryType = iota
52+
PropertyExistsQuery
53+
PropertyMaskQuery
54+
PropertyQueryMaxDefined
55+
)
56+
57+
type StoragePropertyQuery struct {
58+
PropertyID StoragePropertyID
59+
QueryType StorageQueryType
60+
Byte []AdditionalParameters
61+
}
62+
63+
type AdditionalParameters byte
64+
65+
type StorageDeviceIDDescriptor struct {
66+
Version uint32
67+
Size uint32
68+
NumberOfIdentifiers uint32
69+
Identifiers [1]byte
70+
}
71+
72+
type StorageIdentifierCodeSet uint32
73+
74+
const (
75+
StorageIDCodeSetReserved StorageIdentifierCodeSet = 0
76+
StorageIDCodeSetBinary = 1
77+
StorageIDCodeSetASCII = 2
78+
StorageIDCodeSetUtf8 = 3
79+
)
80+
81+
type StorageIdentifierType uint32
82+
83+
const (
84+
StorageIdTypeVendorSpecific StorageIdentifierType = 0
85+
StorageIDTypeVendorID = 1
86+
StorageIDTypeEUI64 = 2
87+
StorageIDTypeFCPHName = 3
88+
StorageIDTypePortRelative = 4
89+
StorageIDTypeTargetPortGroup = 5
90+
StorageIDTypeLogicalUnitGroup = 6
91+
StorageIDTypeMD5LogicalUnitIdentifier = 7
92+
StorageIDTypeScsiNameString = 8
93+
)
94+
95+
type StorageAssociationType uint32
96+
97+
const (
98+
StorageIDAssocDevice StorageAssociationType = 0
99+
StorageIDAssocPort = 1
100+
StorageIDAssocTarget = 2
101+
)
102+
103+
type StorageIdentifier struct {
104+
CodeSet StorageIdentifierCodeSet
105+
Type StorageIdentifierType
106+
IdentifierSize uint16
107+
NextOffset uint16
108+
Association StorageAssociationType
109+
Identifier [1]byte
110+
}
111+
112+
type DiskPath struct {
113+
Path string `json:"Path"`
114+
}

0 commit comments

Comments
 (0)