@ohos-ports/drivelist 12.0.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,741 @@
1
+ /*
2
+ * Copyright 2017 balena.io
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // See https://support.microsoft.com/en-us/kb/165721
18
+ #ifndef WIN32_LEAN_AND_MEAN
19
+ #define WIN32_LEAN_AND_MEAN
20
+ #endif
21
+
22
+ #include <windows.h>
23
+ #include <winioctl.h>
24
+ #include <cfgmgr32.h>
25
+ #include <setupapi.h>
26
+ #include <shlobj.h>
27
+ #include <string.h>
28
+ #include <stdint.h>
29
+ #include <inttypes.h>
30
+ #include <napi.h>
31
+ #include <wchar.h>
32
+ #include <string>
33
+ #include <vector>
34
+ #include <set>
35
+ #include "../drivelist.hpp"
36
+ #include "list.hpp"
37
+
38
+ namespace Drivelist {
39
+
40
+ std::string WCharToUtf8String(const wchar_t* wstr) {
41
+ if (!wstr) {
42
+ return std::string();
43
+ }
44
+
45
+ int wstrSize = static_cast<int>(wcslen(wstr));
46
+ int size = WideCharToMultiByte(
47
+ CP_UTF8, 0, wstr, wstrSize, NULL, 0, NULL, NULL);
48
+ if (!size) {
49
+ return std::string();
50
+ }
51
+
52
+ std::string result(size, 0);
53
+ int utf8Size = WideCharToMultiByte(
54
+ CP_UTF8, 0, wstr, wstrSize, &result[0], size, NULL, NULL);
55
+ if (utf8Size != size) {
56
+ return std::string();
57
+ }
58
+
59
+ return result;
60
+ }
61
+
62
+ std::string GetEnumeratorName(HDEVINFO hDeviceInfo,
63
+ SP_DEVINFO_DATA deviceInfoData) {
64
+ char buffer[MAX_PATH];
65
+
66
+ ZeroMemory(&buffer, sizeof(buffer));
67
+
68
+ BOOL hasEnumeratorName = SetupDiGetDeviceRegistryPropertyA(
69
+ hDeviceInfo, &deviceInfoData, SPDRP_ENUMERATOR_NAME,
70
+ NULL, (LPBYTE) buffer, sizeof(buffer), NULL);
71
+
72
+ return hasEnumeratorName ? std::string(buffer) : std::string();
73
+ }
74
+
75
+ std::string GetFriendlyName(HDEVINFO hDeviceInfo,
76
+ SP_DEVINFO_DATA deviceInfoData) {
77
+ wchar_t wbuffer[MAX_PATH];
78
+
79
+ ZeroMemory(&wbuffer, sizeof(wbuffer));
80
+
81
+ BOOL hasFriendlyName = SetupDiGetDeviceRegistryPropertyW(
82
+ hDeviceInfo, &deviceInfoData, SPDRP_FRIENDLYNAME,
83
+ NULL, (PBYTE) wbuffer, sizeof(wbuffer), NULL);
84
+
85
+ return hasFriendlyName ? WCharToUtf8String(wbuffer) : std::string("");
86
+ }
87
+
88
+ bool IsSCSIDevice(std::string enumeratorName) {
89
+ for (std::string driverName : GENERIC_STORAGE_DRIVERS) {
90
+ if (enumeratorName == driverName) {
91
+ return true;
92
+ }
93
+ }
94
+
95
+ return false;
96
+ }
97
+
98
+ bool IsUSBDevice(std::string enumeratorName) {
99
+ for (std::string driverName : USB_STORAGE_DRIVERS) {
100
+ if (enumeratorName == driverName) {
101
+ return true;
102
+ }
103
+ }
104
+
105
+ return false;
106
+ }
107
+
108
+ bool IsRemovableDevice(HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
109
+ DWORD result = 0;
110
+
111
+ BOOL hasRemovalPolicy = SetupDiGetDeviceRegistryProperty(
112
+ hDeviceInfo, &deviceInfoData, SPDRP_REMOVAL_POLICY,
113
+ NULL, (PBYTE) &result, sizeof(result), NULL);
114
+
115
+ switch (result) {
116
+ case CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL:
117
+ case CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL:
118
+ return true;
119
+ default:
120
+ return false;
121
+ }
122
+
123
+ return false;
124
+ }
125
+
126
+ bool IsVirtualHardDrive(HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
127
+ char buffer[MAX_PATH];
128
+
129
+ ZeroMemory(&buffer, sizeof(buffer));
130
+
131
+ BOOL hasHardwareId = SetupDiGetDeviceRegistryPropertyA(
132
+ hDeviceInfo, &deviceInfoData, SPDRP_HARDWAREID,
133
+ NULL, (LPBYTE) buffer, sizeof(buffer), NULL);
134
+
135
+ if (!hasHardwareId) {
136
+ return false;
137
+ }
138
+
139
+ // printf("SPDRP_HARDWAREID: %s\n", buffer);
140
+
141
+ std::string hardwareId(buffer);
142
+
143
+ for (std::string vhdHardwareId : VHD_HARDWARE_IDS) {
144
+ if (hardwareId.find(vhdHardwareId, 0) != std::string::npos) {
145
+ return true;
146
+ }
147
+ }
148
+
149
+ return false;
150
+ }
151
+
152
+ bool IsSystemDevice(HDEVINFO hDeviceInfo, DeviceDescriptor *device) {
153
+ PWSTR folderPath = NULL;
154
+ BOOL isSystem = false;
155
+
156
+ for (const GUID folderId : KNOWN_FOLDER_IDS) {
157
+ HRESULT result = SHGetKnownFolderPath(
158
+ folderId, 0, NULL, &folderPath);
159
+
160
+ if (result == S_OK) {
161
+ std::string systemPath = WCharToUtf8String(folderPath);
162
+ // printf("systemPath %s\n", systemPath.c_str());
163
+ for (std::string mountpoint : device->mountpoints) {
164
+ // printf("%s find %s\n", systemPath.c_str(), mountpoint.c_str());
165
+ if (systemPath.find(mountpoint, 0) != std::string::npos) {
166
+ isSystem = true;
167
+ break;
168
+ }
169
+ }
170
+ }
171
+
172
+ CoTaskMemFree(folderPath);
173
+ }
174
+
175
+ return isSystem;
176
+ }
177
+
178
+ std::vector<std::string> GetAvailableVolumes() {
179
+ DWORD logicalDrivesMask = GetLogicalDrives();
180
+ std::vector<std::string> logicalDrives;
181
+
182
+ if (logicalDrivesMask == 0) {
183
+ return logicalDrives;
184
+ }
185
+
186
+ char currentDriveLetter = 'A';
187
+
188
+ while (logicalDrivesMask) {
189
+ if (logicalDrivesMask & 1) {
190
+ logicalDrives.push_back(std::string(1, currentDriveLetter));
191
+ }
192
+ currentDriveLetter++;
193
+ logicalDrivesMask >>= 1;
194
+ }
195
+
196
+ return logicalDrives;
197
+ }
198
+
199
+ int32_t GetDeviceNumber(HANDLE hDevice) {
200
+ BOOL result;
201
+ DWORD size;
202
+ DWORD errorCode = 0;
203
+ int32_t diskNumber = -1;
204
+
205
+ STORAGE_DEVICE_NUMBER deviceNumber;
206
+ VOLUME_DISK_EXTENTS diskExtents;
207
+
208
+ // Some devices will have the diskNumber exposed through their disk extents,
209
+ // while most of them will only have one accessible through
210
+ // `IOCTL_STORAGE_GET_DEVICE_NUMBER`, so we check this one first,
211
+ // augmenting / overriding it with the latter
212
+ result = DeviceIoControl(
213
+ hDevice, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,
214
+ &diskExtents, sizeof(VOLUME_DISK_EXTENTS), &size, NULL);
215
+
216
+ if (result && diskExtents.NumberOfDiskExtents > 0) {
217
+ // printf("[INFO] DiskNumber: %i\n", diskExtents.Extents[0].DiskNumber);
218
+
219
+ // NOTE: Always ignore RAIDs
220
+ // TODO(jhermsmeier): Handle RAIDs properly
221
+ if (diskExtents.NumberOfDiskExtents >= 2) {
222
+ // printf("[INFO] Possible RAID: %i\n",
223
+ // diskExtents.Extents[0].DiskNumber);
224
+ return -1;
225
+ }
226
+ diskNumber = diskExtents.Extents[0].DiskNumber;
227
+ } else {
228
+ errorCode = GetLastError();
229
+ // printf("[INFO] VOLUME_GET_VOLUME_DISK_EXTENTS: Error 0x%08lX\n",
230
+ // errorCode);
231
+ }
232
+
233
+ result = DeviceIoControl(
234
+ hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
235
+ &deviceNumber, sizeof(deviceNumber), &size, NULL);
236
+
237
+ if (result) {
238
+ // printf("[INFO] DeviceNumber: %i\n", deviceNumber.DeviceNumber);
239
+ diskNumber = deviceNumber.DeviceNumber;
240
+ }
241
+
242
+ // errorCode = GetLastError();
243
+ // printf("[INFO] STORAGE_GET_DEVICE_NUMBER: Error 0x%08lX\n", errorCode);
244
+
245
+ return diskNumber;
246
+ }
247
+
248
+ void GetMountpoints(int32_t deviceNumber,
249
+ std::vector<std::string> *mountpoints) {
250
+ HANDLE hLogical = INVALID_HANDLE_VALUE;
251
+ int32_t logicalVolumeDeviceNumber = -1;
252
+ UINT driveType;
253
+
254
+ std::vector<std::string> logicalVolumes = GetAvailableVolumes();
255
+
256
+ for (std::string volumeName : logicalVolumes) {
257
+ if (hLogical != INVALID_HANDLE_VALUE) {
258
+ CloseHandle(hLogical);
259
+ hLogical = INVALID_HANDLE_VALUE;
260
+ }
261
+
262
+ // NOTE: Ignore everything that's not a fixed or removable drive,
263
+ // as device numbers are not unique across storage type drivers (!?),
264
+ // and this would otherwise cause CD/DVD drive letters to be
265
+ // attributed to blockdevices
266
+ driveType = GetDriveTypeA((volumeName + ":\\").c_str());
267
+
268
+ // printf("[INFO] Checking %s:/\n", volumeName.c_str());
269
+
270
+ if ((driveType != DRIVE_FIXED) && (driveType != DRIVE_REMOVABLE)) {
271
+ // printf("[INFO] Ignoring volume %s:/ - Not FIXED | REMOVABLE\n",
272
+ // volumeName.c_str());
273
+ continue;
274
+ }
275
+
276
+ hLogical = CreateFileA(
277
+ ("\\\\.\\" + volumeName + ":").c_str(), 0,
278
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
279
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
280
+
281
+ if (hLogical == INVALID_HANDLE_VALUE) {
282
+ // printf("[INFO] Couldn't open handle to logical volume %s\n",
283
+ // volumeName.c_str());
284
+ continue;
285
+ }
286
+
287
+ logicalVolumeDeviceNumber = GetDeviceNumber(hLogical);
288
+
289
+ if (logicalVolumeDeviceNumber == -1) {
290
+ // printf("[INFO] Couldn't get device number for logical volume %s\n",
291
+ // volumeName.c_str());
292
+ continue;
293
+ }
294
+
295
+ if (logicalVolumeDeviceNumber == deviceNumber) {
296
+ // printf("[INFO] Device number for logical volume %s is %i\n",
297
+ // volumeName.c_str(), logicalVolumeDeviceNumber);
298
+ mountpoints->push_back(volumeName + ":\\");
299
+ }
300
+ }
301
+
302
+ if (hLogical != INVALID_HANDLE_VALUE) {
303
+ CloseHandle(hLogical);
304
+ hLogical = INVALID_HANDLE_VALUE;
305
+ }
306
+ }
307
+
308
+ std::string GetBusType(STORAGE_ADAPTER_DESCRIPTOR *adapterDescriptor) {
309
+ switch (adapterDescriptor->BusType) {
310
+ case STORAGE_BUS_TYPE::BusTypeUnknown: return "UNKNOWN";
311
+ case STORAGE_BUS_TYPE::BusTypeScsi: return "SCSI";
312
+ case STORAGE_BUS_TYPE::BusTypeAtapi: return "ATAPI";
313
+ case STORAGE_BUS_TYPE::BusTypeAta: return "ATA";
314
+ case STORAGE_BUS_TYPE::BusType1394: return "1394"; // IEEE 1394
315
+ case STORAGE_BUS_TYPE::BusTypeSsa: return "SSA";
316
+ case STORAGE_BUS_TYPE::BusTypeFibre: return "FIBRE";
317
+ case STORAGE_BUS_TYPE::BusTypeUsb: return "USB";
318
+ case STORAGE_BUS_TYPE::BusTypeRAID: return "RAID";
319
+ case STORAGE_BUS_TYPE::BusTypeiScsi: return "iSCSI";
320
+ case STORAGE_BUS_TYPE::BusTypeSas: return "SAS"; // Serial-Attached SCSI
321
+ case STORAGE_BUS_TYPE::BusTypeSata: return "SATA";
322
+ case STORAGE_BUS_TYPE::BusTypeSd: return "SD"; // Secure Digital (SD)
323
+ case STORAGE_BUS_TYPE::BusTypeMmc: return "MMC"; // Multimedia card
324
+ case STORAGE_BUS_TYPE::BusTypeVirtual: return "VIRTUAL";
325
+ case STORAGE_BUS_TYPE::BusTypeFileBackedVirtual: return "FILEBACKEDVIRTUAL";
326
+ default: return "INVALID";
327
+ }
328
+ }
329
+
330
+ bool GetAdapterInfo(HANDLE hPhysical, DeviceDescriptor *device) {
331
+ STORAGE_PROPERTY_QUERY query;
332
+ STORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
333
+ DWORD size = 0;
334
+
335
+ ZeroMemory(&query, sizeof(query));
336
+
337
+ query.QueryType = STORAGE_QUERY_TYPE::PropertyStandardQuery;
338
+ query.PropertyId = STORAGE_PROPERTY_ID::StorageAdapterProperty;
339
+
340
+ BOOL hasAdapterInfo = DeviceIoControl(
341
+ hPhysical, IOCTL_STORAGE_QUERY_PROPERTY,
342
+ &query, sizeof(STORAGE_PROPERTY_QUERY),
343
+ &adapterDescriptor, sizeof(STORAGE_ADAPTER_DESCRIPTOR), &size, NULL);
344
+
345
+ if (hasAdapterInfo) {
346
+ device->busType = GetBusType(&adapterDescriptor);
347
+ device->busVersion = std::to_string(adapterDescriptor.BusMajorVersion) +
348
+ "." + std::to_string(adapterDescriptor.BusMinorVersion);
349
+ return true;
350
+ }
351
+
352
+ return false;
353
+ }
354
+
355
+ bool GetDeviceBlockSize(HANDLE hPhysical, DeviceDescriptor *device) {
356
+ STORAGE_PROPERTY_QUERY query;
357
+ STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR alignmentDescriptor;
358
+ DWORD size = 0;
359
+
360
+ ZeroMemory(&query, sizeof(query));
361
+
362
+ query.QueryType = STORAGE_QUERY_TYPE::PropertyStandardQuery;
363
+ query.PropertyId = STORAGE_PROPERTY_ID::StorageAccessAlignmentProperty;
364
+
365
+ BOOL hasAlignmentDescriptor = DeviceIoControl(
366
+ hPhysical, IOCTL_STORAGE_QUERY_PROPERTY,
367
+ &query, sizeof(STORAGE_PROPERTY_QUERY),
368
+ &alignmentDescriptor, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
369
+ &size, NULL);
370
+
371
+ if (hasAlignmentDescriptor) {
372
+ device->blockSize = alignmentDescriptor.BytesPerPhysicalSector;
373
+ device->logicalBlockSize = alignmentDescriptor.BytesPerLogicalSector;
374
+ return true;
375
+ }
376
+
377
+ return false;
378
+ }
379
+
380
+ bool GetPartitionTableType(HANDLE hPhysical, DeviceDescriptor *device) {
381
+ // Works for up to 256 partitions (Windows only allows 128 for GPT partition
382
+ // tables anyway)
383
+ int lsize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + \
384
+ 256 * sizeof(PARTITION_INFORMATION_EX);
385
+ DRIVE_LAYOUT_INFORMATION_EX *diskLayout;
386
+ diskLayout = reinterpret_cast<DRIVE_LAYOUT_INFORMATION_EX*>(new BYTE[lsize]);
387
+ DWORD diskLayoutSize = 0;
388
+ BOOL hasDiskLayout = DeviceIoControl(
389
+ hPhysical,
390
+ IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
391
+ NULL,
392
+ 0,
393
+ diskLayout,
394
+ lsize,
395
+ &diskLayoutSize,
396
+ NULL);
397
+ if (!hasDiskLayout) {
398
+ free(diskLayout);
399
+ return hasDiskLayout;
400
+ }
401
+ /*
402
+ diskLayout->PartitionStyle will never be PARTITION_STYLE_RAW, it will be
403
+ * PARTITION_STYLE_GPT for gpt partition tables
404
+ * PARTITION_STYLE_MBR for anything else: mbr partition tables, zeroes,
405
+ random data, raw partitions
406
+ The only way to differentiate a real mbr partition table from random data
407
+ is that for real mbr partition tables diskLayout->PartitionCount will be a
408
+ multiple of 4 and 1 for anything else.
409
+ See the table below.
410
+
411
+ *pe0 = PartitionEntry[0]
412
+
413
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
414
+ | field \ partition table type | gpt | mbr with one part | empty mbr | zeroes | random | raw ext4 partition | raw fat partition |
415
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+--------------------+----------------------+
416
+ | PartitionStyle | PARTITION_STYLE_GPT | PARTITION_STYLE_MBR | PARTITION_STYLE_MBR | PARTITION_STYLE_MBR | PARTITION_STYLE_MBR | PARTITION_STYLE_MBR | PARTITION_STYLE_MBR |
417
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
418
+ | PartitionCount | 5 | 4 | 4 | 1 | 1 | 1 | 1 |
419
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
420
+ | Mbr.Signature | na | 600574350 | 1477769759 | 1 | 1 | 1 | 1 |
421
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
422
+ | pe0.StartingOffset | na | 1048576 | 0 | 0 | 0 | 0 | 0 |
423
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
424
+ | pe0.PartitionLength | na | 31913410560 | 0 | 31914983424 | 31914983424 | 31914983424 | 31914983424 |
425
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
426
+ | pe0.PartitionNumber | na | 1 | 0 | 1 | 1 | 1 | 1 |
427
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
428
+ | pe0.Mbr.PartitionType | na | 7 | 0 | 4 | 4 | 4 | 4 |
429
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
430
+ | pe0.Mbr.BootIndicator | na | 0 | 0 | 0 | 0 | 0 | 0 |
431
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
432
+ | pe0.Mbr.RecognizedPartition | na | 1 | 0 | 1 | 1 | 1 | 1 |
433
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
434
+ | pe0.Mbr.HiddenSectors | na | 2048 | 0 | 0 | 0 | 0 | 0 |
435
+ +------------------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
436
+ */
437
+ if ((diskLayout->PartitionStyle == PARTITION_STYLE_MBR) &&
438
+ ((diskLayout->PartitionCount % 4) == 0)) {
439
+ device->partitionTableType = "mbr";
440
+ } else if (diskLayout->PartitionStyle == PARTITION_STYLE_GPT) {
441
+ device->partitionTableType = "gpt";
442
+ }
443
+ free(diskLayout);
444
+ return hasDiskLayout;
445
+ }
446
+
447
+ bool GetDeviceSize(HANDLE hPhysical, DeviceDescriptor *device) {
448
+ DISK_GEOMETRY_EX diskGeometry;
449
+
450
+ // printf("[INFO] hasDiskGeometry\n");
451
+
452
+ BOOL hasDiskGeometry = false;
453
+ DWORD size = 0;
454
+
455
+ hasDiskGeometry = DeviceIoControl(
456
+ hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0,
457
+ &diskGeometry, sizeof(DISK_GEOMETRY_EX), &size, NULL);
458
+
459
+ // printf("[INFO] hasDiskGeometry %i\n", hasDiskGeometry);
460
+
461
+ // NOTE: Another way to get the block size would be
462
+ // `IOCTL_STORAGE_QUERY_PROPERTY` with `STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR`,
463
+ // which can yield more (or possibly more accurate?) info,
464
+ // but might not work with external HDDs/SSDs
465
+ if (hasDiskGeometry) {
466
+ device->size = diskGeometry.DiskSize.QuadPart;
467
+ device->blockSize = diskGeometry.Geometry.BytesPerSector;
468
+ }
469
+
470
+ return hasDiskGeometry;
471
+ }
472
+
473
+ bool GetDetailData(DeviceDescriptor* device,
474
+ HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
475
+ DWORD index;
476
+ DWORD size;
477
+ DWORD errorCode = 0;
478
+ bool result = true;
479
+
480
+ HANDLE hDevice = INVALID_HANDLE_VALUE;
481
+ HANDLE hPhysical = INVALID_HANDLE_VALUE;
482
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
483
+ PSP_DEVICE_INTERFACE_DETAIL_DATA_W deviceDetailData(NULL);
484
+
485
+ for (index = 0; ; index++) {
486
+ if (hDevice != INVALID_HANDLE_VALUE) {
487
+ CloseHandle(hDevice);
488
+ hDevice = INVALID_HANDLE_VALUE;
489
+ }
490
+
491
+ if (hPhysical != INVALID_HANDLE_VALUE) {
492
+ CloseHandle(hPhysical);
493
+ hPhysical = INVALID_HANDLE_VALUE;
494
+ }
495
+
496
+ deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
497
+
498
+ // printf("[INFO] (%i) SetupDiEnumDeviceInterfaces - isDisk\n", index);
499
+
500
+ BOOL isDisk = SetupDiEnumDeviceInterfaces(
501
+ hDeviceInfo, &deviceInfoData, &GUID_DEVICE_INTERFACE_DISK,
502
+ index, &deviceInterfaceData);
503
+
504
+ if (!isDisk) {
505
+ errorCode = GetLastError();
506
+ if (errorCode == ERROR_NO_MORE_ITEMS) {
507
+ // printf("[INFO] (%i) EnumDeviceInterfaces: No more items 0x%08lX\n",
508
+ // index, errorCode);
509
+ result = index != 0;
510
+ break;
511
+ } else {
512
+ device->error = "SetupDiEnumDeviceInterfaces: Error " +
513
+ std::to_string(errorCode);
514
+ }
515
+ result = false;
516
+ break;
517
+ }
518
+
519
+ BOOL hasDeviceInterfaceData = SetupDiGetDeviceInterfaceDetailW(
520
+ hDeviceInfo, &deviceInterfaceData, NULL, 0, &size, NULL);
521
+
522
+ if (!hasDeviceInterfaceData) {
523
+ errorCode = GetLastError();
524
+ if (errorCode == ERROR_INSUFFICIENT_BUFFER) {
525
+ deviceDetailData = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>
526
+ (malloc(size));
527
+ if (deviceDetailData == NULL) {
528
+ device->error = "SetupDiGetDeviceInterfaceDetailW: "
529
+ "Unable to allocate SP_DEVICE_INTERFACE_DETAIL_DATA_W"
530
+ "(" + std::to_string(size) + "); "
531
+ "Error " + std::to_string(errorCode);
532
+ result = false;
533
+ break;
534
+ }
535
+ // printf("Allocated SP_DEVICE_INTERFACE_DETAIL_DATA_W\n");
536
+ } else {
537
+ device->error = "SetupDiGetDeviceInterfaceDetailW: "
538
+ "Couldn't get detail data; Error " + std::to_string(errorCode);
539
+ result = false;
540
+ break;
541
+ }
542
+ }
543
+
544
+ // printf("[INFO] (%i) Getting SP_DEVICE_INTERFACE_DETAIL_DATA_W\n", index);
545
+
546
+ deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
547
+
548
+ BOOL hasDeviceDetail = SetupDiGetDeviceInterfaceDetailW(
549
+ hDeviceInfo, &deviceInterfaceData, deviceDetailData, size, &size, NULL);
550
+
551
+ if (!hasDeviceDetail) {
552
+ errorCode = GetLastError();
553
+ device->error = "Couldn't SetupDiGetDeviceInterfaceDetailW: Error " +
554
+ std::to_string(errorCode);
555
+ result = false;
556
+ break;
557
+ }
558
+
559
+ // printf("[INFO] (%i) SetupDiGetDeviceInterfaceDetailW:\n %s\n",
560
+ // index, WCharToUtf8(deviceDetailData->DevicePath));
561
+
562
+ // Passing zero to `CreateFile()` doesn't require permissions to
563
+ // open the device handle, but only lets you acquire device metadata,
564
+ // which is all we want
565
+ hDevice = CreateFileW(
566
+ deviceDetailData->DevicePath, 0,
567
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
568
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
569
+
570
+ if (hDevice == INVALID_HANDLE_VALUE) {
571
+ errorCode = GetLastError();
572
+ // printf("[ERROR] Couldn't open handle to device: Error %i", errorCode);
573
+ device->error = "Couldn't open handle to device: Error " +
574
+ std::to_string(errorCode);
575
+ result = false;
576
+ break;
577
+ }
578
+
579
+ int32_t deviceNumber = GetDeviceNumber(hDevice);
580
+
581
+ if (deviceNumber == -1) {
582
+ device->error = "Couldn't get device number";
583
+ result = false;
584
+ break;
585
+ }
586
+
587
+ device->raw = "\\\\.\\PhysicalDrive" + std::to_string(deviceNumber);
588
+ device->device = device->raw;
589
+
590
+ GetMountpoints(deviceNumber, &device->mountpoints);
591
+
592
+ // printf("[INFO] Opening handle to %s\n", device->raw.c_str());
593
+
594
+ hPhysical = CreateFileA(
595
+ device->raw.c_str(), 0,
596
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
597
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
598
+
599
+ // printf("[INFO] Opened handle to %s\n", device->raw.c_str());
600
+ // printf("[INFO] Handle %i (INVALID %i)\n",
601
+ // hPhysical, INVALID_HANDLE_VALUE);
602
+
603
+ if (hPhysical == INVALID_HANDLE_VALUE) {
604
+ errorCode = GetLastError();
605
+ // printf("[INFO] Couldn't open handle to %s: Error %i\n",
606
+ // device->raw.c_str(), errorCode);
607
+ device->error = "Couldn't open handle to physical device: Error " +
608
+ std::to_string(errorCode);
609
+ result = false;
610
+ break;
611
+ }
612
+
613
+ // printf("[INFO] GetDeviceSize( %s )\n", device->raw.c_str());
614
+
615
+ if (!GetDeviceSize(hPhysical, device)) {
616
+ errorCode = GetLastError();
617
+ // printf("[ERROR] Couldn't get disk geometry: Error %i\n", errorCode);
618
+ device->error = "Couldn't get disk geometry: Error " +
619
+ std::to_string(errorCode);
620
+ result = false;
621
+ break;
622
+ }
623
+
624
+ if (!GetPartitionTableType(hPhysical, device)) {
625
+ errorCode = GetLastError();
626
+ device->error = "Couldn't get disk partition table type: Error " +
627
+ std::to_string(errorCode);
628
+ result = false;
629
+ break;
630
+ }
631
+
632
+ // printf("[INFO] GetAdapterInfo( %s )\n", device->raw.c_str());
633
+
634
+ if (!GetAdapterInfo(hPhysical, device)) {
635
+ errorCode = GetLastError();
636
+ // printf("[ERROR] Couldn't get device adapter descriptor: Error %i\n",
637
+ // errorCode);
638
+ device->error = "Couldn't get device adapter descriptor: Error " +
639
+ std::to_string(errorCode);
640
+ result = false;
641
+ break;
642
+ }
643
+
644
+ // printf("[INFO] GetDeviceBlockSize( %s )\n", device->raw.c_str());
645
+
646
+ // NOTE: No need to fail over this one,
647
+ // as we can safely default to a 512B block size
648
+ if (!GetDeviceBlockSize(hPhysical, device)) {
649
+ errorCode = GetLastError();
650
+ // printf("[INFO] Couldn't get block size: Error %u\n", errorCode);
651
+ }
652
+
653
+ // printf("[INFO] isWritable( %s )\n", device->raw.c_str());
654
+
655
+ BOOL isWritable = DeviceIoControl(
656
+ hPhysical, IOCTL_DISK_IS_WRITABLE, NULL, 0,
657
+ NULL, 0, &size, NULL);
658
+
659
+ device->isReadOnly = !isWritable;
660
+ } // end for (index = 0; ; index++)
661
+
662
+ if (hDevice != INVALID_HANDLE_VALUE) {
663
+ CloseHandle(hDevice);
664
+ hDevice = INVALID_HANDLE_VALUE;
665
+ }
666
+
667
+ if (hPhysical != INVALID_HANDLE_VALUE) {
668
+ CloseHandle(hPhysical);
669
+ hPhysical = INVALID_HANDLE_VALUE;
670
+ }
671
+
672
+ free(deviceDetailData);
673
+
674
+ return result;
675
+ }
676
+
677
+ std::vector<DeviceDescriptor> ListStorageDevices() {
678
+ HDEVINFO hDeviceInfo = NULL;
679
+ SP_DEVINFO_DATA deviceInfoData;
680
+ std::vector<DeviceDescriptor> deviceList;
681
+
682
+ DWORD i;
683
+ std::string enumeratorName;
684
+ DeviceDescriptor device;
685
+
686
+ hDeviceInfo = SetupDiGetClassDevsA(
687
+ &GUID_DEVICE_INTERFACE_DISK, NULL, NULL,
688
+ DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
689
+
690
+ if (hDeviceInfo == INVALID_HANDLE_VALUE) {
691
+ // printf("[ERROR] Invalid DeviceInfo handle\n");
692
+ return deviceList;
693
+ }
694
+
695
+ deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
696
+
697
+ for (i = 0; SetupDiEnumDeviceInfo(hDeviceInfo, i, &deviceInfoData); i++) {
698
+ enumeratorName = GetEnumeratorName(hDeviceInfo, deviceInfoData);
699
+
700
+ // printf("[INFO] Enumerating %s\n", enumeratorName.c_str());
701
+
702
+ // If it failed to get the SPDRP_ENUMERATOR_NAME, skip it
703
+ if (enumeratorName.empty()) {
704
+ continue;
705
+ }
706
+
707
+ device = DeviceDescriptor();
708
+
709
+ device.enumerator = enumeratorName;
710
+ device.description = GetFriendlyName(hDeviceInfo, deviceInfoData);
711
+ device.isRemovable = IsRemovableDevice(hDeviceInfo, deviceInfoData);
712
+ device.isVirtual = IsVirtualHardDrive(hDeviceInfo, deviceInfoData);
713
+ device.isSCSI = IsSCSIDevice(enumeratorName);
714
+ device.isUSB = IsUSBDevice(enumeratorName);
715
+ device.isCard = device.enumerator == "SD";
716
+ device.isSystem = !device.isRemovable &&
717
+ (device.enumerator == "SCSI" || device.enumerator == "IDE");
718
+ device.isUAS = device.isSCSI && device.isRemovable &&
719
+ !device.isVirtual && !device.isCard;
720
+ device.devicePathNull = true;
721
+
722
+ if (GetDetailData(&device, hDeviceInfo, deviceInfoData)) {
723
+ device.isSystem = device.isSystem || IsSystemDevice(hDeviceInfo, &device);
724
+ device.isCard = device.busType == "SD" || device.busType == "MMC";
725
+ device.isUAS = device.enumerator == "SCSI" && device.busType == "USB";
726
+ device.isVirtual = device.isVirtual ||
727
+ device.busType == "VIRTUAL" ||
728
+ device.busType == "FILEBACKEDVIRTUAL";
729
+ } else if (device.error == "") {
730
+ device.error = "Couldn't get detail data";
731
+ }
732
+
733
+ deviceList.push_back(device);
734
+ }
735
+
736
+ SetupDiDestroyDeviceInfoList(hDeviceInfo);
737
+
738
+ return deviceList;
739
+ }
740
+
741
+ } // namespace Drivelist