[SDK][FMIFS] Partially implement QueryDeviceInformation

On Windows, QueryDeviceInformation leverages the ifsutil.dll's API.
This is a standalone implementation that mimics Vista behaviour.
This commit is contained in:
Adam Słaboń 2024-03-02 23:48:33 +01:00 committed by Hermès BÉLUSCA - MAÏTO
parent 8de4d4d2ea
commit 4838d7bd56
3 changed files with 178 additions and 5 deletions

View file

@ -8,7 +8,7 @@
@ stdcall FormatEx(wstr ptr wstr wstr long long ptr) @ stdcall FormatEx(wstr ptr wstr wstr long long ptr)
@ stub FormatEx2 @ stub FormatEx2
@ stdcall QueryAvailableFileSystemFormat(long wstr str str ptr) @ stdcall QueryAvailableFileSystemFormat(long wstr str str ptr)
@ stub QueryDeviceInformation @ stdcall QueryDeviceInformation(wstr ptr long)
@ stub QueryDeviceInformationByHandle @ stub QueryDeviceInformationByHandle
@ stub QueryFileSystemName @ stub QueryFileSystemName
@ stub QueryLatestFileSystemVersion @ stub QueryLatestFileSystemVersion

View file

@ -8,6 +8,12 @@
*/ */
#include "precomp.h" #include "precomp.h"
#include <ntddstor.h>
#include <ntstrsafe.h>
#define NTOS_MODE_USER
#include <ndk/iofuncs.h>
#include <ndk/obfuncs.h>
BOOLEAN BOOLEAN
NTAPI NTAPI
@ -43,3 +49,155 @@ QueryAvailableFileSystemFormat(
return TRUE; return TRUE;
} }
/**
* @brief
* Retrieves disk device information.
*
* @param[in] DriveRoot
* String which contains a DOS device name,
*
* @param[in,out] DeviceInformation
* Pointer to buffer with DEVICE_INFORMATION structure which will receive data.
*
* @param[in] BufferSize
* Size of buffer in bytes.
*
* @return
* TRUE if the buffer was large enough and was filled with
* the requested information, FALSE otherwise.
*
* @remarks
* The returned information is mostly related to Sony Memory Stick devices.
* On Vista+ the returned information is disk sector size and volume length in sectors,
* regardless of the type of disk.
* ReactOS implementation returns DEVICE_HOTPLUG flag if inspected device is a hotplug device
* as well as sector size and volume length of disk device.
*/
BOOL
NTAPI
QueryDeviceInformation(
_In_ PWCHAR DriveRoot,
_Out_ PVOID DeviceInformation,
_In_ ULONG BufferSize)
{
PDEVICE_INFORMATION DeviceInfo = DeviceInformation;
IO_STATUS_BLOCK Iosb;
DISK_GEOMETRY DiskGeometry;
STORAGE_HOTPLUG_INFO HotplugInfo;
GET_LENGTH_INFORMATION LengthInformation;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING DeviceName;
HANDLE FileHandle;
NTSTATUS Status;
WCHAR DiskDevice[MAX_PATH];
WCHAR DriveName[MAX_PATH];
/* Buffer should be able to at least hold DeviceFlags */
if (BufferSize < sizeof(ULONG) ||
!NT_SUCCESS(RtlStringCchCopyW(DriveName, ARRAYSIZE(DriveName), DriveRoot)))
{
return FALSE;
}
if (DriveName[wcslen(DriveName) - 1] != L'\\')
{
/* Append the trailing backslash for GetVolumeNameForVolumeMountPointW */
if (!NT_SUCCESS(RtlStringCchCatW(DriveName, ARRAYSIZE(DriveName), L"\\")))
return FALSE;
}
if (!GetVolumeNameForVolumeMountPointW(DriveName, DiskDevice, ARRAYSIZE(DiskDevice)) ||
!RtlDosPathNameToNtPathName_U(DiskDevice, &DeviceName, NULL, NULL))
{
/* Disk has no volume GUID, fallback to QueryDosDevice */
DriveName[wcslen(DriveName) - 1] = UNICODE_NULL;
if (!QueryDosDeviceW(DriveName, DiskDevice, ARRAYSIZE(DiskDevice)))
return FALSE;
RtlInitUnicodeString(&DeviceName, DiskDevice);
}
else
{
/* Trim the trailing backslash since we will work with a device object */
DeviceName.Length -= sizeof(WCHAR);
}
InitializeObjectAttributes(&ObjectAttributes,
&DeviceName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&FileHandle,
FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&Iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
return FALSE;
Status = NtDeviceIoControlFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
IOCTL_STORAGE_GET_HOTPLUG_INFO,
NULL,
0,
&HotplugInfo,
sizeof(HotplugInfo));
if (!NT_SUCCESS(Status))
goto Quit;
DeviceInfo->DeviceFlags = 0;
if (HotplugInfo.MediaHotplug || HotplugInfo.DeviceHotplug)
{
/* This is a hotplug device */
DeviceInfo->DeviceFlags |= DEVICE_HOTPLUG;
}
/* Other flags that would be set here are related to Sony "Memory Stick"
* type of devices which we do not have any special support for */
if (BufferSize >= sizeof(DEVICE_INFORMATION))
{
/* This is the Vista+ version of the structure.
* We need to also provide disk sector size and volume length in sectors. */
Status = NtDeviceIoControlFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&DiskGeometry,
sizeof(DiskGeometry));
if (!NT_SUCCESS(Status))
goto Quit;
Status = NtDeviceIoControlFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
IOCTL_DISK_GET_LENGTH_INFO,
NULL,
0,
&LengthInformation,
sizeof(LengthInformation));
if (!NT_SUCCESS(Status))
goto Quit;
LengthInformation.Length.QuadPart /= DiskGeometry.BytesPerSector;
DeviceInfo->SectorSize = DiskGeometry.BytesPerSector;
DeviceInfo->SectorCount = LengthInformation.Length;
}
Status = STATUS_SUCCESS;
Quit:
NtClose(FileHandle);
return NT_SUCCESS(Status);
}

View file

@ -33,6 +33,20 @@ typedef struct
PCHAR Output; PCHAR Output;
} TEXTOUTPUT, *PTEXTOUTPUT; } TEXTOUTPUT, *PTEXTOUTPUT;
/* Device information */
typedef struct _DEVICE_INFORMATION
{
ULONG DeviceFlags;
ULONG SectorSize;
LARGE_INTEGER SectorCount;
} DEVICE_INFORMATION, *PDEVICE_INFORMATION;
/* Device information flags */
#define MEMORYSTICK_FORMAT_CAPABLE 0x10
#define MEMORYSTICK_SUPPORTS_PROGRESS_BAR 0x20
#define DEVICE_HOTPLUG 0x40
#define DEVICE_MEMORYSTICK 0x41
/* media flags */ /* media flags */
typedef enum typedef enum
{ {
@ -163,11 +177,12 @@ QueryAvailableFileSystemFormat(
OUT UCHAR* Minor, OUT UCHAR* Minor,
OUT BOOLEAN* LatestVersion); OUT BOOLEAN* LatestVersion);
BOOL NTAPI BOOL
NTAPI
QueryDeviceInformation( QueryDeviceInformation(
IN PWCHAR DriveRoot, _In_ PWCHAR DriveRoot,
OUT ULONG* Buffer, /* That is probably some 4-bytes structure */ _Out_ PVOID DeviceInformation,
IN ULONG BufferSize); /* 4 */ _In_ ULONG BufferSize);
BOOL NTAPI BOOL NTAPI
QueryFileSystemName( QueryFileSystemName(