1cc1deb29SHermès Bélusca-Maïto /*
2cc1deb29SHermès Bélusca-Maïto * PROJECT: ReactOS API Tests
3cc1deb29SHermès Bélusca-Maïto * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4cc1deb29SHermès Bélusca-Maïto * PURPOSE: Test for IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH(S)
5cc1deb29SHermès Bélusca-Maïto * COPYRIGHT: Copyright 2025 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
6cc1deb29SHermès Bélusca-Maïto */
7cc1deb29SHermès Bélusca-Maïto
8cc1deb29SHermès Bélusca-Maïto #include "precomp.h"
9cc1deb29SHermès Bélusca-Maïto
10cc1deb29SHermès Bélusca-Maïto
11cc1deb29SHermès Bélusca-Maïto /**
12cc1deb29SHermès Bélusca-Maïto * @brief
13cc1deb29SHermès Bélusca-Maïto * Invokes either IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH or
14cc1deb29SHermès Bélusca-Maïto * IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS for testing, given
15cc1deb29SHermès Bélusca-Maïto * the volume device name, and returns an allocated volume
16cc1deb29SHermès Bélusca-Maïto * paths buffer. This buffer must be freed by the caller via
17cc1deb29SHermès Bélusca-Maïto * RtlFreeHeap(RtlGetProcessHeap(), ...) .
18cc1deb29SHermès Bélusca-Maïto *
19cc1deb29SHermès Bélusca-Maïto * These IOCTLs return both the drive letter (if any) and the
20cc1deb29SHermès Bélusca-Maïto * volume GUID symlink path, as well as any other file-system
21cc1deb29SHermès Bélusca-Maïto * mount reparse points linking to the volume.
22cc1deb29SHermès Bélusca-Maïto **/
23cc1deb29SHermès Bélusca-Maïto static VOID
Call_QueryDosVolume_Path_Paths(_In_ HANDLE MountMgrHandle,_In_ PCWSTR NtVolumeName,_In_ ULONG IoctlPathOrPaths,_Out_ PMOUNTMGR_VOLUME_PATHS * pVolumePathPtr)24cc1deb29SHermès Bélusca-Maïto Call_QueryDosVolume_Path_Paths(
25cc1deb29SHermès Bélusca-Maïto _In_ HANDLE MountMgrHandle,
26cc1deb29SHermès Bélusca-Maïto _In_ PCWSTR NtVolumeName,
27cc1deb29SHermès Bélusca-Maïto _In_ ULONG IoctlPathOrPaths,
28cc1deb29SHermès Bélusca-Maïto _Out_ PMOUNTMGR_VOLUME_PATHS* pVolumePathPtr)
29cc1deb29SHermès Bélusca-Maïto {
30cc1deb29SHermès Bélusca-Maïto NTSTATUS Status;
31cc1deb29SHermès Bélusca-Maïto ULONG Length;
32cc1deb29SHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
33cc1deb29SHermès Bélusca-Maïto UNICODE_STRING VolumeName;
34cc1deb29SHermès Bélusca-Maïto MOUNTMGR_VOLUME_PATHS VolumePath;
35cc1deb29SHermès Bélusca-Maïto PMOUNTMGR_VOLUME_PATHS VolumePathPtr;
36cc1deb29SHermès Bélusca-Maïto ULONG DeviceNameLength;
37cc1deb29SHermès Bélusca-Maïto /*
38cc1deb29SHermès Bélusca-Maïto * This variable is used to query the device name.
39cc1deb29SHermès Bélusca-Maïto * It's based on MOUNTMGR_TARGET_NAME (mountmgr.h).
40cc1deb29SHermès Bélusca-Maïto * Doing it this way prevents memory allocation.
41cc1deb29SHermès Bélusca-Maïto * The device name won't be longer.
42cc1deb29SHermès Bélusca-Maïto */
43cc1deb29SHermès Bélusca-Maïto struct
44cc1deb29SHermès Bélusca-Maïto {
45cc1deb29SHermès Bélusca-Maïto USHORT NameLength;
46cc1deb29SHermès Bélusca-Maïto WCHAR DeviceName[256];
47cc1deb29SHermès Bélusca-Maïto } DeviceName;
48cc1deb29SHermès Bélusca-Maïto
49cc1deb29SHermès Bélusca-Maïto
50cc1deb29SHermès Bélusca-Maïto *pVolumePathPtr = NULL;
51cc1deb29SHermès Bélusca-Maïto
52cc1deb29SHermès Bélusca-Maïto /* First, build the corresponding device name */
53cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&VolumeName, NtVolumeName);
54cc1deb29SHermès Bélusca-Maïto DeviceName.NameLength = VolumeName.Length;
55cc1deb29SHermès Bélusca-Maïto RtlCopyMemory(&DeviceName.DeviceName, VolumeName.Buffer, VolumeName.Length);
56cc1deb29SHermès Bélusca-Maïto DeviceNameLength = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + DeviceName.NameLength;
57cc1deb29SHermès Bélusca-Maïto
58cc1deb29SHermès Bélusca-Maïto /* Now, query the MountMgr for the DOS path(s) */
59cc1deb29SHermès Bélusca-Maïto Status = NtDeviceIoControlFile(MountMgrHandle,
60cc1deb29SHermès Bélusca-Maïto NULL, NULL, NULL,
61cc1deb29SHermès Bélusca-Maïto &IoStatusBlock,
62cc1deb29SHermès Bélusca-Maïto IoctlPathOrPaths,
63cc1deb29SHermès Bélusca-Maïto &DeviceName, DeviceNameLength,
64cc1deb29SHermès Bélusca-Maïto &VolumePath, sizeof(VolumePath));
65cc1deb29SHermès Bélusca-Maïto
66cc1deb29SHermès Bélusca-Maïto /* Check for unsupported device */
67cc1deb29SHermès Bélusca-Maïto if (Status == STATUS_NO_MEDIA_IN_DEVICE || Status == STATUS_INVALID_DEVICE_REQUEST)
68cc1deb29SHermès Bélusca-Maïto {
69cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Doesn't support MountMgr queries, Status 0x%08lx\n",
70cc1deb29SHermès Bélusca-Maïto NtVolumeName, Status);
71cc1deb29SHermès Bélusca-Maïto return;
72cc1deb29SHermès Bélusca-Maïto }
73cc1deb29SHermès Bélusca-Maïto
74cc1deb29SHermès Bélusca-Maïto /* The only tolerated failure here is buffer too small, which is expected */
75cc1deb29SHermès Bélusca-Maïto ok(NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW),
76cc1deb29SHermès Bélusca-Maïto "Device '%S': IOCTL 0x%lx failed unexpectedly, Status 0x%08lx\n",
77cc1deb29SHermès Bélusca-Maïto NtVolumeName, IoctlPathOrPaths, Status);
78cc1deb29SHermès Bélusca-Maïto if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW))
79cc1deb29SHermès Bélusca-Maïto {
80cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Wrong Status\n", NtVolumeName);
81cc1deb29SHermès Bélusca-Maïto return;
82cc1deb29SHermès Bélusca-Maïto }
83cc1deb29SHermès Bélusca-Maïto
84cc1deb29SHermès Bélusca-Maïto /* Compute the needed size to store the DOS path(s).
85cc1deb29SHermès Bélusca-Maïto * Even if MOUNTMGR_VOLUME_PATHS allows bigger name lengths
86cc1deb29SHermès Bélusca-Maïto * than MAXUSHORT, we can't use them, because we have to return
87cc1deb29SHermès Bélusca-Maïto * this in an UNICODE_STRING that stores length in a USHORT. */
88cc1deb29SHermès Bélusca-Maïto Length = sizeof(VolumePath) + VolumePath.MultiSzLength;
89cc1deb29SHermès Bélusca-Maïto ok(Length <= MAXUSHORT,
90cc1deb29SHermès Bélusca-Maïto "Device '%S': DOS volume path too large: %lu\n",
91cc1deb29SHermès Bélusca-Maïto NtVolumeName, Length);
92cc1deb29SHermès Bélusca-Maïto if (Length > MAXUSHORT)
93cc1deb29SHermès Bélusca-Maïto {
94cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Wrong Length\n", NtVolumeName);
95cc1deb29SHermès Bélusca-Maïto return;
96cc1deb29SHermès Bélusca-Maïto }
97cc1deb29SHermès Bélusca-Maïto
98cc1deb29SHermès Bélusca-Maïto /* Allocate the buffer and fill it with test pattern */
99cc1deb29SHermès Bélusca-Maïto VolumePathPtr = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
100cc1deb29SHermès Bélusca-Maïto if (!VolumePathPtr)
101cc1deb29SHermès Bélusca-Maïto {
102cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Failed to allocate buffer with size %lu)\n",
103cc1deb29SHermès Bélusca-Maïto NtVolumeName, Length);
104cc1deb29SHermès Bélusca-Maïto return;
105cc1deb29SHermès Bélusca-Maïto }
106cc1deb29SHermès Bélusca-Maïto RtlFillMemory(VolumePathPtr, Length, 0xCC);
107cc1deb29SHermès Bélusca-Maïto
108cc1deb29SHermès Bélusca-Maïto /* Re-query the DOS path(s) with the proper size */
109cc1deb29SHermès Bélusca-Maïto Status = NtDeviceIoControlFile(MountMgrHandle,
110cc1deb29SHermès Bélusca-Maïto NULL, NULL, NULL,
111cc1deb29SHermès Bélusca-Maïto &IoStatusBlock,
112cc1deb29SHermès Bélusca-Maïto IoctlPathOrPaths,
113cc1deb29SHermès Bélusca-Maïto &DeviceName, DeviceNameLength,
114cc1deb29SHermès Bélusca-Maïto VolumePathPtr, Length);
115cc1deb29SHermès Bélusca-Maïto ok(NT_SUCCESS(Status),
116cc1deb29SHermès Bélusca-Maïto "Device '%S': IOCTL 0x%lx failed unexpectedly, Status 0x%08lx\n",
117cc1deb29SHermès Bélusca-Maïto NtVolumeName, IoctlPathOrPaths, Status);
118cc1deb29SHermès Bélusca-Maïto
119cc1deb29SHermès Bélusca-Maïto if (winetest_debug > 1)
120cc1deb29SHermès Bélusca-Maïto {
121cc1deb29SHermès Bélusca-Maïto trace("Buffer:\n");
122cc1deb29SHermès Bélusca-Maïto DumpBuffer(VolumePathPtr, Length);
123cc1deb29SHermès Bélusca-Maïto printf("\n");
124cc1deb29SHermès Bélusca-Maïto }
125cc1deb29SHermès Bélusca-Maïto
126cc1deb29SHermès Bélusca-Maïto /* Return the buffer */
127cc1deb29SHermès Bélusca-Maïto *pVolumePathPtr = VolumePathPtr;
128cc1deb29SHermès Bélusca-Maïto }
129cc1deb29SHermès Bélusca-Maïto
130cc1deb29SHermès Bélusca-Maïto /**
131cc1deb29SHermès Bélusca-Maïto * @brief
132cc1deb29SHermès Bélusca-Maïto * Invokes IOCTL_MOUNTMGR_QUERY_POINTS for testing, given
133cc1deb29SHermès Bélusca-Maïto * the volume device name, and returns an allocated mount
134cc1deb29SHermès Bélusca-Maïto * points buffer. This buffer must be freed by the caller
135cc1deb29SHermès Bélusca-Maïto * via RtlFreeHeap(RtlGetProcessHeap(), ...) .
136cc1deb29SHermès Bélusca-Maïto *
137cc1deb29SHermès Bélusca-Maïto * This IOCTL only returns both the drive letter (if any)
138cc1deb29SHermès Bélusca-Maïto * and the volume GUID symlink path, but does NOT return
139cc1deb29SHermès Bélusca-Maïto * file-system mount reparse points.
140cc1deb29SHermès Bélusca-Maïto **/
141cc1deb29SHermès Bélusca-Maïto static VOID
Call_QueryPoints(_In_ HANDLE MountMgrHandle,_In_ PCWSTR NtVolumeName,_Out_ PMOUNTMGR_MOUNT_POINTS * pMountPointsPtr)142cc1deb29SHermès Bélusca-Maïto Call_QueryPoints(
143cc1deb29SHermès Bélusca-Maïto _In_ HANDLE MountMgrHandle,
144cc1deb29SHermès Bélusca-Maïto _In_ PCWSTR NtVolumeName,
145cc1deb29SHermès Bélusca-Maïto _Out_ PMOUNTMGR_MOUNT_POINTS* pMountPointsPtr)
146cc1deb29SHermès Bélusca-Maïto {
147cc1deb29SHermès Bélusca-Maïto NTSTATUS Status;
148cc1deb29SHermès Bélusca-Maïto ULONG Length;
149cc1deb29SHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
150cc1deb29SHermès Bélusca-Maïto UNICODE_STRING VolumeName;
151cc1deb29SHermès Bélusca-Maïto MOUNTMGR_MOUNT_POINTS MountPoints;
152cc1deb29SHermès Bélusca-Maïto PMOUNTMGR_MOUNT_POINTS MountPointsPtr;
153cc1deb29SHermès Bélusca-Maïto /*
154cc1deb29SHermès Bélusca-Maïto * This variable is used to query the device name.
155cc1deb29SHermès Bélusca-Maïto * It's based on MOUNTMGR_MOUNT_POINT (mountmgr.h).
156cc1deb29SHermès Bélusca-Maïto * Doing it this way prevents memory allocation.
157cc1deb29SHermès Bélusca-Maïto * The device name won't be longer.
158cc1deb29SHermès Bélusca-Maïto */
159cc1deb29SHermès Bélusca-Maïto struct
160cc1deb29SHermès Bélusca-Maïto {
161cc1deb29SHermès Bélusca-Maïto MOUNTMGR_MOUNT_POINT;
162cc1deb29SHermès Bélusca-Maïto WCHAR DeviceName[256];
163cc1deb29SHermès Bélusca-Maïto } DeviceName;
164cc1deb29SHermès Bélusca-Maïto
165cc1deb29SHermès Bélusca-Maïto
166cc1deb29SHermès Bélusca-Maïto *pMountPointsPtr = NULL;
167cc1deb29SHermès Bélusca-Maïto
168cc1deb29SHermès Bélusca-Maïto /* First, build the corresponding device name */
169cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&VolumeName, NtVolumeName);
170cc1deb29SHermès Bélusca-Maïto DeviceName.SymbolicLinkNameOffset = DeviceName.UniqueIdOffset = 0;
171cc1deb29SHermès Bélusca-Maïto DeviceName.SymbolicLinkNameLength = DeviceName.UniqueIdLength = 0;
172cc1deb29SHermès Bélusca-Maïto DeviceName.DeviceNameOffset = ((ULONG_PTR)&DeviceName.DeviceName - (ULONG_PTR)&DeviceName);
173cc1deb29SHermès Bélusca-Maïto DeviceName.DeviceNameLength = VolumeName.Length;
174cc1deb29SHermès Bélusca-Maïto RtlCopyMemory(&DeviceName.DeviceName, VolumeName.Buffer, VolumeName.Length);
175cc1deb29SHermès Bélusca-Maïto
176cc1deb29SHermès Bélusca-Maïto /* Now, query the MountMgr for the mount points */
177cc1deb29SHermès Bélusca-Maïto Status = NtDeviceIoControlFile(MountMgrHandle,
178cc1deb29SHermès Bélusca-Maïto NULL, NULL, NULL,
179cc1deb29SHermès Bélusca-Maïto &IoStatusBlock,
180cc1deb29SHermès Bélusca-Maïto IOCTL_MOUNTMGR_QUERY_POINTS,
181cc1deb29SHermès Bélusca-Maïto &DeviceName, sizeof(DeviceName),
182cc1deb29SHermès Bélusca-Maïto &MountPoints, sizeof(MountPoints));
183cc1deb29SHermès Bélusca-Maïto
184cc1deb29SHermès Bélusca-Maïto /* Check for unsupported device */
185cc1deb29SHermès Bélusca-Maïto if (Status == STATUS_NO_MEDIA_IN_DEVICE || Status == STATUS_INVALID_DEVICE_REQUEST)
186cc1deb29SHermès Bélusca-Maïto {
187cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Doesn't support MountMgr queries, Status 0x%08lx\n",
188cc1deb29SHermès Bélusca-Maïto NtVolumeName, Status);
189cc1deb29SHermès Bélusca-Maïto return;
190cc1deb29SHermès Bélusca-Maïto }
191cc1deb29SHermès Bélusca-Maïto
192cc1deb29SHermès Bélusca-Maïto /* The only tolerated failure here is buffer too small, which is expected */
193cc1deb29SHermès Bélusca-Maïto ok(NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW),
194cc1deb29SHermès Bélusca-Maïto "Device '%S': IOCTL 0x%lx failed unexpectedly, Status 0x%08lx\n",
195cc1deb29SHermès Bélusca-Maïto NtVolumeName, IOCTL_MOUNTMGR_QUERY_POINTS, Status);
196cc1deb29SHermès Bélusca-Maïto if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW))
197cc1deb29SHermès Bélusca-Maïto {
198cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Wrong Status\n", NtVolumeName);
199cc1deb29SHermès Bélusca-Maïto return;
200cc1deb29SHermès Bélusca-Maïto }
201cc1deb29SHermès Bélusca-Maïto
202cc1deb29SHermès Bélusca-Maïto /* Compute the needed size to retrieve the mount points */
203cc1deb29SHermès Bélusca-Maïto Length = MountPoints.Size;
204cc1deb29SHermès Bélusca-Maïto
205cc1deb29SHermès Bélusca-Maïto /* Allocate the buffer and fill it with test pattern */
206cc1deb29SHermès Bélusca-Maïto MountPointsPtr = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
207cc1deb29SHermès Bélusca-Maïto if (!MountPointsPtr)
208cc1deb29SHermès Bélusca-Maïto {
209cc1deb29SHermès Bélusca-Maïto skip("Device '%S': Failed to allocate buffer with size %lu)\n",
210cc1deb29SHermès Bélusca-Maïto NtVolumeName, Length);
211cc1deb29SHermès Bélusca-Maïto return;
212cc1deb29SHermès Bélusca-Maïto }
213cc1deb29SHermès Bélusca-Maïto RtlFillMemory(MountPointsPtr, Length, 0xCC);
214cc1deb29SHermès Bélusca-Maïto
215cc1deb29SHermès Bélusca-Maïto /* Re-query the mount points with the proper size */
216cc1deb29SHermès Bélusca-Maïto Status = NtDeviceIoControlFile(MountMgrHandle,
217cc1deb29SHermès Bélusca-Maïto NULL, NULL, NULL,
218cc1deb29SHermès Bélusca-Maïto &IoStatusBlock,
219cc1deb29SHermès Bélusca-Maïto IOCTL_MOUNTMGR_QUERY_POINTS,
220cc1deb29SHermès Bélusca-Maïto &DeviceName, sizeof(DeviceName),
221cc1deb29SHermès Bélusca-Maïto MountPointsPtr, Length);
222cc1deb29SHermès Bélusca-Maïto ok(NT_SUCCESS(Status),
223cc1deb29SHermès Bélusca-Maïto "Device '%S': IOCTL 0x%lx failed unexpectedly, Status 0x%08lx\n",
224cc1deb29SHermès Bélusca-Maïto NtVolumeName, IOCTL_MOUNTMGR_QUERY_POINTS, Status);
225cc1deb29SHermès Bélusca-Maïto
226cc1deb29SHermès Bélusca-Maïto if (winetest_debug > 1)
227cc1deb29SHermès Bélusca-Maïto {
228cc1deb29SHermès Bélusca-Maïto trace("IOCTL_MOUNTMGR_QUERY_POINTS returned:\n"
229cc1deb29SHermès Bélusca-Maïto " Size: %lu\n"
230cc1deb29SHermès Bélusca-Maïto " NumberOfMountPoints: %lu\n",
231cc1deb29SHermès Bélusca-Maïto MountPointsPtr->Size,
232cc1deb29SHermès Bélusca-Maïto MountPointsPtr->NumberOfMountPoints);
233cc1deb29SHermès Bélusca-Maïto
234cc1deb29SHermès Bélusca-Maïto trace("Buffer:\n");
235cc1deb29SHermès Bélusca-Maïto DumpBuffer(MountPointsPtr, Length);
236cc1deb29SHermès Bélusca-Maïto printf("\n");
237cc1deb29SHermès Bélusca-Maïto }
238cc1deb29SHermès Bélusca-Maïto
239cc1deb29SHermès Bélusca-Maïto /* Return the buffer */
240cc1deb29SHermès Bélusca-Maïto *pMountPointsPtr = MountPointsPtr;
241cc1deb29SHermès Bélusca-Maïto }
242cc1deb29SHermès Bélusca-Maïto
243cc1deb29SHermès Bélusca-Maïto
244cc1deb29SHermès Bélusca-Maïto #define IS_DRIVE_LETTER_PFX(s) \
245cc1deb29SHermès Bélusca-Maïto ((s)->Length >= 2*sizeof(WCHAR) && (s)->Buffer[0] >= 'A' && \
246cc1deb29SHermès Bélusca-Maïto (s)->Buffer[0] <= 'Z' && (s)->Buffer[1] == ':')
247cc1deb29SHermès Bélusca-Maïto
248cc1deb29SHermès Bélusca-Maïto /* Differs from MOUNTMGR_IS_DRIVE_LETTER(): no '\DosDevices\' accounted for */
249cc1deb29SHermès Bélusca-Maïto #define IS_DRIVE_LETTER(s) \
250cc1deb29SHermès Bélusca-Maïto (IS_DRIVE_LETTER_PFX(s) && (s)->Length == 2*sizeof(WCHAR))
251cc1deb29SHermès Bélusca-Maïto
252cc1deb29SHermès Bélusca-Maïto
253cc1deb29SHermès Bélusca-Maïto /**
254cc1deb29SHermès Bélusca-Maïto * @brief Tests the output of IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH.
255cc1deb29SHermès Bélusca-Maïto **/
256cc1deb29SHermès Bélusca-Maïto static VOID
Test_QueryDosVolumePath(_In_ PCWSTR NtVolumeName,_In_ PMOUNTMGR_VOLUME_PATHS VolumePath)257cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePath(
258cc1deb29SHermès Bélusca-Maïto _In_ PCWSTR NtVolumeName,
259cc1deb29SHermès Bélusca-Maïto _In_ PMOUNTMGR_VOLUME_PATHS VolumePath)
260cc1deb29SHermès Bélusca-Maïto {
261cc1deb29SHermès Bélusca-Maïto UNICODE_STRING DosPath;
262cc1deb29SHermès Bélusca-Maïto
263cc1deb29SHermès Bélusca-Maïto UNREFERENCED_PARAMETER(NtVolumeName);
264cc1deb29SHermès Bélusca-Maïto
265cc1deb29SHermès Bélusca-Maïto /* The VolumePath should contain one NUL-terminated string (always there?),
266cc1deb29SHermès Bélusca-Maïto * plus one final NUL-terminator */
267cc1deb29SHermès Bélusca-Maïto ok(VolumePath->MultiSzLength >= 2 * sizeof(UNICODE_NULL),
268cc1deb29SHermès Bélusca-Maïto "DOS volume path string too short (length: %lu)\n",
269cc1deb29SHermès Bélusca-Maïto VolumePath->MultiSzLength / sizeof(WCHAR));
270cc1deb29SHermès Bélusca-Maïto ok(VolumePath->MultiSz[VolumePath->MultiSzLength / sizeof(WCHAR) - 2] == UNICODE_NULL,
271cc1deb29SHermès Bélusca-Maïto "Missing NUL-terminator (2)\n");
272cc1deb29SHermès Bélusca-Maïto ok(VolumePath->MultiSz[VolumePath->MultiSzLength / sizeof(WCHAR) - 1] == UNICODE_NULL,
273cc1deb29SHermès Bélusca-Maïto "Missing NUL-terminator (1)\n");
274cc1deb29SHermès Bélusca-Maïto
275cc1deb29SHermès Bélusca-Maïto /* Build the result string */
276cc1deb29SHermès Bélusca-Maïto // RtlInitUnicodeString(&DosPath, VolumePath->MultiSz);
277cc1deb29SHermès Bélusca-Maïto DosPath.Length = (USHORT)VolumePath->MultiSzLength - 2 * sizeof(UNICODE_NULL);
278cc1deb29SHermès Bélusca-Maïto DosPath.MaximumLength = DosPath.Length + sizeof(UNICODE_NULL);
279cc1deb29SHermès Bélusca-Maïto DosPath.Buffer = VolumePath->MultiSz;
280cc1deb29SHermès Bélusca-Maïto
281cc1deb29SHermès Bélusca-Maïto /* The returned DOS path is either a drive letter (*WITHOUT* any
282cc1deb29SHermès Bélusca-Maïto * '\DosDevices\' prefix present) or a Win32 file-system reparse point
283cc1deb29SHermès Bélusca-Maïto * path, or a volume GUID name in Win32 format, i.e. prefixed by '\\?\' */
284cc1deb29SHermès Bélusca-Maïto ok(IS_DRIVE_LETTER_PFX(&DosPath) || MOUNTMGR_IS_DOS_VOLUME_NAME(&DosPath),
285cc1deb29SHermès Bélusca-Maïto "Invalid DOS volume path returned '%s'\n", wine_dbgstr_us(&DosPath));
286cc1deb29SHermès Bélusca-Maïto }
287cc1deb29SHermès Bélusca-Maïto
288cc1deb29SHermès Bélusca-Maïto /**
289cc1deb29SHermès Bélusca-Maïto * @brief Tests the output of IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS.
290cc1deb29SHermès Bélusca-Maïto **/
291cc1deb29SHermès Bélusca-Maïto static VOID
Test_QueryDosVolumePaths(_In_ PCWSTR NtVolumeName,_In_ PMOUNTMGR_VOLUME_PATHS VolumePaths,_In_opt_ PMOUNTMGR_VOLUME_PATHS VolumePath)292cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePaths(
293cc1deb29SHermès Bélusca-Maïto _In_ PCWSTR NtVolumeName,
294cc1deb29SHermès Bélusca-Maïto _In_ PMOUNTMGR_VOLUME_PATHS VolumePaths,
295cc1deb29SHermès Bélusca-Maïto _In_opt_ PMOUNTMGR_VOLUME_PATHS VolumePath)
296cc1deb29SHermès Bélusca-Maïto {
297cc1deb29SHermès Bélusca-Maïto UNICODE_STRING DosPath;
298cc1deb29SHermès Bélusca-Maïto PCWSTR pMountPoint;
299cc1deb29SHermès Bélusca-Maïto
300cc1deb29SHermès Bélusca-Maïto /* The VolumePaths should contain zero or more NUL-terminated strings,
301cc1deb29SHermès Bélusca-Maïto * plus one final NUL-terminator */
302cc1deb29SHermès Bélusca-Maïto
303cc1deb29SHermès Bélusca-Maïto ok(VolumePaths->MultiSzLength >= sizeof(UNICODE_NULL),
304cc1deb29SHermès Bélusca-Maïto "DOS volume path string too short (length: %lu)\n",
305cc1deb29SHermès Bélusca-Maïto VolumePaths->MultiSzLength / sizeof(WCHAR));
306cc1deb29SHermès Bélusca-Maïto
307cc1deb29SHermès Bélusca-Maïto /* Check for correct double-NUL-termination, if there is at least one string */
308cc1deb29SHermès Bélusca-Maïto if (VolumePaths->MultiSzLength >= 2 * sizeof(UNICODE_NULL),
309cc1deb29SHermès Bélusca-Maïto VolumePaths->MultiSz[0] != UNICODE_NULL)
310cc1deb29SHermès Bélusca-Maïto {
311cc1deb29SHermès Bélusca-Maïto ok(VolumePaths->MultiSz[VolumePaths->MultiSzLength / sizeof(WCHAR) - 2] == UNICODE_NULL,
312cc1deb29SHermès Bélusca-Maïto "Missing NUL-terminator (2)\n");
313cc1deb29SHermès Bélusca-Maïto }
314cc1deb29SHermès Bélusca-Maïto /* Check for the final NUL-terminator */
315cc1deb29SHermès Bélusca-Maïto ok(VolumePaths->MultiSz[VolumePaths->MultiSzLength / sizeof(WCHAR) - 1] == UNICODE_NULL,
316cc1deb29SHermès Bélusca-Maïto "Missing NUL-terminator (1)\n");
317cc1deb29SHermès Bélusca-Maïto
318cc1deb29SHermès Bélusca-Maïto if (winetest_debug > 1)
319cc1deb29SHermès Bélusca-Maïto {
320cc1deb29SHermès Bélusca-Maïto trace("\n%S =>\n", NtVolumeName);
321cc1deb29SHermès Bélusca-Maïto for (pMountPoint = VolumePaths->MultiSz; *pMountPoint;
322cc1deb29SHermès Bélusca-Maïto pMountPoint += wcslen(pMountPoint) + 1)
323cc1deb29SHermès Bélusca-Maïto {
324cc1deb29SHermès Bélusca-Maïto printf(" '%S'\n", pMountPoint);
325cc1deb29SHermès Bélusca-Maïto }
326cc1deb29SHermès Bélusca-Maïto printf("\n");
327cc1deb29SHermès Bélusca-Maïto }
328cc1deb29SHermès Bélusca-Maïto
329cc1deb29SHermès Bélusca-Maïto for (pMountPoint = VolumePaths->MultiSz; *pMountPoint;
330cc1deb29SHermès Bélusca-Maïto pMountPoint += wcslen(pMountPoint) + 1)
331cc1deb29SHermès Bélusca-Maïto {
332cc1deb29SHermès Bélusca-Maïto /* The returned DOS path is either a drive letter (*WITHOUT* any
333cc1deb29SHermès Bélusca-Maïto * '\DosDevices\' prefix present) or a Win32 file-system reparse point
334cc1deb29SHermès Bélusca-Maïto * path, or a volume GUID name in Win32 format, i.e. prefixed by '\\?\' */
335cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&DosPath, pMountPoint);
336cc1deb29SHermès Bélusca-Maïto ok(IS_DRIVE_LETTER_PFX(&DosPath) || MOUNTMGR_IS_DOS_VOLUME_NAME(&DosPath),
337cc1deb29SHermès Bélusca-Maïto "Invalid DOS volume path returned '%s'\n", wine_dbgstr_us(&DosPath));
338cc1deb29SHermès Bélusca-Maïto }
339cc1deb29SHermès Bélusca-Maïto
340cc1deb29SHermès Bélusca-Maïto /*
341cc1deb29SHermès Bélusca-Maïto * If provided, verify that the single VolumePath is found at the
342cc1deb29SHermès Bélusca-Maïto * first position in the volume paths list, *IF* this is a DOS path;
343cc1deb29SHermès Bélusca-Maïto * otherwise if it's a Volume{GUID} path, this means there is no
344cc1deb29SHermès Bélusca-Maïto * DOS path associated, and none is listed in the volume paths list.
345cc1deb29SHermès Bélusca-Maïto */
346cc1deb29SHermès Bélusca-Maïto if (VolumePath)
347cc1deb29SHermès Bélusca-Maïto {
348cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&DosPath, VolumePath->MultiSz);
349cc1deb29SHermès Bélusca-Maïto if (IS_DRIVE_LETTER_PFX(&DosPath))
350cc1deb29SHermès Bélusca-Maïto {
351cc1deb29SHermès Bélusca-Maïto /*
352cc1deb29SHermès Bélusca-Maïto * The single path is a DOS path (single drive letter or Win32
353cc1deb29SHermès Bélusca-Maïto * file-system reparse point path). It has to be listed first
354cc1deb29SHermès Bélusca-Maïto * in the volume paths list.
355cc1deb29SHermès Bélusca-Maïto */
356cc1deb29SHermès Bélusca-Maïto UNICODE_STRING FirstPath;
357cc1deb29SHermès Bélusca-Maïto BOOLEAN AreEqual;
358cc1deb29SHermès Bélusca-Maïto
359cc1deb29SHermès Bélusca-Maïto ok(VolumePaths->MultiSzLength >= 2 * sizeof(UNICODE_NULL),
360cc1deb29SHermès Bélusca-Maïto "DOS VolumePaths list isn't long enough\n");
361cc1deb29SHermès Bélusca-Maïto ok(*VolumePaths->MultiSz != UNICODE_NULL,
362cc1deb29SHermès Bélusca-Maïto "Empty DOS VolumePaths list\n");
363cc1deb29SHermès Bélusca-Maïto
364cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&FirstPath, VolumePaths->MultiSz);
365cc1deb29SHermès Bélusca-Maïto AreEqual = RtlEqualUnicodeString(&DosPath, &FirstPath, FALSE);
366cc1deb29SHermès Bélusca-Maïto ok(AreEqual, "DOS paths '%s' and '%s' are not the same!\n",
367cc1deb29SHermès Bélusca-Maïto wine_dbgstr_us(&DosPath), wine_dbgstr_us(&FirstPath));
368cc1deb29SHermès Bélusca-Maïto }
369cc1deb29SHermès Bélusca-Maïto else if (MOUNTMGR_IS_DOS_VOLUME_NAME(&DosPath))
370cc1deb29SHermès Bélusca-Maïto {
371cc1deb29SHermès Bélusca-Maïto /*
372cc1deb29SHermès Bélusca-Maïto * The single "DOS" path is actually a volume name. This means
373cc1deb29SHermès Bélusca-Maïto * that it wasn't really mounted, and the volume paths list must
374cc1deb29SHermès Bélusca-Maïto * be empty. It contains only the last NUL-terminator.
375cc1deb29SHermès Bélusca-Maïto */
376cc1deb29SHermès Bélusca-Maïto ok(VolumePaths->MultiSzLength == sizeof(UNICODE_NULL),
377cc1deb29SHermès Bélusca-Maïto "DOS VolumePaths list isn't 1 WCHAR long\n");
378cc1deb29SHermès Bélusca-Maïto ok(*VolumePaths->MultiSz == UNICODE_NULL,
379cc1deb29SHermès Bélusca-Maïto "Non-empty DOS VolumePaths list\n");
380cc1deb29SHermès Bélusca-Maïto }
381cc1deb29SHermès Bélusca-Maïto else
382cc1deb29SHermès Bélusca-Maïto {
383cc1deb29SHermès Bélusca-Maïto /* The volume path is invalid (shouldn't happen) */
384cc1deb29SHermès Bélusca-Maïto ok(FALSE, "Invalid DOS volume path returned '%s'\n", wine_dbgstr_us(&DosPath));
385cc1deb29SHermès Bélusca-Maïto }
386cc1deb29SHermès Bélusca-Maïto }
387cc1deb29SHermès Bélusca-Maïto }
388cc1deb29SHermès Bélusca-Maïto
389cc1deb29SHermès Bélusca-Maïto static BOOLEAN
doesPathExistInMountPoints(_In_ PMOUNTMGR_MOUNT_POINTS MountPoints,_In_ PUNICODE_STRING DosPath)390cc1deb29SHermès Bélusca-Maïto doesPathExistInMountPoints(
391cc1deb29SHermès Bélusca-Maïto _In_ PMOUNTMGR_MOUNT_POINTS MountPoints,
392cc1deb29SHermès Bélusca-Maïto _In_ PUNICODE_STRING DosPath)
393cc1deb29SHermès Bélusca-Maïto {
394cc1deb29SHermès Bélusca-Maïto UNICODE_STRING DosDevicesPrefix = RTL_CONSTANT_STRING(L"\\DosDevices\\");
395cc1deb29SHermès Bélusca-Maïto ULONG i;
396cc1deb29SHermès Bélusca-Maïto BOOLEAN IsDosVolName;
397cc1deb29SHermès Bélusca-Maïto BOOLEAN Found = FALSE;
398cc1deb29SHermès Bélusca-Maïto
399cc1deb29SHermès Bélusca-Maïto IsDosVolName = MOUNTMGR_IS_DOS_VOLUME_NAME(DosPath);
400cc1deb29SHermès Bélusca-Maïto /* Temporarily patch \\?\ to \??\ in DosPath for comparison */
401cc1deb29SHermès Bélusca-Maïto if (IsDosVolName)
402cc1deb29SHermès Bélusca-Maïto DosPath->Buffer[1] = L'?';
403cc1deb29SHermès Bélusca-Maïto
404cc1deb29SHermès Bélusca-Maïto for (i = 0; i < MountPoints->NumberOfMountPoints; ++i)
405cc1deb29SHermès Bélusca-Maïto {
406cc1deb29SHermès Bélusca-Maïto UNICODE_STRING SymLink;
407cc1deb29SHermès Bélusca-Maïto
408cc1deb29SHermès Bélusca-Maïto SymLink.Length = SymLink.MaximumLength = MountPoints->MountPoints[i].SymbolicLinkNameLength;
409cc1deb29SHermès Bélusca-Maïto SymLink.Buffer = (PWCHAR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[i].SymbolicLinkNameOffset);
410cc1deb29SHermès Bélusca-Maïto
411cc1deb29SHermès Bélusca-Maïto if (IS_DRIVE_LETTER(DosPath))
412cc1deb29SHermès Bélusca-Maïto {
413cc1deb29SHermès Bélusca-Maïto if (RtlPrefixUnicodeString(&DosDevicesPrefix, &SymLink, FALSE))
414cc1deb29SHermès Bélusca-Maïto {
415cc1deb29SHermès Bélusca-Maïto /* Advance past the prefix */
416cc1deb29SHermès Bélusca-Maïto SymLink.Length -= DosDevicesPrefix.Length;
417cc1deb29SHermès Bélusca-Maïto SymLink.MaximumLength -= DosDevicesPrefix.Length;
418cc1deb29SHermès Bélusca-Maïto SymLink.Buffer += DosDevicesPrefix.Length / sizeof(WCHAR);
419cc1deb29SHermès Bélusca-Maïto
420cc1deb29SHermès Bélusca-Maïto Found = RtlEqualUnicodeString(DosPath, &SymLink, FALSE);
421cc1deb29SHermès Bélusca-Maïto }
422cc1deb29SHermès Bélusca-Maïto }
423cc1deb29SHermès Bélusca-Maïto else if (/*MOUNTMGR_IS_DOS_VOLUME_NAME(DosPath) ||*/ // See above
424cc1deb29SHermès Bélusca-Maïto MOUNTMGR_IS_NT_VOLUME_NAME(DosPath))
425cc1deb29SHermès Bélusca-Maïto {
426cc1deb29SHermès Bélusca-Maïto Found = RtlEqualUnicodeString(DosPath, &SymLink, FALSE);
427cc1deb29SHermès Bélusca-Maïto }
428cc1deb29SHermès Bélusca-Maïto else
429cc1deb29SHermès Bélusca-Maïto {
430cc1deb29SHermès Bélusca-Maïto /* Just test for simple string comparison, the path should not be found */
431cc1deb29SHermès Bélusca-Maïto Found = RtlEqualUnicodeString(DosPath, &SymLink, FALSE);
432cc1deb29SHermès Bélusca-Maïto }
433cc1deb29SHermès Bélusca-Maïto
434cc1deb29SHermès Bélusca-Maïto /* Stop searching if we've found something */
435cc1deb29SHermès Bélusca-Maïto if (Found)
436cc1deb29SHermès Bélusca-Maïto break;
437cc1deb29SHermès Bélusca-Maïto }
438cc1deb29SHermès Bélusca-Maïto
439cc1deb29SHermès Bélusca-Maïto /* Revert \??\ back to \\?\ */
440cc1deb29SHermès Bélusca-Maïto if (IsDosVolName)
441cc1deb29SHermès Bélusca-Maïto DosPath->Buffer[1] = L'\\';
442cc1deb29SHermès Bélusca-Maïto
443cc1deb29SHermès Bélusca-Maïto return Found;
444cc1deb29SHermès Bélusca-Maïto }
445cc1deb29SHermès Bélusca-Maïto
446cc1deb29SHermès Bélusca-Maïto /**
447cc1deb29SHermès Bélusca-Maïto * @brief Tests the output of IOCTL_MOUNTMGR_QUERY_POINTS.
448cc1deb29SHermès Bélusca-Maïto **/
449cc1deb29SHermès Bélusca-Maïto static VOID
Test_QueryPoints(_In_ PCWSTR NtVolumeName,_In_ PMOUNTMGR_MOUNT_POINTS MountPoints,_In_opt_ PMOUNTMGR_VOLUME_PATHS VolumePath,_In_opt_ PMOUNTMGR_VOLUME_PATHS VolumePaths)450cc1deb29SHermès Bélusca-Maïto Test_QueryPoints(
451cc1deb29SHermès Bélusca-Maïto _In_ PCWSTR NtVolumeName,
452cc1deb29SHermès Bélusca-Maïto _In_ PMOUNTMGR_MOUNT_POINTS MountPoints,
453cc1deb29SHermès Bélusca-Maïto _In_opt_ PMOUNTMGR_VOLUME_PATHS VolumePath,
454cc1deb29SHermès Bélusca-Maïto _In_opt_ PMOUNTMGR_VOLUME_PATHS VolumePaths)
455cc1deb29SHermès Bélusca-Maïto {
456cc1deb29SHermès Bélusca-Maïto UNICODE_STRING DosPath;
457cc1deb29SHermès Bélusca-Maïto PCWSTR pMountPoint;
458cc1deb29SHermès Bélusca-Maïto BOOLEAN ExpectedFound, Found;
459cc1deb29SHermès Bélusca-Maïto
460cc1deb29SHermès Bélusca-Maïto if (winetest_debug > 1)
461cc1deb29SHermès Bélusca-Maïto {
462cc1deb29SHermès Bélusca-Maïto ULONG i;
463cc1deb29SHermès Bélusca-Maïto trace("\n%S =>\n", NtVolumeName);
464cc1deb29SHermès Bélusca-Maïto for (i = 0; i < MountPoints->NumberOfMountPoints; ++i)
465cc1deb29SHermès Bélusca-Maïto {
466cc1deb29SHermès Bélusca-Maïto UNICODE_STRING DevName, SymLink;
467cc1deb29SHermès Bélusca-Maïto
468cc1deb29SHermès Bélusca-Maïto DevName.Length = DevName.MaximumLength = MountPoints->MountPoints[i].DeviceNameLength;
469cc1deb29SHermès Bélusca-Maïto DevName.Buffer = (PWCHAR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[i].DeviceNameOffset);
470cc1deb29SHermès Bélusca-Maïto
471cc1deb29SHermès Bélusca-Maïto SymLink.Length = SymLink.MaximumLength = MountPoints->MountPoints[i].SymbolicLinkNameLength;
472cc1deb29SHermès Bélusca-Maïto SymLink.Buffer = (PWCHAR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[i].SymbolicLinkNameOffset);
473cc1deb29SHermès Bélusca-Maïto
474cc1deb29SHermès Bélusca-Maïto printf(" '%s' -- '%s'\n", wine_dbgstr_us(&DevName), wine_dbgstr_us(&SymLink));
475cc1deb29SHermès Bélusca-Maïto }
476cc1deb29SHermès Bélusca-Maïto printf("\n");
477cc1deb29SHermès Bélusca-Maïto }
478cc1deb29SHermès Bélusca-Maïto
479cc1deb29SHermès Bélusca-Maïto /*
480cc1deb29SHermès Bélusca-Maïto * The Win32 file-system reparse point paths are NOT listed amongst
481cc1deb29SHermès Bélusca-Maïto * the mount points. Only the drive letter and the volume GUID name
482cc1deb29SHermès Bélusca-Maïto * are, but in an NT format (using '\DosDevices\' or '\??\' prefixes).
483cc1deb29SHermès Bélusca-Maïto */
484cc1deb29SHermès Bélusca-Maïto
485cc1deb29SHermès Bélusca-Maïto if (VolumePath)
486cc1deb29SHermès Bélusca-Maïto {
487cc1deb29SHermès Bélusca-Maïto /* VolumePath can either be a drive letter (usual case), a Win32
488cc1deb29SHermès Bélusca-Maïto * reparse point path (if the volume is mounted only with these),
489cc1deb29SHermès Bélusca-Maïto * or a volume GUID name (if the volume is NOT mounted). */
490cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&DosPath, VolumePath->MultiSz);
491cc1deb29SHermès Bélusca-Maïto ExpectedFound = (IS_DRIVE_LETTER(&DosPath) || MOUNTMGR_IS_DOS_VOLUME_NAME(&DosPath));
492cc1deb29SHermès Bélusca-Maïto Found = doesPathExistInMountPoints(MountPoints, &DosPath);
493cc1deb29SHermès Bélusca-Maïto ok(Found == ExpectedFound,
494cc1deb29SHermès Bélusca-Maïto "DOS path '%s' %sfound in the mount points list, expected %sto be found\n",
495cc1deb29SHermès Bélusca-Maïto wine_dbgstr_us(&DosPath), Found ? "" : "NOT ", ExpectedFound ? "" : "NOT ");
496cc1deb29SHermès Bélusca-Maïto }
497cc1deb29SHermès Bélusca-Maïto
498cc1deb29SHermès Bélusca-Maïto if (VolumePaths)
499cc1deb29SHermès Bélusca-Maïto {
500cc1deb29SHermès Bélusca-Maïto /* VolumePaths only contains a drive letter (usual case) or a Win32
501cc1deb29SHermès Bélusca-Maïto * reparse point path (if the volume is mounted only with these).
502cc1deb29SHermès Bélusca-Maïto * If the volume is NOT mounted, VolumePaths does not list the
503cc1deb29SHermès Bélusca-Maïto * volume GUID name, contrary to VolumePath. */
504cc1deb29SHermès Bélusca-Maïto for (pMountPoint = VolumePaths->MultiSz; *pMountPoint;
505cc1deb29SHermès Bélusca-Maïto pMountPoint += wcslen(pMountPoint) + 1)
506cc1deb29SHermès Bélusca-Maïto {
507cc1deb29SHermès Bélusca-Maïto /* Only the drive letter (but NOT the volume GUID name!) can be found in the list */
508cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&DosPath, pMountPoint);
509cc1deb29SHermès Bélusca-Maïto ExpectedFound = IS_DRIVE_LETTER(&DosPath);
510cc1deb29SHermès Bélusca-Maïto Found = doesPathExistInMountPoints(MountPoints, &DosPath);
511cc1deb29SHermès Bélusca-Maïto ok(Found == ExpectedFound,
512cc1deb29SHermès Bélusca-Maïto "DOS path '%s' %sfound in the mount points list, expected %sto be found\n",
513cc1deb29SHermès Bélusca-Maïto wine_dbgstr_us(&DosPath), Found ? "" : "NOT ", ExpectedFound ? "" : "NOT ");
514cc1deb29SHermès Bélusca-Maïto }
515cc1deb29SHermès Bélusca-Maïto }
516cc1deb29SHermès Bélusca-Maïto }
517cc1deb29SHermès Bélusca-Maïto
518cc1deb29SHermès Bélusca-Maïto /**
519cc1deb29SHermès Bélusca-Maïto * @brief
520cc1deb29SHermès Bélusca-Maïto * Tests the consistency of IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
521cc1deb29SHermès Bélusca-Maïto * IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS and IOCTL_MOUNTMGR_QUERY_POINTS.
522cc1deb29SHermès Bélusca-Maïto **/
523cc1deb29SHermès Bélusca-Maïto static VOID
Test_QueryDosVolumePathAndPaths(_In_ HANDLE MountMgrHandle,_In_ PCWSTR NtVolumeName)524cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePathAndPaths(
525cc1deb29SHermès Bélusca-Maïto _In_ HANDLE MountMgrHandle,
526cc1deb29SHermès Bélusca-Maïto _In_ PCWSTR NtVolumeName)
527cc1deb29SHermès Bélusca-Maïto {
528cc1deb29SHermès Bélusca-Maïto PMOUNTMGR_VOLUME_PATHS VolumePath = NULL;
529cc1deb29SHermès Bélusca-Maïto PMOUNTMGR_VOLUME_PATHS VolumePaths = NULL;
530cc1deb29SHermès Bélusca-Maïto PMOUNTMGR_MOUNT_POINTS MountPoints = NULL;
531cc1deb29SHermès Bélusca-Maïto
532cc1deb29SHermès Bélusca-Maïto if (winetest_debug > 1)
533cc1deb29SHermès Bélusca-Maïto trace("%S\n", NtVolumeName);
534cc1deb29SHermès Bélusca-Maïto
535cc1deb29SHermès Bélusca-Maïto Call_QueryDosVolume_Path_Paths(MountMgrHandle,
536cc1deb29SHermès Bélusca-Maïto NtVolumeName,
537cc1deb29SHermès Bélusca-Maïto IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
538cc1deb29SHermès Bélusca-Maïto &VolumePath);
539cc1deb29SHermès Bélusca-Maïto if (VolumePath)
540cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePath(NtVolumeName, VolumePath);
541cc1deb29SHermès Bélusca-Maïto else
542cc1deb29SHermès Bélusca-Maïto skip("Device '%S': IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH failed\n", NtVolumeName);
543cc1deb29SHermès Bélusca-Maïto
544cc1deb29SHermès Bélusca-Maïto Call_QueryDosVolume_Path_Paths(MountMgrHandle,
545cc1deb29SHermès Bélusca-Maïto NtVolumeName,
546cc1deb29SHermès Bélusca-Maïto IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS,
547cc1deb29SHermès Bélusca-Maïto &VolumePaths);
548cc1deb29SHermès Bélusca-Maïto if (VolumePaths)
549cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePaths(NtVolumeName, VolumePaths, VolumePath);
550cc1deb29SHermès Bélusca-Maïto else
551cc1deb29SHermès Bélusca-Maïto skip("Device '%S': IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS failed\n", NtVolumeName);
552cc1deb29SHermès Bélusca-Maïto
553cc1deb29SHermès Bélusca-Maïto Call_QueryPoints(MountMgrHandle, NtVolumeName, &MountPoints);
554cc1deb29SHermès Bélusca-Maïto if (MountPoints)
555cc1deb29SHermès Bélusca-Maïto Test_QueryPoints(NtVolumeName, MountPoints, VolumePath, VolumePaths);
556cc1deb29SHermès Bélusca-Maïto else
557cc1deb29SHermès Bélusca-Maïto skip("Device '%S': IOCTL_MOUNTMGR_QUERY_POINTS failed\n", NtVolumeName);
558cc1deb29SHermès Bélusca-Maïto
559cc1deb29SHermès Bélusca-Maïto if (MountPoints)
560cc1deb29SHermès Bélusca-Maïto RtlFreeHeap(RtlGetProcessHeap(), 0, MountPoints);
561cc1deb29SHermès Bélusca-Maïto if (VolumePaths)
562cc1deb29SHermès Bélusca-Maïto RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
563cc1deb29SHermès Bélusca-Maïto if (VolumePath)
564cc1deb29SHermès Bélusca-Maïto RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePath);
565cc1deb29SHermès Bélusca-Maïto }
566cc1deb29SHermès Bélusca-Maïto
567cc1deb29SHermès Bélusca-Maïto
START_TEST(QueryDosVolumePaths)568cc1deb29SHermès Bélusca-Maïto START_TEST(QueryDosVolumePaths)
569cc1deb29SHermès Bélusca-Maïto {
570cc1deb29SHermès Bélusca-Maïto HANDLE MountMgrHandle;
571cc1deb29SHermès Bélusca-Maïto HANDLE hFindVolume;
572cc1deb29SHermès Bélusca-Maïto WCHAR szVolumeName[MAX_PATH];
573cc1deb29SHermès Bélusca-Maïto
574*cf2cbe6fSHermès Bélusca-Maïto MountMgrHandle = GetMountMgrHandle(FILE_READ_ATTRIBUTES);
575cc1deb29SHermès Bélusca-Maïto if (!MountMgrHandle)
576cc1deb29SHermès Bélusca-Maïto {
577cc1deb29SHermès Bélusca-Maïto win_skip("MountMgr unavailable: %lu\n", GetLastError());
578cc1deb29SHermès Bélusca-Maïto return;
579cc1deb29SHermès Bélusca-Maïto }
580cc1deb29SHermès Bélusca-Maïto
581cc1deb29SHermès Bélusca-Maïto hFindVolume = FindFirstVolumeW(szVolumeName, _countof(szVolumeName));
582cc1deb29SHermès Bélusca-Maïto if (hFindVolume == INVALID_HANDLE_VALUE)
583cc1deb29SHermès Bélusca-Maïto goto otherTests;
584cc1deb29SHermès Bélusca-Maïto do
585cc1deb29SHermès Bélusca-Maïto {
586cc1deb29SHermès Bélusca-Maïto UNICODE_STRING VolumeName;
587cc1deb29SHermès Bélusca-Maïto USHORT Length;
588cc1deb29SHermès Bélusca-Maïto
589cc1deb29SHermès Bélusca-Maïto /*
590cc1deb29SHermès Bélusca-Maïto * The Win32 FindFirst/NextVolumeW() functions convert the '\??\'
591cc1deb29SHermès Bélusca-Maïto * prefix in '\??\Volume{...}' to '\\?\' and append a trailing
592cc1deb29SHermès Bélusca-Maïto * backslash. Test this behaviour.
593cc1deb29SHermès Bélusca-Maïto *
594cc1deb29SHermès Bélusca-Maïto * NOTE: these functions actively filter out anything that is NOT
595cc1deb29SHermès Bélusca-Maïto * '\??\Volume{...}' returned from IOCTL_MOUNTMGR_QUERY_POINTS.
596cc1deb29SHermès Bélusca-Maïto * Thus, it also excludes mount-points specified as drive letters,
597cc1deb29SHermès Bélusca-Maïto * like '\DosDevices\C:' .
598cc1deb29SHermès Bélusca-Maïto */
599cc1deb29SHermès Bélusca-Maïto
600cc1deb29SHermès Bélusca-Maïto RtlInitUnicodeString(&VolumeName, szVolumeName);
601cc1deb29SHermès Bélusca-Maïto Length = VolumeName.Length / sizeof(WCHAR);
602cc1deb29SHermès Bélusca-Maïto ok(Length >= 1 && VolumeName.Buffer[Length - 1] == L'\\',
603cc1deb29SHermès Bélusca-Maïto "No trailing backslash found\n");
604cc1deb29SHermès Bélusca-Maïto
605cc1deb29SHermès Bélusca-Maïto /* Remove the trailing backslash */
606cc1deb29SHermès Bélusca-Maïto if (Length >= 1)
607cc1deb29SHermès Bélusca-Maïto {
608cc1deb29SHermès Bélusca-Maïto VolumeName.Length -= sizeof(WCHAR);
609cc1deb29SHermès Bélusca-Maïto if (szVolumeName[Length - 1] == L'\\')
610cc1deb29SHermès Bélusca-Maïto szVolumeName[Length - 1] = UNICODE_NULL;
611cc1deb29SHermès Bélusca-Maïto }
612cc1deb29SHermès Bélusca-Maïto
613cc1deb29SHermès Bélusca-Maïto ok(MOUNTMGR_IS_DOS_VOLUME_NAME(&VolumeName),
614cc1deb29SHermès Bélusca-Maïto "Invalid DOS volume path returned '%s'\n", wine_dbgstr_us(&VolumeName));
615cc1deb29SHermès Bélusca-Maïto
616cc1deb29SHermès Bélusca-Maïto /* Patch '\\?\' back to '\??\' to convert to an NT path */
617cc1deb29SHermès Bélusca-Maïto if (szVolumeName[0] == L'\\' && szVolumeName[1] == L'\\' &&
618cc1deb29SHermès Bélusca-Maïto szVolumeName[2] == L'?' && szVolumeName[3] == L'\\')
619cc1deb29SHermès Bélusca-Maïto {
620cc1deb29SHermès Bélusca-Maïto szVolumeName[1] = L'?';
621cc1deb29SHermès Bélusca-Maïto }
622cc1deb29SHermès Bélusca-Maïto
623cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePathAndPaths(MountMgrHandle, szVolumeName);
624cc1deb29SHermès Bélusca-Maïto } while (FindNextVolumeW(hFindVolume, szVolumeName, _countof(szVolumeName)));
625cc1deb29SHermès Bélusca-Maïto FindVolumeClose(hFindVolume);
626cc1deb29SHermès Bélusca-Maïto
627cc1deb29SHermès Bélusca-Maïto otherTests:
628cc1deb29SHermès Bélusca-Maïto /* Test the drive containing SystemRoot */
629cc1deb29SHermès Bélusca-Maïto wcscpy(szVolumeName, L"\\DosDevices\\?:");
630cc1deb29SHermès Bélusca-Maïto szVolumeName[sizeof("\\DosDevices\\")-1] = SharedUserData->NtSystemRoot[0];
631cc1deb29SHermès Bélusca-Maïto Test_QueryDosVolumePathAndPaths(MountMgrHandle, szVolumeName);
632cc1deb29SHermès Bélusca-Maïto
633cc1deb29SHermès Bélusca-Maïto /* We are done */
634cc1deb29SHermès Bélusca-Maïto CloseHandle(MountMgrHandle);
635cc1deb29SHermès Bélusca-Maïto }
636