summaryrefslogtreecommitdiffstats
path: root/src/detection/disk/disk_windows.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/detection/disk/disk_windows.c')
-rw-r--r--src/detection/disk/disk_windows.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/detection/disk/disk_windows.c b/src/detection/disk/disk_windows.c
new file mode 100644
index 0000000..0b3c93d
--- /dev/null
+++ b/src/detection/disk/disk_windows.c
@@ -0,0 +1,128 @@
+#include "disk.h"
+#include "common/io.h"
+#include "common/time.h"
+#include "common/windows/unicode.h"
+#include "common/windows/nt.h"
+
+#include <windows.h>
+#include <winioctl.h>
+#include <ntstatus.h>
+#include <stdalign.h>
+
+const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
+ PROCESS_DEVICEMAP_INFORMATION_EX info = {};
+ ULONG size = 0;
+ if (!NT_SUCCESS(NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap, &info, sizeof(info), &size))) {
+ return "NtQueryInformationProcess(ProcessDeviceMap) failed";
+ }
+
+ // For cross-platform portability; used by `presets/examples/13.jsonc`
+ if (options->folders.length == 1 && options->folders.chars[0] == '/') {
+ options->folders.chars[0] = (char) SharedUserData->NtSystemRoot[0];
+ ffStrbufAppendS(&options->folders, ":\\");
+ }
+
+ wchar_t mountpointW[] = L"X:\\";
+ char mountpointA[] = "X:\\";
+
+ for (wchar_t i = L'A'; i <= L'Z'; i++) {
+ if (!(info.Query.DriveMap & (1 << (i - L'A')))) {
+ continue;
+ }
+ mountpointW[0] = i;
+ mountpointA[0] = (char) i;
+
+ UINT driveType = info.Query.DriveType[i - L'A'];
+
+ if (__builtin_expect((long) options->folders.length, 0)) {
+ if (!ffStrbufSeparatedContainNS(&options->folders, 3, mountpointA, FF_DISK_FOLDER_SEPARATOR)) {
+ continue;
+ }
+ } else if (driveType == DRIVE_NO_ROOT_DIR) {
+ continue;
+ }
+
+ if (options->hideFolders.length && ffStrbufSeparatedContainNS(&options->hideFolders, 3, mountpointA, FF_DISK_FOLDER_SEPARATOR)) {
+ continue;
+ }
+
+ FF_AUTO_CLOSE_FD HANDLE handle = CreateFileW(mountpointW, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ continue;
+ }
+
+ IO_STATUS_BLOCK iosb;
+
+ alignas(FILE_FS_ATTRIBUTE_INFORMATION) uint8_t bufFsAttr[1024];
+ FILE_FS_ATTRIBUTE_INFORMATION* fsAttr = NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, bufFsAttr, sizeof(bufFsAttr), FileFsAttributeInformation))
+ ? (FILE_FS_ATTRIBUTE_INFORMATION*) bufFsAttr
+ : NULL;
+
+ FF_STRBUF_AUTO_DESTROY diskFileSystemBuf = ffStrbufCreate();
+ if (fsAttr) {
+ ffStrbufSetNWS(&diskFileSystemBuf, fsAttr->FileSystemNameLength / sizeof(WCHAR), fsAttr->FileSystemName);
+ if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &diskFileSystemBuf, ':')) {
+ continue;
+ }
+ }
+
+ FFDisk* disk = FF_LIST_ADD(FFDisk, *disks);
+
+ disk->filesUsed = 0;
+ disk->filesTotal = 0;
+ disk->bytesTotal = 0;
+ disk->bytesFree = 0;
+ disk->bytesUsed = 0; // To be filled in ./disk.c
+ disk->bytesAvailable = 0;
+ disk->createTime = 0;
+ ffStrbufInit(&disk->filesystem);
+ ffStrbufInit(&disk->name);
+ ffStrbufInitNS(&disk->mountpoint, 3, mountpointA);
+ ffStrbufInit(&disk->mountFrom);
+ disk->type = driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM
+ ? FF_DISK_VOLUME_TYPE_EXTERNAL_BIT
+ : driveType == DRIVE_FIXED
+ ? FF_DISK_VOLUME_TYPE_REGULAR_BIT
+ : FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
+
+ {
+ wchar_t volumeName[MAX_PATH + 1];
+ mountpointW[2] = L'\0';
+ if (QueryDosDeviceW(mountpointW, volumeName, ARRAY_SIZE(volumeName))) {
+ ffStrbufSetWS(&disk->mountFrom, volumeName);
+ }
+ mountpointW[2] = L'\\';
+ }
+
+ alignas(FILE_FS_VOLUME_INFORMATION) uint8_t bufFsVolume[1024];
+ FILE_FS_VOLUME_INFORMATION* fsVolume = NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, bufFsVolume, sizeof(bufFsVolume), FileFsVolumeInformation))
+ ? (FILE_FS_VOLUME_INFORMATION*) bufFsVolume
+ : NULL;
+
+ if (fsVolume) {
+ if (fsVolume->VolumeLabelLength > 0) {
+ ffStrbufSetNWS(&disk->name, fsVolume->VolumeLabelLength / sizeof(WCHAR), fsVolume->VolumeLabel);
+ }
+ if (fsVolume->VolumeCreationTime.QuadPart) {
+ disk->createTime = ffFileTimeToUnixMs((uint64_t) fsVolume->VolumeCreationTime.QuadPart);
+ }
+ }
+
+ if (fsAttr) {
+ ffStrbufInitMove(&disk->filesystem, &diskFileSystemBuf);
+ if (fsAttr->FileSystemAttributes & FILE_READ_ONLY_VOLUME) {
+ disk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
+ }
+ }
+
+ FILE_FS_FULL_SIZE_INFORMATION fsFullSize;
+ if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSize, sizeof(fsFullSize), FileFsFullSizeInformation))) {
+ uint64_t units = fsFullSize.BytesPerSector * fsFullSize.SectorsPerAllocationUnit;
+ disk->bytesTotal = (uint64_t) fsFullSize.TotalAllocationUnits.QuadPart * units;
+ disk->bytesFree = (uint64_t) fsFullSize.ActualAvailableAllocationUnits.QuadPart * units;
+ disk->bytesAvailable = (uint64_t) fsFullSize.CallerAvailableAllocationUnits.QuadPart * units;
+ }
+ }
+
+ return NULL;
+}