summaryrefslogtreecommitdiffstats
path: root/src/detection/diskio
diff options
context:
space:
mode:
Diffstat (limited to 'src/detection/diskio')
-rw-r--r--src/detection/diskio/diskio.c88
-rw-r--r--src/detection/diskio/diskio.h15
-rw-r--r--src/detection/diskio/diskio_apple.c57
-rw-r--r--src/detection/diskio/diskio_bsd.c120
-rw-r--r--src/detection/diskio/diskio_linux.c99
-rw-r--r--src/detection/diskio/diskio_nbsd.c50
-rw-r--r--src/detection/diskio/diskio_nosupport.c5
-rw-r--r--src/detection/diskio/diskio_obsd.c39
-rw-r--r--src/detection/diskio/diskio_sunos.c42
-rw-r--r--src/detection/diskio/diskio_windows.c101
10 files changed, 616 insertions, 0 deletions
diff --git a/src/detection/diskio/diskio.c b/src/detection/diskio/diskio.c
new file mode 100644
index 0000000..6ff66be
--- /dev/null
+++ b/src/detection/diskio/diskio.c
@@ -0,0 +1,88 @@
+#include "diskio.h"
+
+#include "common/time.h"
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options);
+
+static FFlist ioCounters1;
+static uint64_t time1;
+
+void ffPrepareDiskIO(FFDiskIOOptions* options) {
+ if (options->detectTotal) {
+ return;
+ }
+
+ if (time1 != 0) {
+ return; // Already prepared
+ }
+
+ ffListInit(&ioCounters1);
+ ffDiskIOGetIoCounters(&ioCounters1, options);
+ time1 = ffTimeGetNow();
+}
+
+const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options) {
+ const char* error = NULL;
+
+ if (options->detectTotal) {
+ error = ffDiskIOGetIoCounters(result, options);
+ if (error) {
+ return error;
+ }
+ return NULL;
+ }
+
+ if (time1 == 0) {
+ ffListInit(&ioCounters1);
+ error = ffDiskIOGetIoCounters(&ioCounters1, options);
+ if (error) {
+ return error;
+ }
+ time1 = ffTimeGetNow();
+ }
+
+ if (ioCounters1.length == 0) {
+ return "No physical disk found";
+ }
+
+ uint64_t time2 = ffTimeGetNow();
+ while (time2 - time1 < options->waitTime) {
+ ffTimeSleep((uint32_t) (options->waitTime - (time2 - time1)));
+ time2 = ffTimeGetNow();
+ }
+
+ error = ffDiskIOGetIoCounters(result, options);
+ if (error) {
+ return error;
+ }
+
+ if (result->length != ioCounters1.length) {
+ return "Different number of physical disks. Hardware change?";
+ }
+
+ for (uint32_t i = 0; i < result->length; ++i) {
+ FFDiskIOResult* icPrev = FF_LIST_GET(FFDiskIOResult, ioCounters1, i);
+ FFDiskIOResult* icCurr = FF_LIST_GET(FFDiskIOResult, *result, i);
+ if (!ffStrbufEqual(&icPrev->devPath, &icCurr->devPath)) {
+ return "Physical disk device path changed";
+ }
+
+ static_assert(sizeof(FFDiskIOResult) - offsetof(FFDiskIOResult, bytesRead) == sizeof(uint64_t) * 4, "Unexpected struct FFDiskIOResult layout");
+ for (size_t off = offsetof(FFDiskIOResult, bytesRead); off < sizeof(FFDiskIOResult); off += sizeof(uint64_t)) {
+ uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
+ uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
+ uint64_t temp = *currValue;
+ *currValue -= *prevValue;
+ *currValue /= (time2 - time1) / 1000 /* seconds */;
+
+ // For next function call
+ *prevValue = temp;
+ }
+ }
+
+ // For next function call
+ time1 = time2;
+ // Leak ioCounters1 here
+
+ return NULL;
+}
diff --git a/src/detection/diskio/diskio.h b/src/detection/diskio/diskio.h
new file mode 100644
index 0000000..39c665a
--- /dev/null
+++ b/src/detection/diskio/diskio.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "fastfetch.h"
+#include "modules/diskio/option.h"
+
+typedef struct FFDiskIOResult {
+ FFstrbuf name;
+ FFstrbuf devPath;
+ uint64_t bytesRead;
+ uint64_t readCount;
+ uint64_t bytesWritten;
+ uint64_t writeCount;
+} FFDiskIOResult;
+
+const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options);
diff --git a/src/detection/diskio/diskio_apple.c b/src/detection/diskio/diskio_apple.c
new file mode 100644
index 0000000..dc28907
--- /dev/null
+++ b/src/detection/diskio/diskio_apple.c
@@ -0,0 +1,57 @@
+#include "diskio.h"
+#include "common/apple/cf_helpers.h"
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
+#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0;
+ if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOBlockStorageDriverClass), &iterator) != KERN_SUCCESS) {
+ return "IOServiceGetMatchingServices() failed";
+ }
+
+ io_registry_entry_t registryEntry;
+ while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
+ FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDriver = registryEntry;
+
+ FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryMedia = IO_OBJECT_NULL;
+ if (IORegistryEntryGetChildEntry(entryDriver, kIOServicePlane, &entryMedia) != KERN_SUCCESS) {
+ continue;
+ }
+
+ io_name_t deviceName;
+ if (IORegistryEntryGetName(entryMedia, deviceName) != KERN_SUCCESS) {
+ continue;
+ }
+
+ if (options->namePrefix.length && strncmp(deviceName, options->namePrefix.chars, options->namePrefix.length) != 0) {
+ continue;
+ }
+
+ FF_CFTYPE_AUTO_RELEASE CFDictionaryRef statistics = IORegistryEntryCreateCFProperty(entryDriver, CFSTR(kIOBlockStorageDriverStatisticsKey), kCFAllocatorDefault, kNilOptions);
+ if (!statistics) {
+ continue;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInitS(&device->name, deviceName);
+ ffStrbufInit(&device->devPath);
+
+ ffCfDictGetInt64(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey), (int64_t*) &device->bytesRead);
+ ffCfDictGetInt64(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey), (int64_t*) &device->bytesWritten);
+ ffCfDictGetInt64(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey), (int64_t*) &device->readCount);
+ ffCfDictGetInt64(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey), (int64_t*) &device->writeCount);
+
+ FF_CFTYPE_AUTO_RELEASE CFStringRef bsdName = IORegistryEntryCreateCFProperty(entryMedia, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, kNilOptions);
+ if (bsdName) {
+ ffCfStrGetString(bsdName, &device->devPath);
+ ffStrbufPrependS(&device->devPath, "/dev/");
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/detection/diskio/diskio_bsd.c b/src/detection/diskio/diskio_bsd.c
new file mode 100644
index 0000000..f5eb4b8
--- /dev/null
+++ b/src/detection/diskio/diskio_bsd.c
@@ -0,0 +1,120 @@
+#include "diskio.h"
+
+#if __has_include(<libgeom.h>)
+
+ #include "common/strutil.h"
+
+ #include <devstat.h>
+ #include <memory.h>
+ #include <fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/disk.h>
+ #include <libgeom.h>
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ FF_A_CLEANUP(geom_deletetree) struct gmesh geomTree = {};
+ if (geom_gettree(&geomTree) < 0) {
+ return "geom_gettree() failed";
+ }
+
+ if (geom_stats_open() < 0) {
+ return "geom_stats_open() failed";
+ }
+
+ void* snap = geom_stats_snapshot_get();
+ if (!snap) {
+ return "geom_stats_snapshot_get() failed";
+ }
+
+ struct devstat* snapIter;
+ while ((snapIter = geom_stats_snapshot_next(snap)) != NULL) {
+ if (snapIter->device_type & DEVSTAT_TYPE_PASS) {
+ continue;
+ }
+ struct gident* geomId = geom_lookupid(&geomTree, snapIter->id);
+ if (geomId == NULL) {
+ continue;
+ }
+ if (geomId->lg_what != ISPROVIDER) {
+ continue;
+ }
+ struct gprovider* provider = (struct gprovider*) geomId->lg_ptr;
+ if (provider->lg_geom->lg_rank != 1) {
+ continue;
+ }
+
+ FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
+ for (struct gconfig* ptr = provider->lg_config.lh_first; ptr; ptr = ptr->lg_config.le_next) {
+ if (ffStrEquals(ptr->lg_name, "descr")) {
+ ffStrbufSetS(&name, ptr->lg_val);
+ }
+ }
+ if (name.length == 0) {
+ ffStrbufSetS(&name, provider->lg_name);
+ }
+
+ if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) {
+ continue;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
+ device->bytesRead = snapIter->bytes[DEVSTAT_READ];
+ device->readCount = snapIter->operations[DEVSTAT_READ];
+ device->bytesWritten = snapIter->bytes[DEVSTAT_WRITE];
+ device->writeCount = snapIter->operations[DEVSTAT_WRITE];
+ ffStrbufInitMove(&device->name, &name);
+ }
+
+ geom_stats_snapshot_free(snap);
+ geom_stats_close();
+
+ return NULL;
+}
+
+#else
+
+ #include <devstat.h>
+ #include <memory.h>
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ if (checkversion() < 0) {
+ return "checkversion() failed";
+ }
+
+ struct statinfo stats = {
+ .dinfo = (struct devinfo*) calloc(1, sizeof(struct devinfo)),
+ };
+ if (getdevs(&stats) < 0) {
+ return "getdevs() failed";
+ }
+
+ for (int i = 0; i < stats.dinfo->numdevs; i++) {
+ struct devstat* current = &stats.dinfo->devices[i];
+ if (current->device_type & DEVSTAT_TYPE_PASS) {
+ continue;
+ }
+
+ char deviceName[128];
+ snprintf(deviceName, sizeof(deviceName), "%s%d", current->device_name, current->unit_number);
+
+ if (options->namePrefix.length && strncmp(deviceName, options->namePrefix.chars, options->namePrefix.length) != 0) {
+ continue;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInitS(&device->name, deviceName);
+ ffStrbufInitF(&device->devPath, "/dev/%s", deviceName);
+ device->bytesRead = current->bytes_read;
+ device->readCount = current->num_reads;
+ device->bytesWritten = current->bytes_written;
+ device->writeCount = current->num_writes;
+ }
+
+ free(stats.dinfo->mem_ptr);
+ free(stats.dinfo);
+
+ return NULL;
+}
+
+#endif
diff --git a/src/detection/diskio/diskio_linux.c b/src/detection/diskio/diskio_linux.c
new file mode 100644
index 0000000..c7ddc55
--- /dev/null
+++ b/src/detection/diskio/diskio_linux.c
@@ -0,0 +1,99 @@
+#include "diskio.h"
+#include "common/io.h"
+#include "common/properties.h"
+#include "common/strutil.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <fcntl.h>
+
+static const char* parseDiskIOCounters(int dfd, const char* devName, FFlist* result, FFDiskIOOptions* options) {
+ FF_AUTO_CLOSE_FD int devfd = openat(dfd, "device", O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
+ if (devfd < 0) {
+ return "virtual device";
+ }
+
+ FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
+
+ {
+ if (ffAppendFileBufferRelative(devfd, "vendor", &name)) {
+ ffStrbufTrimRightSpace(&name);
+ if (name.length > 0) {
+ ffStrbufAppendC(&name, ' ');
+ }
+ }
+
+ ffAppendFileBufferRelative(devfd, "model", &name);
+ ffStrbufTrimRightSpace(&name);
+
+ if (name.length == 0) {
+ ffStrbufSetS(&name, devName);
+ } else if (ffStrStartsWith(devName, "nvme")) {
+ int devid, nsid;
+ if (sscanf(devName, "nvme%dn%d", &devid, &nsid) == 2) {
+ bool multiNs = nsid > 1;
+ if (!multiNs) {
+ char pathSysBlock[16];
+ snprintf(pathSysBlock, ARRAY_SIZE(pathSysBlock), "nvme%dn2", devid);
+ multiNs = faccessat(devfd, pathSysBlock, F_OK, 0) == 0;
+ }
+ if (multiNs) {
+ // In Asahi Linux, there are multiple namespaces for the same NVMe drive.
+ ffStrbufAppendF(&name, " - %d", nsid);
+ }
+ }
+ }
+
+ if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) {
+ return "ignored";
+ }
+ }
+
+ // I/Os merges sectors ticks ...
+ uint64_t nRead, sectorRead, nWritten, sectorWritten;
+ {
+ char sysBlockStat[PROC_FILE_BUFFSIZ];
+ ssize_t fileSize = ffReadFileDataRelative(dfd, "stat", ARRAY_SIZE(sysBlockStat) - 1, sysBlockStat);
+ if (fileSize <= 0) {
+ return "failed to read stat file";
+ }
+ sysBlockStat[fileSize] = '\0';
+ if (sscanf(sysBlockStat, "%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u", &nRead, &sectorRead, &nWritten, &sectorWritten) <= 0) {
+ return "invalid stat file format";
+ }
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInitMove(&device->name, &name);
+ ffStrbufInitF(&device->devPath, "/dev/%s", devName);
+ device->bytesRead = sectorRead * 512;
+ device->bytesWritten = sectorWritten * 512;
+ device->readCount = nRead;
+ device->writeCount = nWritten;
+
+ return NULL;
+}
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ FF_AUTO_CLOSE_DIR DIR* sysBlockDirp = opendir("/sys/block/");
+ if (sysBlockDirp == NULL) {
+ return "opendir(\"/sys/block/\") == NULL";
+ }
+
+ struct dirent* sysBlockEntry;
+ while ((sysBlockEntry = readdir(sysBlockDirp)) != NULL) {
+ const char* const devName = sysBlockEntry->d_name;
+
+ if (devName[0] == '.') {
+ continue;
+ }
+
+ FF_AUTO_CLOSE_FD int dfd = openat(dirfd(sysBlockDirp), devName, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
+ if (dfd > 0) {
+ parseDiskIOCounters(dfd, devName, result, options);
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/detection/diskio/diskio_nbsd.c b/src/detection/diskio/diskio_nbsd.c
new file mode 100644
index 0000000..9ca9578
--- /dev/null
+++ b/src/detection/diskio/diskio_nbsd.c
@@ -0,0 +1,50 @@
+#include "diskio.h"
+#include "common/io.h"
+#include "common/strutil.h"
+#include "common/mallocHelper.h"
+
+#include <sys/iostat.h>
+#include <sys/sysctl.h>
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ int mib[] = { CTL_HW, HW_IOSTATS, sizeof(struct io_sysctl) };
+ size_t len;
+ if (sysctl(mib, ARRAY_SIZE(mib), NULL, &len, NULL, 0) < 0) {
+ return "sysctl({HW_IOSTATS}, NULL) failed";
+ }
+ uint32_t nDrive = (uint32_t) (len / sizeof(struct io_sysctl));
+
+ FF_AUTO_FREE struct io_sysctl* stats = malloc(len);
+
+ if (sysctl(mib, ARRAY_SIZE(mib), stats, &len, NULL, 0) < 0) {
+ return "sysctl({HW_IOSTATS}, stats) failed";
+ }
+
+ char path[64] = "/dev/";
+
+ for (uint32_t i = 0; i < nDrive; ++i) {
+ struct io_sysctl* st = &stats[i];
+
+ if (options->namePrefix.length && strncmp(st->name, options->namePrefix.chars, options->namePrefix.length) != 0) {
+ continue;
+ }
+
+ // Skip partitions
+ char* end = ffStrCopy(&path[5], st->name, ARRAY_SIZE(path) - 8);
+ *end++ = 'c';
+ *end = '\0';
+ if (!ffPathExists(path, FF_PATHTYPE_ANY)) {
+ continue;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInitNS(&device->devPath, (uint32_t) (end - path), path);
+ ffStrbufInitS(&device->name, st->name);
+ device->bytesRead = st->rbytes;
+ device->readCount = st->rxfer;
+ device->bytesWritten = st->wbytes;
+ device->writeCount = st->wxfer;
+ }
+
+ return NULL;
+}
diff --git a/src/detection/diskio/diskio_nosupport.c b/src/detection/diskio/diskio_nosupport.c
new file mode 100644
index 0000000..f5de15d
--- /dev/null
+++ b/src/detection/diskio/diskio_nosupport.c
@@ -0,0 +1,5 @@
+#include "diskio.h"
+
+const char* ffDiskIOGetIoCounters(FF_A_UNUSED FFlist* result, FF_A_UNUSED FFDiskIOOptions* options) {
+ return "Not supported on this platform";
+}
diff --git a/src/detection/diskio/diskio_obsd.c b/src/detection/diskio/diskio_obsd.c
new file mode 100644
index 0000000..8dbc67e
--- /dev/null
+++ b/src/detection/diskio/diskio_obsd.c
@@ -0,0 +1,39 @@
+#include "diskio.h"
+#include "common/strutil.h"
+#include "common/mallocHelper.h"
+
+#include <sys/disk.h>
+#include <sys/sysctl.h>
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ int mib[] = { CTL_HW, HW_DISKSTATS };
+ size_t len;
+ if (sysctl(mib, ARRAY_SIZE(mib), NULL, &len, NULL, 0) < 0) {
+ return "sysctl({HW_DISKSTATS}, NULL) failed";
+ }
+ uint32_t nDrive = (uint32_t) (len / sizeof(struct diskstats));
+
+ FF_AUTO_FREE struct diskstats* stats = malloc(len);
+
+ if (sysctl(mib, ARRAY_SIZE(mib), stats, &len, NULL, 0) < 0) {
+ return "sysctl({HW_DISKSTATS}, stats) failed";
+ }
+
+ for (uint32_t i = 0; i < nDrive; ++i) {
+ struct diskstats* st = &stats[i];
+
+ if (options->namePrefix.length && strncmp(st->ds_name, options->namePrefix.chars, options->namePrefix.length) != 0) {
+ continue;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInitF(&device->devPath, "/dev/%s", st->ds_name);
+ ffStrbufInitS(&device->name, st->ds_name);
+ device->bytesRead = st->ds_rbytes;
+ device->readCount = st->ds_rxfer;
+ device->bytesWritten = st->ds_wbytes;
+ device->writeCount = st->ds_wxfer;
+ }
+
+ return NULL;
+}
diff --git a/src/detection/diskio/diskio_sunos.c b/src/detection/diskio/diskio_sunos.c
new file mode 100644
index 0000000..7cda420
--- /dev/null
+++ b/src/detection/diskio/diskio_sunos.c
@@ -0,0 +1,42 @@
+#include "diskio.h"
+#include "common/strutil.h"
+#include <kstat.h>
+
+static inline void kstatFreeWrap(kstat_ctl_t** pkc) {
+ assert(pkc);
+ if (*pkc) {
+ kstat_close(*pkc);
+ }
+}
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) {
+ FF_A_CLEANUP(kstatFreeWrap) kstat_ctl_t* kc = kstat_open();
+ if (!kc) {
+ return "kstat_open() failed";
+ }
+
+ for (kstat_t* ks = kc->kc_chain; ks; ks = ks->ks_next) {
+ if (ks->ks_type != KSTAT_TYPE_IO || !ffStrEquals(ks->ks_class, "disk")) {
+ continue;
+ }
+
+ if (options->namePrefix.length && strncmp(ks->ks_name, options->namePrefix.chars, options->namePrefix.length) != 0) {
+ continue;
+ }
+
+ kstat_io_t kio;
+ if (kstat_read(kc, ks, &kio) < 0) {
+ continue;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ ffStrbufInit(&device->devPath); // unlike other platforms, `/dev/ks_name` is not available
+ ffStrbufInitS(&device->name, ks->ks_name);
+ device->bytesRead = kio.nread;
+ device->readCount = kio.reads;
+ device->bytesWritten = kio.nwritten;
+ device->writeCount = kio.writes;
+ }
+
+ return NULL;
+}
diff --git a/src/detection/diskio/diskio_windows.c b/src/detection/diskio/diskio_windows.c
new file mode 100644
index 0000000..80ad94e
--- /dev/null
+++ b/src/detection/diskio/diskio_windows.c
@@ -0,0 +1,101 @@
+#include "diskio.h"
+#include "common/io.h"
+#include "common/windows/unicode.h"
+
+#include <windows.h>
+#include <winioctl.h>
+
+static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFDiskIOOptions* 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;
+ }
+
+ DWORD retSize;
+ char sddBuffer[4096];
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &(STORAGE_PROPERTY_QUERY) {
+ .PropertyId = StorageDeviceProperty,
+ .QueryType = PropertyStandardQuery,
+ },
+ sizeof(STORAGE_PROPERTY_QUERY),
+ &sddBuffer,
+ ARRAY_SIZE(sddBuffer),
+ &retSize,
+ NULL) ||
+ retSize == 0) {
+ return true;
+ }
+
+ FFDiskIOResult* device = FF_LIST_ADD(FFDiskIOResult, *result);
+ STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
+
+ ffStrbufInit(&device->name);
+ 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, ' ');
+ }
+
+ ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
+ ffStrbufTrimRight(&device->name, ' ');
+ }
+
+ if (!device->name.length) {
+ ffStrbufSetWS(&device->name, szDevice);
+ }
+
+ if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix)) {
+ ffStrbufDestroy(&device->name);
+ result->length--;
+ return true;
+ }
+
+ DISK_PERFORMANCE dp = {};
+ if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &dp, sizeof(dp), &retSize, NULL)) {
+ device->bytesRead = (uint64_t) dp.BytesRead.QuadPart;
+ device->readCount = (uint64_t) dp.ReadCount;
+ device->bytesWritten = (uint64_t) dp.BytesWritten.QuadPart;
+ device->writeCount = (uint64_t) dp.WriteCount;
+ } else {
+ ffStrbufDestroy(&device->name);
+ result->length--;
+ }
+
+ ffStrbufInitWS(&device->devPath, szDevice);
+
+ return true;
+}
+
+const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* 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;
+ }
+ }
+ }
+
+ return NULL;
+}