master ohmu/fastfetch-openbsd / src / detection / disk / disk_windows.c
ohmu  ·  2026-10-15
  1#include "disk.h"
  2#include "common/debug.h"
  3#include "common/io.h"
  4#include "common/time.h"
  5#include "common/windows/unicode.h"
  6#include "common/windows/nt.h"
  7
  8#include <windows.h>
  9#include <winioctl.h>
 10#include <ntstatus.h>
 11#include <stdalign.h>
 12
 13const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
 14    PROCESS_DEVICEMAP_INFORMATION_EX info = {};
 15    ULONG size = 0;
 16    NTSTATUS status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap, &info, sizeof(info), &size);
 17    if (!NT_SUCCESS(status)) {
 18        FF_DEBUG("NtQueryInformationProcess(ProcessDeviceMap) failed: %s", ffDebugNtStatus(status));
 19        return "NtQueryInformationProcess(ProcessDeviceMap) failed";
 20    }
 21
 22    // For cross-platform portability; used by `presets/examples/13.jsonc`
 23    if (options->folders.length == 1 && options->folders.chars[0] == '/') {
 24        options->folders.chars[0] = (char) SharedUserData->NtSystemRoot[0];
 25        ffStrbufAppendS(&options->folders, ":\\");
 26    }
 27
 28    wchar_t mountpointW[] = L"X:\\";
 29    char mountpointA[] = "X:\\";
 30
 31    for (wchar_t i = L'A'; i <= L'Z'; i++) {
 32        if (!(info.Query.DriveMap & (1 << (i - L'A')))) {
 33            continue;
 34        }
 35        mountpointW[0] = i;
 36        mountpointA[0] = (char) i;
 37
 38        UINT driveType = info.Query.DriveType[i - L'A'];
 39
 40        if (__builtin_expect((long) options->folders.length, 0)) {
 41            if (!ffStrbufSeparatedContainNS(&options->folders, 3, mountpointA, FF_DISK_FOLDER_SEPARATOR)) {
 42                continue;
 43            }
 44        } else if (driveType == DRIVE_NO_ROOT_DIR) {
 45            continue;
 46        }
 47
 48        if (options->hideFolders.length && ffStrbufSeparatedContainNS(&options->hideFolders, 3, mountpointA, FF_DISK_FOLDER_SEPARATOR)) {
 49            continue;
 50        }
 51
 52        FF_AUTO_CLOSE_FD HANDLE handle = CreateFileW(mountpointW, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
 53        if (handle == INVALID_HANDLE_VALUE) {
 54            continue;
 55        }
 56
 57        IO_STATUS_BLOCK iosb;
 58
 59        alignas(FILE_FS_ATTRIBUTE_INFORMATION) uint8_t bufFsAttr[1024];
 60        FILE_FS_ATTRIBUTE_INFORMATION* fsAttr = NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, bufFsAttr, sizeof(bufFsAttr), FileFsAttributeInformation))
 61            ? (FILE_FS_ATTRIBUTE_INFORMATION*) bufFsAttr
 62            : nullptr;
 63
 64        FF_STRBUF_AUTO_DESTROY diskFileSystemBuf = ffStrbufCreate();
 65        if (fsAttr) {
 66            ffStrbufSetNWS(&diskFileSystemBuf, fsAttr->FileSystemNameLength / sizeof(WCHAR), fsAttr->FileSystemName);
 67            if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &diskFileSystemBuf, ':')) {
 68                continue;
 69            }
 70        }
 71
 72        FFDisk* disk = FF_LIST_ADD(FFDisk, *disks);
 73
 74        disk->filesUsed = 0;
 75        disk->filesTotal = 0;
 76        disk->bytesTotal = 0;
 77        disk->bytesFree = 0;
 78        disk->createTime = 0;
 79        ffStrbufInit(&disk->filesystem);
 80        ffStrbufInit(&disk->name);
 81        ffStrbufInitNS(&disk->mountpoint, 3, mountpointA);
 82        ffStrbufInit(&disk->mountFrom);
 83        disk->type = driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM
 84            ? FF_DISK_VOLUME_TYPE_EXTERNAL_BIT
 85            : driveType == DRIVE_FIXED
 86            ? FF_DISK_VOLUME_TYPE_REGULAR_BIT
 87            : FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
 88
 89        {
 90            wchar_t volumeName[MAX_PATH + 1];
 91            mountpointW[2] = L'\0';
 92            if (QueryDosDeviceW(mountpointW, volumeName, ARRAY_SIZE(volumeName))) {
 93                ffStrbufSetWS(&disk->mountFrom, volumeName);
 94            }
 95            mountpointW[2] = L'\\';
 96        }
 97
 98        alignas(FILE_FS_VOLUME_INFORMATION) uint8_t bufFsVolume[1024];
 99        FILE_FS_VOLUME_INFORMATION* fsVolume = NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, bufFsVolume, sizeof(bufFsVolume), FileFsVolumeInformation))
100            ? (FILE_FS_VOLUME_INFORMATION*) bufFsVolume
101            : nullptr;
102
103        if (fsVolume) {
104            if (fsVolume->VolumeLabelLength > 0) {
105                ffStrbufSetNWS(&disk->name, fsVolume->VolumeLabelLength / sizeof(WCHAR), fsVolume->VolumeLabel);
106            }
107            if (fsVolume->VolumeCreationTime.QuadPart) {
108                disk->createTime = ffFileTimeToUnixMs((uint64_t) fsVolume->VolumeCreationTime.QuadPart);
109            }
110        }
111
112        if (fsAttr) {
113            ffStrbufInitMove(&disk->filesystem, &diskFileSystemBuf);
114            if (fsAttr->FileSystemAttributes & FILE_READ_ONLY_VOLUME) {
115                disk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
116            }
117        }
118
119        if (options->calcType == FF_DISK_CALC_TYPE_AVAILABLE || !ffIsFileFsFullSizeInformationExAvailable()) {
120            FILE_FS_FULL_SIZE_INFORMATION fsFullSize;
121            if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSize, sizeof(fsFullSize), FileFsFullSizeInformation))) {
122                uint64_t units = fsFullSize.BytesPerSector * fsFullSize.SectorsPerAllocationUnit;
123                disk->bytesTotal = (uint64_t) fsFullSize.TotalAllocationUnits.QuadPart * units;
124                disk->bytesFree = (uint64_t) fsFullSize.CallerAvailableAllocationUnits.QuadPart * units;
125            }
126        } else {
127            FILE_FS_FULL_SIZE_INFORMATION_EX fsFullSizeEx;
128            if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSizeEx, sizeof(fsFullSizeEx), FileFsFullSizeInformationEx))) {
129                // Space info without considering the quota setting
130                uint64_t units = fsFullSizeEx.BytesPerSector * fsFullSizeEx.SectorsPerAllocationUnit;
131                disk->bytesTotal = (uint64_t) fsFullSizeEx.ActualTotalAllocationUnits * units;
132                disk->bytesFree = (uint64_t) fsFullSizeEx.ActualAvailableAllocationUnits * units;
133            }
134        }
135    }
136
137    return nullptr;
138}