diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/physicaldisk/physicaldisk_windows.c | |
Add the files
Diffstat (limited to 'src/detection/physicaldisk/physicaldisk_windows.c')
| -rw-r--r-- | src/detection/physicaldisk/physicaldisk_windows.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/src/detection/physicaldisk/physicaldisk_windows.c b/src/detection/physicaldisk/physicaldisk_windows.c new file mode 100644 index 0000000..5d4f7f7 --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_windows.c @@ -0,0 +1,349 @@ +#include "physicaldisk.h" +#include "common/io.h" +#include "common/windows/unicode.h" +#include "common/mallocHelper.h" +#include "common/debug.h" + +#include <stdalign.h> +#include <windows.h> +#include <winioctl.h> +#include <cfgmgr32.h> + +static const char* detectPhysicalDisk(const char* physicalType, const wchar_t* szDevice, FFlist* result, FFPhysicalDiskOptions* options) { + FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) { + return "CreateFileW() failed"; + } + + DWORD retSize; + FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE; + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + + const char* interconnect = NULL; + uint64_t size = 0; + { + alignas(DISK_GEOMETRY_EX) uint8_t dgeBuffer[4096]; + if (DeviceIoControl( + hDevice, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + NULL, + 0, + dgeBuffer, + sizeof(dgeBuffer), + &retSize, + NULL)) { + const DISK_GEOMETRY_EX* dge = (const DISK_GEOMETRY_EX*) dgeBuffer; + size = (uint64_t) dge->DiskSize.QuadPart; + } else if (DeviceIoControl( + hDevice, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + dgeBuffer, + sizeof(dgeBuffer), + &retSize, + NULL) && + retSize >= sizeof(DISK_GEOMETRY)) { + const DISK_GEOMETRY* dg = (const DISK_GEOMETRY*) dgeBuffer; + size = (uint64_t) dg->BytesPerSector * dg->SectorsPerTrack * dg->TracksPerCylinder * (uint64_t) dg->Cylinders.QuadPart; + switch (dg->MediaType) { + case F3_1Pt44_512: + case F3_2Pt88_512: + case F3_20Pt8_512: + case F3_720_512: + case F3_120M_512: + case F3_640_512: + case F3_1Pt2_512: + case F3_1Pt23_1024: + case F3_128Mb_512: + case F3_230Mb_512: + case F3_200Mb_512: + case F3_240M_512: + case F3_32M_512: + ffStrbufSetStatic(&name, "3.5-inch Floppy Disk"); + break; + case F5_1Pt2_512: + case F5_360_512: + case F5_320_512: + case F5_320_1024: + case F5_180_512: + case F5_160_512: + case F5_640_512: + case F5_720_512: + case F5_1Pt23_1024: + ffStrbufSetStatic(&name, "5.25-inch Floppy Disk"); + break; + case F8_256_128: + ffStrbufSetStatic(&name, "8-inch Floppy Disk"); + break; + default: + return "Unsupported media type"; + } + interconnect = "Floppy Controller"; + type |= FF_PHYSICALDISK_TYPE_HDD | FF_PHYSICALDISK_TYPE_REMOVABLE; + } + } + if (size == 0) { + if (options->hideType & FF_PHYSICALDISK_TYPE_UNUSED) { + return "Skipping unknown disk with size 0"; + } + + type |= FF_PHYSICALDISK_TYPE_UNUSED; + } + + const STORAGE_DEVICE_DESCRIPTOR* sdd = NULL; + alignas(STORAGE_DEVICE_DESCRIPTOR) uint8_t sddBuffer[4096]; + if (!interconnect) { + if (DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &(STORAGE_PROPERTY_QUERY) { + .PropertyId = StorageDeviceProperty, + .QueryType = PropertyStandardQuery, + }, + sizeof(STORAGE_PROPERTY_QUERY), + &sddBuffer, + sizeof(sddBuffer), + &retSize, + NULL) || + retSize == 0) { + sdd = (const STORAGE_DEVICE_DESCRIPTOR*) sddBuffer; + + switch (sdd->BusType) { + case BusTypeScsi: + interconnect = "SCSI"; + break; + case BusTypeAtapi: + interconnect = "ATAPI"; + break; + case BusTypeAta: + interconnect = "ATA"; + break; + case BusType1394: + interconnect = "IEEE 1394"; + break; + case BusTypeSsa: + interconnect = "SSA"; + break; + case BusTypeFibre: + interconnect = "Fibre"; + break; + case BusTypeUsb: + interconnect = "USB"; + break; + case BusTypeRAID: + interconnect = "RAID"; + break; + case BusTypeiScsi: + interconnect = "iSCSI"; + break; + case BusTypeSas: + interconnect = "SAS"; + break; + case BusTypeSata: + interconnect = "SATA"; + break; + case BusTypeSd: + interconnect = "SD"; + break; + case BusTypeMmc: + interconnect = "MMC"; + break; + case BusTypeVirtual: + interconnect = "Virtual"; + type |= FF_PHYSICALDISK_TYPE_VIRTUAL; + break; + case BusTypeFileBackedVirtual: + interconnect = "File Backed Virtual"; + type |= FF_PHYSICALDISK_TYPE_VIRTUAL; + break; + case BusTypeSpaces: + interconnect = "Storage Spaces"; + type |= FF_PHYSICALDISK_TYPE_VIRTUAL; + break; + case BusTypeNvme: + interconnect = "NVMe"; + break; + case BusTypeSCM: + interconnect = "SCM"; + break; + case BusTypeUfs: + interconnect = "UFS"; + break; + case 0x14 /*BusTypeNvmeof*/: + interconnect = "NVMe-oF"; + break; + default: + interconnect = "Unknown"; + break; + } + + if (type & FF_PHYSICALDISK_TYPE_VIRTUAL && options->hideType & FF_PHYSICALDISK_TYPE_VIRTUAL) { + return "Skipping virtual disk"; + } + + if (sdd->VendorIdOffset != 0) { + ffStrbufSetS(&name, (const char*) sdd + sdd->VendorIdOffset); + ffStrbufTrim(&name, ' '); + } + if (sdd->ProductIdOffset != 0) { + if (name.length) { + ffStrbufAppendC(&name, ' '); + } + + ffStrbufAppendS(&name, (const char*) sdd + sdd->ProductIdOffset); + ffStrbufTrimRight(&name, ' '); + } + } + if (!name.length) { + ffStrbufSetStatic(&name, physicalType); + } + } + + if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) { + return "Name prefix mismatch"; + } + + FFPhysicalDiskResult* device = FF_LIST_ADD(FFPhysicalDiskResult, *result); + ffStrbufInit(&device->serial); + ffStrbufInit(&device->revision); + ffStrbufInitMove(&device->name, &name); + ffStrbufInit(&device->devPath); + ffStrbufInitStatic(&device->interconnect, interconnect); + device->type = type; + device->size = size; + device->temperature = FF_PHYSICALDISK_TEMP_UNSET; + + ffStrbufSetWS(&device->devPath, szDevice); + + if (sdd) { + if (sdd->SerialNumberOffset != 0) { + ffStrbufSetS(&device->serial, (const char*) sdd + sdd->SerialNumberOffset); + ffStrbufTrimSpace(&device->serial); + } + + if (sdd->ProductRevisionOffset != 0) { + ffStrbufSetS(&device->revision, (const char*) sdd + sdd->ProductRevisionOffset); + ffStrbufTrimRightSpace(&device->revision); + } + + device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; + } + + { + alignas(GET_MEDIA_TYPES) uint8_t buffer[4096]; + GET_MEDIA_TYPES* gmt = (GET_MEDIA_TYPES*) buffer; + if (DeviceIoControl( + hDevice, + IOCTL_STORAGE_GET_MEDIA_TYPES_EX, + NULL, + 0, + gmt, + sizeof(buffer), + &retSize, + NULL) && + gmt->MediaInfoCount > 0) { + // DiskInfo and RemovableDiskInfo have the same structures. TapeInfo doesn't. + if (gmt->DeviceType != FILE_DEVICE_TAPE) { + __auto_type diskInfo = &gmt->MediaInfo[0].DeviceSpecific.DiskInfo; + if (diskInfo->MediaCharacteristics & MEDIA_READ_ONLY) { + device->type |= FF_PHYSICALDISK_TYPE_READONLY; + } else if (diskInfo->MediaCharacteristics & MEDIA_READ_WRITE) { + device->type |= FF_PHYSICALDISK_TYPE_READWRITE; + } + } else { + __auto_type tapeInfo = &gmt->MediaInfo[0].DeviceSpecific.TapeInfo; + if (tapeInfo->MediaCharacteristics & MEDIA_READ_ONLY) { + device->type |= FF_PHYSICALDISK_TYPE_READONLY; + } else if (tapeInfo->MediaCharacteristics & MEDIA_READ_WRITE) { + device->type |= FF_PHYSICALDISK_TYPE_READWRITE; + } + } + } + } + + if (!(device->type & FF_PHYSICALDISK_TYPE_VIRTUAL) && !(device->type & FF_PHYSICALDISK_TYPE_HDD)) { + DEVICE_SEEK_PENALTY_DESCRIPTOR dspd = {}; + if (DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &(STORAGE_PROPERTY_QUERY) { + .PropertyId = StorageDeviceSeekPenaltyProperty, + .QueryType = PropertyStandardQuery, + }, + sizeof(STORAGE_PROPERTY_QUERY), + &dspd, + sizeof(dspd), + &retSize, + NULL) && + retSize == sizeof(dspd)) { + device->type |= dspd.IncursSeekPenalty ? FF_PHYSICALDISK_TYPE_HDD : FF_PHYSICALDISK_TYPE_SSD; + } + + if (options->temp) { + STORAGE_TEMPERATURE_DATA_DESCRIPTOR stdd = {}; + if (DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &(STORAGE_PROPERTY_QUERY) { + .PropertyId = StorageDeviceTemperatureProperty, + .QueryType = PropertyStandardQuery, + }, + sizeof(STORAGE_PROPERTY_QUERY), + &stdd, + sizeof(stdd), + &retSize, + NULL) && + retSize == sizeof(stdd)) { + device->temperature = stdd.TemperatureInfo[0].Temperature; + } + } + } + + return NULL; +} + +static void detectPhysicalDisksByInterfaceClass(const char* type, const GUID* interfaceClassGuid, FFlist* result, FFPhysicalDiskOptions* options) { + ULONG cchDeviceInterfaces = 0; + if (CM_Get_Device_Interface_List_SizeW( + &cchDeviceInterfaces, + (LPGUID) interfaceClassGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS || + cchDeviceInterfaces <= 1) { + return; + } + + wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*) malloc(cchDeviceInterfaces * sizeof(wchar_t)); + if (!mszDeviceInterfaces) { + return; + } + + if (CM_Get_Device_Interface_ListW( + (LPGUID) interfaceClassGuid, + NULL, + mszDeviceInterfaces, + cchDeviceInterfaces, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS) { + return; + } + + // MULTI_SZ: "str1\0str2\0...\0\0" + for (const wchar_t* p = mszDeviceInterfaces; *p; p += wcslen(p) + 1) { + FF_DEBUG("Probing %s: %ls", type, p); + FF_A_UNUSED const char* error = detectPhysicalDisk(type, p, result, options); + if (error == NULL) { + FF_DEBUG("Detected device \"%s\"", FF_LIST_LAST(FFPhysicalDiskResult, *result)->name.chars); + } else { + FF_DEBUG("Failed to detect device %s: %s", type, error); + } + } +} + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { + detectPhysicalDisksByInterfaceClass("Floppy", &GUID_DEVINTERFACE_FLOPPY, result, options); + detectPhysicalDisksByInterfaceClass("Disk", &GUID_DEVINTERFACE_DISK, result, options); + detectPhysicalDisksByInterfaceClass("CD-ROM", &GUID_DEVINTERFACE_CDROM, result, options); + detectPhysicalDisksByInterfaceClass("Tape", &GUID_DEVINTERFACE_TAPE, result, options); + return NULL; +} |