a3011f3d1414e5a21fb56945c525b5e55afd60d8
[reactos.git] / rostests / drivers / kmtest / deviface.c
1 /*
2 * PnP Test
3 * ReactOS Device Interface functions implementation
4 *
5 * Copyright 2003, 2004 Filip Navara <xnavara@volny.cz>
6 * Copyright 2003, 2004 Matthew Brace <ismarc@austin.rr.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; see the file COPYING.LIB.
20 * If not, write to the Free Software Foundation,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 /* INCLUDES *******************************************************************/
25
26 #include <ddk/ntddk.h>
27 #include "kmtest.h"
28
29 //#define NDEBUG
30 #include "debug.h"
31
32 /* PUBLIC FUNCTIONS ***********************************************************/
33
34 /*
35 * IoGetDeviceInterfaces
36 *
37 * Returns a list of device interfaces of a particular device interface class.
38 *
39 * Parameters
40 * InterfaceClassGuid
41 * Points to a class GUID specifying the device interface class.
42 *
43 * PhysicalDeviceObject
44 * Points to an optional PDO that narrows the search to only the
45 * device interfaces of the device represented by the PDO.
46 *
47 * Flags
48 * Specifies flags that modify the search for device interfaces. The
49 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
50 * returned symbolic links should contain also disabled device
51 * interfaces in addition to the enabled ones.
52 *
53 * SymbolicLinkList
54 * Points to a character pointer that is filled in on successful return
55 * with a list of unicode strings identifying the device interfaces
56 * that match the search criteria. The newly allocated buffer contains
57 * a list of symbolic link names. Each unicode string in the list is
58 * null-terminated; the end of the whole list is marked by an additional
59 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
60 * when it is no longer needed.
61 * If no device interfaces match the search criteria, this routine
62 * returns STATUS_SUCCESS and the string contains a single NULL
63 * character.
64 *
65 * Status
66 * @unimplemented
67 *
68 * The parameters PhysicalDeviceObject and Flags aren't correctly
69 * processed. Rest of the cases was tested under Win XP and the
70 * function worked correctly.
71 */
72
73 NTSTATUS NTAPI
74 ReactOS_IoGetDeviceInterfaces(
75 IN CONST GUID *InterfaceClassGuid,
76 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
77 IN ULONG Flags,
78 OUT PWSTR *SymbolicLinkList)
79 {
80 PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
81 PWCHAR BaseInterfaceString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
82 UNICODE_STRING GuidString;
83 UNICODE_STRING BaseKeyName;
84 UNICODE_STRING AliasKeyName;
85 UNICODE_STRING SymbolicLink;
86 UNICODE_STRING Control;
87 UNICODE_STRING SubKeyName;
88 UNICODE_STRING SymbolicLinkKeyName;
89 UNICODE_STRING ControlKeyName;
90 UNICODE_STRING TempString;
91 HANDLE InterfaceKey;
92 HANDLE SubKey;
93 HANDLE SymbolicLinkKey;
94 PKEY_FULL_INFORMATION fip;
95 PKEY_FULL_INFORMATION bfip=NULL;
96 PKEY_BASIC_INFORMATION bip;
97 PKEY_VALUE_PARTIAL_INFORMATION vpip=NULL;
98 PWCHAR SymLinkList = NULL;
99 ULONG SymLinkListSize = 0;
100 NTSTATUS Status;
101 ULONG Size = 0;
102 ULONG i = 0;
103 ULONG j = 0;
104 OBJECT_ATTRIBUTES ObjectAttributes;
105
106 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
107 if (!NT_SUCCESS(Status))
108 {
109 DPRINT("RtlStringFromGUID() Failed.\n");
110 return STATUS_INVALID_HANDLE;
111 }
112
113 RtlInitUnicodeString(&AliasKeyName, BaseInterfaceString);
114 RtlInitUnicodeString(&SymbolicLink, L"SymbolicLink");
115 RtlInitUnicodeString(&Control, L"\\Control");
116 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
117 BaseKeyName.MaximumLength = BaseKeyName.Length + (38 * sizeof(WCHAR));
118 BaseKeyName.Buffer = ExAllocatePool(
119 NonPagedPool,
120 BaseKeyName.MaximumLength);
121 ASSERT(BaseKeyName.Buffer != NULL);
122 wcscpy(BaseKeyName.Buffer, BaseKeyString);
123 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
124
125 if (PhysicalDeviceObject)
126 {
127 WCHAR GuidBuffer[40];
128 UNICODE_STRING PdoGuidString;
129
130 RtlFreeUnicodeString(&BaseKeyName);
131
132 IoGetDeviceProperty(
133 PhysicalDeviceObject,
134 DevicePropertyClassGuid,
135 sizeof(GuidBuffer),
136 GuidBuffer,
137 &Size);
138
139 RtlInitUnicodeString(&PdoGuidString, GuidBuffer);
140 if (RtlCompareUnicodeString(&GuidString, &PdoGuidString, TRUE))
141 {
142 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
143 return STATUS_INVALID_HANDLE;
144 }
145
146 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
147 return STATUS_NOT_IMPLEMENTED;
148 }
149 else
150 {
151 InitializeObjectAttributes(
152 &ObjectAttributes,
153 &BaseKeyName,
154 OBJ_CASE_INSENSITIVE,
155 NULL,
156 NULL);
157
158 Status = ZwOpenKey(
159 &InterfaceKey,
160 KEY_READ,
161 &ObjectAttributes);
162
163 if (!NT_SUCCESS(Status))
164 {
165 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
166 RtlFreeUnicodeString(&BaseKeyName);
167 return Status;
168 }
169
170 Status = ZwQueryKey(
171 InterfaceKey,
172 KeyFullInformation,
173 NULL,
174 0,
175 &Size);
176
177 if (Status != STATUS_BUFFER_TOO_SMALL)
178 {
179 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
180 RtlFreeUnicodeString(&BaseKeyName);
181 ZwClose(InterfaceKey);
182 return Status;
183 }
184
185 fip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
186 ASSERT(fip != NULL);
187
188 Status = ZwQueryKey(
189 InterfaceKey,
190 KeyFullInformation,
191 fip,
192 Size,
193 &Size);
194
195 if (!NT_SUCCESS(Status))
196 {
197 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
198 ExFreePool(fip);
199 RtlFreeUnicodeString(&BaseKeyName);
200 ZwClose(InterfaceKey);
201 return Status;
202 }
203
204 for (; i < fip->SubKeys; i++)
205 {
206 Status = ZwEnumerateKey(
207 InterfaceKey,
208 i,
209 KeyBasicInformation,
210 NULL,
211 0,
212 &Size);
213
214 if (Status != STATUS_BUFFER_TOO_SMALL)
215 {
216 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
217 ExFreePool(fip);
218 if (SymLinkList != NULL)
219 ExFreePool(SymLinkList);
220 RtlFreeUnicodeString(&BaseKeyName);
221 ZwClose(InterfaceKey);
222 return Status;
223 }
224
225 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
226 ASSERT(bip != NULL);
227
228 Status = ZwEnumerateKey(
229 InterfaceKey,
230 i,
231 KeyBasicInformation,
232 bip,
233 Size,
234 &Size);
235
236 if (!NT_SUCCESS(Status))
237 {
238 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
239 ExFreePool(fip);
240 ExFreePool(bip);
241 if (SymLinkList != NULL)
242 ExFreePool(SymLinkList);
243 RtlFreeUnicodeString(&BaseKeyName);
244 ZwClose(InterfaceKey);
245 return Status;
246 }
247
248 SubKeyName.Length = 0;
249 SubKeyName.MaximumLength = BaseKeyName.Length + bip->NameLength + sizeof(WCHAR);
250 SubKeyName.Buffer = ExAllocatePool(NonPagedPool, SubKeyName.MaximumLength);
251 ASSERT(SubKeyName.Buffer != NULL);
252 TempString.Length = TempString.MaximumLength = bip->NameLength;
253 TempString.Buffer = bip->Name;
254 RtlCopyUnicodeString(&SubKeyName, &BaseKeyName);
255 RtlAppendUnicodeToString(&SubKeyName, L"\\");
256 RtlAppendUnicodeStringToString(&SubKeyName, &TempString);
257
258 ExFreePool(bip);
259
260 InitializeObjectAttributes(
261 &ObjectAttributes,
262 &SubKeyName,
263 OBJ_CASE_INSENSITIVE,
264 NULL,
265 NULL);
266
267 Status = ZwOpenKey(
268 &SubKey,
269 KEY_READ,
270 &ObjectAttributes);
271
272 if (!NT_SUCCESS(Status))
273 {
274 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
275 ExFreePool(fip);
276 if (SymLinkList != NULL)
277 ExFreePool(SymLinkList);
278 RtlFreeUnicodeString(&SubKeyName);
279 RtlFreeUnicodeString(&BaseKeyName);
280 ZwClose(InterfaceKey);
281 return Status;
282 }
283
284 Status = ZwQueryKey(
285 SubKey,
286 KeyFullInformation,
287 NULL,
288 0,
289 &Size);
290
291 if (Status != STATUS_BUFFER_TOO_SMALL)
292 {
293 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
294 ExFreePool(fip);
295 RtlFreeUnicodeString(&BaseKeyName);
296 RtlFreeUnicodeString(&SubKeyName);
297 ZwClose(SubKey);
298 ZwClose(InterfaceKey);
299 return Status;
300 }
301
302 bfip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
303 ASSERT(bfip != NULL);
304
305 Status = ZwQueryKey(
306 SubKey,
307 KeyFullInformation,
308 bfip,
309 Size,
310 &Size);
311
312 if (!NT_SUCCESS(Status))
313 {
314 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
315 ExFreePool(fip);
316 RtlFreeUnicodeString(&SubKeyName);
317 RtlFreeUnicodeString(&BaseKeyName);
318 ZwClose(SubKey);
319 ZwClose(InterfaceKey);
320 return Status;
321 }
322
323 for(j = 0; j < bfip->SubKeys; j++)
324 {
325 Status = ZwEnumerateKey(
326 SubKey,
327 j,
328 KeyBasicInformation,
329 NULL,
330 0,
331 &Size);
332
333 if (Status == STATUS_NO_MORE_ENTRIES)
334 continue;
335
336 if (Status != STATUS_BUFFER_TOO_SMALL)
337 {
338 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
339 ExFreePool(bfip);
340 ExFreePool(fip);
341 if (SymLinkList != NULL)
342 ExFreePool(SymLinkList);
343 RtlFreeUnicodeString(&SubKeyName);
344 RtlFreeUnicodeString(&BaseKeyName);
345 ZwClose(SubKey);
346 ZwClose(InterfaceKey);
347 return Status;
348 }
349
350 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
351 ASSERT(bip != NULL);
352
353 Status = ZwEnumerateKey(
354 SubKey,
355 j,
356 KeyBasicInformation,
357 bip,
358 Size,
359 &Size);
360
361 if (!NT_SUCCESS(Status))
362 {
363 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
364 ExFreePool(fip);
365 ExFreePool(bfip);
366 ExFreePool(bip);
367 if (SymLinkList != NULL)
368 ExFreePool(SymLinkList);
369 RtlFreeUnicodeString(&SubKeyName);
370 RtlFreeUnicodeString(&BaseKeyName);
371 ZwClose(SubKey);
372 ZwClose(InterfaceKey);
373 return Status;
374 }
375
376 if (!wcsncmp(bip->Name, L"Control", bip->NameLength))
377 {
378 continue;
379 }
380
381 SymbolicLinkKeyName.Length = 0;
382 SymbolicLinkKeyName.MaximumLength = SubKeyName.Length + bip->NameLength + sizeof(WCHAR);
383 SymbolicLinkKeyName.Buffer = ExAllocatePool(NonPagedPool, SymbolicLinkKeyName.MaximumLength);
384 ASSERT(SymbolicLinkKeyName.Buffer != NULL);
385 TempString.Length = TempString.MaximumLength = bip->NameLength;
386 TempString.Buffer = bip->Name;
387 RtlCopyUnicodeString(&SymbolicLinkKeyName, &SubKeyName);
388 RtlAppendUnicodeToString(&SymbolicLinkKeyName, L"\\");
389 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName, &TempString);
390
391 ControlKeyName.Length = 0;
392 ControlKeyName.MaximumLength = SymbolicLinkKeyName.Length + Control.Length + sizeof(WCHAR);
393 ControlKeyName.Buffer = ExAllocatePool(NonPagedPool, ControlKeyName.MaximumLength);
394 ASSERT(ControlKeyName.Buffer != NULL);
395 RtlCopyUnicodeString(&ControlKeyName, &SymbolicLinkKeyName);
396 RtlAppendUnicodeStringToString(&ControlKeyName, &Control);
397
398 ExFreePool(bip);
399
400 InitializeObjectAttributes(
401 &ObjectAttributes,
402 &SymbolicLinkKeyName,
403 OBJ_CASE_INSENSITIVE,
404 NULL,
405 NULL);
406
407 Status = ZwOpenKey(
408 &SymbolicLinkKey,
409 KEY_READ,
410 &ObjectAttributes);
411
412 if (!NT_SUCCESS(Status))
413 {
414 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
415 ExFreePool(fip);
416 ExFreePool(bfip);
417 if (SymLinkList != NULL)
418 ExFreePool(SymLinkList);
419 RtlFreeUnicodeString(&SymbolicLinkKeyName);
420 RtlFreeUnicodeString(&SubKeyName);
421 RtlFreeUnicodeString(&BaseKeyName);
422 ZwClose(SubKey);
423 ZwClose(InterfaceKey);
424 return Status;
425 }
426
427 Status = ZwQueryValueKey(
428 SymbolicLinkKey,
429 &SymbolicLink,
430 KeyValuePartialInformation,
431 NULL,
432 0,
433 &Size);
434
435 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
436 continue;
437
438 if (Status != STATUS_BUFFER_TOO_SMALL)
439 {
440 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
441 ExFreePool(fip);
442 ExFreePool(bfip);
443 if (SymLinkList != NULL)
444 ExFreePool(SymLinkList);
445 RtlFreeUnicodeString(&SymbolicLinkKeyName);
446 RtlFreeUnicodeString(&SubKeyName);
447 RtlFreeUnicodeString(&BaseKeyName);
448 ZwClose(SymbolicLinkKey);
449 ZwClose(SubKey);
450 ZwClose(InterfaceKey);
451 return Status;
452 }
453
454 vpip = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
455 ASSERT(vpip != NULL);
456
457 Status = ZwQueryValueKey(
458 SymbolicLinkKey,
459 &SymbolicLink,
460 KeyValuePartialInformation,
461 vpip,
462 Size,
463 &Size);
464
465 if (!NT_SUCCESS(Status))
466 {
467 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
468 ExFreePool(fip);
469 ExFreePool(bfip);
470 ExFreePool(vpip);
471 if (SymLinkList != NULL)
472 ExFreePool(SymLinkList);
473 RtlFreeUnicodeString(&SymbolicLinkKeyName);
474 RtlFreeUnicodeString(&SubKeyName);
475 RtlFreeUnicodeString(&BaseKeyName);
476 ZwClose(SymbolicLinkKey);
477 ZwClose(SubKey);
478 ZwClose(InterfaceKey);
479 return Status;
480 }
481
482 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ControlKeyName.Buffer);
483
484 if (NT_SUCCESS(Status))
485 {
486 /* Put the name in the string here */
487 if (SymLinkList == NULL)
488 {
489 SymLinkListSize = vpip->DataLength;
490 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
491 ASSERT(SymLinkList != NULL);
492 RtlCopyMemory(SymLinkList, vpip->Data, vpip->DataLength);
493 SymLinkList[vpip->DataLength / sizeof(WCHAR)] = 0;
494 SymLinkList[1] = '?';
495 }
496 else
497 {
498 PWCHAR OldSymLinkList;
499 ULONG OldSymLinkListSize;
500 PWCHAR SymLinkListPtr;
501
502 OldSymLinkList = SymLinkList;
503 OldSymLinkListSize = SymLinkListSize;
504 SymLinkListSize += vpip->DataLength;
505 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
506 ASSERT(SymLinkList != NULL);
507 RtlCopyMemory(SymLinkList, OldSymLinkList, OldSymLinkListSize);
508 ExFreePool(OldSymLinkList);
509 SymLinkListPtr = SymLinkList + (OldSymLinkListSize / sizeof(WCHAR));
510 RtlCopyMemory(SymLinkListPtr, vpip->Data, vpip->DataLength);
511 SymLinkListPtr[vpip->DataLength / sizeof(WCHAR)] = 0;
512 SymLinkListPtr[1] = '?';
513 }
514 }
515
516 RtlFreeUnicodeString(&SymbolicLinkKeyName);
517 RtlFreeUnicodeString(&ControlKeyName);
518 ZwClose(SymbolicLinkKey);
519 }
520
521 ExFreePool(vpip);
522 RtlFreeUnicodeString(&SubKeyName);
523 ZwClose(SubKey);
524 }
525
526 if (SymLinkList != NULL)
527 {
528 SymLinkList[SymLinkListSize / sizeof(WCHAR)] = 0;
529 }
530 else
531 {
532 SymLinkList = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
533 SymLinkList[0] = 0;
534 }
535
536 *SymbolicLinkList = SymLinkList;
537
538 RtlFreeUnicodeString(&BaseKeyName);
539 ZwClose(InterfaceKey);
540 ExFreePool(bfip);
541 ExFreePool(fip);
542 }
543
544 return STATUS_SUCCESS;
545 }