Qt/QML edition

This commit is contained in:
Floris Bos 2020-03-04 16:55:40 +01:00
commit d7b361ba44
2168 changed files with 721948 additions and 0 deletions

View file

@ -0,0 +1,41 @@
/*
* Copyright 2019 balena.io
* Copyright 2018 Robin Andersson <me@robinwassen.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_DARWIN_REDISKLIST_H_
#define SRC_DARWIN_REDISKLIST_H_
#import <Foundation/Foundation.h>
/**
* Class to return a list of disks synchronously
* To use the class, just init an instance of it and
* it will populate the disks property with NSStrings
*
* @author Robin Andersson
*/
@interface REDiskList : NSObject
/**
* NSArray of disks and partitions
* Disks are in the format disk0, disk1 etc
* Partitions are in the format disk0s1, disk1s1 etc
*/
@property(readonly) NSArray *disks;
@end
#endif // SRC_DARWIN_REDISKLIST_H_

View file

@ -0,0 +1,61 @@
/*
* Copyright 2019 balena.io
* Copyright 2018 Robin Andersson <me@robinwassen.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "REDiskList.h"
#import <DiskArbitration/DiskArbitration.h>
@implementation REDiskList
- (id)init {
self = [super init];
if (self) {
_disks = [[NSMutableArray alloc] init];
[self populateDisksBlocking];
[_disks sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}
return self;
}
-(void)dealloc {
[_disks release];
[super dealloc];
}
void appendDisk(DADiskRef disk, void *context) {
NSMutableArray *_disks = (__bridge NSMutableArray*)context;
const char *bsdName = DADiskGetBSDName(disk);
if (bsdName != nil) {
[_disks addObject:[NSString stringWithUTF8String:bsdName]];
}
}
- (void)populateDisksBlocking {
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
if (session) {
DARegisterDiskAppearedCallback(session, NULL, appendDisk, (void*)_disks);
CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
DASessionScheduleWithRunLoop(session, runLoop, kCFRunLoopDefaultMode);
CFRunLoopStop(runLoop);
CFRunLoopRunInMode((CFStringRef)NSDefaultRunLoopMode, 0.05, NO);
DAUnregisterCallback(session, appendDisk, (void*)_disks);
CFRelease(session);
}
}
@end

View file

@ -0,0 +1,179 @@
/*
* Copyright 2019 balena.io
* Copyright 2018 Robin Andersson <me@robinwassen.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nan.h>
#include "../drivelist.hpp"
#import "REDiskList.h"
#import <Cocoa/Cocoa.h>
#import <DiskArbitration/DiskArbitration.h>
namespace Drivelist {
bool IsDiskPartition(NSString *disk) {
NSPredicate *partitionRegEx = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"disk\\d+s\\d+"];
return [partitionRegEx evaluateWithObject:disk];
}
bool IsCard(CFDictionaryRef diskDescription) {
CFDictionaryRef mediaIconDict = (CFDictionaryRef)CFDictionaryGetValue(
diskDescription,
kDADiskDescriptionMediaIconKey
);
if (mediaIconDict == nil) {
return false;
}
CFStringRef iconFileNameKeyRef = CFStringCreateWithCString(NULL, "IOBundleResourceFile", kCFStringEncodingUTF8);
CFStringRef iconFileNameRef = (CFStringRef)CFDictionaryGetValue(mediaIconDict, iconFileNameKeyRef);
CFRelease(iconFileNameKeyRef);
if (iconFileNameRef == nil) {
return false;
}
// macOS 10.14.3 - External SD card reader provides `Removable.icns`, not `SD.icns`.
// But we can't use it to detect SD card, because external drive has `Removable.icns` as well.
return [(NSString *)iconFileNameRef isEqualToString:@"SD.icns"];
}
NSNumber *DictionaryGetNumber(CFDictionaryRef dict, const void *key) {
return (NSNumber*)CFDictionaryGetValue(dict, key);
}
DeviceDescriptor CreateDeviceDescriptorFromDiskDescription(std::string diskBsdName, CFDictionaryRef diskDescription) {
NSString *deviceProtocol = (NSString*)CFDictionaryGetValue(diskDescription, kDADiskDescriptionDeviceProtocolKey);
NSNumber *blockSize = DictionaryGetNumber(diskDescription, kDADiskDescriptionMediaBlockSizeKey);
bool isInternal = [DictionaryGetNumber(diskDescription, kDADiskDescriptionDeviceInternalKey) boolValue];
bool isRemovable = [DictionaryGetNumber(diskDescription, kDADiskDescriptionMediaRemovableKey) boolValue];
bool isEjectable = [DictionaryGetNumber(diskDescription, kDADiskDescriptionMediaEjectableKey) boolValue];
DeviceDescriptor device = DeviceDescriptor();
device.enumerator = "DiskArbitration";
device.busType = (deviceProtocol != nil) ? [deviceProtocol UTF8String] : "";
device.busVersion = "";
device.busVersionNull = true;
device.device = "/dev/" + diskBsdName;
NSString *devicePath = (NSString*)CFDictionaryGetValue(diskDescription, kDADiskDescriptionBusPathKey);
device.devicePath = (devicePath != nil) ? [devicePath UTF8String] : "";
device.raw = "/dev/r" + diskBsdName;
NSString *description = (NSString*)CFDictionaryGetValue(diskDescription, kDADiskDescriptionMediaNameKey);
device.description = (description != nil) ? [description UTF8String] : "";
device.error = "";
// NOTE: Not sure if kDADiskDescriptionMediaBlockSizeKey returns
// the physical or logical block size since both values are equal
// on my machine
//
// The can be checked with the following command:
// diskutil info / | grep "Block Size"
device.blockSize = [blockSize unsignedIntValue];
device.logicalBlockSize = [blockSize unsignedIntValue];
device.size = [DictionaryGetNumber(diskDescription, kDADiskDescriptionMediaSizeKey) unsignedLongValue];
device.isReadOnly = ![DictionaryGetNumber(diskDescription, kDADiskDescriptionMediaWritableKey) boolValue];
device.isSystem = isInternal && !isRemovable;
device.isVirtual = ((deviceProtocol != nil) && [deviceProtocol isEqualToString:@"Virtual Interface"]);
device.isRemovable = isRemovable || isEjectable;
device.isCard = IsCard(diskDescription);
// NOTE(robin): Not convinced that these bus types should result
// in device.isSCSI = true, it is rather "not usb or sd drive" bool
// But the old implementation was like this so kept it this way
NSArray *scsiTypes = [NSArray arrayWithObjects:@"SATA", @"SCSI", @"ATA", @"IDE", @"PCI", nil];
device.isSCSI = ((deviceProtocol != nil) && [scsiTypes containsObject:deviceProtocol]);
device.isUSB = ((deviceProtocol != nil) && [deviceProtocol isEqualToString:@"USB"]);
device.isUAS = false;
device.isUASNull = true;
return device;
}
std::vector<DeviceDescriptor> ListStorageDevices() {
std::vector<DeviceDescriptor> deviceList;
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
if (session == nil) {
return deviceList;
}
REDiskList *dl = [[REDiskList alloc] init];
for (NSString* diskBsdName in dl.disks) {
if (IsDiskPartition(diskBsdName)) {
continue;
}
std::string diskBsdNameStr = [diskBsdName UTF8String];
DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, diskBsdNameStr.c_str());
if (disk == nil) {
continue;
}
CFDictionaryRef diskDescription = DADiskCopyDescription(disk);
if (diskDescription == nil) {
CFRelease(disk);
continue;
}
DeviceDescriptor device = CreateDeviceDescriptorFromDiskDescription(diskBsdNameStr, diskDescription);
deviceList.push_back(device);
CFRelease(diskDescription);
CFRelease(disk);
}
[dl release];
// Add mount points
NSArray *volumeKeys = [NSArray arrayWithObjects:NSURLVolumeNameKey, NSURLVolumeLocalizedNameKey, nil];
NSArray *volumePaths = [
[NSFileManager defaultManager]
mountedVolumeURLsIncludingResourceValuesForKeys:volumeKeys
options:0
];
for (NSURL *path in volumePaths) {
DADiskRef disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, (__bridge CFURLRef)path);
if (disk == nil) {
continue;
}
const char *bsdnameChar = DADiskGetBSDName(disk);
if (bsdnameChar == nil) {
CFRelease(disk);
continue;
}
NSString *volumeName;
[path getResourceValue:&volumeName forKey:NSURLVolumeLocalizedNameKey error:nil];
std::string partitionBsdName = std::string(bsdnameChar);
std::string diskBsdName = partitionBsdName.substr(0, partitionBsdName.find("s", 5));
for(std::vector<int>::size_type i = 0; i != deviceList.size(); i++) {
DeviceDescriptor *dd = &deviceList[i];
if (dd->device == "/dev/" + diskBsdName) {
dd->mountpoints.push_back([[path path] UTF8String]);
dd->mountpointLabels.push_back([volumeName UTF8String]);
break;
}
}
CFRelease(disk);
}
CFRelease(session);
return deviceList;
}
} // namespace Drivelist

View file

@ -0,0 +1,152 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nan.h>
#include "drivelist.hpp"
using v8::String;
using v8::Number;
using v8::Boolean;
using v8::Local;
using v8::Value;
using Nan::New;
namespace Drivelist {
v8::Local<v8::Object> PackDriveDescriptor(const DeviceDescriptor *instance) {
v8::Local<v8::Object> object = Nan::New<v8::Object>();
Nan::Set(object,
New<String>("enumerator").ToLocalChecked(),
New<String>(instance->enumerator).ToLocalChecked());
Nan::Set(object,
New<String>("busType").ToLocalChecked(),
New<String>(instance->busType).ToLocalChecked());
Local<Value> busVersion = instance->busVersionNull ?
(Local<Value>)Nan::Null() :
(Local<Value>)New<String>(instance->busVersion).ToLocalChecked();
Nan::Set(object,
New<String>("busVersion").ToLocalChecked(),
busVersion);
Nan::Set(object,
New<String>("device").ToLocalChecked(),
New<String>(instance->device).ToLocalChecked());
Local<Value> devicePath = instance->devicePathNull ?
(Local<Value>)Nan::Null() :
(Local<Value>)New<String>(instance->devicePath).ToLocalChecked();
Nan::Set(object,
New<String>("devicePath").ToLocalChecked(),
devicePath);
Nan::Set(object,
New<String>("raw").ToLocalChecked(),
New<String>(instance->raw).ToLocalChecked());
Nan::Set(object,
New<String>("description").ToLocalChecked(),
New<String>(instance->description).ToLocalChecked());
if (instance->error != "") {
Nan::Set(object,
New<String>("error").ToLocalChecked(),
New<String>(instance->error).ToLocalChecked());
} else {
Nan::Set(object,
New<String>("error").ToLocalChecked(),
Nan::Null());
}
Nan::Set(object,
New<String>("size").ToLocalChecked(),
New<Number>(static_cast<double>(instance->size)));
Nan::Set(object,
New<String>("blockSize").ToLocalChecked(),
New<Number>(static_cast<double>(instance->blockSize)));
Nan::Set(object,
New<String>("logicalBlockSize").ToLocalChecked(),
New<Number>(static_cast<double>(instance->logicalBlockSize)));
v8::Local<v8::Object> mountpoints = Nan::New<v8::Array>();
uint32_t index = 0;
for (std::string mountpointPath : instance->mountpoints) {
v8::Local<v8::Object> mountpoint = Nan::New<v8::Object>();
Nan::Set(mountpoint,
New<String>("path").ToLocalChecked(),
New<String>(mountpointPath).ToLocalChecked());
if (index < instance->mountpointLabels.size()) {
Nan::Set(mountpoint,
New<String>("label").ToLocalChecked(),
New<String>(instance->mountpointLabels[index]).ToLocalChecked());
}
Nan::Set(mountpoints, index, mountpoint);
index++;
}
Nan::Set(object,
New<String>("mountpoints").ToLocalChecked(),
mountpoints);
Nan::Set(object,
New<String>("isReadOnly").ToLocalChecked(),
New<Boolean>(instance->isReadOnly));
Nan::Set(object,
New<String>("isSystem").ToLocalChecked(),
New<Boolean>(instance->isSystem));
Nan::Set(object,
New<String>("isVirtual").ToLocalChecked(),
New<Boolean>(instance->isVirtual));
Nan::Set(object,
New<String>("isRemovable").ToLocalChecked(),
New<Boolean>(instance->isRemovable));
Nan::Set(object,
New<String>("isCard").ToLocalChecked(),
New<Boolean>(instance->isCard));
Nan::Set(object,
New<String>("isSCSI").ToLocalChecked(),
New<Boolean>(instance->isSCSI));
Nan::Set(object,
New<String>("isUSB").ToLocalChecked(),
New<Boolean>(instance->isUSB));
Local<Value> isUAS = instance->isUASNull ?
(Local<Value>)Nan::Null() :
(Local<Value>)New<Boolean>(instance->isUAS);
Nan::Set(object,
New<String>("isUAS").ToLocalChecked(),
isUAS);
return object;
}
} // namespace Drivelist

View file

@ -0,0 +1,66 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nan.h>
#include <vector>
#include "drivelist.hpp"
class DriveListWorker : public Nan::AsyncWorker {
public:
explicit DriveListWorker(Nan::Callback *callback)
: Nan::AsyncWorker(callback), devices() {}
~DriveListWorker() {}
void Execute() {
devices = Drivelist::ListStorageDevices();
}
void HandleOKCallback() {
Nan::HandleScope scope;
v8::Local<v8::Object> drives = Nan::New<v8::Array>();
uint32_t i;
uint32_t size = (uint32_t) devices.size();
for (i = 0; i < size; i++) {
Nan::Set(drives, i, Drivelist::PackDriveDescriptor(&devices[i]));
}
v8::Local<v8::Value> argv[] = { Nan::Null(), drives };
callback->Call(2, argv, async_resource);
}
private:
std::vector<Drivelist::DeviceDescriptor> devices;
};
NAN_METHOD(list) {
if (!info[0]->IsFunction()) {
return Nan::ThrowTypeError("Callback must be a function");
}
Nan::Callback *callback = new Nan::Callback(info[0].As<v8::Function>());
Nan::AsyncQueueWorker(new DriveListWorker(callback));
info.GetReturnValue().SetUndefined();
}
NAN_MODULE_INIT(InitAll) {
NAN_EXPORT(target, list);
}
NODE_MODULE(DriveList, InitAll);

View file

@ -0,0 +1,64 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_DRIVELIST_HPP_
#define SRC_DRIVELIST_HPP_
#include <nan.h>
#include <string>
#include <vector>
namespace Drivelist {
struct MountPoint {
std::string path;
};
struct DeviceDescriptor {
std::string enumerator;
std::string busType;
std::string busVersion;
bool busVersionNull;
std::string device;
std::string devicePath;
bool devicePathNull;
std::string raw;
std::string description;
std::string error;
uint64_t size;
uint32_t blockSize = 512;
uint32_t logicalBlockSize = 512;
std::vector<std::string> mountpoints;
std::vector<std::string> mountpointLabels;
bool isReadOnly; // Device is read-only
bool isSystem; // Device is a system drive
bool isVirtual; // Device is a virtual storage device
bool isRemovable; // Device is removable from the running system
bool isCard; // Device is an SD-card
bool isSCSI; // Connected via the Small Computer System Interface (SCSI)
bool isUSB; // Connected via Universal Serial Bus (USB)
bool isUAS; // Connected via the USB Attached SCSI (UAS)
bool isUASNull;
};
std::vector<DeviceDescriptor> ListStorageDevices();
v8::Local<v8::Object> PackDriveDescriptor(const DeviceDescriptor *instance);
} // namespace Drivelist
NAN_METHOD(list);
#endif // SRC_DRIVELIST_HPP_

View file

@ -0,0 +1,28 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nan.h>
#include "../drivelist.hpp"
namespace Drivelist {
// TODO(jhermsmeier): Implement
std::vector<DeviceDescriptor> ListStorageDevices() {
std::vector<DeviceDescriptor> drivelist;
return drivelist;
}
} // namespace Drivelist

View file

@ -0,0 +1,680 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// See https://support.microsoft.com/en-us/kb/165721
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <winioctl.h>
#include <cfgmgr32.h>
#include <setupapi.h>
#include <shlobj.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <nan.h>
#include <string>
#include <vector>
#include <set>
#include "../drivelist.hpp"
#include "list.hpp"
#include <devpkey.h>
// Maxnet edit
#ifndef DEVPKEY_Device_EnumeratorName
DEFINE_DEVPROPKEY(DEVPKEY_Device_EnumeratorName, 0xa45c254e,0xdf1c,0x4efd,0x80,0x20,0x67,0xd1,0x46,0xa8,0x50,0xe0, 24);
#endif
//
namespace Drivelist {
char* WCharToUtf8(const wchar_t* wstr) {
char *str = NULL;
size_t size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
if (size <= 1) {
return NULL;
}
if ((str = reinterpret_cast<char*>(calloc(size, 1))) == NULL) {
return NULL;
}
size_t utf8Size = WideCharToMultiByte(
CP_UTF8, 0, wstr, -1, str, size, NULL, NULL);
if (utf8Size != size) {
free(str);
return NULL;
}
return str;
}
char* GetEnumeratorName(HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
char buffer[MAX_PATH];
ZeroMemory(&buffer, sizeof(buffer));
BOOL hasEnumeratorName = SetupDiGetDeviceRegistryPropertyA(
hDeviceInfo, &deviceInfoData, SPDRP_ENUMERATOR_NAME,
NULL, (LPBYTE) buffer, sizeof(buffer), NULL);
/*if (!hasEnumeratorName)
{
hasEnumeratorName = SetupDiGetDevicePropertyW(hDeviceInfo, &deviceInfoData, &DEVPKEY_Device_EnumeratorName, NULL, (LPBYTE) buffer, sizeof(buffer), NULL, 0);
}*/
return hasEnumeratorName ? buffer : NULL;
}
std::string GetFriendlyName(HDEVINFO hDeviceInfo,
SP_DEVINFO_DATA deviceInfoData) {
wchar_t wbuffer[MAX_PATH];
ZeroMemory(&wbuffer, sizeof(wbuffer));
BOOL hasFriendlyName = SetupDiGetDeviceRegistryPropertyW(
hDeviceInfo, &deviceInfoData, SPDRP_FRIENDLYNAME,
NULL, (PBYTE) wbuffer, sizeof(wbuffer), NULL);
return hasFriendlyName ? WCharToUtf8(wbuffer) : std::string("");
}
bool IsSCSIDevice(std::string enumeratorName) {
for (std::string driverName : GENERIC_STORAGE_DRIVERS) {
if (enumeratorName == driverName) {
return true;
}
}
return false;
}
bool IsUSBDevice(std::string enumeratorName) {
for (std::string driverName : USB_STORAGE_DRIVERS) {
if (enumeratorName == driverName) {
return true;
}
}
return false;
}
bool IsRemovableDevice(HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
DWORD result = 0;
BOOL hasRemovalPolicy = SetupDiGetDeviceRegistryProperty(
hDeviceInfo, &deviceInfoData, SPDRP_REMOVAL_POLICY,
NULL, (PBYTE) &result, sizeof(result), NULL);
switch (result) {
case CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL:
case CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL:
return true;
default:
return false;
}
return false;
}
bool IsVirtualHardDrive(HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
char buffer[MAX_PATH];
ZeroMemory(&buffer, sizeof(buffer));
BOOL hasHardwareId = SetupDiGetDeviceRegistryPropertyA(
hDeviceInfo, &deviceInfoData, SPDRP_HARDWAREID,
NULL, (LPBYTE) buffer, sizeof(buffer), NULL);
if (!hasHardwareId) {
return false;
}
// printf("SPDRP_HARDWAREID: %s\n", buffer);
std::string hardwareId(buffer);
for (std::string vhdHardwareId : VHD_HARDWARE_IDS) {
if (hardwareId.find(vhdHardwareId, 0) != std::string::npos) {
return true;
}
}
return false;
}
bool IsSystemDevice(HDEVINFO hDeviceInfo, DeviceDescriptor *device) {
PWSTR folderPath = NULL;
BOOL isSystem = false;
for (const GUID folderId : KNOWN_FOLDER_IDS) {
HRESULT result = SHGetKnownFolderPath(
folderId, 0, NULL, &folderPath);
if (result == S_OK) {
std::string systemPath = WCharToUtf8(folderPath);
// printf("systemPath %s\n", systemPath.c_str());
for (std::string mountpoint : device->mountpoints) {
// printf("%s find %s\n", systemPath.c_str(), mountpoint.c_str());
if (systemPath.find(mountpoint, 0) != std::string::npos) {
isSystem = true;
break;
}
}
}
CoTaskMemFree(folderPath);
}
return isSystem;
}
std::vector<std::string> GetAvailableVolumes() {
DWORD logicalDrivesMask = GetLogicalDrives();
std::vector<std::string> logicalDrives;
if (logicalDrivesMask == 0) {
return logicalDrives;
}
char currentDriveLetter = 'A';
while (logicalDrivesMask) {
if (logicalDrivesMask & 1) {
logicalDrives.push_back(std::string(1, currentDriveLetter));
}
currentDriveLetter++;
logicalDrivesMask >>= 1;
}
return logicalDrives;
}
int32_t GetDeviceNumber(HANDLE hDevice) {
BOOL result;
DWORD size;
DWORD errorCode = 0;
int32_t diskNumber = -1;
STORAGE_DEVICE_NUMBER deviceNumber;
VOLUME_DISK_EXTENTS diskExtents;
// Some devices will have the diskNumber exposed through their disk extents,
// while most of them will only have one accessible through
// `IOCTL_STORAGE_GET_DEVICE_NUMBER`, so we check this one first,
// augmenting / overriding it with the latter
result = DeviceIoControl(
hDevice, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,
&diskExtents, sizeof(VOLUME_DISK_EXTENTS), &size, NULL);
if (result && diskExtents.NumberOfDiskExtents > 0) {
// printf("[INFO] DiskNumber: %i\n", diskExtents.Extents[0].DiskNumber);
// NOTE: Always ignore RAIDs
// TODO(jhermsmeier): Handle RAIDs properly
if (diskExtents.NumberOfDiskExtents >= 2) {
// printf("[INFO] Possible RAID: %i\n",
// diskExtents.Extents[0].DiskNumber);
return -1;
}
diskNumber = diskExtents.Extents[0].DiskNumber;
} else {
errorCode = GetLastError();
// printf("[INFO] VOLUME_GET_VOLUME_DISK_EXTENTS: Error 0x%08lX\n",
// errorCode);
}
result = DeviceIoControl(
hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
&deviceNumber, sizeof(deviceNumber), &size, NULL);
if (result) {
// printf("[INFO] DeviceNumber: %i\n", deviceNumber.DeviceNumber);
diskNumber = deviceNumber.DeviceNumber;
}
// errorCode = GetLastError();
// printf("[INFO] STORAGE_GET_DEVICE_NUMBER: Error 0x%08lX\n", errorCode);
return diskNumber;
}
void GetMountpoints(int32_t deviceNumber,
std::vector<std::string> *mountpoints) {
HANDLE hLogical = INVALID_HANDLE_VALUE;
int32_t logicalVolumeDeviceNumber = -1;
UINT driveType;
std::vector<std::string> logicalVolumes = GetAvailableVolumes();
for (std::string volumeName : logicalVolumes) {
if (hLogical != INVALID_HANDLE_VALUE) {
CloseHandle(hLogical);
hLogical = INVALID_HANDLE_VALUE;
}
// NOTE: Ignore everything that's not a fixed or removable drive,
// as device numbers are not unique across storage type drivers (!?),
// and this would otherwise cause CD/DVD drive letters to be
// attributed to blockdevices
driveType = GetDriveTypeA((volumeName + ":\\").c_str());
// printf("[INFO] Checking %s:/\n", volumeName.c_str());
if ((driveType != DRIVE_FIXED) && (driveType != DRIVE_REMOVABLE)) {
// printf("[INFO] Ignoring volume %s:/ - Not FIXED | REMOVABLE\n",
// volumeName.c_str());
continue;
}
hLogical = CreateFileA(
("\\\\.\\" + volumeName + ":").c_str(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hLogical == INVALID_HANDLE_VALUE) {
// printf("[INFO] Couldn't open handle to logical volume %s\n",
// volumeName.c_str());
continue;
}
logicalVolumeDeviceNumber = GetDeviceNumber(hLogical);
if (logicalVolumeDeviceNumber == -1) {
// printf("[INFO] Couldn't get device number for logical volume %s\n",
// volumeName.c_str());
continue;
}
if (logicalVolumeDeviceNumber == deviceNumber) {
// printf("[INFO] Device number for logical volume %s is %i\n",
// volumeName.c_str(), logicalVolumeDeviceNumber);
mountpoints->push_back(volumeName + ":\\");
}
}
if (hLogical != INVALID_HANDLE_VALUE) {
CloseHandle(hLogical);
hLogical = INVALID_HANDLE_VALUE;
}
}
std::string GetBusType(STORAGE_ADAPTER_DESCRIPTOR *adapterDescriptor) {
switch (adapterDescriptor->BusType) {
case STORAGE_BUS_TYPE::BusTypeUnknown: return "UNKNOWN";
case STORAGE_BUS_TYPE::BusTypeScsi: return "SCSI";
case STORAGE_BUS_TYPE::BusTypeAtapi: return "ATAPI";
case STORAGE_BUS_TYPE::BusTypeAta: return "ATA";
case STORAGE_BUS_TYPE::BusType1394: return "1394"; // IEEE 1394
case STORAGE_BUS_TYPE::BusTypeSsa: return "SSA";
case STORAGE_BUS_TYPE::BusTypeFibre: return "FIBRE";
case STORAGE_BUS_TYPE::BusTypeUsb: return "USB";
case STORAGE_BUS_TYPE::BusTypeRAID: return "RAID";
case STORAGE_BUS_TYPE::BusTypeiScsi: return "iSCSI";
case STORAGE_BUS_TYPE::BusTypeSas: return "SAS"; // Serial-Attached SCSI
case STORAGE_BUS_TYPE::BusTypeSata: return "SATA";
case STORAGE_BUS_TYPE::BusTypeSd: return "SD"; // Secure Digital (SD)
case STORAGE_BUS_TYPE::BusTypeMmc: return "MMC"; // Multimedia card
case STORAGE_BUS_TYPE::BusTypeVirtual: return "VIRTUAL";
case STORAGE_BUS_TYPE::BusTypeFileBackedVirtual: return "FILEBACKEDVIRTUAL";
default: return "INVALID";
}
}
bool GetAdapterInfo(HANDLE hPhysical, DeviceDescriptor *device) {
STORAGE_PROPERTY_QUERY query;
STORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
DWORD size = 0;
ZeroMemory(&query, sizeof(query));
query.QueryType = STORAGE_QUERY_TYPE::PropertyStandardQuery;
query.PropertyId = STORAGE_PROPERTY_ID::StorageAdapterProperty;
BOOL hasAdapterInfo = DeviceIoControl(
hPhysical, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
&adapterDescriptor, sizeof(STORAGE_ADAPTER_DESCRIPTOR), &size, NULL);
if (hasAdapterInfo) {
device->busType = GetBusType(&adapterDescriptor);
device->busVersion = std::to_string(adapterDescriptor.BusMajorVersion) +
"." + std::to_string(adapterDescriptor.BusMinorVersion);
return true;
}
return false;
}
bool GetDeviceBlockSize(HANDLE hPhysical, DeviceDescriptor *device) {
STORAGE_PROPERTY_QUERY query;
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR alignmentDescriptor;
DWORD size = 0;
ZeroMemory(&query, sizeof(query));
query.QueryType = STORAGE_QUERY_TYPE::PropertyStandardQuery;
query.PropertyId = STORAGE_PROPERTY_ID::StorageAccessAlignmentProperty;
BOOL hasAlignmentDescriptor = DeviceIoControl(
hPhysical, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
&alignmentDescriptor, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
&size, NULL);
if (hasAlignmentDescriptor) {
device->blockSize = alignmentDescriptor.BytesPerPhysicalSector;
device->logicalBlockSize = alignmentDescriptor.BytesPerLogicalSector;
return true;
}
return false;
}
bool GetDeviceSize(HANDLE hPhysical, DeviceDescriptor *device) {
DISK_GEOMETRY_EX diskGeometry;
// printf("[INFO] hasDiskGeometry\n");
BOOL hasDiskGeometry = false;
DWORD size = 0;
hasDiskGeometry = DeviceIoControl(
hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0,
&diskGeometry, sizeof(DISK_GEOMETRY_EX), &size, NULL);
// printf("[INFO] hasDiskGeometry %i\n", hasDiskGeometry);
// NOTE: Another way to get the block size would be
// `IOCTL_STORAGE_QUERY_PROPERTY` with `STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR`,
// which can yield more (or possibly more accurate?) info,
// but might not work with external HDDs/SSDs
if (hasDiskGeometry) {
device->size = diskGeometry.DiskSize.QuadPart;
device->blockSize = diskGeometry.Geometry.BytesPerSector;
}
return hasDiskGeometry;
}
bool GetDetailData(DeviceDescriptor* device,
HDEVINFO hDeviceInfo, SP_DEVINFO_DATA deviceInfoData) {
DWORD index;
DWORD size;
DWORD errorCode = 0;
bool result = true;
HANDLE hDevice = INVALID_HANDLE_VALUE;
HANDLE hPhysical = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA_W deviceDetailData(NULL);
for (index = 0; ; index++) {
if (hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
hDevice = INVALID_HANDLE_VALUE;
}
if (hPhysical != INVALID_HANDLE_VALUE) {
CloseHandle(hPhysical);
hPhysical = INVALID_HANDLE_VALUE;
}
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// printf("[INFO] (%i) SetupDiEnumDeviceInterfaces - isDisk\n", index);
BOOL isDisk = SetupDiEnumDeviceInterfaces(
hDeviceInfo, &deviceInfoData, &GUID_DEVICE_INTERFACE_DISK,
index, &deviceInterfaceData);
if (!isDisk) {
errorCode = GetLastError();
if (errorCode == ERROR_NO_MORE_ITEMS) {
// printf("[INFO] (%i) EnumDeviceInterfaces: No more items 0x%08lX\n",
// index, errorCode);
result = index != 0;
break;
} else {
device->error = "SetupDiEnumDeviceInterfaces: Error " +
std::to_string(errorCode);
}
result = false;
break;
}
BOOL hasDeviceInterfaceData = SetupDiGetDeviceInterfaceDetailW(
hDeviceInfo, &deviceInterfaceData, NULL, 0, &size, NULL);
if (!hasDeviceInterfaceData) {
errorCode = GetLastError();
if (errorCode == ERROR_INSUFFICIENT_BUFFER) {
deviceDetailData = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>
(malloc(size));
if (deviceDetailData == NULL) {
device->error = "SetupDiGetDeviceInterfaceDetailW: "
"Unable to allocate SP_DEVICE_INTERFACE_DETAIL_DATA_W"
"(" + std::to_string(size) + "); "
"Error " + std::to_string(errorCode);
result = false;
break;
}
// printf("Allocated SP_DEVICE_INTERFACE_DETAIL_DATA_W\n");
} else {
device->error = "SetupDiGetDeviceInterfaceDetailW: "
"Couldn't get detail data; Error " + std::to_string(errorCode);
result = false;
break;
}
}
// printf("[INFO] (%i) Getting SP_DEVICE_INTERFACE_DETAIL_DATA_W\n", index);
deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
BOOL hasDeviceDetail = SetupDiGetDeviceInterfaceDetailW(
hDeviceInfo, &deviceInterfaceData, deviceDetailData, size, &size, NULL);
if (!hasDeviceDetail) {
errorCode = GetLastError();
device->error = "Couldn't SetupDiGetDeviceInterfaceDetailW: Error " +
std::to_string(errorCode);
result = false;
break;
}
// printf("[INFO] (%i) SetupDiGetDeviceInterfaceDetailW:\n %s\n",
// index, WCharToUtf8(deviceDetailData->DevicePath));
// Passing zero to `CreateFile()` doesn't require permissions to
// open the device handle, but only lets you acquire device metadata,
// which is all we want
hDevice = CreateFileW(
deviceDetailData->DevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
errorCode = GetLastError();
// printf("[ERROR] Couldn't open handle to device: Error %i", errorCode);
device->error = "Couldn't open handle to device: Error " +
std::to_string(errorCode);
result = false;
break;
}
int32_t deviceNumber = GetDeviceNumber(hDevice);
if (deviceNumber == -1) {
device->error = "Couldn't get device number";
result = false;
break;
}
device->raw = "\\\\.\\PhysicalDrive" + std::to_string(deviceNumber);
device->device = device->raw;
GetMountpoints(deviceNumber, &device->mountpoints);
// printf("[INFO] Opening handle to %s\n", device->raw.c_str());
hPhysical = CreateFileA(
device->raw.c_str(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// printf("[INFO] Opened handle to %s\n", device->raw.c_str());
// printf("[INFO] Handle %i (INVALID %i)\n",
// hPhysical, INVALID_HANDLE_VALUE);
if (hPhysical == INVALID_HANDLE_VALUE) {
errorCode = GetLastError();
// printf("[INFO] Couldn't open handle to %s: Error %i\n",
// device->raw.c_str(), errorCode);
device->error = "Couldn't open handle to physical device: Error " +
std::to_string(errorCode);
result = false;
break;
}
// printf("[INFO] GetDeviceSize( %s )\n", device->raw.c_str());
if (!GetDeviceSize(hPhysical, device)) {
errorCode = GetLastError();
// printf("[ERROR] Couldn't get disk geometry: Error %i\n", errorCode);
device->error = "Couldn't get disk geometry: Error " +
std::to_string(errorCode);
result = false;
break;
}
// printf("[INFO] GetAdapterInfo( %s )\n", device->raw.c_str());
if (!GetAdapterInfo(hPhysical, device)) {
errorCode = GetLastError();
// printf("[ERROR] Couldn't get device adapter descriptor: Error %i\n",
// errorCode);
device->error = "Couldn't get device adapter descriptor: Error " +
std::to_string(errorCode);
result = false;
break;
}
// printf("[INFO] GetDeviceBlockSize( %s )\n", device->raw.c_str());
// NOTE: No need to fail over this one,
// as we can safely default to a 512B block size
if (!GetDeviceBlockSize(hPhysical, device)) {
errorCode = GetLastError();
// printf("[INFO] Couldn't get block size: Error %u\n", errorCode);
}
// printf("[INFO] isWritable( %s )\n", device->raw.c_str());
BOOL isWritable = DeviceIoControl(
hPhysical, IOCTL_DISK_IS_WRITABLE, NULL, 0,
NULL, 0, &size, NULL);
device->isReadOnly = !isWritable;
} // end for (index = 0; ; index++)
if (hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
hDevice = INVALID_HANDLE_VALUE;
}
if (hPhysical != INVALID_HANDLE_VALUE) {
CloseHandle(hPhysical);
hPhysical = INVALID_HANDLE_VALUE;
}
free(deviceDetailData);
return result;
}
std::vector<DeviceDescriptor> ListStorageDevices() {
HDEVINFO hDeviceInfo = NULL;
SP_DEVINFO_DATA deviceInfoData;
std::vector<DeviceDescriptor> deviceList;
DWORD i;
char *enumeratorName;
DeviceDescriptor device;
hDeviceInfo = SetupDiGetClassDevsA(
&GUID_DEVICE_INTERFACE_DISK, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDeviceInfo == INVALID_HANDLE_VALUE) {
printf("[ERROR] Invalid DeviceInfo handle\n");
return deviceList;
}
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDeviceInfo, i, &deviceInfoData); i++) {
enumeratorName = GetEnumeratorName(hDeviceInfo, deviceInfoData);
printf("[INFO] Enumerating %s\n", enumeratorName);
// If it failed to get the SPDRP_ENUMERATOR_NAME, skip it
//if (enumeratorName == NULL) {
// continue;
//}
device = DeviceDescriptor();
device.enumerator = enumeratorName ? std::string(enumeratorName) : "";
device.description = GetFriendlyName(hDeviceInfo, deviceInfoData);
device.isRemovable = IsRemovableDevice(hDeviceInfo, deviceInfoData);
device.isVirtual = IsVirtualHardDrive(hDeviceInfo, deviceInfoData);
device.isSCSI = enumeratorName ? IsSCSIDevice(enumeratorName) : false;
device.isUSB = enumeratorName ? IsUSBDevice(enumeratorName) : false;
device.isCard = device.enumerator == "SD";
device.isSystem = !device.isRemovable &&
(device.enumerator == "SCSI" || device.enumerator == "IDE");
device.isUAS = device.isSCSI && device.isRemovable &&
!device.isVirtual && !device.isCard;
device.devicePathNull = true;
if (GetDetailData(&device, hDeviceInfo, deviceInfoData)) {
device.isSystem = device.isSystem || IsSystemDevice(hDeviceInfo, &device);
device.isCard = device.busType == "SD" || device.busType == "MMC";
device.isUAS = device.enumerator == "SCSI" && device.busType == "USB";
device.isVirtual = device.isVirtual ||
device.busType == "VIRTUAL" ||
device.busType == "FILEBACKEDVIRTUAL";
} else if (device.error == "") {
device.error = "Couldn't get detail data";
}
deviceList.push_back(device);
}
SetupDiDestroyDeviceInfoList(hDeviceInfo);
return deviceList;
}
} // namespace Drivelist

View file

@ -0,0 +1,108 @@
/*
* Copyright 2017 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_WINDOWS_LIST_HPP_
#define SRC_WINDOWS_LIST_HPP_
#include <knownfolders.h>
#include <string>
#include <set>
namespace Drivelist {
// The <ntddstor.h>, and <usbiodef.h> headers include the following
// device interface GUIDs we're interested in;
// @see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/install-reference
// @see https://msdn.microsoft.com/en-us/library/windows/hardware/ff541389(v=vs.85).aspx
// To avoid cluttering the global namespace,
// we'll just define here what we need:
//
// - GUID_DEVINTERFACE_DISK { 53F56307-B6BF-11D0-94F2-00A0C91EFB8B }
// - GUID_DEVINTERFACE_CDROM { 53F56308-B6BF-11D0-94F2-00A0C91EFB8B }
// - GUID_DEVINTERFACE_USB_HUB { F18A0E88-C30C-11D0-8815-00A0C906BED8 }
// - GUID_DEVINTERFACE_FLOPPY { 53F56311-B6BF-11D0-94F2-00A0C91EFB8B }
// - GUID_DEVINTERFACE_WRITEONCEDISK { 53F5630C-B6BF-11D0-94F2-00A0C91EFB8B }
// - GUID_DEVINTERFACE_TAPE { 53F5630B-B6BF-11D0-94F2-00A0C91EFB8B }
// - GUID_DEVINTERFACE_USB_DEVICE { A5DCBF10-6530-11D2-901F-00C04FB951ED }
// - GUID_DEVINTERFACE_VOLUME { 53F5630D-B6BF-11D0-94F2-00A0C91EFB8B }
// - GUID_DEVINTERFACE_STORAGEPORT { 2ACCFE60-C130-11D2-B082-00A0C91EFB8B }
//
const GUID GUID_DEVICE_INTERFACE_DISK = {
0x53F56307L, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const GUID GUID_DEVICE_INTERFACE_CDROM = {
0x53F56308L, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const GUID GUID_DEVICE_INTERFACE_USB_HUB = {
0xF18A0E88L, 0xC30C, 0x11D0, { 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 }
};
const GUID GUID_DEVICE_INTERFACE_FLOPPY = {
0x53F56311L, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const GUID GUID_DEVICE_INTERFACE_WRITEONCEDISK = {
0x53F5630CL, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const GUID GUID_DEVICE_INTERFACE_TAPE = {
0x53F5630BL, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const GUID GUID_DEVICE_INTERFACE_USB_DEVICE = {
0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED }
};
const GUID GUID_DEVICE_INTERFACE_VOLUME = {
0x53F5630DL, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const GUID GUID_DEVICE_INTERFACE_STORAGEPORT = {
0x2ACCFE60L, 0xC130, 0x11D2, { 0xB0, 0x82, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
const std::set<std::string> USB_STORAGE_DRIVERS {
"USBSTOR", "UASPSTOR", "VUSBSTOR",
"RTUSER", "CMIUCR", "EUCR",
"ETRONSTOR", "ASUSSTPT"
};
const std::set<std::string> GENERIC_STORAGE_DRIVERS {
"SCSI", "SD", "PCISTOR",
"RTSOR", "JMCR", "JMCF", "RIMMPTSK", "RIMSPTSK", "RIXDPTSK",
"TI21SONY", "ESD7SK", "ESM7SK", "O2MD", "O2SD", "VIACR"
};
// List of known virtual disk hardware IDs
const std::set<std::string> VHD_HARDWARE_IDS {
"Arsenal_________Virtual_",
"KernSafeVirtual_________",
"Msft____Virtual_Disk____",
"VMware__VMware_Virtual_S"
};
const GUID KNOWN_FOLDER_IDS[] {
FOLDERID_Windows,
FOLDERID_Profile,
FOLDERID_ProgramFiles,
FOLDERID_ProgramFilesX86
};
} // namespace Drivelist
#endif // SRC_WINDOWS_LIST_HPP_