PPH_STRING DiskDriveQueryDosMountPoints( _In_ ULONG DeviceNumber ) { ULONG driveMask; WCHAR deviceNameBuffer[7] = L"\\\\.\\?:"; PH_STRING_BUILDER stringBuilder; PhInitializeStringBuilder(&stringBuilder, MAX_PATH); driveMask = DiskDriveQueryDeviceMap(); // NOTE: This isn't the best way of doing this but it works. for (INT i = 0; i < 0x1A; i++) { if (driveMask & (0x1 << i)) { HANDLE deviceHandle; deviceNameBuffer[4] = (WCHAR)('A' + i); if (NT_SUCCESS(PhCreateFileWin32( &deviceHandle, deviceNameBuffer, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { ULONG deviceNumber = ULONG_MAX; // Note: Do not initialize to zero. DEVICE_TYPE deviceType = 0; if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber( deviceHandle, &deviceNumber, &deviceType ))) { // BUG: Device numbers are re-used on seperate device controllers and this // causes drive letters to be assigned to disks at those same indexes. // For now, just filter CD_ROM devices but we may need to be a lot more strict and // only allow devices of type FILE_DEVICE_DISK to be scanned for mount points. if (deviceNumber == DeviceNumber && deviceType != FILE_DEVICE_CD_ROM) { PhAppendFormatStringBuilder(&stringBuilder, L"%c: ", deviceNameBuffer[4]); } } NtClose(deviceHandle); } } } if (stringBuilder.String->Length != 0) PhRemoveEndStringBuilder(&stringBuilder, 1); return PhFinalStringBuilderString(&stringBuilder); }
PPH_LIST DiskDriveQueryMountPointHandles( _In_ ULONG DeviceNumber ) { ULONG driveMask; PPH_LIST deviceList; WCHAR deviceNameBuffer[7] = L"\\\\.\\?:"; driveMask = DiskDriveQueryDeviceMap(); deviceList = PhCreateList(2); // NOTE: This isn't the best way of doing this but it works. for (INT i = 0; i < 0x1A; i++) { if (driveMask & (0x1 << i)) { HANDLE deviceHandle; deviceNameBuffer[4] = (WCHAR)('A' + i); if (NT_SUCCESS(PhCreateFileWin32( &deviceHandle, deviceNameBuffer, PhGetOwnTokenAttributes().Elevated ? FILE_GENERIC_READ : FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { ULONG deviceNumber = ULONG_MAX; // Note: Do not initialize to zero. DEVICE_TYPE deviceType = 0; if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber( deviceHandle, &deviceNumber, &deviceType ))) { // BUG: Device numbers are re-used on seperate device controllers and this // causes drive letters to be assigned to disks at those same indexes. // For now, just filter CD_ROM devices but we may need to be a lot more strict and // only allow devices of type FILE_DEVICE_DISK to be scanned for mount points. if (deviceNumber == DeviceNumber && deviceType != FILE_DEVICE_CD_ROM) { PDISK_HANDLE_ENTRY entry = PhAllocate(sizeof(DISK_HANDLE_ENTRY)); memset(entry, 0, sizeof(DISK_HANDLE_ENTRY)); entry->DeviceLetter = deviceNameBuffer[4]; entry->DeviceHandle = deviceHandle; PhAddItemList(deviceList, entry); } } } } } return deviceList; }
PPH_STRING DiskDriveQueryDosMountPoints( _In_ ULONG DeviceNumber ) { ULONG driveMask; PH_STRING_BUILDER stringBuilder; WCHAR devicePath[] = L"\\\\.\\?:"; PhInitializeStringBuilder(&stringBuilder, MAX_PATH); driveMask = DiskDriveQueryDeviceMap(); // NOTE: This isn't the best way of doing this but it works (It's also what Task Manager does). for (INT i = 0; i < 0x1A; i++) { if (driveMask & (0x1 << i)) { HANDLE deviceHandle; devicePath[4] = 'A' + i; if (NT_SUCCESS(PhCreateFileWin32( &deviceHandle, devicePath, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { ULONG deviceNumber = ULONG_MAX; // Note: Do not initialize to zero. if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber( deviceHandle, &deviceNumber, NULL ))); { if (deviceNumber == DeviceNumber) { PhAppendFormatStringBuilder(&stringBuilder, L"%c: ", devicePath[4]); } } NtClose(deviceHandle); } } } if (stringBuilder.String->Length != 0) PhRemoveEndStringBuilder(&stringBuilder, 1); return PhFinalStringBuilderString(&stringBuilder); }
VOID DiskDriveUpdateDeviceInfo( _In_opt_ HANDLE DeviceHandle, _In_ PDV_DISK_ENTRY DiskEntry ) { if (!DiskEntry->DiskName || DiskEntry->DiskIndex == ULONG_MAX) { HANDLE deviceHandle = NULL; if (!DeviceHandle) { DiskDriveCreateHandle(&deviceHandle, DiskEntry->Id.DevicePath); } else { deviceHandle = DeviceHandle; } if (deviceHandle) { if (!DiskEntry->DiskName) { PPH_STRING diskName = NULL; if (NT_SUCCESS(DiskDriveQueryDeviceInformation(deviceHandle, NULL, &diskName, NULL, NULL))) { DiskEntry->DiskName = diskName; } } if (DiskEntry->DiskIndex == ULONG_MAX) { ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero. if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber(deviceHandle, &diskIndex, NULL))) { DiskEntry->DiskIndex = diskIndex; } } if (!DeviceHandle) { NtClose(deviceHandle); } } } }
VOID FindDiskDrives( _In_ PDV_DISK_OPTIONS_CONTEXT Context ) { PPH_LIST deviceList; HDEVINFO deviceInfoHandle; SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) }; SP_DEVINFO_DATA deviceInfoData = { sizeof(SP_DEVINFO_DATA) }; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail; ULONG deviceInfoLength = 0; if ((deviceInfoHandle = SetupDiGetClassDevs( &GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_DEVICEINTERFACE )) == INVALID_HANDLE_VALUE) { return; } deviceList = PH_AUTO(PhCreateList(1)); for (ULONG i = 0; SetupDiEnumDeviceInterfaces(deviceInfoHandle, NULL, &GUID_DEVINTERFACE_DISK, i, &deviceInterfaceData); i++) { if (SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, &deviceInterfaceData, 0, 0, &deviceInfoLength, &deviceInfoData ) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { continue; } deviceInterfaceDetail = PhAllocate(deviceInfoLength); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, &deviceInterfaceData, deviceInterfaceDetail, deviceInfoLength, &deviceInfoLength, &deviceInfoData )) { HANDLE deviceHandle; PDISK_ENUM_ENTRY diskEntry; WCHAR diskFriendlyName[MAX_PATH] = L""; // This crashes on XP with error 0xC06D007F //SetupDiGetDeviceProperty( // deviceInfoHandle, // &deviceInfoData, // &DEVPKEY_Device_FriendlyName, // &devicePropertyType, // (PBYTE)diskFriendlyName, // ARRAYSIZE(diskFriendlyName), // NULL, // 0 // ); if (!SetupDiGetDeviceRegistryProperty( deviceInfoHandle, &deviceInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)diskFriendlyName, ARRAYSIZE(diskFriendlyName), NULL )) { continue; } diskEntry = PhAllocate(sizeof(DISK_ENUM_ENTRY)); memset(diskEntry, 0, sizeof(DISK_ENUM_ENTRY)); diskEntry->DeviceIndex = ULONG_MAX; // Note: Do not initialize to zero. diskEntry->DeviceName = PhCreateString(diskFriendlyName); diskEntry->DevicePath = PhCreateString(deviceInterfaceDetail->DevicePath); if (NT_SUCCESS(DiskDriveCreateHandle( &deviceHandle, diskEntry->DevicePath ))) { ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber( deviceHandle, &diskIndex, NULL ))) { PPH_STRING diskMountPoints = PH_AUTO_T(PH_STRING, DiskDriveQueryDosMountPoints(diskIndex)); diskEntry->DeviceIndex = diskIndex; diskEntry->DevicePresent = TRUE; if (!PhIsNullOrEmptyString(diskMountPoints)) { diskEntry->DeviceMountPoints = PhFormatString( L"Disk %lu (%s) [%s]", diskIndex, diskMountPoints->Buffer, diskFriendlyName ); } else { diskEntry->DeviceMountPoints = PhFormatString( L"Disk %lu [%s]", diskIndex, diskFriendlyName ); } } NtClose(deviceHandle); } PhAddItemList(deviceList, diskEntry); } PhFree(deviceInterfaceDetail); } SetupDiDestroyDeviceInfoList(deviceInfoHandle); // Sort the entries qsort(deviceList->Items, deviceList->Count, sizeof(PVOID), DiskEntryCompareFunction); Context->EnumeratingDisks = TRUE; PhAcquireQueuedLockShared(&DiskDrivesListLock); for (ULONG i = 0; i < deviceList->Count; i++) { PDISK_ENUM_ENTRY entry = deviceList->Items[i]; AddDiskDriveToListView( Context, entry->DevicePresent, entry->DevicePath, entry->DeviceMountPoints ? entry->DeviceMountPoints : entry->DeviceName ); if (entry->DeviceMountPoints) PhDereferenceObject(entry->DeviceMountPoints); if (entry->DeviceName) PhDereferenceObject(entry->DeviceName); // Note: DevicePath is disposed by WM_DESTROY. PhFree(entry); } PhReleaseQueuedLockShared(&DiskDrivesListLock); Context->EnumeratingDisks = FALSE; // HACK: Show all unknown devices. Context->EnumeratingDisks = TRUE; PhAcquireQueuedLockShared(&DiskDrivesListLock); for (ULONG i = 0; i < DiskDrivesList->Count; i++) { ULONG index = -1; BOOLEAN found = FALSE; PDV_DISK_ENTRY entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]); if (!entry) continue; while ((index = PhFindListViewItemByFlags( Context->ListViewHandle, index, LVNI_ALL )) != -1) { PDV_DISK_ID param; if (PhGetListViewItemParam(Context->ListViewHandle, index, ¶m)) { if (EquivalentDiskId(param, &entry->Id)) { found = TRUE; } } } if (!found) { PPH_STRING description; if (description = PhCreateString(L"Unknown disk")) { AddDiskDriveToListView( Context, FALSE, entry->Id.DevicePath, description ); PhDereferenceObject(description); } } PhDereferenceObjectDeferDelete(entry); } PhReleaseQueuedLockShared(&DiskDrivesListLock); Context->EnumeratingDisks = FALSE; }
VOID DiskDrivesUpdate( VOID ) { static ULONG runCount = 0; // MUST keep in sync with runCount in process provider PhAcquireQueuedLockShared(&DiskDrivesListLock); for (ULONG i = 0; i < DiskDrivesList->Count; i++) { HANDLE deviceHandle = NULL; PDV_DISK_ENTRY entry; entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]); if (!entry) continue; if (NT_SUCCESS(DiskDriveCreateHandle( &deviceHandle, entry->Id.DevicePath ))) { DISK_PERFORMANCE diskPerformance; if (NT_SUCCESS(DiskDriveQueryStatistics( deviceHandle, &diskPerformance ))) { ULONG64 readTime; ULONG64 writeTime; ULONG64 idleTime; ULONG readCount; ULONG writeCount; ULONG64 queryTime; PhUpdateDelta(&entry->BytesReadDelta, diskPerformance.BytesRead.QuadPart); PhUpdateDelta(&entry->BytesWrittenDelta, diskPerformance.BytesWritten.QuadPart); PhUpdateDelta(&entry->ReadTimeDelta, diskPerformance.ReadTime.QuadPart); PhUpdateDelta(&entry->WriteTimeDelta, diskPerformance.WriteTime.QuadPart); PhUpdateDelta(&entry->IdleTimeDelta, diskPerformance.IdleTime.QuadPart); PhUpdateDelta(&entry->ReadCountDelta, diskPerformance.ReadCount); PhUpdateDelta(&entry->WriteCountDelta, diskPerformance.WriteCount); PhUpdateDelta(&entry->QueryTimeDelta, diskPerformance.QueryTime.QuadPart); readTime = entry->ReadTimeDelta.Delta; writeTime = entry->WriteTimeDelta.Delta; idleTime = entry->IdleTimeDelta.Delta; readCount = entry->ReadCountDelta.Delta; writeCount = entry->WriteCountDelta.Delta; queryTime = entry->QueryTimeDelta.Delta; if (readCount + writeCount != 0) entry->ResponseTime = ((FLOAT)readTime + (FLOAT)writeTime) / (readCount + writeCount); else entry->ResponseTime = 0; if (queryTime != 0) entry->ActiveTime = (FLOAT)(queryTime - idleTime) / queryTime * 100; else entry->ActiveTime = 0.0f; if (entry->ActiveTime > 100.f) entry->ActiveTime = 0.f; if (entry->ActiveTime < 0.f) entry->ActiveTime = 0.f; entry->QueueDepth = diskPerformance.QueueDepth; entry->SplitCount = diskPerformance.SplitCount; } else { // Disk has been disconnected or dismounted. PhInitializeDelta(&entry->BytesReadDelta); PhInitializeDelta(&entry->BytesWrittenDelta); PhInitializeDelta(&entry->ReadTimeDelta); PhInitializeDelta(&entry->WriteTimeDelta); PhInitializeDelta(&entry->IdleTimeDelta); PhInitializeDelta(&entry->ReadCountDelta); PhInitializeDelta(&entry->WriteCountDelta); PhInitializeDelta(&entry->QueryTimeDelta); entry->ResponseTime = 0; entry->ActiveTime = 0.0f; entry->QueueDepth = 0; entry->SplitCount = 0; } // HACK: Pull the Disk name from the current query. if (!entry->DiskName) { DiskDriveQueryDeviceInformation(deviceHandle, NULL, &entry->DiskName, NULL, NULL); } // HACK: Pull the Disk index from the current query. if (entry->DiskIndex == ULONG_MAX) { ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero. if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber(deviceHandle, &diskIndex, NULL))) { entry->DiskIndex = diskIndex; } } NtClose(deviceHandle); } else { // Disk has been disconnected or dismounted. PhInitializeDelta(&entry->BytesReadDelta); PhInitializeDelta(&entry->BytesWrittenDelta); PhInitializeDelta(&entry->ReadTimeDelta); PhInitializeDelta(&entry->WriteTimeDelta); PhInitializeDelta(&entry->IdleTimeDelta); PhInitializeDelta(&entry->ReadCountDelta); PhInitializeDelta(&entry->WriteCountDelta); PhInitializeDelta(&entry->QueryTimeDelta); entry->ResponseTime = 0; entry->ActiveTime = 0.0f; entry->QueueDepth = 0; entry->SplitCount = 0; } if (!entry->HaveFirstSample) { // The first sample must be zero. entry->BytesReadDelta.Delta = 0; entry->BytesWrittenDelta.Delta = 0; entry->HaveFirstSample = TRUE; } if (runCount != 0) { PhAddItemCircularBuffer_ULONG64(&entry->ReadBuffer, entry->BytesReadDelta.Delta); PhAddItemCircularBuffer_ULONG64(&entry->WriteBuffer, entry->BytesWrittenDelta.Delta); } PhDereferenceObjectDeferDelete(entry); } PhReleaseQueuedLockShared(&DiskDrivesListLock); runCount++; }