|
| 1 | +// +build windows |
| 2 | + |
1 | 3 | package disk |
2 | 4 |
|
3 | 5 | import ( |
4 | 6 | "encoding/json" |
5 | 7 | "fmt" |
6 | 8 | "os/exec" |
| 9 | + "strconv" |
7 | 10 | "strings" |
| 11 | + "syscall" |
| 12 | + "unsafe" |
8 | 13 |
|
9 | 14 | shared "github.com/kubernetes-csi/csi-proxy/internal/shared/disk" |
10 | 15 | "k8s.io/klog" |
11 | 16 | ) |
12 | 17 |
|
| 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 | + |
13 | 27 | // Implements the OS API calls related to Disk Devices. All code here should be very simple |
14 | 28 | // pass-through to the OS APIs or cmdlets. Any logic around the APIs/cmdlet invocation |
15 | 29 | // 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 { |
123 | 137 | return nil |
124 | 138 | } |
125 | 139 |
|
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() |
129 | 198 | 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") |
131 | 200 | } |
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) |
133 | 219 | } |
0 commit comments