From 78870673018ce08cf9f65db74160161e7c0a4bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 5 Apr 2026 18:44:32 +0800 Subject: [PATCH] PhysicalDisk (Windows): switches to CMAPI; adds floppy support --- .../physicaldisk/physicaldisk_windows.c | 359 ++++++++++-------- 1 file changed, 205 insertions(+), 154 deletions(-) diff --git a/src/detection/physicaldisk/physicaldisk_windows.c b/src/detection/physicaldisk/physicaldisk_windows.c index dfa4e1310..f919f227b 100644 --- a/src/detection/physicaldisk/physicaldisk_windows.c +++ b/src/detection/physicaldisk/physicaldisk_windows.c @@ -1,12 +1,14 @@ #include "physicaldisk.h" #include "common/io.h" #include "common/windows/unicode.h" +#include "common/mallocHelper.h" #include #include #include +#include -static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysicalDiskOptions* options) { +static bool 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 false; @@ -14,7 +16,9 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic 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]; @@ -29,146 +33,194 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic 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 true; // Unsupported + } + interconnect = "Floppy Controller"; + type |= FF_PHYSICALDISK_TYPE_HDD | FF_PHYSICALDISK_TYPE_REMOVABLE; } } if (size == 0) { type |= FF_PHYSICALDISK_TYPE_UNKNOWN; } + const STORAGE_DEVICE_DESCRIPTOR* sdd = NULL; alignas(STORAGE_DEVICE_DESCRIPTOR) uint8_t sddBuffer[4096]; - 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) { - return true; - } - const STORAGE_DEVICE_DESCRIPTOR* sdd = (const STORAGE_DEVICE_DESCRIPTOR*) sddBuffer; + 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; - const char* interconnect; - 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; + 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 (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 true; } FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); ffStrbufInit(&device->serial); ffStrbufInit(&device->revision); - ffStrbufInit(&device->name); + ffStrbufInitMove(&device->name, &name); ffStrbufInit(&device->devPath); ffStrbufInitStatic(&device->interconnect, interconnect); device->type = type; device->size = size; device->temperature = FF_PHYSICALDISK_TEMP_UNSET; - if (sdd->VendorIdOffset != 0) { - ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset); - ffStrbufTrim(&device->name, ' '); - } - if (sdd->ProductIdOffset != 0) { - if (device->name.length) { - ffStrbufAppendC(&device->name, ' '); + ffStrbufSetWS(&device->devPath, szDevice); + + if (sdd) { + if (sdd->SerialNumberOffset != 0) { + ffStrbufSetS(&device->serial, (const char*) sdd + sdd->SerialNumberOffset); + ffStrbufTrimSpace(&device->serial); } - ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset); - ffStrbufTrimRight(&device->name, ' '); - } + if (sdd->ProductRevisionOffset != 0) { + ffStrbufSetS(&device->revision, (const char*) sdd + sdd->ProductRevisionOffset); + ffStrbufTrimRightSpace(&device->revision); + } - if (!device->name.length) { - ffStrbufSetWS(&device->name, szDevice); + device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; } - if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix)) { - ffStrbufDestroy(&device->name); - result->length--; - return true; - } - - ffStrbufSetWS(&device->devPath, szDevice); - if (sdd->SerialNumberOffset != 0) { - ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset); - ffStrbufTrimSpace(&device->serial); - } - - if (sdd->ProductRevisionOffset != 0) { - ffStrbufSetS(&device->revision, (const char*) sddBuffer + 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; @@ -201,7 +253,7 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic } } - if (!(device->type & FF_PHYSICALDISK_TYPE_VIRTUAL)) { + if (!(device->type & FF_PHYSICALDISK_TYPE_VIRTUAL) && !(device->type & FF_PHYSICALDISK_TYPE_HDD)) { DEVICE_SEEK_PENALTY_DESCRIPTOR dspd = {}; if (DeviceIoControl( hDevice, @@ -242,42 +294,41 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic return true; } +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) { + detectPhysicalDisk(type, p, result, options); + } +} + const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { - { - wchar_t szPhysicalDrive[32] = L"\\\\.\\PhysicalDrive"; - wchar_t* pNum = szPhysicalDrive + strlen("\\\\.\\PhysicalDrive"); - for (uint32_t idev = 0;; ++idev) { - _ultow(idev, pNum, 10); - - if (!detectPhysicalDisk(szPhysicalDrive, result, options)) { - break; - } - } - } - - { - wchar_t szCdrom[32] = L"\\\\.\\CDROM"; - wchar_t* pNum = szCdrom + strlen("\\\\.\\CDROM"); - for (uint32_t idev = 0;; ++idev) { - _ultow(idev, pNum, 10); - - if (!detectPhysicalDisk(szCdrom, result, options)) { - break; - } - } - } - - { - wchar_t szTape[32] = L"\\\\.\\Tape"; - wchar_t* pNum = szTape + strlen("\\\\.\\Tape"); - for (uint32_t idev = 0;; ++idev) { - _ultow(idev, pNum, 10); - - if (!detectPhysicalDisk(szTape, result, options)) { - break; - } - } - } - + 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; }