ReactOS 0.4.16-dev-747-gbc52d5f
StorDeviceNumber.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Test for IOCTL_STORAGE_GET_DEVICE_NUMBER
5 * COPYRIGHT: Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
6 */
7
8#include "precomp.h"
9#include <ntddstor.h>
10
12{
13 if (!us) return "(null)";
14 return wine_dbgstr_wn(us->Buffer, us->Length / sizeof(WCHAR));
15}
16
17/* Flags combination allowing all the read, write and delete share modes.
18 * Currently similar to FILE_SHARE_VALID_FLAGS. */
19#define FILE_SHARE_ALL \
20 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
21
22static BOOLEAN
24 _In_ PCWSTR NtDeviceName)
25{
26 BOOLEAN Success = FALSE; // Suppose failure.
28 HANDLE DeviceHandle1 = NULL, DeviceHandle2 = NULL;
34 WCHAR NtLegacyDeviceName[MAX_PATH];
35
37 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } DeviceName1Buffer;
38 PUNICODE_STRING DeviceName1 = &DeviceName1Buffer.Name;
39 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } DeviceName2Buffer;
40 PUNICODE_STRING DeviceName2 = &DeviceName2Buffer.Name;
41
42 /* Open a handle to the device */
43 RtlInitUnicodeString(&DeviceName, NtDeviceName);
47 NULL,
48 NULL);
49 Status = NtOpenFile(&DeviceHandle1,
54 /* FILE_NON_DIRECTORY_FILE | */ FILE_SYNCHRONOUS_IO_NONALERT);
56 if (!NT_SUCCESS(Status))
57 {
58 skip("Device '%s': Opening failed\n", wine_dbgstr_us(&DeviceName));
59 goto Quit;
60 }
61
62 /* Verify the device information before proceeding further */
66 sizeof(DeviceInfo),
69 if (!NT_SUCCESS(Status))
70 {
71 skip("FileFsDeviceInformation('%s') failed, Status 0x%08lx\n",
73 goto Quit;
74 }
75
76 /* Ignore volumes that are NOT on usual disks */
77 switch (DeviceInfo.DeviceType)
78 {
79 /* Testable devices */
81 // case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
83 // case FILE_DEVICE_DISK_FILE_SYSTEM:
84 // case FILE_DEVICE_NETWORK:
85 // case FILE_DEVICE_NETWORK_FILE_SYSTEM:
87 break;
88
89 /* Untestable devices */
90 default:
91 skip("Device '%s': Cannot test, device type %lu\n",
93 goto Quit;
94 }
95#if 0
96 if (DeviceInfo.DeviceType != FILE_DEVICE_DISK &&
98 DeviceInfo.DeviceType != FILE_DEVICE_CD_ROM)
99 {
100 skip("Device '%s': Cannot test, device type %lu\n",
101 wine_dbgstr_us(&DeviceName), DeviceInfo.DeviceType);
102 goto Quit;
103 }
104#endif
105
106 /*
107 * Retrieve the storage device number.
108 * Note that this call is unsupported if this is a dynamic volume.
109 * NOTE: Usually fails for floppy disks.
110 */
111 Status = NtDeviceIoControlFile(DeviceHandle1,
112 NULL, NULL, NULL,
115 NULL, 0,
116 &DeviceNumber, sizeof(DeviceNumber));
117 if (!NT_SUCCESS(Status))
118 {
119 skip("Device '%s': Couldn't retrieve disk number\n", wine_dbgstr_us(&DeviceName));
120 goto Quit;
121 }
122 ok(DeviceNumber.DeviceType == DeviceInfo.DeviceType,
123 "Device '%s': Device type mismatch\n", wine_dbgstr_us(&DeviceName));
124
125 /* NOTE: this value is set to 0xFFFFFFFF (-1) for the disks that
126 * represent the physical paths of a multipath I/O (MPIO) disk. */
127 ok(DeviceNumber.DeviceNumber != ULONG_MAX,
128 "Device '%s': Invalid disk number reported\n", wine_dbgstr_us(&DeviceName));
129 if (DeviceNumber.DeviceNumber == ULONG_MAX)
130 goto Quit;
131
132 switch (DeviceInfo.DeviceType)
133 {
134 /* Testable devices */
136 // case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
137 {
138 /* CD-ROMs don't have partitions, their partition number is -1 */
139 ok(DeviceNumber.PartitionNumber == ULONG_MAX,
140 "Device '%s': Invalid partition number (%lu) reported, expected ULONG_MAX (-1)\n",
141 wine_dbgstr_us(&DeviceName), DeviceNumber.PartitionNumber);
142
143 /* Map to an NT device name */
144 RtlStringCchPrintfW(NtLegacyDeviceName, _countof(NtLegacyDeviceName),
145 L"\\Device\\CdRom%lu",
146 DeviceNumber.DeviceNumber);
147 break;
148 }
149
150 case FILE_DEVICE_DISK:
151 // case FILE_DEVICE_DISK_FILE_SYSTEM:
153 {
154 /* Check whether this is a floppy or a partitionable device */
155 if (DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE)
156 {
157 /* Floppies don't have partitions, their partition number is -1 */
158 ok(DeviceNumber.PartitionNumber == ULONG_MAX,
159 "Device '%s': Invalid partition number (%lu) reported, expected ULONG_MAX (-1)\n",
160 wine_dbgstr_us(&DeviceName), DeviceNumber.PartitionNumber);
161
162 /* Map to an NT device name */
163 RtlStringCchPrintfW(NtLegacyDeviceName, _countof(NtLegacyDeviceName),
164 L"\\Device\\Floppy%lu",
165 DeviceNumber.DeviceNumber);
166 }
167 else
168 {
169 /* The device is partitionable, so it must have a valid partition number */
170 ok(DeviceNumber.PartitionNumber != ULONG_MAX,
171 "Device '%s': Invalid partition number (%lu) reported; unpartitionable device?\n",
172 wine_dbgstr_us(&DeviceName), DeviceNumber.PartitionNumber);
173 if (DeviceNumber.PartitionNumber == ULONG_MAX)
174 goto Quit;
175
176 /* Map to an NT device name */
177 RtlStringCchPrintfW(NtLegacyDeviceName, _countof(NtLegacyDeviceName),
178 L"\\Device\\Harddisk%lu\\Partition%lu",
179 DeviceNumber.DeviceNumber, DeviceNumber.PartitionNumber);
180 }
181 break;
182 }
183
184 /* Untestable devices */
185 default:
186 skip("Device '%s': Cannot test, device type %lu\n",
187 wine_dbgstr_us(&DeviceName), DeviceInfo.DeviceType);
188 goto Quit;
189 }
190
191 /* Open the device using the legacy path */
192 RtlInitUnicodeString(&DeviceName, NtLegacyDeviceName);
194 &DeviceName,
196 NULL,
197 NULL);
198 Status = NtOpenFile(&DeviceHandle2,
203 /* FILE_NON_DIRECTORY_FILE | */ FILE_SYNCHRONOUS_IO_NONALERT);
205 if (!NT_SUCCESS(Status))
206 {
207 skip("Device '%s': Opening failed\n", wine_dbgstr_us(&DeviceName));
208 goto Quit;
209 }
210
211 /*
212 * Verify whether both retrieved handles refer to the same device.
213 * Since we're not running on Windows 10, we cannot use kernel32!CompareObjectHandles()
214 * or ntdll!NtCompareObjects(), therefore we have to rely on comparing
215 * whether the devices referred by both handles have the same canonical name.
216 */
217 Status = NtQueryObject(DeviceHandle1,
219 &DeviceName1Buffer,
220 sizeof(DeviceName1Buffer),
221 &BufferSize);
223
224 Status = NtQueryObject(DeviceHandle2,
226 &DeviceName2Buffer,
227 sizeof(DeviceName2Buffer),
228 &BufferSize);
230
231 Success = RtlEqualUnicodeString(DeviceName1, DeviceName2, FALSE);
232 ok(Success, "Devices '%s' and '%s' are not the same!\n",
233 wine_dbgstr_us(DeviceName1), wine_dbgstr_us(DeviceName2));
234
235Quit:
236 /* Cleanup */
237 if (DeviceHandle2)
238 NtClose(DeviceHandle2);
239 if (DeviceHandle1)
240 NtClose(DeviceHandle1);
241
242 return Success;
243}
244
245static BOOLEAN
248{
249 WCHAR NtDeviceName[] = L"\\DosDevices\\?:";
250 NtDeviceName[sizeof("\\DosDevices\\")-1] = Drive;
251 return Test_Device_StorDeviceNumber(NtDeviceName);
252}
253
254START_TEST(StorDeviceNumber)
255{
256 DWORD Drives;
257 UCHAR i;
258
259 /* Enumerate existing testable drives */
260 Drives = GetLogicalDrives();
261 if (Drives == 0)
262 {
263 skip("Drives map unavailable, error 0x%lx\n", GetLastError());
264 goto otherTests;
265 }
266 for (i = 0; i <= 'Z'-'A'; ++i)
267 {
268 WCHAR DriveName[] = L"?:\\";
270
271 /* Skip non-existing drives */
272 if (!(Drives & (1 << i)))
273 continue;
274
275 /* Retrieve the drive type and see whether we can test it */
276 DriveName[0] = L'A' + i;
277 DriveType = GetDriveTypeW(DriveName);
278
279 switch (DriveType)
280 {
281 case DRIVE_REMOVABLE:
282 case DRIVE_FIXED:
283 case DRIVE_CDROM:
284 case DRIVE_RAMDISK:
285 {
287 break;
288 }
289
290 case DRIVE_UNKNOWN:
292 case DRIVE_REMOTE:
293 default:
294 /* Unhandled drive type, just skip it silently */
295 trace("Drive %c with unhandled type %u\n", 'A' + i, DriveType);
296 break;
297 }
298 }
299
300otherTests:
301 /* Test the drive containing SystemRoot */
303
304 /* Test \??\PhysicalDrive0, if it exists */
305 Test_Device_StorDeviceNumber(L"\\??\\PhysicalDrive0");
306}
UINT DriveType
@ ObjectNameInformation
Definition: DriverTester.h:55
NTSTATUS NtQueryObject(IN HANDLE Handle, IN OBJECT_INFO_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG ObjectInformationLength, OUT PULONG ReturnLength)
unsigned char BOOLEAN
#define FILE_SHARE_ALL
static BOOLEAN Test_Drive_StorDeviceNumber(_In_ WCHAR Drive)
static LPCSTR wine_dbgstr_us(const UNICODE_STRING *us)
static BOOLEAN Test_Device_StorDeviceNumber(_In_ PCWSTR NtDeviceName)
#define ok_ntstatus(status, expected)
Definition: atltest.h:135
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
PWCHAR Drive
Definition: chkdsk.c:73
Definition: bufpool.h:45
_In_ PCHAR _In_ ULONG DeviceNumber
Definition: classpnp.h:1230
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define BufferSize
Definition: mmc.h:75
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define MAX_PATH
Definition: compat.h:34
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
@ Success
Definition: eventcreate.c:712
unsigned long DWORD
Definition: ntddk_ex.h:95
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
@ FileFsDeviceInformation
Definition: from_kernel.h:222
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define ULONG_MAX
Definition: intsafe.h:155
#define DRIVE_CDROM
Definition: machpc98.h:119
static const BYTE us[]
Definition: encode.c:689
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
unsigned int UINT
Definition: ndis.h:50
#define _In_
Definition: no_sal2.h:158
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3953
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
struct _OBJECT_NAME_INFORMATION OBJECT_NAME_INFORMATION
NTSYSAPI NTSTATUS NTAPI NtDeviceIoControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define FILE_FLOPPY_DISKETTE
Definition: nt_native.h:809
#define IOCTL_STORAGE_GET_DEVICE_NUMBER
Definition: ntddstor.h:143
NTSTRSAFEVAPI RtlStringCchPrintfW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1110
#define L(x)
Definition: ntvdm.h:50
#define FILE_DEVICE_CD_ROM
Definition: winioctl.h:47
#define FILE_DEVICE_DISK
Definition: winioctl.h:52
#define FILE_DEVICE_VIRTUAL_DISK
Definition: winioctl.h:81
#define wine_dbgstr_wn
Definition: testlist.c:2
#define SharedUserData
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _countof(array)
Definition: sndvol32.h:70
const uint16_t * PCWSTR
Definition: typedefs.h:57
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
#define DRIVE_UNKNOWN
Definition: winbase.h:282
#define DRIVE_NO_ROOT_DIR
Definition: winbase.h:283
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define DRIVE_REMOTE
Definition: winbase.h:279
DWORD WINAPI GetLogicalDrives(void)
Definition: disk.c:110
#define DRIVE_RAMDISK
Definition: winbase.h:281
#define DRIVE_FIXED
Definition: winbase.h:278
#define DRIVE_REMOVABLE
Definition: winbase.h:277
const char * LPCSTR
Definition: xmlstorage.h:183
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180