[FREELDR] Verbose error output for FS errors
[reactos.git] / boot / freeldr / freeldr / ntldr / wlregistry.c
1 /*
2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: boot/freeldr/freeldr/windows/wlregistry.c
5 * PURPOSE: Registry support functions
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
7 */
8
9 /* INCLUDES ***************************************************************/
10
11 #include <freeldr.h>
12 #include "winldr.h"
13 #include "registry.h"
14
15 #include <debug.h>
16 DBG_DEFAULT_CHANNEL(WINDOWS);
17
18 // The only global var here, used to mark mem pages as NLS in WinLdrSetupMemoryLayout()
19 ULONG TotalNLSSize = 0;
20
21 static BOOLEAN
22 WinLdrGetNLSNames(LPSTR AnsiName,
23 LPSTR OemName,
24 LPSTR LangName);
25
26 static VOID
27 WinLdrScanRegistry(IN OUT PLIST_ENTRY BootDriverListHead,
28 IN LPCSTR DirectoryPath);
29
30
31 /* FUNCTIONS **************************************************************/
32
33 static BOOLEAN
34 WinLdrLoadSystemHive(
35 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
36 IN PCSTR DirectoryPath,
37 IN PCSTR HiveName)
38 {
39 ULONG FileId;
40 CHAR FullHiveName[MAX_PATH];
41 ARC_STATUS Status;
42 FILEINFORMATION FileInfo;
43 ULONG HiveFileSize;
44 ULONG_PTR HiveDataPhysical;
45 PVOID HiveDataVirtual;
46 ULONG BytesRead;
47 PCWSTR FsService;
48
49 /* Concatenate path and filename to get the full name */
50 strcpy(FullHiveName, DirectoryPath);
51 strcat(FullHiveName, HiveName);
52
53 Status = ArcOpen(FullHiveName, OpenReadOnly, &FileId);
54 if (Status != ESUCCESS)
55 {
56 WARN("Error while opening '%s', Status: %u\n", FullHiveName, Status);
57 UiMessageBox("Opening hive file failed!");
58 return FALSE;
59 }
60
61 /* Get the file length */
62 Status = ArcGetFileInformation(FileId, &FileInfo);
63 if (Status != ESUCCESS)
64 {
65 ArcClose(FileId);
66 UiMessageBox("Hive file has 0 size!");
67 return FALSE;
68 }
69 HiveFileSize = FileInfo.EndingAddress.LowPart;
70
71 /* Round up the size to page boundary and alloc memory */
72 HiveDataPhysical = (ULONG_PTR)MmAllocateMemoryWithType(
73 MM_SIZE_TO_PAGES(HiveFileSize + MM_PAGE_SIZE - 1) << MM_PAGE_SHIFT,
74 LoaderRegistryData);
75
76 if (HiveDataPhysical == 0)
77 {
78 ArcClose(FileId);
79 UiMessageBox("Unable to alloc memory for a hive!");
80 return FALSE;
81 }
82
83 /* Convert address to virtual */
84 HiveDataVirtual = PaToVa((PVOID)HiveDataPhysical);
85
86 /* Fill LoaderBlock's entries */
87 LoaderBlock->RegistryLength = HiveFileSize;
88 LoaderBlock->RegistryBase = HiveDataVirtual;
89
90 /* Finally read from file to the memory */
91 Status = ArcRead(FileId, (PVOID)HiveDataPhysical, HiveFileSize, &BytesRead);
92 if (Status != ESUCCESS)
93 {
94 ArcClose(FileId);
95 WARN("Error while reading '%s', Status: %u\n", FullHiveName, Status);
96 UiMessageBox("Unable to read from hive file!");
97 return FALSE;
98 }
99
100 /* Add boot filesystem driver to the list */
101 FsService = FsGetServiceName(FileId);
102 if (FsService)
103 {
104 BOOLEAN Success;
105 TRACE(" Adding filesystem service %S\n", FsService);
106 Success = WinLdrAddDriverToList(&LoaderBlock->BootDriverListHead,
107 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
108 NULL,
109 (LPWSTR)FsService);
110 if (!Success)
111 TRACE(" Failed to add filesystem service\n");
112 }
113 else
114 {
115 TRACE(" No required filesystem service\n");
116 }
117
118 ArcClose(FileId);
119 return TRUE;
120 }
121
122 BOOLEAN
123 WinLdrInitSystemHive(
124 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
125 IN PCSTR SystemRoot,
126 IN BOOLEAN Setup)
127 {
128 CHAR SearchPath[1024];
129 PCSTR HiveName;
130 BOOLEAN Success;
131
132 if (Setup)
133 {
134 strcpy(SearchPath, SystemRoot);
135 HiveName = "SETUPREG.HIV";
136 }
137 else
138 {
139 // There is a simple logic here: try to load usual hive (system), if it
140 // fails, then give system.alt a try, and finally try a system.sav
141
142 // FIXME: For now we only try system
143 strcpy(SearchPath, SystemRoot);
144 strcat(SearchPath, "system32\\config\\");
145 HiveName = "SYSTEM";
146 }
147
148 TRACE("WinLdrInitSystemHive: loading hive %s%s\n", SearchPath, HiveName);
149 Success = WinLdrLoadSystemHive(LoaderBlock, SearchPath, HiveName);
150
151 /* Fail if failed... */
152 if (!Success)
153 return FALSE;
154
155 /* Import what was loaded */
156 Success = RegImportBinaryHive(VaToPa(LoaderBlock->RegistryBase), LoaderBlock->RegistryLength);
157 if (!Success)
158 {
159 UiMessageBox("Importing binary hive failed!");
160 return FALSE;
161 }
162
163 /* Initialize the 'CurrentControlSet' link */
164 if (RegInitCurrentControlSet(FALSE) != ERROR_SUCCESS)
165 {
166 UiMessageBox("Initializing CurrentControlSet link failed!");
167 return FALSE;
168 }
169
170 return TRUE;
171 }
172
173 BOOLEAN WinLdrScanSystemHive(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
174 IN LPCSTR DirectoryPath)
175 {
176 CHAR SearchPath[1024];
177 CHAR AnsiName[256], OemName[256], LangName[256];
178 BOOLEAN Success;
179
180 /* Scan registry and prepare boot drivers list */
181 WinLdrScanRegistry(&LoaderBlock->BootDriverListHead, DirectoryPath);
182
183 /* Get names of NLS files */
184 Success = WinLdrGetNLSNames(AnsiName, OemName, LangName);
185 if (!Success)
186 {
187 UiMessageBox("Getting NLS names from registry failed!");
188 return FALSE;
189 }
190
191 TRACE("NLS data %s %s %s\n", AnsiName, OemName, LangName);
192
193 /* Load NLS data */
194 strcpy(SearchPath, DirectoryPath);
195 strcat(SearchPath, "system32\\");
196 Success = WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
197 TRACE("NLS data loading %s\n", Success ? "successful" : "failed");
198
199 /* TODO: Load OEM HAL font */
200 // In HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage,
201 // REG_SZ value "OEMHAL"
202
203 return TRUE;
204 }
205
206
207 /* PRIVATE FUNCTIONS ******************************************************/
208
209 // Queries registry for those three file names
210 static BOOLEAN
211 WinLdrGetNLSNames(LPSTR AnsiName,
212 LPSTR OemName,
213 LPSTR LangName)
214 {
215 LONG rc = ERROR_SUCCESS;
216 HKEY hKey;
217 WCHAR szIdBuffer[80];
218 WCHAR NameBuffer[80];
219 ULONG BufferSize;
220
221 /* open the codepage key */
222 rc = RegOpenKey(NULL,
223 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage",
224 &hKey);
225 if (rc != ERROR_SUCCESS)
226 {
227 //strcpy(szErrorOut, "Couldn't open CodePage registry key");
228 return FALSE;
229 }
230
231 /* Get ANSI codepage */
232 BufferSize = sizeof(szIdBuffer);
233 rc = RegQueryValue(hKey, L"ACP", NULL, (PUCHAR)szIdBuffer, &BufferSize);
234 if (rc != ERROR_SUCCESS)
235 {
236 //strcpy(szErrorOut, "Couldn't get ACP NLS setting");
237 return FALSE;
238 }
239
240 BufferSize = sizeof(NameBuffer);
241 rc = RegQueryValue(hKey, szIdBuffer, NULL, (PUCHAR)NameBuffer, &BufferSize);
242 if (rc != ERROR_SUCCESS)
243 {
244 //strcpy(szErrorOut, "ACP NLS Setting exists, but isn't readable");
245 //return FALSE;
246 wcscpy(NameBuffer, L"c_1252.nls"); // HACK: ReactOS bug CORE-6105
247 }
248 sprintf(AnsiName, "%S", NameBuffer);
249
250 /* Get OEM codepage */
251 BufferSize = sizeof(szIdBuffer);
252 rc = RegQueryValue(hKey, L"OEMCP", NULL, (PUCHAR)szIdBuffer, &BufferSize);
253 if (rc != ERROR_SUCCESS)
254 {
255 //strcpy(szErrorOut, "Couldn't get OEMCP NLS setting");
256 return FALSE;
257 }
258
259 BufferSize = sizeof(NameBuffer);
260 rc = RegQueryValue(hKey, szIdBuffer, NULL, (PUCHAR)NameBuffer, &BufferSize);
261 if (rc != ERROR_SUCCESS)
262 {
263 //strcpy(szErrorOut, "OEMCP NLS setting exists, but isn't readable");
264 //return FALSE;
265 wcscpy(NameBuffer, L"c_437.nls"); // HACK: ReactOS bug CORE-6105
266 }
267 sprintf(OemName, "%S", NameBuffer);
268
269 /* Open the language key */
270 rc = RegOpenKey(NULL,
271 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\Language",
272 &hKey);
273 if (rc != ERROR_SUCCESS)
274 {
275 //strcpy(szErrorOut, "Couldn't open Language registry key");
276 return FALSE;
277 }
278
279 /* Get the Unicode case table */
280 BufferSize = sizeof(szIdBuffer);
281 rc = RegQueryValue(hKey, L"Default", NULL, (PUCHAR)szIdBuffer, &BufferSize);
282 if (rc != ERROR_SUCCESS)
283 {
284 //strcpy(szErrorOut, "Couldn't get Language Default setting");
285 return FALSE;
286 }
287
288 BufferSize = sizeof(NameBuffer);
289 rc = RegQueryValue(hKey, szIdBuffer, NULL, (PUCHAR)NameBuffer, &BufferSize);
290 if (rc != ERROR_SUCCESS)
291 {
292 //strcpy(szErrorOut, "Language Default setting exists, but isn't readable");
293 return FALSE;
294 }
295 sprintf(LangName, "%S", NameBuffer);
296
297 return TRUE;
298 }
299
300 BOOLEAN
301 WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
302 IN LPCSTR DirectoryPath,
303 IN LPCSTR AnsiFileName,
304 IN LPCSTR OemFileName,
305 IN LPCSTR LanguageFileName)
306 {
307 CHAR FileName[255];
308 ULONG AnsiFileId;
309 ULONG OemFileId;
310 ULONG LanguageFileId;
311 ULONG AnsiFileSize, OemFileSize, LanguageFileSize;
312 ULONG TotalSize;
313 ULONG_PTR NlsDataBase;
314 PVOID NlsVirtual;
315 BOOLEAN AnsiEqualsOem = FALSE;
316 FILEINFORMATION FileInfo;
317 ULONG BytesRead;
318 ARC_STATUS Status;
319
320 /* There may be a case, when OEM and ANSI page coincide */
321 if (!strcmp(AnsiFileName, OemFileName))
322 AnsiEqualsOem = TRUE;
323
324 /* Open file with ANSI and store its size */
325 strcpy(FileName, DirectoryPath);
326 strcat(FileName, AnsiFileName);
327 Status = ArcOpen(FileName, OpenReadOnly, &AnsiFileId);
328 if (Status != ESUCCESS)
329 {
330 WARN("Error while opening '%s', Status: %u\n", FileName, Status);
331 goto Failure;
332 }
333
334 Status = ArcGetFileInformation(AnsiFileId, &FileInfo);
335 if (Status != ESUCCESS)
336 goto Failure;
337 AnsiFileSize = FileInfo.EndingAddress.LowPart;
338 TRACE("AnsiFileSize: %d\n", AnsiFileSize);
339 ArcClose(AnsiFileId);
340
341 /* Open OEM file and store its length */
342 if (AnsiEqualsOem)
343 {
344 OemFileSize = 0;
345 }
346 else
347 {
348 //Print(L"Loading %s...\n", Filename);
349 strcpy(FileName, DirectoryPath);
350 strcat(FileName, OemFileName);
351 Status = ArcOpen(FileName, OpenReadOnly, &OemFileId);
352 if (Status != ESUCCESS)
353 {
354 WARN("Error while opening '%s', Status: %u\n", FileName, Status);
355 goto Failure;
356 }
357
358 Status = ArcGetFileInformation(OemFileId, &FileInfo);
359 if (Status != ESUCCESS)
360 goto Failure;
361 OemFileSize = FileInfo.EndingAddress.LowPart;
362 ArcClose(OemFileId);
363 }
364 TRACE("OemFileSize: %d\n", OemFileSize);
365
366 /* And finally open the language codepage file and store its length */
367 //Print(L"Loading %s...\n", Filename);
368 strcpy(FileName, DirectoryPath);
369 strcat(FileName, LanguageFileName);
370 Status = ArcOpen(FileName, OpenReadOnly, &LanguageFileId);
371 if (Status != ESUCCESS)
372 {
373 WARN("Error while opening '%s', Status: %u\n", FileName, Status);
374 goto Failure;
375 }
376
377 Status = ArcGetFileInformation(LanguageFileId, &FileInfo);
378 if (Status != ESUCCESS)
379 goto Failure;
380 LanguageFileSize = FileInfo.EndingAddress.LowPart;
381 ArcClose(LanguageFileId);
382 TRACE("LanguageFileSize: %d\n", LanguageFileSize);
383
384 /* Sum up all three length, having in mind that every one of them
385 must start at a page boundary => thus round up each file to a page */
386 TotalSize = MM_SIZE_TO_PAGES(AnsiFileSize) +
387 MM_SIZE_TO_PAGES(OemFileSize) +
388 MM_SIZE_TO_PAGES(LanguageFileSize);
389
390 /* Store it for later marking the pages as NlsData type */
391 TotalNLSSize = TotalSize;
392
393 NlsDataBase = (ULONG_PTR)MmAllocateMemoryWithType(TotalSize*MM_PAGE_SIZE, LoaderNlsData);
394
395 if (NlsDataBase == 0)
396 goto Failure;
397
398 NlsVirtual = PaToVa((PVOID)NlsDataBase);
399 LoaderBlock->NlsData->AnsiCodePageData = NlsVirtual;
400 LoaderBlock->NlsData->OemCodePageData = (PVOID)((PUCHAR)NlsVirtual +
401 (MM_SIZE_TO_PAGES(AnsiFileSize) << MM_PAGE_SHIFT));
402 LoaderBlock->NlsData->UnicodeCodePageData = (PVOID)((PUCHAR)NlsVirtual +
403 (MM_SIZE_TO_PAGES(AnsiFileSize) << MM_PAGE_SHIFT) +
404 (MM_SIZE_TO_PAGES(OemFileSize) << MM_PAGE_SHIFT));
405
406 /* Ansi and OEM data are the same - just set pointers to the same area */
407 if (AnsiEqualsOem)
408 LoaderBlock->NlsData->OemCodePageData = LoaderBlock->NlsData->AnsiCodePageData;
409
410
411 /* Now actually read the data into memory, starting with Ansi file */
412 strcpy(FileName, DirectoryPath);
413 strcat(FileName, AnsiFileName);
414 Status = ArcOpen(FileName, OpenReadOnly, &AnsiFileId);
415 if (Status != ESUCCESS)
416 {
417 WARN("Error while opening '%s', Status: %u\n", FileName, Status);
418 goto Failure;
419 }
420
421 Status = ArcRead(AnsiFileId, VaToPa(LoaderBlock->NlsData->AnsiCodePageData), AnsiFileSize, &BytesRead);
422 if (Status != ESUCCESS)
423 {
424 WARN("Error while reading '%s', Status: %u\n", FileName, Status);
425 goto Failure;
426 }
427
428 ArcClose(AnsiFileId);
429
430 /* OEM now, if it doesn't equal Ansi of course */
431 if (!AnsiEqualsOem)
432 {
433 strcpy(FileName, DirectoryPath);
434 strcat(FileName, OemFileName);
435 Status = ArcOpen(FileName, OpenReadOnly, &OemFileId);
436 if (Status != ESUCCESS)
437 {
438 WARN("Error while opening '%s', Status: %u\n", FileName, Status);
439 goto Failure;
440 }
441
442 Status = ArcRead(OemFileId, VaToPa(LoaderBlock->NlsData->OemCodePageData), OemFileSize, &BytesRead);
443 if (Status != ESUCCESS)
444 {
445 WARN("Error while reading '%s', Status: %u\n", FileName, Status);
446 goto Failure;
447 }
448
449 ArcClose(OemFileId);
450 }
451
452 /* finally the language file */
453 strcpy(FileName, DirectoryPath);
454 strcat(FileName, LanguageFileName);
455 Status = ArcOpen(FileName, OpenReadOnly, &LanguageFileId);
456 if (Status != ESUCCESS)
457 {
458 WARN("Error while opening '%s', Status: %u\n", FileName, Status);
459 goto Failure;
460 }
461
462 Status = ArcRead(LanguageFileId, VaToPa(LoaderBlock->NlsData->UnicodeCodePageData), LanguageFileSize, &BytesRead);
463 if (Status != ESUCCESS)
464 {
465 WARN("Error while reading '%s', Status: %u\n", FileName, Status);
466 goto Failure;
467 }
468
469 ArcClose(LanguageFileId);
470
471 //
472 // THIS IS HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK
473 // Should go to WinLdrLoadOemHalFont(), when it will be implemented
474 //
475 LoaderBlock->OemFontFile = VaToPa(LoaderBlock->NlsData->UnicodeCodePageData);
476
477 /* Convert NlsTables address to VA */
478 LoaderBlock->NlsData = PaToVa(LoaderBlock->NlsData);
479
480 return TRUE;
481
482 Failure:
483 UiMessageBox("Error reading NLS file %s", FileName);
484 return FALSE;
485 }
486
487 static VOID
488 WinLdrScanRegistry(IN OUT PLIST_ENTRY BootDriverListHead,
489 IN LPCSTR DirectoryPath)
490 {
491 LONG rc = 0;
492 HKEY hGroupKey, hOrderKey, hServiceKey, hDriverKey;
493 LPWSTR GroupNameBuffer;
494 WCHAR ServiceName[256];
495 ULONG OrderList[128];
496 ULONG BufferSize;
497 ULONG Index;
498 ULONG TagIndex;
499 LPWSTR GroupName;
500
501 ULONG ValueSize;
502 ULONG ValueType;
503 ULONG StartValue;
504 ULONG TagValue;
505 WCHAR DriverGroup[256];
506 ULONG DriverGroupSize;
507
508 CHAR ImagePath[256];
509 WCHAR TempImagePath[256];
510
511 BOOLEAN Success;
512
513 /* get 'service group order' key */
514 rc = RegOpenKey(NULL,
515 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder",
516 &hGroupKey);
517 if (rc != ERROR_SUCCESS) {
518
519 TRACE_CH(REACTOS, "Failed to open the 'ServiceGroupOrder' key (rc %d)\n", (int)rc);
520 return;
521 }
522
523 /* get 'group order list' key */
524 rc = RegOpenKey(NULL,
525 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\GroupOrderList",
526 &hOrderKey);
527 if (rc != ERROR_SUCCESS) {
528
529 TRACE_CH(REACTOS, "Failed to open the 'GroupOrderList' key (rc %d)\n", (int)rc);
530 return;
531 }
532
533 /* enumerate drivers */
534 rc = RegOpenKey(NULL,
535 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services",
536 &hServiceKey);
537 if (rc != ERROR_SUCCESS) {
538
539 TRACE_CH(REACTOS, "Failed to open the 'Services' key (rc %d)\n", (int)rc);
540 return;
541 }
542
543 /* Get the Name Group */
544 BufferSize = 4096;
545 GroupNameBuffer = FrLdrHeapAlloc(BufferSize, TAG_WLDR_NAME);
546 rc = RegQueryValue(hGroupKey, L"List", NULL, (PUCHAR)GroupNameBuffer, &BufferSize);
547 TRACE_CH(REACTOS, "RegQueryValue(): rc %d\n", (int)rc);
548 if (rc != ERROR_SUCCESS)
549 return;
550 TRACE_CH(REACTOS, "BufferSize: %d \n", (int)BufferSize);
551 TRACE_CH(REACTOS, "GroupNameBuffer: '%S' \n", GroupNameBuffer);
552
553 /* Loop through each group */
554 GroupName = GroupNameBuffer;
555 while (*GroupName)
556 {
557 TRACE("Driver group: '%S'\n", GroupName);
558
559 /* Query the Order */
560 BufferSize = sizeof(OrderList);
561 rc = RegQueryValue(hOrderKey, GroupName, NULL, (PUCHAR)OrderList, &BufferSize);
562 if (rc != ERROR_SUCCESS) OrderList[0] = 0;
563
564 /* enumerate all drivers */
565 for (TagIndex = 1; TagIndex <= OrderList[0]; TagIndex++)
566 {
567 Index = 0;
568
569 while (TRUE)
570 {
571 /* Get the Driver's Name */
572 ValueSize = sizeof(ServiceName);
573 rc = RegEnumKey(hServiceKey, Index, ServiceName, &ValueSize, &hDriverKey);
574 TRACE("RegEnumKey(): rc %d\n", (int)rc);
575
576 /* Make sure it's valid, and check if we're done */
577 if (rc == ERROR_NO_MORE_ITEMS)
578 break;
579 if (rc != ERROR_SUCCESS)
580 {
581 FrLdrHeapFree(GroupNameBuffer, TAG_WLDR_NAME);
582 return;
583 }
584 //TRACE_CH(REACTOS, "Service %d: '%S'\n", (int)Index, ServiceName);
585
586 /* Read the Start Value */
587 ValueSize = sizeof(ULONG);
588 rc = RegQueryValue(hDriverKey, L"Start", &ValueType, (PUCHAR)&StartValue, &ValueSize);
589 if (rc != ERROR_SUCCESS) StartValue = (ULONG)-1;
590 //TRACE_CH(REACTOS, " Start: %x \n", (int)StartValue);
591
592 /* Read the Tag */
593 ValueSize = sizeof(ULONG);
594 rc = RegQueryValue(hDriverKey, L"Tag", &ValueType, (PUCHAR)&TagValue, &ValueSize);
595 if (rc != ERROR_SUCCESS) TagValue = (ULONG)-1;
596 //TRACE_CH(REACTOS, " Tag: %x \n", (int)TagValue);
597
598 /* Read the driver's group */
599 DriverGroupSize = sizeof(DriverGroup);
600 rc = RegQueryValue(hDriverKey, L"Group", NULL, (PUCHAR)DriverGroup, &DriverGroupSize);
601 //TRACE_CH(REACTOS, " Group: '%S' \n", DriverGroup);
602
603 /* Make sure it should be started */
604 if ((StartValue == 0) &&
605 (TagValue == OrderList[TagIndex]) &&
606 (_wcsicmp(DriverGroup, GroupName) == 0))
607 {
608 /* Get the Driver's Location */
609 ValueSize = sizeof(TempImagePath);
610 rc = RegQueryValue(hDriverKey, L"ImagePath", NULL, (PUCHAR)TempImagePath, &ValueSize);
611
612 /* Write the whole path if it succeeded, else prepare to fail */
613 if (rc != ERROR_SUCCESS)
614 {
615 TRACE_CH(REACTOS, "ImagePath: not found\n");
616 TempImagePath[0] = 0;
617 RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%s\\system32\\drivers\\%S.sys", DirectoryPath, ServiceName);
618 }
619 else if (TempImagePath[0] != L'\\')
620 {
621 RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%s%S", DirectoryPath, TempImagePath);
622 }
623 else
624 {
625 RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%S", TempImagePath);
626 TRACE_CH(REACTOS, "ImagePath: '%s'\n", ImagePath);
627 }
628
629 TRACE("Adding boot driver: '%s'\n", ImagePath);
630
631 Success = WinLdrAddDriverToList(BootDriverListHead,
632 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
633 TempImagePath,
634 ServiceName);
635 if (!Success)
636 ERR("Failed to add boot driver\n");
637 }
638 else
639 {
640 //TRACE(" Skipping driver '%S' with Start %d, Tag %d and Group '%S' (Current Tag %d, current group '%S')\n",
641 // ServiceName, StartValue, TagValue, DriverGroup, OrderList[TagIndex], GroupName);
642 }
643
644 Index++;
645 }
646 }
647
648 Index = 0;
649 while (TRUE)
650 {
651 /* Get the Driver's Name */
652 ValueSize = sizeof(ServiceName);
653 rc = RegEnumKey(hServiceKey, Index, ServiceName, &ValueSize, &hDriverKey);
654
655 //TRACE_CH(REACTOS, "RegEnumKey(): rc %d\n", (int)rc);
656 if (rc == ERROR_NO_MORE_ITEMS)
657 break;
658 if (rc != ERROR_SUCCESS)
659 {
660 FrLdrHeapFree(GroupNameBuffer, TAG_WLDR_NAME);
661 return;
662 }
663 TRACE("Service %d: '%S'\n", (int)Index, ServiceName);
664
665 /* Read the Start Value */
666 ValueSize = sizeof(ULONG);
667 rc = RegQueryValue(hDriverKey, L"Start", &ValueType, (PUCHAR)&StartValue, &ValueSize);
668 if (rc != ERROR_SUCCESS) StartValue = (ULONG)-1;
669 //TRACE_CH(REACTOS, " Start: %x \n", (int)StartValue);
670
671 /* Read the Tag */
672 ValueSize = sizeof(ULONG);
673 rc = RegQueryValue(hDriverKey, L"Tag", &ValueType, (PUCHAR)&TagValue, &ValueSize);
674 if (rc != ERROR_SUCCESS) TagValue = (ULONG)-1;
675 //TRACE_CH(REACTOS, " Tag: %x \n", (int)TagValue);
676
677 /* Read the driver's group */
678 DriverGroupSize = sizeof(DriverGroup);
679 rc = RegQueryValue(hDriverKey, L"Group", NULL, (PUCHAR)DriverGroup, &DriverGroupSize);
680 //TRACE_CH(REACTOS, " Group: '%S' \n", DriverGroup);
681
682 for (TagIndex = 1; TagIndex <= OrderList[0]; TagIndex++)
683 {
684 if (TagValue == OrderList[TagIndex]) break;
685 }
686
687 if ((StartValue == 0) &&
688 (TagIndex > OrderList[0]) &&
689 (_wcsicmp(DriverGroup, GroupName) == 0))
690 {
691 ValueSize = sizeof(TempImagePath);
692 rc = RegQueryValue(hDriverKey, L"ImagePath", NULL, (PUCHAR)TempImagePath, &ValueSize);
693 if (rc != ERROR_SUCCESS)
694 {
695 TRACE_CH(REACTOS, "ImagePath: not found\n");
696 TempImagePath[0] = 0;
697 RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%ssystem32\\drivers\\%S.sys", DirectoryPath, ServiceName);
698 }
699 else if (TempImagePath[0] != L'\\')
700 {
701 RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%s%S", DirectoryPath, TempImagePath);
702 }
703 else
704 {
705 RtlStringCbPrintfA(ImagePath, sizeof(ImagePath), "%S", TempImagePath);
706 TRACE_CH(REACTOS, "ImagePath: '%s'\n", ImagePath);
707 }
708 TRACE(" Adding boot driver: '%s'\n", ImagePath);
709
710 Success = WinLdrAddDriverToList(BootDriverListHead,
711 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
712 TempImagePath,
713 ServiceName);
714 if (!Success)
715 ERR(" Failed to add boot driver\n");
716 }
717 else
718 {
719 //TRACE(" Skipping driver '%S' with Start %d, Tag %d and Group '%S' (Current group '%S')\n",
720 // ServiceName, StartValue, TagValue, DriverGroup, GroupName);
721 }
722
723 Index++;
724 }
725
726 /* Move to the next group name */
727 GroupName = GroupName + wcslen(GroupName) + 1;
728 }
729
730 /* Free allocated memory */
731 FrLdrHeapFree(GroupNameBuffer, TAG_WLDR_NAME);
732 }
733
734 static
735 BOOLEAN
736 InsertInBootDriverList(
737 PLIST_ENTRY BootDriverListHead,
738 PBOOT_DRIVER_LIST_ENTRY BootDriverEntry)
739 {
740 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
741 PLIST_ENTRY ListEntry;
742
743 ASSERT(BootDriverEntry->FilePath.Buffer != NULL);
744 ASSERT(BootDriverEntry->RegistryPath.Buffer != NULL);
745
746 for (ListEntry = BootDriverListHead->Flink;
747 ListEntry != BootDriverListHead;
748 ListEntry = ListEntry->Flink)
749 {
750 DriverEntry = CONTAINING_RECORD(ListEntry,
751 BOOT_DRIVER_LIST_ENTRY,
752 Link);
753 if ((DriverEntry->FilePath.Buffer != NULL) &&
754 RtlEqualUnicodeString(&BootDriverEntry->FilePath,
755 &DriverEntry->FilePath,
756 TRUE))
757 {
758 return FALSE;
759 }
760
761 if ((DriverEntry->RegistryPath.Buffer != NULL) &&
762 RtlEqualUnicodeString(&BootDriverEntry->RegistryPath,
763 &DriverEntry->RegistryPath,
764 TRUE))
765 {
766 return FALSE;
767 }
768 }
769
770 InsertTailList(BootDriverListHead, &BootDriverEntry->Link);
771 return TRUE;
772 }
773
774 BOOLEAN
775 WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead,
776 LPWSTR RegistryPath,
777 LPWSTR ImagePath,
778 LPWSTR ServiceName)
779 {
780 PBOOT_DRIVER_LIST_ENTRY BootDriverEntry;
781 NTSTATUS Status;
782 USHORT PathLength;
783
784 BootDriverEntry = FrLdrHeapAlloc(sizeof(BOOT_DRIVER_LIST_ENTRY), TAG_WLDR_BDE);
785
786 if (!BootDriverEntry)
787 return FALSE;
788
789 // DTE will be filled during actual load of the driver
790 BootDriverEntry->LdrEntry = NULL;
791
792 // Check - if we have a valid ImagePath, if not - we need to build it
793 // like "System32\\Drivers\\blah.sys"
794 if (ImagePath && (ImagePath[0] != 0))
795 {
796 // Just copy ImagePath to the corresponding field in the structure
797 PathLength = (USHORT)wcslen(ImagePath) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
798
799 BootDriverEntry->FilePath.Length = 0;
800 BootDriverEntry->FilePath.MaximumLength = PathLength;
801 BootDriverEntry->FilePath.Buffer = FrLdrHeapAlloc(PathLength, TAG_WLDR_NAME);
802
803 if (!BootDriverEntry->FilePath.Buffer)
804 {
805 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
806 return FALSE;
807 }
808
809 Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ImagePath);
810 if (!NT_SUCCESS(Status))
811 {
812 FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
813 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
814 return FALSE;
815 }
816 }
817 else
818 {
819 // we have to construct ImagePath ourselves
820 PathLength = (USHORT)wcslen(ServiceName)*sizeof(WCHAR) + sizeof(L"system32\\drivers\\.sys");
821 BootDriverEntry->FilePath.Length = 0;
822 BootDriverEntry->FilePath.MaximumLength = PathLength;
823 BootDriverEntry->FilePath.Buffer = FrLdrHeapAlloc(PathLength, TAG_WLDR_NAME);
824
825 if (!BootDriverEntry->FilePath.Buffer)
826 {
827 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_NAME);
828 return FALSE;
829 }
830
831 Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L"system32\\drivers\\");
832 if (!NT_SUCCESS(Status))
833 {
834 FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
835 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_NAME);
836 return FALSE;
837 }
838
839 Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ServiceName);
840 if (!NT_SUCCESS(Status))
841 {
842 FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
843 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_NAME);
844 return FALSE;
845 }
846
847 Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L".sys");
848 if (!NT_SUCCESS(Status))
849 {
850 FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
851 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_NAME);
852 return FALSE;
853 }
854 }
855
856 // Add registry path
857 PathLength = (USHORT)(wcslen(RegistryPath) + wcslen(ServiceName))*sizeof(WCHAR) + sizeof(UNICODE_NULL);
858 BootDriverEntry->RegistryPath.Length = 0;
859 BootDriverEntry->RegistryPath.MaximumLength = PathLength;
860 BootDriverEntry->RegistryPath.Buffer = FrLdrHeapAlloc(PathLength, TAG_WLDR_NAME);
861 if (!BootDriverEntry->RegistryPath.Buffer)
862 return FALSE;
863
864 Status = RtlAppendUnicodeToString(&BootDriverEntry->RegistryPath, RegistryPath);
865 if (!NT_SUCCESS(Status))
866 return FALSE;
867
868 Status = RtlAppendUnicodeToString(&BootDriverEntry->RegistryPath, ServiceName);
869 if (!NT_SUCCESS(Status))
870 return FALSE;
871
872 // Insert entry into the list
873 if (!InsertInBootDriverList(BootDriverListHead, BootDriverEntry))
874 {
875 // It was already there, so delete our entry
876 if (BootDriverEntry->FilePath.Buffer) FrLdrHeapFree(BootDriverEntry->FilePath.Buffer, TAG_WLDR_NAME);
877 if (BootDriverEntry->RegistryPath.Buffer) FrLdrHeapFree(BootDriverEntry->RegistryPath.Buffer, TAG_WLDR_NAME);
878 FrLdrHeapFree(BootDriverEntry, TAG_WLDR_BDE);
879 }
880
881 return TRUE;
882 }