be3086eddafd3651bec86d43bb65e87934d413cc
[reactos.git] / modules / rostests / apitests / kernel32 / DeviceIoControl.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for DeviceIoControl
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include <apitest.h>
9 #include <strsafe.h>
10 #include <winioctl.h>
11 #include <mountmgr.h>
12 #include <mountdev.h>
13
14 WCHAR Letter;
15 HANDLE Device;
16 UINT DriveType;
17
18 #define ok_type(condition, format, ...) ok(condition, "(%d): " format, DriveType, ##__VA_ARGS__)
19 #define skip_type(format, ...) skip("(%d): " format, DriveType, ##__VA_ARGS__)
20
21 static
22 BOOL
23 GetDiskGeometry(VOID)
24 {
25 UINT Ret;
26 DISK_GEOMETRY DG;
27 DWORD Size, Error;
28 DISK_GEOMETRY_EX DGE;
29
30 Size = 0;
31 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DG, sizeof(DG) - 1, &Size, NULL);
32 ok_type(Ret == 0, "DeviceIoControl succeed\n");
33 Error = GetLastError();
34 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
35 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
36
37 Size = 0;
38 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DG, sizeof(DG), &Size, NULL);
39 /* Specific for CDROM, no disk present */
40 if (Ret == 0 && GetLastError() == ERROR_NOT_READY)
41 {
42 skip_type("No CDROM present\n");
43 return FALSE;
44 }
45 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
46 ok_type(Size == sizeof(DG), "Invalid output size: %ld\n", Size);
47
48 Size = 0;
49 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DGE, FIELD_OFFSET(DISK_GEOMETRY_EX, Data) - 1, &Size, NULL);
50 ok_type(Ret == 0, "DeviceIoControl succeed\n");
51 Error = GetLastError();
52 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
53 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
54
55 Size = 0;
56 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DGE, FIELD_OFFSET(DISK_GEOMETRY_EX, Data), &Size, NULL);
57 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
58 ok_type(Size == FIELD_OFFSET(DISK_GEOMETRY_EX, Data), "Invalid output size: %ld\n", Size);
59
60 Size = 0;
61 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DGE, sizeof(DGE), &Size, NULL);
62 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
63 if (DriveType == DRIVE_FIXED)
64 {
65 ok_type(Size == sizeof(DGE), "Invalid output size: %ld\n", Size);
66 }
67 else
68 {
69 ok_type(Size == FIELD_OFFSET(DISK_GEOMETRY_EX, Data), "Invalid output size: %ld\n", Size);
70 }
71
72 return TRUE;
73 }
74
75 static
76 VOID
77 QueryDeviceName(VOID)
78 {
79 UINT Ret;
80 BOOL IsValid;
81 DWORD Size, Error;
82 MOUNTDEV_NAME MDN, *AllocatedMDN;
83
84 Size = 0;
85 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &MDN, sizeof(MDN) - 1, &Size, NULL);
86 ok_type(Ret == 0, "DeviceIoControl succeed\n");
87 Error = GetLastError();
88 if (DriveType == DRIVE_FIXED)
89 {
90 ok_type(Error == ERROR_INVALID_PARAMETER, "Expecting ERROR_INVALID_PARAMETER, got %ld\n", Error);
91 }
92 else
93 {
94 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
95 }
96 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
97
98 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &MDN, sizeof(MDN), &Size, NULL);
99 ok_type(Ret == 0, "DeviceIoControl succeed\n");
100 Error = GetLastError();
101 ok_type(Error == ERROR_MORE_DATA, "Expecting ERROR_MORE_DATA, got %ld\n", Error);
102 ok_type(Size == sizeof(MOUNTDEV_NAME), "Invalid output size: %ld\n", Size);
103
104 AllocatedMDN = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MOUNTDEV_NAME, Name) + MDN.NameLength + sizeof(UNICODE_NULL));
105 if (AllocatedMDN == NULL)
106 {
107 skip_type("Memory allocation failure\n");
108 return;
109 }
110
111 Size = 0;
112 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, AllocatedMDN, FIELD_OFFSET(MOUNTDEV_NAME, Name) + MDN.NameLength, &Size, NULL);
113 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
114 ok_type(Size == FIELD_OFFSET(MOUNTDEV_NAME, Name) + MDN.NameLength, "Invalid output size: %ld\n", Size);
115 ok_type(AllocatedMDN->NameLength == MDN.NameLength, "Mismatching sizes: %d %d\n", AllocatedMDN->NameLength, MDN.NameLength);
116
117 if (Ret != 0)
118 {
119 IsValid = FALSE;
120 AllocatedMDN->Name[AllocatedMDN->NameLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
121
122 if ((DriveType == DRIVE_FIXED && wcsstr(AllocatedMDN->Name, L"\\Device\\HarddiskVolume") != NULL) ||
123 (DriveType == DRIVE_CDROM && wcsstr(AllocatedMDN->Name, L"\\Device\\CdRom") != NULL))
124 {
125 IsValid = TRUE;
126 }
127 else if (wcsstr(AllocatedMDN->Name, L"\\DosDevices\\") != NULL)
128 {
129 IsValid = (AllocatedMDN->Name[12] == Letter && AllocatedMDN->Name[13] == L':');
130 }
131
132 ok_type(IsValid, "Invalid name: %.*S\n", AllocatedMDN->NameLength, AllocatedMDN->Name);
133 }
134 else
135 {
136 skip_type("Failed to query device name\n");
137 }
138
139 HeapFree(GetProcessHeap(), 0, AllocatedMDN);
140 }
141
142 static
143 VOID
144 QueryUniqueId(VOID)
145 {
146 UINT Ret;
147 DWORD Size, Error;
148 MOUNTDEV_UNIQUE_ID MUI, *AllocatedMUI;
149
150 Size = 0;
151 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, NULL, 0, &MUI, sizeof(MUI) - 1, &Size, NULL);
152 ok_type(Ret == 0, "DeviceIoControl succeed\n");
153 Error = GetLastError();
154 if (DriveType == DRIVE_FIXED)
155 {
156 ok_type(Error == ERROR_INVALID_PARAMETER, "Expecting ERROR_INVALID_PARAMETER, got %ld\n", Error);
157 }
158 else
159 {
160 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
161 }
162 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
163
164 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, NULL, 0, &MUI, sizeof(MUI), &Size, NULL);
165 ok_type(Ret == 0, "DeviceIoControl succeed\n");
166 Error = GetLastError();
167 ok_type(Error == ERROR_MORE_DATA, "Expecting ERROR_MORE_DATA, got %ld\n", Error);
168 ok_type(Size == sizeof(MOUNTDEV_UNIQUE_ID), "Invalid output size: %ld\n", Size);
169
170 AllocatedMUI = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + MUI.UniqueIdLength + sizeof(UNICODE_NULL));
171 if (AllocatedMUI == NULL)
172 {
173 skip_type("Memory allocation failure\n");
174 return;
175 }
176
177 Size = 0;
178 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, NULL, 0, AllocatedMUI, FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + MUI.UniqueIdLength, &Size, NULL);
179 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
180 ok_type(Size == FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + MUI.UniqueIdLength, "Invalid output size: %ld\n", Size);
181 ok_type(AllocatedMUI->UniqueIdLength == MUI.UniqueIdLength, "Mismatching sizes: %d %d\n", AllocatedMUI->UniqueIdLength, MUI.UniqueIdLength);
182
183 HeapFree(GetProcessHeap(), 0, AllocatedMUI);
184 }
185
186 static
187 VOID
188 QuerySuggestedLinkName(VOID)
189 {
190 UINT Ret;
191 DWORD Size, Error;
192 MOUNTDEV_SUGGESTED_LINK_NAME MSLN;
193
194 Size = 0;
195 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME, NULL, 0, &MSLN, sizeof(MSLN) - 1, &Size, NULL);
196 ok_type(Ret == 0, "DeviceIoControl succeed\n");
197 Error = GetLastError();
198 if (DriveType == DRIVE_FIXED)
199 {
200 ok_type(Error == ERROR_INVALID_PARAMETER, "Expecting ERROR_INVALID_PARAMETER, got %ld\n", Error);
201 }
202 else
203 {
204 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
205 }
206 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
207
208 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME, NULL, 0, &MSLN, sizeof(MSLN), &Size, NULL);
209 ok_type(Ret == 0, "DeviceIoControl succeed\n");
210 Error = GetLastError();
211 if (DriveType == DRIVE_FIXED)
212 {
213 ok_type(Error == ERROR_NOT_FOUND, "Expecting ERROR_NOT_FOUND, got %ld\n", Error);
214 }
215 else
216 {
217 ok_type(Error == ERROR_FILE_NOT_FOUND, "Expecting ERROR_FILE_NOT_FOUND, got %ld\n", Error);
218 }
219 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
220 }
221
222 START_TEST(DeviceIoControl)
223 {
224 UINT Ret;
225 WCHAR Path[MAX_PATH];
226 DWORD DriveMap, Current;
227 BOOL DiskDone, CdRomDone;
228
229 DiskDone = FALSE;
230 CdRomDone = FALSE;
231 DriveMap = GetLogicalDrives();
232 for (Current = 0; Current < 26; ++Current)
233 {
234 if (DriveMap & (1 << Current))
235 {
236 Ret = StringCchPrintfW(Path, MAX_PATH, L"%c:\\", Current + L'A');
237 ok(Ret == S_OK, "StringCchPrintfW failed: %d\n", Ret);
238
239 DriveType = GetDriveTypeW(Path);
240 if ((DriveType == DRIVE_FIXED && !DiskDone) ||
241 (DriveType == DRIVE_CDROM && !CdRomDone))
242 {
243 Ret = StringCchPrintfW(Path, MAX_PATH, L"\\\\?\\%c:", Current + L'A');
244 ok(Ret == S_OK, "StringCchPrintfW failed: %d\n", Ret);
245
246 Device = CreateFileW(Path, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
247 if (Device == INVALID_HANDLE_VALUE)
248 {
249 skip_type("CreateFileW for %S failed: %ld\n", Path, GetLastError());
250 continue;
251 }
252
253 DiskDone = (DiskDone || (DriveType == DRIVE_FIXED));
254 CdRomDone = (CdRomDone || (DriveType == DRIVE_CDROM));
255
256 if (GetDiskGeometry())
257 {
258 QueryDeviceName();
259 QueryUniqueId();
260 QuerySuggestedLinkName();
261 }
262
263 CloseHandle(Device);
264 }
265
266 if (CdRomDone && DiskDone)
267 {
268 break;
269 }
270 }
271 }
272
273 if (!DiskDone)
274 {
275 skip("No disk drive found\n");
276 }
277
278 if (!CdRomDone)
279 {
280 skip("No CDROM drive found\n");
281 }
282 }