Fixed line endings.
[reactos.git] / reactos / ntoskrnl / io / driver.c
1 /* $Id: driver.c,v 1.21 2003/10/06 18:49:50 navaraf Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/driver.c
6 * PURPOSE: Manage devices
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * 15/05/98: Created
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <limits.h>
15 #include <ddk/ntddk.h>
16 #include <internal/io.h>
17 #include <internal/po.h>
18 #include <internal/ldr.h>
19 #include <internal/id.h>
20 #include <internal/pool.h>
21 #include <internal/registry.h>
22
23 #include <roscfg.h>
24
25 #define NDEBUG
26 #include <internal/debug.h>
27
28
29 typedef struct _SERVICE_GROUP
30 {
31 LIST_ENTRY GroupListEntry;
32 UNICODE_STRING GroupName;
33
34 BOOLEAN ServicesRunning;
35
36 } SERVICE_GROUP, *PSERVICE_GROUP;
37
38
39 typedef struct _SERVICE
40 {
41 LIST_ENTRY ServiceListEntry;
42 UNICODE_STRING ServiceName;
43 UNICODE_STRING RegistryPath;
44 UNICODE_STRING ServiceGroup;
45 UNICODE_STRING ImagePath;
46
47 ULONG Start;
48 ULONG Type;
49 ULONG ErrorControl;
50 ULONG Tag;
51
52 BOOLEAN ServiceRunning; // needed ??
53
54 } SERVICE, *PSERVICE;
55
56
57 /* GLOBALS *******************************************************************/
58
59 static LIST_ENTRY GroupListHead = {NULL, NULL};
60 static LIST_ENTRY ServiceListHead = {NULL, NULL};
61
62 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
63
64 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
65 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
66
67
68 /* FUNCTIONS ***************************************************************/
69
70 NTSTATUS STDCALL
71 IopCreateDriver(PVOID ObjectBody,
72 PVOID Parent,
73 PWSTR RemainingPath,
74 POBJECT_ATTRIBUTES ObjectAttributes)
75 {
76 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
77 ObjectBody,
78 Parent,
79 RemainingPath);
80 if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
81 {
82 return(STATUS_UNSUCCESSFUL);
83 }
84
85 return(STATUS_SUCCESS);
86 }
87
88
89 VOID
90 IopInitDriverImplementation(VOID)
91 {
92 /* Register the process object type */
93 IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
94 IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'R');
95 IoDriverObjectType->TotalObjects = 0;
96 IoDriverObjectType->TotalHandles = 0;
97 IoDriverObjectType->MaxObjects = ULONG_MAX;
98 IoDriverObjectType->MaxHandles = ULONG_MAX;
99 IoDriverObjectType->PagedPoolCharge = 0;
100 IoDriverObjectType->NonpagedPoolCharge = sizeof(DRIVER_OBJECT);
101 IoDriverObjectType->Dump = NULL;
102 IoDriverObjectType->Open = NULL;
103 IoDriverObjectType->Close = NULL;
104 IoDriverObjectType->Delete = NULL;
105 IoDriverObjectType->Parse = NULL;
106 IoDriverObjectType->Security = NULL;
107 IoDriverObjectType->QueryName = NULL;
108 IoDriverObjectType->OkayToClose = NULL;
109 IoDriverObjectType->Create = IopCreateDriver;
110 IoDriverObjectType->DuplicationNotify = NULL;
111 RtlInitUnicodeStringFromLiteral(&IoDriverObjectType->TypeName, L"Driver");
112 }
113
114 /**********************************************************************
115 * NAME EXPORTED
116 * NtLoadDriver
117 *
118 * DESCRIPTION
119 * Loads a device driver.
120 *
121 * ARGUMENTS
122 * DriverServiceName
123 * Name of the service to load (registry key).
124 *
125 * RETURN VALUE
126 * Status.
127 *
128 * REVISIONS
129 */
130 NTSTATUS STDCALL
131 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
132 {
133 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
134 WCHAR FullImagePathBuffer[MAX_PATH];
135 UNICODE_STRING ImagePath;
136 UNICODE_STRING FullImagePath;
137 NTSTATUS Status;
138 ULONG Type;
139 PDEVICE_NODE DeviceNode;
140 PMODULE_OBJECT ModuleObject;
141 LPWSTR Start;
142
143 DPRINT("NtLoadDriver(%wZ) called\n", DriverServiceName);
144
145 RtlInitUnicodeString(&ImagePath, NULL);
146
147 /* Get service data */
148 RtlZeroMemory(&QueryTable,
149 sizeof(QueryTable));
150
151 QueryTable[0].Name = L"Type";
152 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
153 QueryTable[0].EntryContext = &Type;
154
155 QueryTable[1].Name = L"ImagePath";
156 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
157 QueryTable[1].EntryContext = &ImagePath;
158
159 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
160 DriverServiceName->Buffer,
161 QueryTable,
162 NULL,
163 NULL);
164 if (!NT_SUCCESS(Status))
165 {
166 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
167 RtlFreeUnicodeString(&ImagePath);
168 return(Status);
169 }
170
171 if (ImagePath.Length == 0)
172 {
173 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\system32\\drivers");
174 wcscat(FullImagePathBuffer, wcsrchr(DriverServiceName->Buffer, L'\\'));
175 wcscat(FullImagePathBuffer, L".sys");
176 }
177 else if (ImagePath.Buffer[0] != L'\\')
178 {
179 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\");
180 wcscat(FullImagePathBuffer, ImagePath.Buffer);
181 }
182 else
183 {
184 wcscpy(FullImagePathBuffer, ImagePath.Buffer);
185 }
186
187 RtlFreeUnicodeString(&ImagePath);
188 RtlInitUnicodeString(&FullImagePath, FullImagePathBuffer);
189
190 DPRINT("FullImagePath: '%S'\n", FullImagePathBuffer);
191 DPRINT("Type %lx\n", Type);
192
193 /* Use IopRootDeviceNode for now */
194 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
195 if (!NT_SUCCESS(Status))
196 {
197 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
198 return(Status);
199 }
200
201 ModuleObject = LdrGetModuleObject(DriverServiceName);
202 if (ModuleObject != NULL)
203 {
204 return(STATUS_IMAGE_ALREADY_LOADED);
205 }
206
207 Status = LdrLoadModule(&FullImagePath, &ModuleObject);
208 if (!NT_SUCCESS(Status))
209 {
210 DPRINT1("LdrLoadModule() failed (Status %lx)\n", Status);
211 IopFreeDeviceNode(DeviceNode);
212 return(Status);
213 }
214
215 /* Set a service name for the device node */
216 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
217 if (Start == NULL)
218 Start = DriverServiceName->Buffer;
219 else
220 Start++;
221 RtlCreateUnicodeString(&DeviceNode->ServiceName, Start);
222
223 Status = IopInitializeDriver(ModuleObject->EntryPoint,
224 DeviceNode,
225 (Type == 2 || Type == 8),
226 ModuleObject->Base,
227 ModuleObject->Length,
228 FALSE);
229 if (!NT_SUCCESS(Status))
230 {
231 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
232 LdrUnloadModule(ModuleObject);
233 IopFreeDeviceNode(DeviceNode);
234 }
235
236 return(Status);
237 }
238
239
240 NTSTATUS STDCALL
241 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
242 {
243 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
244 WCHAR FullImagePathBuffer[MAX_PATH];
245 UNICODE_STRING ImagePath;
246 UNICODE_STRING FullImagePath;
247 UNICODE_STRING ObjectName;
248 PDRIVER_OBJECT DriverObject;
249 NTSTATUS Status;
250 PMODULE_OBJECT ModuleObject;
251 LPWSTR Start;
252
253 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName);
254
255 /* Get the service name from the module name */
256 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
257 if (Start == NULL)
258 Start = DriverServiceName->Buffer;
259 else
260 Start++;
261
262 ObjectName.Length = wcslen(Start) + 8;
263 ObjectName.Buffer = ExAllocatePool(NonPagedPool,
264 ObjectName.Length * sizeof(WCHAR));
265 wcscpy(ObjectName.Buffer, L"\\Driver\\");
266 memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
267
268 /* Find the driver object */
269 Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
270 KernelMode, 0, (PVOID*)&DriverObject);
271 if (!NT_SUCCESS(Status))
272 {
273 DPRINT("Can't locate driver object for %wZ\n", ObjectName);
274 return Status;
275 }
276 ObDereferenceObject(DriverObject);
277
278 RtlInitUnicodeString(&ImagePath, NULL);
279
280 /* Get service data */
281 RtlZeroMemory(&QueryTable,
282 sizeof(QueryTable));
283
284 QueryTable[0].Name = L"ImagePath";
285 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
286 QueryTable[0].EntryContext = &ImagePath;
287
288 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
289 DriverServiceName->Buffer,
290 QueryTable,
291 NULL,
292 NULL);
293 if (!NT_SUCCESS(Status))
294 {
295 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
296 RtlFreeUnicodeString(&ImagePath);
297 return(Status);
298 }
299
300 if (ImagePath.Length == 0)
301 {
302 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\system32\\drivers");
303 wcscat(FullImagePathBuffer, wcsrchr(DriverServiceName->Buffer, L'\\'));
304 wcscat(FullImagePathBuffer, L".sys");
305 }
306 else if (ImagePath.Buffer[0] != L'\\')
307 {
308 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\");
309 wcscat(FullImagePathBuffer, ImagePath.Buffer);
310 }
311 else
312 {
313 wcscpy(FullImagePathBuffer, ImagePath.Buffer);
314 }
315
316 RtlFreeUnicodeString(&ImagePath);
317 RtlInitUnicodeString(&FullImagePath, FullImagePathBuffer);
318
319 ModuleObject = LdrGetModuleObject(DriverServiceName);
320 if (ModuleObject == NULL)
321 {
322 return STATUS_UNSUCCESSFUL;
323 }
324
325 /* Unload the module and release the references to the device object */
326
327 if (DriverObject->DriverUnload)
328 (*DriverObject->DriverUnload)(DriverObject);
329 ObDereferenceObject(DriverObject);
330 ObDereferenceObject(DriverObject);
331 LdrUnloadModule(ModuleObject);
332
333 return STATUS_SUCCESS;
334 }
335
336
337 static NTSTATUS STDCALL
338 IopCreateGroupListEntry(PWSTR ValueName,
339 ULONG ValueType,
340 PVOID ValueData,
341 ULONG ValueLength,
342 PVOID Context,
343 PVOID EntryContext)
344 {
345 PSERVICE_GROUP Group;
346
347 if (ValueType == REG_SZ)
348 {
349 DPRINT("GroupName: '%S'\n", (PWCHAR)ValueData);
350
351 Group = ExAllocatePool(NonPagedPool,
352 sizeof(SERVICE_GROUP));
353 if (Group == NULL)
354 {
355 return(STATUS_INSUFFICIENT_RESOURCES);
356 }
357
358 RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
359
360 if (!RtlCreateUnicodeString(&Group->GroupName,
361 (PWSTR)ValueData))
362 {
363 return(STATUS_INSUFFICIENT_RESOURCES);
364 }
365
366
367 InsertTailList(&GroupListHead,
368 &Group->GroupListEntry);
369 }
370
371 return(STATUS_SUCCESS);
372 }
373
374
375 static NTSTATUS STDCALL
376 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
377 {
378 RTL_QUERY_REGISTRY_TABLE QueryTable[6];
379 PSERVICE Service;
380 NTSTATUS Status;
381
382 DPRINT("ServiceName: '%wZ'\n", ServiceName);
383
384 /* Allocate service entry */
385 Service = (PSERVICE)ExAllocatePool(NonPagedPool, sizeof(SERVICE));
386 if (Service == NULL)
387 {
388 DPRINT1("ExAllocatePool() failed\n");
389 return(STATUS_INSUFFICIENT_RESOURCES);
390 }
391 RtlZeroMemory(Service, sizeof(SERVICE));
392
393 /* Get service data */
394 RtlZeroMemory(&QueryTable,
395 sizeof(QueryTable));
396
397 QueryTable[0].Name = L"Start";
398 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
399 QueryTable[0].EntryContext = &Service->Start;
400
401 QueryTable[1].Name = L"Type";
402 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
403 QueryTable[1].EntryContext = &Service->Type;
404
405 QueryTable[2].Name = L"ErrorControl";
406 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
407 QueryTable[2].EntryContext = &Service->ErrorControl;
408
409 QueryTable[3].Name = L"Group";
410 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
411 QueryTable[3].EntryContext = &Service->ServiceGroup;
412
413 QueryTable[4].Name = L"ImagePath";
414 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
415 QueryTable[4].EntryContext = &Service->ImagePath;
416
417 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
418 ServiceName->Buffer,
419 QueryTable,
420 NULL,
421 NULL);
422 if (!NT_SUCCESS(Status) || Service->Start > 1)
423 {
424 RtlFreeUnicodeString(&Service->ServiceGroup);
425 RtlFreeUnicodeString(&Service->ImagePath);
426 ExFreePool(Service);
427 return(Status);
428 }
429
430 /* Copy service name */
431 Service->ServiceName.Length = ServiceName->Length;
432 Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
433 Service->ServiceName.Buffer = ExAllocatePool(NonPagedPool,
434 Service->ServiceName.MaximumLength);
435 RtlCopyMemory(Service->ServiceName.Buffer,
436 ServiceName->Buffer,
437 ServiceName->Length);
438 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
439
440 /* Build registry path */
441 Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
442 Service->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
443 MAX_PATH * sizeof(WCHAR));
444 wcscpy(Service->RegistryPath.Buffer,
445 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
446 wcscat(Service->RegistryPath.Buffer,
447 Service->ServiceName.Buffer);
448 Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
449
450 DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
451 DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
452 DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
453 DPRINT("ImagePath: '%wZ'\n", &Service->ImagePath);
454 DPRINT("Start %lx Type %lx ErrorControl %lx\n",
455 Service->Start, Service->Type, Service->ErrorControl);
456
457 /* Append service entry */
458 InsertTailList(&ServiceListHead,
459 &Service->ServiceListEntry);
460
461 return(STATUS_SUCCESS);
462 }
463
464
465 NTSTATUS
466 IoCreateDriverList(VOID)
467 {
468 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
469 PKEY_BASIC_INFORMATION KeyInfo = NULL;
470 OBJECT_ATTRIBUTES ObjectAttributes;
471 UNICODE_STRING ServicesKeyName;
472 UNICODE_STRING SubKeyName;
473 HANDLE KeyHandle;
474 NTSTATUS Status;
475 ULONG Index;
476
477 ULONG KeyInfoLength = 0;
478 ULONG ReturnedLength;
479
480 DPRINT("IoCreateDriverList() called\n");
481
482 /* Initialize basic variables */
483 InitializeListHead(&GroupListHead);
484 InitializeListHead(&ServiceListHead);
485
486 /* Build group order list */
487 RtlZeroMemory(&QueryTable,
488 sizeof(QueryTable));
489
490 QueryTable[0].Name = L"List";
491 QueryTable[0].QueryRoutine = IopCreateGroupListEntry;
492
493 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
494 L"ServiceGroupOrder",
495 QueryTable,
496 NULL,
497 NULL);
498 if (!NT_SUCCESS(Status))
499 return(Status);
500
501 /* Enumerate services and create the service list */
502 RtlInitUnicodeStringFromLiteral(&ServicesKeyName,
503 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
504
505 InitializeObjectAttributes(&ObjectAttributes,
506 &ServicesKeyName,
507 OBJ_CASE_INSENSITIVE,
508 NULL,
509 NULL);
510
511 Status = NtOpenKey(&KeyHandle,
512 0x10001,
513 &ObjectAttributes);
514 if (!NT_SUCCESS(Status))
515 {
516 return(Status);
517 }
518
519 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
520 KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
521 if (KeyInfo == NULL)
522 {
523 NtClose(KeyHandle);
524 return(STATUS_INSUFFICIENT_RESOURCES);
525 }
526
527 Index = 0;
528 while (TRUE)
529 {
530 Status = NtEnumerateKey(KeyHandle,
531 Index,
532 KeyBasicInformation,
533 KeyInfo,
534 KeyInfoLength,
535 &ReturnedLength);
536 if (NT_SUCCESS(Status))
537 {
538 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
539 {
540
541 SubKeyName.Length = KeyInfo->NameLength;
542 SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
543 SubKeyName.Buffer = KeyInfo->Name;
544 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
545
546 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
547 IopCreateServiceListEntry(&SubKeyName);
548 }
549 }
550
551 if (!NT_SUCCESS(Status))
552 break;
553
554 Index++;
555 }
556
557 ExFreePool(KeyInfo);
558 NtClose(KeyHandle);
559
560 DPRINT("IoCreateDriverList() done\n");
561
562 return(STATUS_SUCCESS);
563 }
564
565
566 VOID
567 LdrLoadAutoConfigDrivers(VOID)
568 {
569 PLIST_ENTRY GroupEntry;
570 PLIST_ENTRY ServiceEntry;
571 PSERVICE_GROUP CurrentGroup;
572 PSERVICE CurrentService;
573 NTSTATUS Status;
574
575 CHAR TextBuffer [256];
576 ULONG x, y, cx, cy;
577
578 DPRINT("LdrLoadAutoConfigDrivers() called\n");
579
580 GroupEntry = GroupListHead.Flink;
581 while (GroupEntry != &GroupListHead)
582 {
583 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
584
585 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
586
587 ServiceEntry = ServiceListHead.Flink;
588 while (ServiceEntry != &ServiceListHead)
589 {
590 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
591
592 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE) == 0) &&
593 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
594 {
595
596 HalQueryDisplayParameters(&x, &y, &cx, &cy);
597 RtlFillMemory(TextBuffer, x, ' ');
598 TextBuffer[x] = '\0';
599 HalSetDisplayParameters(0, y-1);
600 HalDisplayString(TextBuffer);
601
602 sprintf(TextBuffer, "Loading %S...\n", CurrentService->ServiceName.Buffer);
603 HalSetDisplayParameters(0, y-1);
604 HalDisplayString(TextBuffer);
605 HalSetDisplayParameters(cx, cy);
606
607 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
608 Status = NtLoadDriver(&CurrentService->RegistryPath);
609 if (!NT_SUCCESS(Status))
610 {
611 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
612 #if 0
613 if (CurrentService->ErrorControl == 1)
614 {
615 /* Log error */
616
617 }
618 else if (CurrentService->ErrorControl == 2)
619 {
620 if (IsLastKnownGood == FALSE)
621 {
622 /* Boot last known good configuration */
623
624 }
625 }
626 else if (CurrentService->ErrorControl == 3)
627 {
628 if (IsLastKnownGood == FALSE)
629 {
630 /* Boot last known good configuration */
631
632 }
633 else
634 {
635 /* BSOD! */
636
637 }
638 }
639 #endif
640 }
641 }
642 ServiceEntry = ServiceEntry->Flink;
643 }
644
645 GroupEntry = GroupEntry->Flink;
646 }
647
648 DPRINT("LdrLoadAutoConfigDrivers() done\n");
649 }
650
651
652 NTSTATUS
653 IoDestroyDriverList(VOID)
654 {
655 PLIST_ENTRY GroupEntry;
656 PLIST_ENTRY ServiceEntry;
657 PSERVICE_GROUP CurrentGroup;
658 PSERVICE CurrentService;
659
660 DPRINT("IoDestroyDriverList() called\n");
661
662 /* Destroy group list */
663 GroupEntry = GroupListHead.Flink;
664 while (GroupEntry != &GroupListHead)
665 {
666 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
667
668 RtlFreeUnicodeString(&CurrentGroup->GroupName);
669 RemoveEntryList(GroupEntry);
670 ExFreePool(CurrentGroup);
671
672 GroupEntry = GroupListHead.Flink;
673 }
674
675 /* Destroy service list */
676 ServiceEntry = ServiceListHead.Flink;
677 while (ServiceEntry != &ServiceListHead)
678 {
679 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
680
681 RtlFreeUnicodeString(&CurrentService->ServiceName);
682 RtlFreeUnicodeString(&CurrentService->RegistryPath);
683 RtlFreeUnicodeString(&CurrentService->ServiceGroup);
684 RtlFreeUnicodeString(&CurrentService->ImagePath);
685 RemoveEntryList(ServiceEntry);
686 ExFreePool(CurrentService);
687
688 ServiceEntry = ServiceListHead.Flink;
689 }
690
691 DPRINT("IoDestroyDriverList() done\n");
692
693 return(STATUS_SUCCESS);
694 }
695
696 /* EOF */