IoRegisterDeviceInterface: Create nested keys one-by-one.
[reactos.git] / reactos / ntoskrnl / io / deviface.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/deviface.c
6 * PURPOSE: Device interface functions
7 *
8 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
9 * Matthew Brace (ismarc@austin.rr.com)
10 * Hervé Poussineau (hpoussin@reactos.com)
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <ntoskrnl.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* FUNCTIONS *****************************************************************/
21
22 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
23
24 /*
25 * @unimplemented
26 */
27
28 NTSTATUS STDCALL
29 IoOpenDeviceInterfaceRegistryKey(
30 IN PUNICODE_STRING SymbolicLinkName,
31 IN ACCESS_MASK DesiredAccess,
32 OUT PHANDLE DeviceInterfaceKey)
33 {
34 return STATUS_NOT_IMPLEMENTED;
35 }
36
37 /*
38 * @unimplemented
39 */
40
41 NTSTATUS STDCALL
42 IoGetDeviceInterfaceAlias(
43 IN PUNICODE_STRING SymbolicLinkName,
44 IN CONST GUID *AliasInterfaceClassGuid,
45 OUT PUNICODE_STRING AliasSymbolicLinkName)
46 {
47 return STATUS_NOT_IMPLEMENTED;
48 }
49
50 /*
51 * IoGetDeviceInterfaces
52 *
53 * Returns a list of device interfaces of a particular device interface class.
54 *
55 * Parameters
56 * InterfaceClassGuid
57 * Points to a class GUID specifying the device interface class.
58 *
59 * PhysicalDeviceObject
60 * Points to an optional PDO that narrows the search to only the
61 * device interfaces of the device represented by the PDO.
62 *
63 * Flags
64 * Specifies flags that modify the search for device interfaces. The
65 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
66 * returned symbolic links should contain also disabled device
67 * interfaces in addition to the enabled ones.
68 *
69 * SymbolicLinkList
70 * Points to a character pointer that is filled in on successful return
71 * with a list of unicode strings identifying the device interfaces
72 * that match the search criteria. The newly allocated buffer contains
73 * a list of symbolic link names. Each unicode string in the list is
74 * null-terminated; the end of the whole list is marked by an additional
75 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
76 * when it is no longer needed.
77 * If no device interfaces match the search criteria, this routine
78 * returns STATUS_SUCCESS and the string contains a single NULL
79 * character.
80 *
81 * Status
82 * @implemented
83 *
84 * The parameters PhysicalDeviceObject and Flags aren't correctly
85 * processed. Rest of the cases was tested under Windows(R) XP and
86 * the function worked correctly.
87 */
88
89 NTSTATUS STDCALL
90 IoGetDeviceInterfaces(
91 IN CONST GUID *InterfaceClassGuid,
92 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
93 IN ULONG Flags,
94 OUT PWSTR *SymbolicLinkList)
95 {
96 PWCHAR BaseInterfaceString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
97 UNICODE_STRING GuidString;
98 UNICODE_STRING BaseKeyName;
99 UNICODE_STRING AliasKeyName;
100 UNICODE_STRING SymbolicLink;
101 UNICODE_STRING Control;
102 UNICODE_STRING SubKeyName;
103 UNICODE_STRING SymbolicLinkKeyName;
104 UNICODE_STRING ControlKeyName;
105 UNICODE_STRING TempString;
106 HANDLE InterfaceKey;
107 HANDLE SubKey;
108 HANDLE SymbolicLinkKey;
109 PKEY_FULL_INFORMATION fip;
110 PKEY_FULL_INFORMATION bfip = NULL;
111 PKEY_BASIC_INFORMATION bip;
112 PKEY_VALUE_PARTIAL_INFORMATION vpip = NULL;
113 PWCHAR SymLinkList = NULL;
114 ULONG SymLinkListSize = 0;
115 NTSTATUS Status;
116 ULONG Size = 0;
117 ULONG i = 0;
118 ULONG j = 0;
119 OBJECT_ATTRIBUTES ObjectAttributes;
120
121 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
122 if (!NT_SUCCESS(Status))
123 {
124 DPRINT("RtlStringFromGUID() Failed.\n");
125 return STATUS_INVALID_HANDLE;
126 }
127
128 RtlInitUnicodeString(&AliasKeyName, BaseInterfaceString);
129 RtlInitUnicodeString(&SymbolicLink, L"SymbolicLink");
130 RtlInitUnicodeString(&Control, L"\\Control");
131 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
132 BaseKeyName.MaximumLength = BaseKeyName.Length + (38 * sizeof(WCHAR));
133 BaseKeyName.Buffer = ExAllocatePool(
134 NonPagedPool,
135 BaseKeyName.MaximumLength);
136 ASSERT(BaseKeyName.Buffer != NULL);
137 wcscpy(BaseKeyName.Buffer, BaseKeyString);
138 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
139
140 if (PhysicalDeviceObject)
141 {
142 WCHAR GuidBuffer[40];
143 UNICODE_STRING PdoGuidString;
144
145 RtlFreeUnicodeString(&BaseKeyName);
146
147 IoGetDeviceProperty(
148 PhysicalDeviceObject,
149 DevicePropertyClassGuid,
150 sizeof(GuidBuffer),
151 GuidBuffer,
152 &Size);
153
154 RtlInitUnicodeString(&PdoGuidString, GuidBuffer);
155 if (RtlCompareUnicodeString(&GuidString, &PdoGuidString, TRUE))
156 {
157 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
158 return STATUS_INVALID_HANDLE;
159 }
160
161 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
162 return STATUS_NOT_IMPLEMENTED;
163 }
164 else
165 {
166 InitializeObjectAttributes(
167 &ObjectAttributes,
168 &BaseKeyName,
169 OBJ_CASE_INSENSITIVE,
170 NULL,
171 NULL);
172
173 Status = ZwOpenKey(
174 &InterfaceKey,
175 KEY_READ,
176 &ObjectAttributes);
177
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
181 RtlFreeUnicodeString(&BaseKeyName);
182 return Status;
183 }
184
185 Status = ZwQueryKey(
186 InterfaceKey,
187 KeyFullInformation,
188 NULL,
189 0,
190 &Size);
191
192 if (Status != STATUS_BUFFER_TOO_SMALL)
193 {
194 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
195 RtlFreeUnicodeString(&BaseKeyName);
196 ZwClose(InterfaceKey);
197 return Status;
198 }
199
200 fip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
201 ASSERT(fip != NULL);
202
203 Status = ZwQueryKey(
204 InterfaceKey,
205 KeyFullInformation,
206 fip,
207 Size,
208 &Size);
209
210 if (!NT_SUCCESS(Status))
211 {
212 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
213 ExFreePool(fip);
214 RtlFreeUnicodeString(&BaseKeyName);
215 ZwClose(InterfaceKey);
216 return Status;
217 }
218
219 for (; i < fip->SubKeys; i++)
220 {
221 Status = ZwEnumerateKey(
222 InterfaceKey,
223 i,
224 KeyBasicInformation,
225 NULL,
226 0,
227 &Size);
228
229 if (Status != STATUS_BUFFER_TOO_SMALL)
230 {
231 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
232 ExFreePool(fip);
233 if (SymLinkList != NULL)
234 ExFreePool(SymLinkList);
235 RtlFreeUnicodeString(&BaseKeyName);
236 ZwClose(InterfaceKey);
237 return Status;
238 }
239
240 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
241 ASSERT(bip != NULL);
242
243 Status = ZwEnumerateKey(
244 InterfaceKey,
245 i,
246 KeyBasicInformation,
247 bip,
248 Size,
249 &Size);
250
251 if (!NT_SUCCESS(Status))
252 {
253 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
254 ExFreePool(fip);
255 ExFreePool(bip);
256 if (SymLinkList != NULL)
257 ExFreePool(SymLinkList);
258 RtlFreeUnicodeString(&BaseKeyName);
259 ZwClose(InterfaceKey);
260 return Status;
261 }
262
263 SubKeyName.Length = 0;
264 SubKeyName.MaximumLength = BaseKeyName.Length + bip->NameLength + sizeof(WCHAR);
265 SubKeyName.Buffer = ExAllocatePool(NonPagedPool, SubKeyName.MaximumLength);
266 ASSERT(SubKeyName.Buffer != NULL);
267 TempString.Length = TempString.MaximumLength = bip->NameLength;
268 TempString.Buffer = bip->Name;
269 RtlCopyUnicodeString(&SubKeyName, &BaseKeyName);
270 RtlAppendUnicodeToString(&SubKeyName, L"\\");
271 RtlAppendUnicodeStringToString(&SubKeyName, &TempString);
272
273 ExFreePool(bip);
274
275 InitializeObjectAttributes(
276 &ObjectAttributes,
277 &SubKeyName,
278 OBJ_CASE_INSENSITIVE,
279 NULL,
280 NULL);
281
282 Status = ZwOpenKey(
283 &SubKey,
284 KEY_READ,
285 &ObjectAttributes);
286
287 if (!NT_SUCCESS(Status))
288 {
289 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
290 ExFreePool(fip);
291 if (SymLinkList != NULL)
292 ExFreePool(SymLinkList);
293 RtlFreeUnicodeString(&SubKeyName);
294 RtlFreeUnicodeString(&BaseKeyName);
295 ZwClose(InterfaceKey);
296 return Status;
297 }
298
299 Status = ZwQueryKey(
300 SubKey,
301 KeyFullInformation,
302 NULL,
303 0,
304 &Size);
305
306 if (Status != STATUS_BUFFER_TOO_SMALL)
307 {
308 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
309 ExFreePool(fip);
310 RtlFreeUnicodeString(&BaseKeyName);
311 RtlFreeUnicodeString(&SubKeyName);
312 ZwClose(SubKey);
313 ZwClose(InterfaceKey);
314 return Status;
315 }
316
317 bfip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
318 ASSERT(bfip != NULL);
319
320 Status = ZwQueryKey(
321 SubKey,
322 KeyFullInformation,
323 bfip,
324 Size,
325 &Size);
326
327 if (!NT_SUCCESS(Status))
328 {
329 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
330 ExFreePool(fip);
331 RtlFreeUnicodeString(&SubKeyName);
332 RtlFreeUnicodeString(&BaseKeyName);
333 ZwClose(SubKey);
334 ZwClose(InterfaceKey);
335 return Status;
336 }
337
338 for(j = 0; j < bfip->SubKeys; j++)
339 {
340 Status = ZwEnumerateKey(
341 SubKey,
342 j,
343 KeyBasicInformation,
344 NULL,
345 0,
346 &Size);
347
348 if (Status == STATUS_NO_MORE_ENTRIES)
349 continue;
350
351 if (Status != STATUS_BUFFER_TOO_SMALL)
352 {
353 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
354 ExFreePool(bfip);
355 ExFreePool(fip);
356 if (SymLinkList != NULL)
357 ExFreePool(SymLinkList);
358 RtlFreeUnicodeString(&SubKeyName);
359 RtlFreeUnicodeString(&BaseKeyName);
360 ZwClose(SubKey);
361 ZwClose(InterfaceKey);
362 return Status;
363 }
364
365 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
366 ASSERT(bip != NULL);
367
368 Status = ZwEnumerateKey(
369 SubKey,
370 j,
371 KeyBasicInformation,
372 bip,
373 Size,
374 &Size);
375
376 if (!NT_SUCCESS(Status))
377 {
378 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
379 ExFreePool(fip);
380 ExFreePool(bfip);
381 ExFreePool(bip);
382 if (SymLinkList != NULL)
383 ExFreePool(SymLinkList);
384 RtlFreeUnicodeString(&SubKeyName);
385 RtlFreeUnicodeString(&BaseKeyName);
386 ZwClose(SubKey);
387 ZwClose(InterfaceKey);
388 return Status;
389 }
390
391 if (!wcsncmp(bip->Name, L"Control", bip->NameLength))
392 {
393 continue;
394 }
395
396 SymbolicLinkKeyName.Length = 0;
397 SymbolicLinkKeyName.MaximumLength = SubKeyName.Length + bip->NameLength + sizeof(WCHAR);
398 SymbolicLinkKeyName.Buffer = ExAllocatePool(NonPagedPool, SymbolicLinkKeyName.MaximumLength);
399 ASSERT(SymbolicLinkKeyName.Buffer != NULL);
400 TempString.Length = TempString.MaximumLength = bip->NameLength;
401 TempString.Buffer = bip->Name;
402 RtlCopyUnicodeString(&SymbolicLinkKeyName, &SubKeyName);
403 RtlAppendUnicodeToString(&SymbolicLinkKeyName, L"\\");
404 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName, &TempString);
405
406 ControlKeyName.Length = 0;
407 ControlKeyName.MaximumLength = SymbolicLinkKeyName.Length + Control.Length + sizeof(WCHAR);
408 ControlKeyName.Buffer = ExAllocatePool(NonPagedPool, ControlKeyName.MaximumLength);
409 ASSERT(ControlKeyName.Buffer != NULL);
410 RtlCopyUnicodeString(&ControlKeyName, &SymbolicLinkKeyName);
411 RtlAppendUnicodeStringToString(&ControlKeyName, &Control);
412
413 ExFreePool(bip);
414
415 InitializeObjectAttributes(
416 &ObjectAttributes,
417 &SymbolicLinkKeyName,
418 OBJ_CASE_INSENSITIVE,
419 NULL,
420 NULL);
421
422 Status = ZwOpenKey(
423 &SymbolicLinkKey,
424 KEY_READ,
425 &ObjectAttributes);
426
427 if (!NT_SUCCESS(Status))
428 {
429 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
430 ExFreePool(fip);
431 ExFreePool(bfip);
432 if (SymLinkList != NULL)
433 ExFreePool(SymLinkList);
434 RtlFreeUnicodeString(&SymbolicLinkKeyName);
435 RtlFreeUnicodeString(&SubKeyName);
436 RtlFreeUnicodeString(&BaseKeyName);
437 ZwClose(SubKey);
438 ZwClose(InterfaceKey);
439 return Status;
440 }
441
442 Status = ZwQueryValueKey(
443 SymbolicLinkKey,
444 &SymbolicLink,
445 KeyValuePartialInformation,
446 NULL,
447 0,
448 &Size);
449
450 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
451 continue;
452
453 if (Status != STATUS_BUFFER_TOO_SMALL)
454 {
455 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
456 ExFreePool(fip);
457 ExFreePool(bfip);
458 if (SymLinkList != NULL)
459 ExFreePool(SymLinkList);
460 RtlFreeUnicodeString(&SymbolicLinkKeyName);
461 RtlFreeUnicodeString(&SubKeyName);
462 RtlFreeUnicodeString(&BaseKeyName);
463 ZwClose(SymbolicLinkKey);
464 ZwClose(SubKey);
465 ZwClose(InterfaceKey);
466 return Status;
467 }
468
469 vpip = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
470 ASSERT(vpip != NULL);
471
472 Status = ZwQueryValueKey(
473 SymbolicLinkKey,
474 &SymbolicLink,
475 KeyValuePartialInformation,
476 vpip,
477 Size,
478 &Size);
479
480 if (!NT_SUCCESS(Status))
481 {
482 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
483 ExFreePool(fip);
484 ExFreePool(bfip);
485 ExFreePool(vpip);
486 if (SymLinkList != NULL)
487 ExFreePool(SymLinkList);
488 RtlFreeUnicodeString(&SymbolicLinkKeyName);
489 RtlFreeUnicodeString(&SubKeyName);
490 RtlFreeUnicodeString(&BaseKeyName);
491 ZwClose(SymbolicLinkKey);
492 ZwClose(SubKey);
493 ZwClose(InterfaceKey);
494 return Status;
495 }
496
497 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ControlKeyName.Buffer);
498
499 if (NT_SUCCESS(Status))
500 {
501 /* Put the name in the string here */
502 if (SymLinkList == NULL)
503 {
504 SymLinkListSize = vpip->DataLength;
505 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
506 ASSERT(SymLinkList != NULL);
507 RtlCopyMemory(SymLinkList, vpip->Data, vpip->DataLength);
508 SymLinkList[vpip->DataLength / sizeof(WCHAR)] = 0;
509 SymLinkList[1] = '?';
510 }
511 else
512 {
513 PWCHAR OldSymLinkList;
514 ULONG OldSymLinkListSize;
515 PWCHAR SymLinkListPtr;
516
517 OldSymLinkList = SymLinkList;
518 OldSymLinkListSize = SymLinkListSize;
519 SymLinkListSize += vpip->DataLength;
520 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
521 ASSERT(SymLinkList != NULL);
522 RtlCopyMemory(SymLinkList, OldSymLinkList, OldSymLinkListSize);
523 ExFreePool(OldSymLinkList);
524 SymLinkListPtr = SymLinkList + (OldSymLinkListSize / sizeof(WCHAR));
525 RtlCopyMemory(SymLinkListPtr, vpip->Data, vpip->DataLength);
526 SymLinkListPtr[vpip->DataLength / sizeof(WCHAR)] = 0;
527 SymLinkListPtr[1] = '?';
528 }
529 }
530
531 RtlFreeUnicodeString(&SymbolicLinkKeyName);
532 RtlFreeUnicodeString(&ControlKeyName);
533 ZwClose(SymbolicLinkKey);
534 }
535
536 ExFreePool(vpip);
537 RtlFreeUnicodeString(&SubKeyName);
538 ZwClose(SubKey);
539 }
540
541 if (SymLinkList != NULL)
542 {
543 SymLinkList[SymLinkListSize / sizeof(WCHAR)] = 0;
544 }
545 else
546 {
547 SymLinkList = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
548 SymLinkList[0] = 0;
549 }
550
551 *SymbolicLinkList = SymLinkList;
552
553 RtlFreeUnicodeString(&BaseKeyName);
554 ZwClose(InterfaceKey);
555 ExFreePool(bfip);
556 ExFreePool(fip);
557 }
558
559 return STATUS_SUCCESS;
560 }
561
562 /*
563 * @implemented
564 */
565
566 NTSTATUS STDCALL
567 IoRegisterDeviceInterface(
568 IN PDEVICE_OBJECT PhysicalDeviceObject,
569 IN CONST GUID *InterfaceClassGuid,
570 IN PUNICODE_STRING ReferenceString OPTIONAL,
571 OUT PUNICODE_STRING SymbolicLinkName)
572 {
573 PUNICODE_STRING InstancePath;
574 UNICODE_STRING GuidString;
575 UNICODE_STRING SubKeyName;
576 UNICODE_STRING InterfaceKeyName;
577 UNICODE_STRING BaseKeyName;
578 UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))];
579 POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer;
580 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance");
581 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
582 HANDLE ClassKey;
583 HANDLE InterfaceKey;
584 HANDLE SubKey;
585 ULONG StartIndex;
586 OBJECT_ATTRIBUTES ObjectAttributes;
587 ULONG i;
588 NTSTATUS Status;
589
590 if (!(PhysicalDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE))
591 {
592 DPRINT("PhysicalDeviceObject 0x%p is not a valid Pdo\n", PhysicalDeviceObject);
593 return STATUS_INVALID_PARAMETER_1;
594 }
595
596 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
597 if (!NT_SUCCESS(Status))
598 {
599 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
600 return Status;
601 }
602
603 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
604 Status = ObQueryNameString(
605 PhysicalDeviceObject,
606 PdoNameInfo,
607 sizeof(PdoNameInfoBuffer),
608 &i);
609 if (!NT_SUCCESS(Status))
610 {
611 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status);
612 return Status;
613 }
614 ASSERT(PdoNameInfo->Name.Length);
615
616 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
617 ASSERT(PhysicalDeviceObject->DeviceObjectExtension->DeviceNode);
618 InstancePath = &PhysicalDeviceObject->DeviceObjectExtension->DeviceNode->InstancePath;
619 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
620 BaseKeyName.MaximumLength = BaseKeyName.Length
621 + GuidString.Length;
622 BaseKeyName.Buffer = ExAllocatePool(
623 NonPagedPool,
624 BaseKeyName.MaximumLength);
625 if (!BaseKeyName.Buffer)
626 {
627 DPRINT("ExAllocatePool() failed\n");
628 return STATUS_INSUFFICIENT_RESOURCES;
629 }
630 wcscpy(BaseKeyName.Buffer, BaseKeyString);
631 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
632
633 /* Create BaseKeyName key in registry */
634 InitializeObjectAttributes(
635 &ObjectAttributes,
636 &BaseKeyName,
637 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
638 NULL, /* RootDirectory */
639 NULL); /* SecurityDescriptor */
640
641 Status = ZwCreateKey(
642 &ClassKey,
643 KEY_WRITE,
644 &ObjectAttributes,
645 0, /* TileIndex */
646 NULL, /* Class */
647 REG_OPTION_VOLATILE,
648 NULL); /* Disposition */
649
650 if (!NT_SUCCESS(Status))
651 {
652 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
653 ExFreePool(BaseKeyName.Buffer);
654 return Status;
655 }
656
657 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
658 InterfaceKeyName.Length = 0;
659 InterfaceKeyName.MaximumLength =
660 4 * sizeof(WCHAR) + /* 4 = size of ##?# */
661 InstancePath->Length +
662 sizeof(WCHAR) + /* 1 = size of # */
663 GuidString.Length;
664 InterfaceKeyName.Buffer = ExAllocatePool(
665 NonPagedPool,
666 InterfaceKeyName.MaximumLength);
667 if (!InterfaceKeyName.Buffer)
668 {
669 DPRINT("ExAllocatePool() failed\n");
670 return STATUS_INSUFFICIENT_RESOURCES;
671 }
672
673 RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#");
674 StartIndex = InterfaceKeyName.Length / sizeof(WCHAR);
675 RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath);
676 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
677 {
678 if (InterfaceKeyName.Buffer[StartIndex + i] == '\\')
679 InterfaceKeyName.Buffer[StartIndex + i] = '#';
680 }
681 RtlAppendUnicodeToString(&InterfaceKeyName, L"#");
682 RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString);
683
684 /* Create the interface key in registry */
685 InitializeObjectAttributes(
686 &ObjectAttributes,
687 &InterfaceKeyName,
688 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
689 ClassKey,
690 NULL); /* SecurityDescriptor */
691
692 Status = ZwCreateKey(
693 &InterfaceKey,
694 KEY_WRITE,
695 &ObjectAttributes,
696 0, /* TileIndex */
697 NULL, /* Class */
698 REG_OPTION_VOLATILE,
699 NULL); /* Disposition */
700
701 if (!NT_SUCCESS(Status))
702 {
703 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
704 ZwClose(ClassKey);
705 ExFreePool(BaseKeyName.Buffer);
706 return Status;
707 }
708
709 /* Write DeviceInstance entry. Value is InstancePath */
710 Status = ZwSetValueKey(
711 InterfaceKey,
712 &DeviceInstance,
713 0, /* TileIndex */
714 REG_SZ,
715 InstancePath->Buffer,
716 InstancePath->Length);
717 if (!NT_SUCCESS(Status))
718 {
719 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
720 ZwClose(InterfaceKey);
721 ZwClose(ClassKey);
722 ExFreePool(InterfaceKeyName.Buffer);
723 ExFreePool(BaseKeyName.Buffer);
724 return Status;
725 }
726
727 /* Create subkey. Name is #ReferenceString */
728 SubKeyName.Length = 0;
729 SubKeyName.MaximumLength = sizeof(WCHAR);
730 if (ReferenceString && ReferenceString->Length)
731 SubKeyName.MaximumLength += ReferenceString->Length;
732 SubKeyName.Buffer = ExAllocatePool(
733 NonPagedPool,
734 SubKeyName.MaximumLength);
735 if (!SubKeyName.Buffer)
736 {
737 DPRINT("ExAllocatePool() failed\n");
738 ZwClose(InterfaceKey);
739 ZwClose(ClassKey);
740 ExFreePool(InterfaceKeyName.Buffer);
741 ExFreePool(BaseKeyName.Buffer);
742 return STATUS_INSUFFICIENT_RESOURCES;
743 }
744 RtlAppendUnicodeToString(&SubKeyName, L"#");
745 if (ReferenceString && ReferenceString->Length)
746 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString);
747
748 /* Create SubKeyName key in registry */
749 InitializeObjectAttributes(
750 &ObjectAttributes,
751 &SubKeyName,
752 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
753 InterfaceKey, /* RootDirectory */
754 NULL); /* SecurityDescriptor */
755
756 Status = ZwCreateKey(
757 &SubKey,
758 KEY_WRITE,
759 &ObjectAttributes,
760 0, /* TileIndex */
761 NULL, /* Class */
762 REG_OPTION_VOLATILE,
763 NULL); /* Disposition */
764
765 if (!NT_SUCCESS(Status))
766 {
767 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
768 ZwClose(InterfaceKey);
769 ZwClose(ClassKey);
770 ExFreePool(InterfaceKeyName.Buffer);
771 ExFreePool(BaseKeyName.Buffer);
772 return Status;
773 }
774
775 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
776 SymbolicLinkName->Length = 0;
777 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length
778 + 4 * sizeof(WCHAR) /* 4 = size of \??\ */
779 + InstancePath->Length
780 + sizeof(WCHAR) /* 1 = size of # */
781 + GuidString.Length
782 + sizeof(WCHAR); /* final NULL */
783 if (ReferenceString && ReferenceString->Length)
784 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length;
785 SymbolicLinkName->Buffer = ExAllocatePool(
786 NonPagedPool,
787 SymbolicLinkName->MaximumLength);
788 if (!SymbolicLinkName->Buffer)
789 {
790 DPRINT("ExAllocatePool() failed\n");
791 ZwClose(SubKey);
792 ZwClose(InterfaceKey);
793 ZwClose(ClassKey);
794 ExFreePool(InterfaceKeyName.Buffer);
795 ExFreePool(SubKeyName.Buffer);
796 ExFreePool(BaseKeyName.Buffer);
797 return STATUS_INSUFFICIENT_RESOURCES;
798 }
799 RtlAppendUnicodeToString(SymbolicLinkName, L"\\??\\");
800 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR);
801 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath);
802 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
803 {
804 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\')
805 SymbolicLinkName->Buffer[StartIndex + i] = '#';
806 }
807 RtlAppendUnicodeToString(SymbolicLinkName, L"#");
808 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString);
809 if (ReferenceString && ReferenceString->Length)
810 {
811 RtlAppendUnicodeToString(SymbolicLinkName, L"\\");
812 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString);
813 }
814 SymbolicLinkName->Buffer[SymbolicLinkName->Length] = '\0';
815
816 /* Create symbolic link */
817 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName, &PdoNameInfo->Name);
818 Status = IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name);
819 if (!NT_SUCCESS(Status))
820 {
821 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status);
822 ZwClose(SubKey);
823 ZwClose(InterfaceKey);
824 ZwClose(ClassKey);
825 ExFreePool(SubKeyName.Buffer);
826 ExFreePool(InterfaceKeyName.Buffer);
827 ExFreePool(BaseKeyName.Buffer);
828 ExFreePool(SymbolicLinkName->Buffer);
829 return Status;
830 }
831
832 /* Write symbolic link name in registry */
833 Status = ZwSetValueKey(
834 SubKey,
835 &SymbolicLink,
836 0, /* TileIndex */
837 REG_SZ,
838 SymbolicLinkName->Buffer,
839 SymbolicLinkName->Length);
840 if (!NT_SUCCESS(Status))
841 {
842 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
843 ExFreePool(SymbolicLinkName->Buffer);
844 }
845
846 ZwClose(SubKey);
847 ZwClose(InterfaceKey);
848 ZwClose(ClassKey);
849 ExFreePool(SubKeyName.Buffer);
850 ExFreePool(InterfaceKeyName.Buffer);
851 ExFreePool(BaseKeyName.Buffer);
852
853 return Status;
854 }
855
856 /*
857 * @implemented
858 */
859
860 NTSTATUS STDCALL
861 IoSetDeviceInterfaceState(
862 IN PUNICODE_STRING SymbolicLinkName,
863 IN BOOLEAN Enable)
864 {
865 PDEVICE_OBJECT PhysicalDeviceObject;
866 PFILE_OBJECT FileObject;
867 UNICODE_STRING GuidString;
868 PWCHAR StartPosition;
869 PWCHAR EndPosition;
870 NTSTATUS Status;
871
872 if (SymbolicLinkName == NULL)
873 return STATUS_INVALID_PARAMETER_1;
874
875 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
876 Status = IoGetDeviceObjectPointer(SymbolicLinkName,
877 0, /* DesiredAccess */
878 &FileObject,
879 &PhysicalDeviceObject);
880 if (!NT_SUCCESS(Status))
881 return Status;
882
883 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
884 /* Get GUID from SymbolicLinkName */
885 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
886 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
887 if (!StartPosition ||!EndPosition || StartPosition > EndPosition)
888 return STATUS_INVALID_PARAMETER_1;
889 GuidString.Buffer = StartPosition;
890 GuidString.MaximumLength = GuidString.Length = (ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition;
891
892 IopNotifyPlugPlayNotification(
893 PhysicalDeviceObject,
894 EventCategoryDeviceInterfaceChange,
895 Enable ? (LPGUID)&GUID_DEVICE_INTERFACE_ARRIVAL : (LPGUID)&GUID_DEVICE_INTERFACE_REMOVAL,
896 &GuidString,
897 (PVOID)SymbolicLinkName);
898
899 ObDereferenceObject(FileObject);
900
901 return STATUS_SUCCESS;
902 }
903
904 /* EOF */