host/common/win32/DiskHelpers.cpp (753 lines of code) (raw):
#include "stdafx.h"
#include <winioctl.h>
#include <Windows.h>
#include <diskguid.h>
#include <tchar.h>
#include <strsafe.h>
#include "DiskHelpers.h"
/* Issues the IOCTL_DISK_GET_DRIVE_LAYOUT_EX, returns dli if ioctl succeeds, which must be freed by caller
*/
DRIVE_LAYOUT_INFORMATION_EX* IoctlDiskGetDriveLayoutEx(const HANDLE &h)
{
DRIVE_LAYOUT_INFORMATION_EX *dli = NULL;
int EXPECTEDPARTITIONS = 2;
bool bRetry = false;
unsigned int drivelayoutsize;
DWORD bytesreturned;
DWORD err;
do
{
if (dli)
{
free(dli);
dli = NULL;
}
drivelayoutsize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + ((EXPECTEDPARTITIONS - 1) * sizeof(PARTITION_INFORMATION_EX));
dli = (DRIVE_LAYOUT_INFORMATION_EX *)calloc(1, drivelayoutsize);
if (NULL == dli)
{
DebugPrintf(SV_LOG_ERROR, "Failed to allocate %u bytes for %d expected partitions, "
"for IOCTL_DISK_GET_DRIVE_LAYOUT_EX\n", drivelayoutsize,
EXPECTEDPARTITIONS);
break;
}
bytesreturned = 0;
err = 0;
if (DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, dli, drivelayoutsize, &bytesreturned, NULL))
{
break;
}
else if ((err = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)
{
DebugPrintf(SV_LOG_DEBUG, "with EXPECTEDPARTITIONS = %d, IOCTL_DISK_GET_DRIVE_LAYOUT_EX says insufficient buffer\n", EXPECTEDPARTITIONS);
EXPECTEDPARTITIONS *= 2;
bRetry = true;
continue;
}
else
{
std::stringstream ss;
ss << "IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed with error " << err;
DebugPrintf(SV_LOG_ERROR, "%s\n", ss.str().c_str());
break;
}
} while (bRetry);
return dli;
}
DRIVE_LAYOUT_INFORMATION_EX* IoctlDiskGetDriveLayoutEx(const std::string &diskname)
{
std::stringstream ss;
HANDLE h = CreateFile(diskname.c_str(), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
{
ss << "Failed to open disk " << diskname << " with error " << GetLastError();
DebugPrintf(SV_LOG_ERROR, "%s\n", ss.str().c_str());
return 0;
}
DRIVE_LAYOUT_INFORMATION_EX *dli = IoctlDiskGetDriveLayoutEx(h);
if (!dli)
DebugPrintf(SV_LOG_ERROR, "Failed to get drive layout information for disk %s.\n", diskname.c_str());
CloseHandle(h);
return dli;
}
DWORD GetDiskSectorSize(const DWORD dwIndex, DWORD& dwBytesPerSector, std::string& errorString)
{
std::stringstream ssDiskName, ssError;
ssDiskName << "\\\\.\\PhysicalDrive" << dwIndex;
DWORD dwStatus = ERROR_SUCCESS;
HANDLE hDisk = CreateFile(ssDiskName.str().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hDisk)
{
ssError << "Failed to open disk " << ssDiskName.str() << " with error " << GetLastError();
errorString = ssError.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", errorString.c_str());
return GetLastError();
}
DWORD cbReturned = 0;
DISK_GEOMETRY disk_geometry = { 0 };
if (!DeviceIoControl(hDisk,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&disk_geometry,
sizeof(DISK_GEOMETRY),
&cbReturned,
NULL))
{
ssError << "Failed to get geometry for " << ssDiskName.str() << " with error " << GetLastError();
errorString = ssError.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", errorString.c_str());
dwStatus = GetLastError();
}
else {
dwBytesPerSector = disk_geometry.BytesPerSector;
}
CloseHandle(hDisk);
return dwStatus;
}
DRIVE_LAYOUT_INFORMATION_EX* IoctlDiskGetDriveLayoutEx(const DWORD dwIndex)
{
std::stringstream ssDiskName;
ssDiskName << "\\\\.\\PhysicalDrive" << dwIndex;
return IoctlDiskGetDriveLayoutEx(ssDiskName.str());
}
bool IsDiskDynamic(PDRIVE_LAYOUT_INFORMATION_EX pLayoutEx)
{
/* TODO: unify this reference across all modules */
const GUID PARTITION_LDM_METADATA_GUID = {
0x5808C8AA,
0x7E8F,
0x42E0,
0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3
}; // Logical Disk Manager (LDM) metadata partition on a dynamic disk
if (NULL == pLayoutEx) {
return false;
}
bool isDiskDynamic = false;
const std::string DYNAMIC_DISK_VGNAME = "__INMAGE__DYNAMIC__DG__";
if (NULL == pLayoutEx) {
return false;
}
for (DWORD i = 0; i < pLayoutEx->PartitionCount; i++)
{
PARTITION_INFORMATION_EX &partInfoEx = pLayoutEx->PartitionEntry[i];
if (PARTITION_STYLE_MBR == partInfoEx.PartitionStyle)
{
if (PARTITION_LDM == partInfoEx.Mbr.PartitionType)
{
isDiskDynamic = true;
break;
}
}
else if (PARTITION_STYLE_GPT == partInfoEx.PartitionStyle)
{
if (IsEqualGUID(partInfoEx.Gpt.PartitionType, PARTITION_LDM_METADATA_GUID))
{
isDiskDynamic = true;
break;
}
}
}
return isDiskDynamic;
}
bool HasUefi(SV_LONG diskIndex)
{
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
PDRIVE_LAYOUT_INFORMATION_EX pLayoutEx = IoctlDiskGetDriveLayoutEx(diskIndex);
if (NULL == pLayoutEx) {
DebugPrintf(SV_LOG_ERROR, "Failed to get drive layout for disk %d\n", diskIndex);
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return false;
}
ON_BLOCK_EXIT(boost::bind<void>(&free, pLayoutEx));
if (PARTITION_STYLE_GPT != pLayoutEx->PartitionStyle) {
DebugPrintf(SV_LOG_DEBUG, "Disk %d does not contain UEFI partition Layout is %s\n", diskIndex,
(PARTITION_STYLE_MBR == pLayoutEx->PartitionStyle) ? "MBR" : "RAW");
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return false;
}
for (DWORD i = 0; i < pLayoutEx->PartitionCount; i++)
{
PARTITION_INFORMATION_EX &partInfoEx = pLayoutEx->PartitionEntry[i];
if (IsEqualGUID(partInfoEx.Gpt.PartitionType, PARTITION_SYSTEM_GUID)) {
DebugPrintf(SV_LOG_DEBUG, "Disk %d Partition %d is UEFI\n", diskIndex, i);
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return true;
}
}
DebugPrintf(SV_LOG_DEBUG, "Disk %d doesn't contain UEFI Partition\n", diskIndex);
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return false;
}
DWORD IsDiskDynamic(SV_LONG diskIndex, bool& bDiskDynamic)
{
bool isDiskDynamic = false;
bDiskDynamic = false;
std::stringstream diskName;
diskName << "\\\\.\\PhysicalDrive" << diskIndex;
PDRIVE_LAYOUT_INFORMATION_EX pLayoutEx = IoctlDiskGetDriveLayoutEx(diskName.str());
if (NULL == pLayoutEx) {
DebugPrintf(SV_LOG_DEBUG, "Failed to get Layout for Disk %d error=%d\n", diskIndex, GetLastError());
return GetLastError();
}
isDiskDynamic = IsDiskDynamic(pLayoutEx);
free(pLayoutEx);
bDiskDynamic = isDiskDynamic;
return ERROR_SUCCESS;
}
bool GetRootDiskLayoutInfo(PDRIVE_LAYOUT_INFORMATION_EX &pLayoutEx, DWORD& dwBytesPerSector, std::string &err, DWORD &errcode)
{
std::vector<char> BootVolume(MAX_PATH + 1);
std::vector<char> SystemDrive(MAX_PATH + 1);
std::vector<char> VolumeName(MAX_PATH + 1);
std::stringstream ssError;
HANDLE hVolume = INVALID_HANDLE_VALUE;
PVOLUME_DISK_EXTENTS pDiskExtents = NULL;
std::vector<UCHAR> buffer(sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 127 * sizeof(PARTITION_INFORMATION_EX));
pDiskExtents = (PVOLUME_DISK_EXTENTS)&buffer[0];
if (0 == GetSystemDirectory(&BootVolume[0], MAX_PATH)) {
errcode = GetLastError();
ssError << "GetSystemDirectory failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, ssError.str().c_str());
return false;
}
StringCchPrintf(&SystemDrive[0], MAX_PATH, "%s", DOS_NAME_PREFIX);
if (0 == GetVolumePathName(&BootVolume[0], &SystemDrive[strlen(&SystemDrive[0])], MAX_PATH - strlen(&SystemDrive[0]))){
errcode = GetLastError();
ssError << "GetVolumePathName for directory " << &BootVolume[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, ssError.str().c_str());
return false;
}
UINT uiDriveType = GetDriveType(&SystemDrive[0]);
// Fail check when system is noot booted from system drive
if (DRIVE_FIXED != uiDriveType) {
ssError << "SystemDrive " << &SystemDrive[0] << " is not fixed drive type: " << uiDriveType;
err = ERROR_INVALID_DRIVE_OBJECT;
DebugPrintf(SV_LOG_ERROR, ssError.str().c_str());
return false;
}
SystemDrive[strlen(&SystemDrive[0]) - 1] = '\0';
hVolume = CreateFile(&SystemDrive[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hVolume) {
errcode = GetLastError();
ssError << "CreateFile for volume " << &SystemDrive[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, "CreateFile for volume %s failed with err=%d\n", &SystemDrive[0], errcode);
return false;
}
DWORD bytes;
if (!DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, pDiskExtents, buffer.size(), &bytes, NULL)) {
errcode = GetLastError();
ssError << "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS for volume " << &SystemDrive[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS for volume %s failed with error=%d\n", &SystemDrive[0], errcode);
CloseHandle(hVolume);
return false;
}
CloseHandle(hVolume);
ULONG bootDiskIndex = pDiskExtents->Extents[0].DiskNumber;
if (ERROR_SUCCESS != GetDiskSectorSize(bootDiskIndex, dwBytesPerSector, err)) {
return false;
}
pLayoutEx = IoctlDiskGetDriveLayoutEx(bootDiskIndex);
if (NULL == pLayoutEx) {
errcode = GetLastError();
ssError << "IoctlDiskGetDriveLayoutEx for volume " << &SystemDrive[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, "IoctlDiskGetDriveLayoutEx for volume %s failed with error=%d\n", &SystemDrive[0], errcode);
return false;
}
return true;
}
bool GetDiskGuid(ULONG ulDiskIndex, std::string& deviceId)
{
std::stringstream ssDeviceName;
ssDeviceName << DISK_NAME_PREFIX << ulDiskIndex;
std::stringstream ssErrorMsg;
HANDLE hDisk = CreateFileA(ssDeviceName.str().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE == hDisk) {
ssErrorMsg << "Failed to open device: " << ssDeviceName.str() << "Error Code " << GetLastError();
DebugPrintf(SV_LOG_ERROR, "%s\n", ssErrorMsg.str().c_str());
return false;
}
ON_BLOCK_EXIT(boost::bind<void>(&CloseHandle, hDisk));
deviceId = GetDiskGuid(hDisk);
return true;
}
std::string GetDiskGuid(const HANDLE &h)
{
DebugPrintf(SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME);
if (INVALID_HANDLE_VALUE == h) {
DebugPrintf(SV_LOG_ERROR, "Handle provided to find disk GUID is invalid.\n");
return std::string();
}
DRIVE_LAYOUT_INFORMATION_EX *dli = IoctlDiskGetDriveLayoutEx(h);
if (!dli) {
DebugPrintf(SV_LOG_ERROR, "Failed to get drive layout information.\n");
return std::string();
}
std::string diskGuid;
if (GetDiskGuidFromDli(dli, diskGuid))
DebugPrintf(SV_LOG_DEBUG, "DiskGuid found is %s.\n", diskGuid.c_str());
else
DebugPrintf(SV_LOG_ERROR, "No DiskGuid found.\n");
free(dli);
DebugPrintf(SV_LOG_DEBUG, "EXITED %s\n", FUNCTION_NAME);
return diskGuid;
}
bool GetDiskGuidFromDli(DRIVE_LAYOUT_INFORMATION_EX *pDli, std::string &diskGuid)
{
bool bResult = false;
std::vector<wchar_t> guidBuffer(MAX_PATH+1, 0);
if ((pDli->PartitionStyle == PARTITION_STYLE_MBR) &&
(pDli->Mbr.Signature)) /* the ioctl is wrongly writing PARTITION_STYLE_MBR (value 0) for raw disks. Hence check if signature is non zero */
{
// Adding braces {} around signature to make disk GUID uniform as these braces come for gpt GUID
diskGuid = "{";
diskGuid += std::to_string(pDli->Mbr.Signature);
diskGuid += "}";
bResult = true;
}
else if (pDli->PartitionStyle == PARTITION_STYLE_GPT)
{
StringFromGUID2(pDli->Gpt.DiskId, &guidBuffer[0], MAX_PATH);
diskGuid = CW2A(&guidBuffer[0]);
bResult = true;
}
return bResult;
}
bool IsUEFIBoot(void)
{
bool isUefi = false;
PDRIVE_LAYOUT_INFORMATION_EX pLayoutEx = NULL;
DWORD dwBytesPerSector = 0;
std::string err;
DWORD errcode;
if (!GetRootDiskLayoutInfo(pLayoutEx, dwBytesPerSector, err, errcode))
{
DebugPrintf(SV_LOG_ERROR, "Failed to get DiskLayout err=%d\n", errcode);
return false;
}
ON_BLOCK_EXIT(boost::bind<void>(&free, pLayoutEx));
if (PARTITION_STYLE_GPT == pLayoutEx->PartitionStyle) {
isUefi = true;
}
DebugPrintf(SV_LOG_INFO, "Bios Mode is %s\n", isUefi? "UEFI" : "BIOS");
return isUefi;
}
BOOL GetDeviceAttributes(ULONG ulDiskIndex,
std::string& vendorId,
std::string& productId,
std::string& serialNumber,
std::string& errormessage)
{
std::stringstream ssDeviceName;
ssDeviceName << "\\\\.\\PhysicalDrive" << ulDiskIndex;
HANDLE hDisk = CreateFileA(ssDeviceName.str().c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hDisk)
{
DebugPrintf(SV_LOG_ERROR, "Failed to open device %s error=%d\n", ssDeviceName.str().c_str(), GetLastError());
return FALSE;
}
BOOL bSuccess = GetDeviceAttributes(hDisk, ssDeviceName.str(), vendorId, productId, serialNumber, errormessage);
CloseHandle(hDisk);
return bSuccess;
}
BOOL GetDeviceAttributes(const HANDLE& hDevice,
const std::string & diskname,
std::string& vendorId,
std::string& productId,
std::string& serialNumber,
std::string& errormessage)
{
std::vector<SV_UCHAR> Buffer;
STORAGE_PROPERTY_QUERY queryProperty;
PSTORAGE_DEVICE_DESCRIPTOR pDeviceDescriptor;
BOOL bRet = FALSE;
std::stringstream sserror;
vendorId.clear();
productId.clear();
serialNumber.clear();
ZeroMemory(&queryProperty, sizeof(queryProperty));
queryProperty.PropertyId = StorageDeviceProperty;
queryProperty.QueryType = PropertyStandardQuery;
// Get size of device descriptor
STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = { 0 };
DWORD dwBytesReturned = 0;
bRet = DeviceIoControl(hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&queryProperty, sizeof(queryProperty),
&storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
&dwBytesReturned, NULL);
if (!bRet) {
sserror << FUNCTION_NAME << ": 1: IOCTL_STORAGE_QUERY_PROPERTY failed for disk " << diskname << " error: " << GetLastError();
errormessage = sserror.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", errormessage.c_str());
return FALSE;
}
// Get Storage Device Descriptor
const DWORD dwSize = storageDescriptorHeader.Size;
Buffer.resize(storageDescriptorHeader.Size, 0);
// Get the storage device descriptor
bRet = DeviceIoControl(hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&queryProperty, sizeof(STORAGE_PROPERTY_QUERY),
&Buffer[0], dwSize,
&dwBytesReturned, NULL);
if (!bRet) {
sserror << FUNCTION_NAME << ": 2: IOCTL_STORAGE_QUERY_PROPERTY failed for disk " << diskname << " error: " << GetLastError();
errormessage = sserror.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", errormessage.c_str());
return FALSE;
}
pDeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)&Buffer[0];
if (pDeviceDescriptor->VendorIdOffset < dwSize) {
vendorId = (char *)(&Buffer[0] + pDeviceDescriptor->VendorIdOffset);
// Remove trailing whitespace
boost::algorithm::trim(vendorId);
DebugPrintf(SV_LOG_DEBUG, "disk %s VendorId: %s\n", diskname.c_str(), vendorId.c_str());
}
if (pDeviceDescriptor->ProductIdOffset < dwSize) {
productId = (char *)(&Buffer[0] + pDeviceDescriptor->ProductIdOffset);
boost::algorithm::trim(productId);
DebugPrintf(SV_LOG_DEBUG, "disk %s productId: %s\n", diskname.c_str(), productId.c_str());
}
if (pDeviceDescriptor->SerialNumberOffset < dwSize) {
serialNumber = (char *)(&Buffer[0] + pDeviceDescriptor->SerialNumberOffset);
boost::algorithm::trim(serialNumber);
DebugPrintf(SV_LOG_DEBUG, "disk %s serialNumber: %s\n", diskname.c_str(), serialNumber.c_str());
}
return TRUE;
}
bool GetSystemDiskList(std::set<SV_ULONG>& diskIndices, std::string &err, DWORD &errcode)
{
std::vector<char> BootVolume(MAX_PATH + 1);
std::vector<char> SystemDrive(MAX_PATH + 1);
std::vector<char> VolumeName(MAX_PATH + 1);
std::stringstream ssError;
HANDLE hVolume = INVALID_HANDLE_VALUE;
PVOLUME_DISK_EXTENTS pDiskExtents = NULL;
std::vector<UCHAR> buffer(sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 127 * sizeof(PARTITION_INFORMATION_EX));
pDiskExtents = (PVOLUME_DISK_EXTENTS)&buffer[0];
if (0 == GetSystemDirectory(&BootVolume[0], MAX_PATH)) {
errcode = GetLastError();
ssError << "GetSystemDirectory failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, ssError.str().c_str());
return false;
}
StringCchPrintf(&SystemDrive[0], MAX_PATH, "%s", DOS_NAME_PREFIX);
if (0 == GetVolumePathName(&BootVolume[0], &SystemDrive[strlen(&SystemDrive[0])], MAX_PATH - strlen(&SystemDrive[0]))){
errcode = GetLastError();
ssError << "GetVolumePathName for directory " << &BootVolume[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, ssError.str().c_str());
return false;
}
UINT uiDriveType = GetDriveType(&SystemDrive[0]);
// Fail check when system is noot booted from system drive
if (DRIVE_FIXED != uiDriveType) {
ssError << "SystemDrive " << &SystemDrive[0] << " is not fixed drive type: " << uiDriveType;
err = ERROR_INVALID_DRIVE_OBJECT;
DebugPrintf(SV_LOG_ERROR, ssError.str().c_str());
return false;
}
SystemDrive[strlen(&SystemDrive[0]) - 1] = '\0';
hVolume = CreateFile(&SystemDrive[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hVolume) {
errcode = GetLastError();
ssError << "CreateFile for volume " << &SystemDrive[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, "CreateFile for volume %s failed with err=%d\n", &SystemDrive[0], errcode);
return false;
}
ON_BLOCK_EXIT(boost::bind<void>(&CloseHandle, hVolume));
DWORD bytes;
if (!DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, pDiskExtents, buffer.size(), &bytes, NULL)) {
errcode = GetLastError();
ssError << "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS for volume " << &SystemDrive[0] << " failed with err=" << errcode << std::endl;
err = ssError.str();
DebugPrintf(SV_LOG_ERROR, "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS for volume %s failed with error=%d\n", &SystemDrive[0], errcode);
return false;
}
for (int index = 0; index < pDiskExtents->NumberOfDiskExtents; index++) {
diskIndices.insert(pDiskExtents->Extents[index].DiskNumber);
}
return true;
}
BOOL GetBusType(SV_ULONG ulDiskIndex, STORAGE_BUS_TYPE& busType, std::string& errorMessage)
{
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
std::stringstream ssDiskName;
ssDiskName << DISK_NAME_PREFIX << ulDiskIndex;
return GetBusType(ssDiskName.str(), busType, errorMessage);
}
BOOL GetBusType(std::string deviceName, STORAGE_BUS_TYPE& busType, std::string& errorMessage)
{
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
HANDLE hDisk = INVALID_HANDLE_VALUE;
std::stringstream ssErrorMsg;
busType = BusTypeUnknown;
hDisk = CreateFileA(deviceName.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE == hDisk) {
ssErrorMsg << __FUNCTION__ << "Failed to open device: " << deviceName << "Error Code " << GetLastError();
errorMessage = ssErrorMsg.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", ssErrorMsg.str().c_str());
return false;
}
ON_BLOCK_EXIT(boost::bind<void>(&CloseHandle, hDisk));
BOOL bStatus = GetBusType(hDisk, busType, errorMessage);
if (bStatus) {
DebugPrintf(SV_LOG_INFO, "Device: %s BusType: %d\n", deviceName.c_str(), busType);
}
else {
DebugPrintf(SV_LOG_DEBUG, "%s\n", errorMessage.c_str());
}
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return bStatus;
}
BOOL GetBusType(HANDLE hDisk, STORAGE_BUS_TYPE& busType, std::string& errorMessage)
{
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
std::stringstream ssErrorMsg;
DWORD dwBytes;
std::vector<BYTE> Buffer(sizeof(PSTORAGE_DEVICE_DESCRIPTOR));
PSTORAGE_DEVICE_DESCRIPTOR pStorageDescriptor = NULL;
STORAGE_PROPERTY_QUERY storageProperty;
DWORD retryCount = 0;
DWORD dwInput;
BOOL bResult = FALSE;
STORAGE_DESCRIPTOR_HEADER storageHeader = { 0 };
PVOID pBuffer;
ZeroMemory(&storageProperty, sizeof(storageProperty));
storageProperty.PropertyId = StorageDeviceProperty;
storageProperty.QueryType = PropertyStandardQuery;
busType = BusTypeUnknown;
pBuffer = (PVOID)&storageHeader;
dwInput = sizeof(storageHeader);
do {
bResult = DeviceIoControl(hDisk,
IOCTL_STORAGE_QUERY_PROPERTY,
&storageProperty,
sizeof(storageProperty),
pBuffer,
dwInput,
&dwBytes,
NULL
);
if (!bResult) {
ssErrorMsg << "IOCTL_STORAGE_QUERY_PROPERTY failed with error = " << GetLastError();
errorMessage = ssErrorMsg.str();
DebugPrintf(SV_LOG_DEBUG, "%s\n", errorMessage.c_str());
break;
}
if (retryCount == 1) {
busType = pStorageDescriptor->BusType;
DebugPrintf(SV_LOG_DEBUG, "BusType %d\n", busType);
break;
}
dwInput = storageHeader.Size;
Buffer.resize(dwInput);
pStorageDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)&Buffer[0];
pBuffer = pStorageDescriptor;
retryCount++;
} while (retryCount < 2);
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return bResult;
}
std::set<ULONG>
GetAvailableDiskIndices(
ULONG ulMaxDiskIndex,
ULONG ulMaxConsMissingIndices)
{
std::stringstream ssDeviceName;
ULONG ulDiskIndex = 0;
ULONG ulConsMissingIndices = 0;
std::set<ULONG> diskIndices;
HANDLE hDisk = INVALID_HANDLE_VALUE;
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
while (ulDiskIndex < ulMaxDiskIndex ||
(ulConsMissingIndices < ulMaxConsMissingIndices)) {
ULONG ulDeviceNum = ulDiskIndex;
++ulDiskIndex;
ssDeviceName.str("");
ssDeviceName << DISK_NAME_PREFIX << ulDeviceNum;
hDisk = CreateFileA(ssDeviceName.str().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hDisk) {
DebugPrintf(SV_LOG_INFO, "Adding Disk %s\n", ssDeviceName.str().c_str());
CloseHandle(hDisk);
diskIndices.insert(ulDeviceNum);
ulConsMissingIndices = 0;
continue;
}
ulConsMissingIndices++;
}
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return diskIndices;
}
DiskInterface::DiskInterface(SV_ULONG ulIndex) :
m_ulIndex(ulIndex),
m_hDisk(INVALID_HANDLE_VALUE)
{
if (!Open()) {
throw std::exception(GetErrorMessage().c_str());
}
}
DiskInterface::~DiskInterface()
{
if (INVALID_HANDLE_VALUE != m_hDisk) {
CloseHandle(m_hDisk);
}
m_hDisk = INVALID_HANDLE_VALUE;
}
bool DiskInterface::Open()
{
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
std::stringstream ssDiskName;
std::stringstream ssError;
ssDiskName << DISK_NAME_PREFIX << m_ulIndex;
m_hDisk = CreateFileA(ssDiskName.str().c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE == m_hDisk) {
ssError << "Failed to open disk " << m_ulIndex << " Error: " << GetLastError();
m_errorMessage = ssError.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", m_errorMessage.c_str());
return false;
}
return true;
}
bool DiskInterface::GetBusType(STORAGE_BUS_TYPE& busType)
{
DebugPrintf(SV_LOG_DEBUG, "Entering %s\n", FUNCTION_NAME);
std::stringstream ssErrorMsg;
DWORD dwBytes;
std::vector<BYTE> Buffer(sizeof(PSTORAGE_DEVICE_DESCRIPTOR));
PSTORAGE_DEVICE_DESCRIPTOR pStorageDescriptor = NULL;
STORAGE_PROPERTY_QUERY storageProperty;
DWORD retryCount = 0;
DWORD dwInput;
BOOL bResult = FALSE;
STORAGE_DESCRIPTOR_HEADER storageHeader = { 0 };
PVOID pBuffer;
ZeroMemory(&storageProperty, sizeof(storageProperty));
storageProperty.PropertyId = StorageDeviceProperty;
storageProperty.QueryType = PropertyStandardQuery;
busType = BusTypeUnknown;
pBuffer = (PVOID)&storageHeader;
dwInput = sizeof(storageHeader);
do {
bResult = DeviceIoControl(m_hDisk,
IOCTL_STORAGE_QUERY_PROPERTY,
&storageProperty,
sizeof(storageProperty),
pBuffer,
dwInput,
&dwBytes,
NULL
);
if (!bResult) {
ssErrorMsg << "IOCTL_STORAGE_QUERY_PROPERTY failed with error = " << GetLastError();
m_errorMessage = ssErrorMsg.str();
DebugPrintf(SV_LOG_DEBUG, "%s\n", m_errorMessage.c_str());
break;
}
if (retryCount == 1) {
busType = pStorageDescriptor->BusType;
DebugPrintf(SV_LOG_DEBUG, "BusType %d\n", busType);
break;
}
dwInput = storageHeader.Size;
Buffer.resize(dwInput);
pStorageDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)&Buffer[0];
pBuffer = pStorageDescriptor;
retryCount++;
} while (retryCount < 2);
DebugPrintf(SV_LOG_DEBUG, "Exiting %s\n", FUNCTION_NAME);
return (bResult == TRUE);
}
bool DiskInterface::OfflineDisk()
{
DebugPrintf(SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME);
bool rv = OnlineOfflineDisk(false, false, false);
DebugPrintf(SV_LOG_DEBUG, "EXITED %s\n", FUNCTION_NAME);
return rv;
}
bool DiskInterface::OnlineDisk()
{
DebugPrintf(SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME);
bool rv = OnlineOfflineDisk(true, false, false);
DebugPrintf(SV_LOG_DEBUG, "EXITED %s\n", FUNCTION_NAME);
return rv;
}
bool DiskInterface::OnlineOfflineDisk(bool online, bool readOnly, bool persist)
{
DebugPrintf(SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME);
BOOL rv = FALSE;
std::stringstream ssErrorMsg;
SET_DISK_ATTRIBUTES attributes = { 0 };
attributes.Version = sizeof(SET_DISK_ATTRIBUTES);
attributes.Persist = persist;
attributes.Attributes = (online) ? 0L : DISK_ATTRIBUTE_OFFLINE;
attributes.Attributes |= (readOnly) ? DISK_ATTRIBUTE_READ_ONLY : 0L;
attributes.AttributesMask = DISK_ATTRIBUTE_OFFLINE | DISK_ATTRIBUTE_READ_ONLY;
DWORD dwBytesReturned;
rv = DeviceIoControl(m_hDisk,
IOCTL_DISK_SET_DISK_ATTRIBUTES,
&attributes,
sizeof(SET_DISK_ATTRIBUTES),
NULL,
0,
&dwBytesReturned,
NULL);
if (!rv)
{
ssErrorMsg << "Error: IOCTL_DISK_SET_DISK_ATTRIBUTES failed for disk " << m_ulIndex << " Error: " << GetLastError();
m_errorMessage = ssErrorMsg.str();
DebugPrintf(SV_LOG_ERROR, "%s\n", m_errorMessage.c_str());
}
DebugPrintf(SV_LOG_DEBUG, "EXITED %s\n", FUNCTION_NAME);
return (TRUE == rv);
}
bool DiskInterface::IsResourceDisk()
{
DebugPrintf(SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME);
STORAGE_BUS_TYPE busType;
bool isResourceDisk;
if (!GetBusType(busType)) {
DebugPrintf(SV_LOG_ERROR, "Failed to get BusType Error: %d", GetLastError());
return false;
}
isResourceDisk = ((STORAGE_BUS_TYPE::BusTypeAta == busType) || (STORAGE_BUS_TYPE::BusTypeAtapi == busType));
DebugPrintf(SV_LOG_DEBUG, "EXITED %s\n", FUNCTION_NAME);
return isResourceDisk;
}