1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Setup Library
4 * FILE: base/setup/lib/setuplib.c
5 * PURPOSE: Setup Library - Main initialization helpers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "precomp.h"
13 #include "filesup.h"
14 #include "infsupp.h"
15 #include "inicache.h"
16
17 #include "setuplib.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 /* GLOBALS ******************************************************************/
24
25 /* FUNCTIONS ****************************************************************/
26
27 VOID
CheckUnattendedSetup(IN OUT PUSETUP_DATA pSetupData)28 CheckUnattendedSetup(
29 IN OUT PUSETUP_DATA pSetupData)
30 {
31 INFCONTEXT Context;
32 HINF UnattendInf;
33 UINT ErrorLine;
34 INT IntValue;
35 PCWSTR Value;
36 WCHAR UnattendInfPath[MAX_PATH];
37
38 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
39 pSetupData->SourcePath.Buffer, L"unattend.inf");
40
41 DPRINT("UnattendInf path: '%S'\n", UnattendInfPath);
42
43 if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
44 {
45 DPRINT("Does not exist: %S\n", UnattendInfPath);
46 return;
47 }
48
49 /* Load 'unattend.inf' from installation media */
50 UnattendInf = SpInfOpenInfFile(UnattendInfPath,
51 NULL,
52 INF_STYLE_OLDNT,
53 pSetupData->LanguageId,
54 &ErrorLine);
55 if (UnattendInf == INVALID_HANDLE_VALUE)
56 {
57 DPRINT("SpInfOpenInfFile() failed\n");
58 return;
59 }
60
61 /* Open 'Unattend' section */
62 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"Signature", &Context))
63 {
64 DPRINT("SpInfFindFirstLine() failed for section 'Unattend'\n");
65 goto Quit;
66 }
67
68 /* Get pointer 'Signature' key */
69 if (!INF_GetData(&Context, NULL, &Value))
70 {
71 DPRINT("INF_GetData() failed for key 'Signature'\n");
72 goto Quit;
73 }
74
75 /* Check 'Signature' string */
76 if (_wcsicmp(Value, L"$ReactOS$") != 0)
77 {
78 DPRINT("Signature not $ReactOS$\n");
79 INF_FreeData(Value);
80 goto Quit;
81 }
82
83 INF_FreeData(Value);
84
85 /* Check if Unattend setup is enabled */
86 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
87 {
88 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
89 goto Quit;
90 }
91
92 if (!INF_GetData(&Context, NULL, &Value))
93 {
94 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
95 goto Quit;
96 }
97
98 if (_wcsicmp(Value, L"yes") != 0)
99 {
100 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
101 INF_FreeData(Value);
102 goto Quit;
103 }
104
105 INF_FreeData(Value);
106
107 /* Search for 'DestinationDiskNumber' */
108 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
109 {
110 DPRINT("SpInfFindFirstLine() failed for key 'DestinationDiskNumber'\n");
111 goto Quit;
112 }
113
114 if (!SpInfGetIntField(&Context, 1, &IntValue))
115 {
116 DPRINT("SpInfGetIntField() failed for key 'DestinationDiskNumber'\n");
117 goto Quit;
118 }
119
120 pSetupData->DestinationDiskNumber = (LONG)IntValue;
121
122 /* Search for 'DestinationPartitionNumber' */
123 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
124 {
125 DPRINT("SpInfFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
126 goto Quit;
127 }
128
129 if (!SpInfGetIntField(&Context, 1, &IntValue))
130 {
131 DPRINT("SpInfGetIntField() failed for key 'DestinationPartitionNumber'\n");
132 goto Quit;
133 }
134
135 pSetupData->DestinationPartitionNumber = (LONG)IntValue;
136
137 /* Search for 'InstallationDirectory' (optional) */
138 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
139 {
140 if (INF_GetData(&Context, NULL, &Value))
141 {
142 RtlStringCchCopyW(pSetupData->InstallationDirectory,
143 ARRAYSIZE(pSetupData->InstallationDirectory),
144 Value);
145 INF_FreeData(Value);
146 }
147 else
148 {
149 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
150 }
151 }
152
153 IsUnattendedSetup = TRUE;
154 DPRINT("Running unattended setup\n");
155
156 /* Search for 'BootLoaderLocation' (optional) */
157 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"BootLoaderLocation", &Context))
158 {
159 if (SpInfGetIntField(&Context, 1, &IntValue))
160 pSetupData->BootLoaderLocation = IntValue;
161 }
162
163 /* Search for 'FormatPartition' (optional) */
164 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FormatPartition", &Context))
165 {
166 if (SpInfGetIntField(&Context, 1, &IntValue))
167 pSetupData->FormatPartition = IntValue;
168 }
169
170 /* Search for 'AutoPartition' (optional) */
171 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"AutoPartition", &Context))
172 {
173 if (SpInfGetIntField(&Context, 1, &IntValue))
174 pSetupData->AutoPartition = IntValue;
175 }
176
177 /* Search for 'LocaleID' (optional) */
178 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"LocaleID", &Context))
179 {
180 if (INF_GetData(&Context, NULL, &Value))
181 {
182 LONG Id = wcstol(Value, NULL, 16);
183 RtlStringCchPrintfW(pSetupData->LocaleID,
184 ARRAYSIZE(pSetupData->LocaleID),
185 L"%08lx", Id);
186 INF_FreeData(Value);
187 }
188 }
189
190 /* Search for 'FsType' (optional) */
191 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FsType", &Context))
192 {
193 if (SpInfGetIntField(&Context, 1, &IntValue))
194 pSetupData->FsType = IntValue;
195 }
196
197 Quit:
198 SpInfCloseInfFile(UnattendInf);
199 }
200
201 VOID
InstallSetupInfFile(IN OUT PUSETUP_DATA pSetupData)202 InstallSetupInfFile(
203 IN OUT PUSETUP_DATA pSetupData)
204 {
205 NTSTATUS Status;
206 PINICACHE IniCache;
207
208 #if 0 // HACK FIXME!
209 PINICACHE UnattendCache;
210 PINICACHEITERATOR Iterator;
211 #else
212 // WCHAR CrLf[] = {L'\r', L'\n'};
213 CHAR CrLf[] = {'\r', '\n'};
214 HANDLE FileHandle, UnattendFileHandle, SectionHandle;
215 FILE_STANDARD_INFORMATION FileInfo;
216 ULONG FileSize;
217 PVOID ViewBase;
218 UNICODE_STRING FileName;
219 OBJECT_ATTRIBUTES ObjectAttributes;
220 IO_STATUS_BLOCK IoStatusBlock;
221 #endif
222
223 PINI_SECTION IniSection;
224 WCHAR PathBuffer[MAX_PATH];
225 WCHAR UnattendInfPath[MAX_PATH];
226
227 /* Create a $winnt$.inf file with default entries */
228 IniCache = IniCacheCreate();
229 if (!IniCache)
230 return;
231
232 IniSection = IniAddSection(IniCache, L"SetupParams");
233 if (IniSection)
234 {
235 /* Key "skipmissingfiles" */
236 // RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
237 // L"\"%s\"", L"WinNt5.2");
238 // IniAddKey(IniSection, L"Version", PathBuffer);
239 }
240
241 IniSection = IniAddSection(IniCache, L"Data");
242 if (IniSection)
243 {
244 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
245 L"\"%s\"", IsUnattendedSetup ? L"yes" : L"no");
246 IniAddKey(IniSection, L"UnattendedInstall", PathBuffer);
247
248 // "floppylessbootpath" (yes/no)
249
250 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
251 L"\"%s\"", L"winnt");
252 IniAddKey(IniSection, L"ProductType", PathBuffer);
253
254 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
255 L"\"%s\\\"", pSetupData->SourceRootPath.Buffer);
256 IniAddKey(IniSection, L"SourcePath", PathBuffer);
257
258 // "floppyless" ("0")
259 }
260
261 #if 0
262
263 /* TODO: Append the standard unattend.inf file */
264 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
265 pSetupData->SourcePath.Buffer, L"unattend.inf");
266 if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
267 {
268 DPRINT("Does not exist: %S\n", UnattendInfPath);
269 goto Quit;
270 }
271
272 Status = IniCacheLoad(&UnattendCache, UnattendInfPath, FALSE);
273 if (!NT_SUCCESS(Status))
274 {
275 DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath);
276 goto Quit;
277 }
278
279 IniCacheDestroy(UnattendCache);
280
281 Quit:
282 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
283 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf");
284 IniCacheSave(IniCache, PathBuffer);
285 IniCacheDestroy(IniCache);
286
287 #else
288
289 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
290 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf");
291 IniCacheSave(IniCache, PathBuffer);
292 IniCacheDestroy(IniCache);
293
294 /* TODO: Append the standard unattend.inf file */
295 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
296 pSetupData->SourcePath.Buffer, L"unattend.inf");
297 if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
298 {
299 DPRINT("Does not exist: %S\n", UnattendInfPath);
300 return;
301 }
302
303 RtlInitUnicodeString(&FileName, PathBuffer);
304 InitializeObjectAttributes(&ObjectAttributes,
305 &FileName,
306 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
307 NULL,
308 NULL);
309 Status = NtOpenFile(&FileHandle,
310 FILE_APPEND_DATA | SYNCHRONIZE,
311 &ObjectAttributes,
312 &IoStatusBlock,
313 FILE_SHARE_READ,
314 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
315 if (!NT_SUCCESS(Status))
316 {
317 DPRINT1("Cannot load %S as an INI file!\n", PathBuffer);
318 return;
319 }
320
321 /* Query the file size */
322 Status = NtQueryInformationFile(FileHandle,
323 &IoStatusBlock,
324 &FileInfo,
325 sizeof(FileInfo),
326 FileStandardInformation);
327 if (!NT_SUCCESS(Status))
328 {
329 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
330 FileInfo.EndOfFile.QuadPart = 0ULL;
331 }
332
333 Status = OpenAndMapFile(NULL,
334 UnattendInfPath,
335 &UnattendFileHandle,
336 &FileSize,
337 &SectionHandle,
338 &ViewBase,
339 FALSE);
340 if (!NT_SUCCESS(Status))
341 {
342 DPRINT1("Cannot load %S !\n", UnattendInfPath);
343 NtClose(FileHandle);
344 return;
345 }
346
347 /* Write to the INI file */
348
349 /* "\r\n" */
350 Status = NtWriteFile(FileHandle,
351 NULL,
352 NULL,
353 NULL,
354 &IoStatusBlock,
355 (PVOID)CrLf,
356 sizeof(CrLf),
357 &FileInfo.EndOfFile,
358 NULL);
359
360 Status = NtWriteFile(FileHandle,
361 NULL,
362 NULL,
363 NULL,
364 &IoStatusBlock,
365 ViewBase,
366 FileSize,
367 NULL,
368 NULL);
369 if (!NT_SUCCESS(Status))
370 {
371 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
372 }
373
374 /* Finally, unmap and close the file */
375 UnMapAndCloseFile(UnattendFileHandle, SectionHandle, ViewBase);
376
377 NtClose(FileHandle);
378 #endif
379 }
380
381 /**
382 * @brief
383 * Determine the installation source path and isolate its useful
384 * path components (root path and source sub-directory).
385 *
386 * The installation source path is based either on the installer's
387 * image file path, or on the \SystemRoot full path.
388 *
389 * In case the \SystemRoot full path prefixes the image file path,
390 * use the resolved \SystemRoot as the installation source path.
391 * Otherwise, use the image file path.
392 *
393 * The returned strings are allocated with RtlCreateUnicodeString(),
394 * and need to be freed with RtlFreeUnicodeString() after being used.
395 *
396 * Example of output:
397 * SourcePath: '\Device\CdRom0\I386'
398 * SourceRootPath: '\Device\CdRom0'
399 * SourceRootDir: '\I386'
400 **/
401 NTSTATUS
GetSourcePaths(_Out_ PUNICODE_STRING SourcePath,_Out_ PUNICODE_STRING SourceRootPath,_Out_ PUNICODE_STRING SourceRootDir)402 GetSourcePaths(
403 _Out_ PUNICODE_STRING SourcePath,
404 _Out_ PUNICODE_STRING SourceRootPath,
405 _Out_ PUNICODE_STRING SourceRootDir)
406 {
407 NTSTATUS Status;
408 ULONG BufferSize;
409 PWCHAR Ptr;
410 HANDLE LinkHandle;
411 OBJECT_ATTRIBUTES ObjectAttributes;
412 IO_STATUS_BLOCK IoStatusBlock;
413 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ImageFileBuffer;
414 PUNICODE_STRING InstallSourcePath = &ImageFileBuffer.Name;
415 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } SystemRootBuffer;
416 PUNICODE_STRING SystemRootPath = &SystemRootBuffer.Name;
417 const UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot");
418
419 /* Retrieve the installer's full image file path */
420 RtlInitEmptyUnicodeString(InstallSourcePath,
421 ImageFileBuffer.Buffer,
422 sizeof(ImageFileBuffer.Buffer));
423 BufferSize = sizeof(ImageFileBuffer);
424 Status = NtQueryInformationProcess(NtCurrentProcess(),
425 ProcessImageFileName,
426 InstallSourcePath,
427 BufferSize,
428 NULL);
429 // STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ?
430 if (!NT_SUCCESS(Status))
431 return Status;
432 ASSERT(InstallSourcePath->Length < InstallSourcePath->MaximumLength);
433
434 /* Go to the beginning of the path component, stop at the separator */
435 Ptr = ImageFileBuffer.Buffer + (InstallSourcePath->Length / sizeof(WCHAR));
436 while ((Ptr > ImageFileBuffer.Buffer) && (*Ptr != OBJ_NAME_PATH_SEPARATOR))
437 --Ptr;
438 /* Strip the trailing file name (at the separator or beginning of buffer)
439 * and manually NULL-terminate */
440 InstallSourcePath->Length = (ULONG_PTR)Ptr - (ULONG_PTR)ImageFileBuffer.Buffer;
441 InstallSourcePath->Buffer[InstallSourcePath->Length / sizeof(WCHAR)] = UNICODE_NULL;
442
443
444 /*
445 * Now, resolve the \SystemRoot symlink target full path.
446 *
447 * The symlink target path resolution requires reparsing, because it
448 * can reference other symlinks. This is what happens, for example when
449 * booting the installation from a removable hard-disk. We can have:
450 *
451 * \SystemRoot ---> \Device\Harddisk1\Partition1\ReactOS
452 * and: \Device\Harddisk1\Partition1 ---> \Device\HarddiskVolume2
453 * etc.
454 * and we wish to resolve \SystemRoot to: \Device\HarddiskVolume2\ReactOS
455 *
456 * We then verify whether it prefixes the image file path obtained
457 * from the step above, which is a fully reparsed path.
458 *
459 * - Using NtOpenSymbolicLinkObject(SYMBOLIC_LINK_QUERY) followed by
460 * NtQuerySymbolicLinkObject() would only resolve the first symlink
461 * but not the others (\Device\Harddisk1\Partition1 left as is).
462 *
463 * - Since \SystemRoot has to point to a directory, we try opening
464 * the directory itself: NtOpenFile(..., FILE_DIRECTORY_FILE).
465 *
466 * - A call to NtQueryInformationFile(FileNameInformation) alone on
467 * the obtained handle would only retrieve the FS directory name,
468 * i.e. \ReactOS , but not the whole NT path.
469 *
470 * - We therefore use NtQueryObject(), which allows retrieving the
471 * full resolved NT path (device name + FS directory name).
472 */
473
474 InitializeObjectAttributes(&ObjectAttributes,
475 (PUNICODE_STRING)&SystemRoot,
476 OBJ_CASE_INSENSITIVE,
477 NULL,
478 NULL);
479
480 RtlInitEmptyUnicodeString(SystemRootPath,
481 SystemRootBuffer.Buffer,
482 sizeof(SystemRootBuffer.Buffer));
483
484 Status = NtOpenFile(&LinkHandle,
485 SYNCHRONIZE,
486 &ObjectAttributes,
487 &IoStatusBlock,
488 FILE_SHARE_READ | FILE_SHARE_WRITE,
489 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
490 /*| FILE_OPEN_FOR_BACKUP_INTENT*/);
491 if (NT_SUCCESS(Status))
492 {
493 /* Resolve the path and close its handle */
494 Status = NtQueryObject(LinkHandle,
495 ObjectNameInformation,
496 &SystemRootBuffer,
497 sizeof(SystemRootBuffer),
498 &BufferSize);
499 NtClose(LinkHandle);
500 }
501 /* If any of the calls above failed, try to naively resolve the symlink */
502 if (!NT_SUCCESS(Status))
503 {
504 RtlInitEmptyUnicodeString(SystemRootPath,
505 SystemRootBuffer.Buffer,
506 sizeof(SystemRootBuffer.Buffer));
507
508 Status = NtOpenSymbolicLinkObject(&LinkHandle,
509 SYMBOLIC_LINK_QUERY,
510 &ObjectAttributes);
511 if (NT_SUCCESS(Status))
512 {
513 /* Resolve the link and close its handle */
514 Status = NtQuerySymbolicLinkObject(LinkHandle,
515 SystemRootPath,
516 &BufferSize);
517 NtClose(LinkHandle);
518 }
519 }
520 ASSERT(SystemRootPath->Length < SystemRootPath->MaximumLength);
521
522 /*
523 * If the resolved \SystemRoot is a prefix of the image file path,
524 * use \SystemRoot instead as the installation source path.
525 *
526 * If opening the \SystemRoot link failed (usually due to wrong
527 * access rights), do not consider this as a fatal error, and
528 * use the image file path as the installation source path.
529 */
530 if (NT_SUCCESS(Status) && RtlPrefixUnicodeString(SystemRootPath, InstallSourcePath, TRUE))
531 InstallSourcePath = SystemRootPath;
532
533
534 /*
535 * Retrieve the different source path components.
536 */
537 RtlCreateUnicodeString(SourcePath, InstallSourcePath->Buffer);
538
539 /* Isolate and strip the trailing (source root) directory */
540 Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR);
541 if (Ptr)
542 {
543 RtlCreateUnicodeString(SourceRootDir, Ptr);
544 *Ptr = UNICODE_NULL;
545 }
546 else
547 {
548 RtlCreateUnicodeString(SourceRootDir, L"");
549 }
550
551 RtlCreateUnicodeString(SourceRootPath, InstallSourcePath->Buffer);
552
553 return STATUS_SUCCESS;
554 }
555
556 ERROR_NUMBER
LoadSetupInf(IN OUT PUSETUP_DATA pSetupData)557 LoadSetupInf(
558 IN OUT PUSETUP_DATA pSetupData)
559 {
560 INFCONTEXT Context;
561 UINT ErrorLine;
562 INT IntValue;
563 PCWSTR Value;
564 WCHAR FileNameBuffer[MAX_PATH];
565
566 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2,
567 pSetupData->SourcePath.Buffer, L"txtsetup.sif");
568
569 DPRINT("SetupInf path: '%S'\n", FileNameBuffer);
570
571 pSetupData->SetupInf =
572 SpInfOpenInfFile(FileNameBuffer,
573 NULL,
574 INF_STYLE_WIN4,
575 pSetupData->LanguageId,
576 &ErrorLine);
577 if (pSetupData->SetupInf == INVALID_HANDLE_VALUE)
578 return ERROR_LOAD_TXTSETUPSIF;
579
580 /* Open 'Version' section */
581 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Version", L"Signature", &Context))
582 return ERROR_CORRUPT_TXTSETUPSIF;
583
584 /* Get pointer 'Signature' key */
585 if (!INF_GetData(&Context, NULL, &Value))
586 return ERROR_CORRUPT_TXTSETUPSIF;
587
588 /* Check 'Signature' string */
589 if (_wcsicmp(Value, L"$ReactOS$") != 0 &&
590 _wcsicmp(Value, L"$Windows NT$") != 0)
591 {
592 INF_FreeData(Value);
593 return ERROR_SIGNATURE_TXTSETUPSIF;
594 }
595
596 INF_FreeData(Value);
597
598 /* Open 'DiskSpaceRequirements' section */
599 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
600 return ERROR_CORRUPT_TXTSETUPSIF;
601
602 pSetupData->RequiredPartitionDiskSpace = ~0;
603
604 /* Get the 'FreeSysPartDiskSpace' value */
605 if (!SpInfGetIntField(&Context, 1, &IntValue))
606 return ERROR_CORRUPT_TXTSETUPSIF;
607
608 pSetupData->RequiredPartitionDiskSpace = (ULONG)IntValue;
609
610 //
611 // Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif
612 // See CORE-9023
613 // Support for that should also be added in setupldr.
614 //
615
616 /* Update the Setup Source paths */
617 if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourceDevice", &Context))
618 {
619 /*
620 * Get optional pointer 'SetupSourceDevice' key, its presence
621 * will dictate whether we also need 'SetupSourcePath'.
622 */
623 if (INF_GetData(&Context, NULL, &Value))
624 {
625 /* Free the old source root path string and create the new one */
626 RtlFreeUnicodeString(&pSetupData->SourceRootPath);
627 RtlCreateUnicodeString(&pSetupData->SourceRootPath, Value);
628 INF_FreeData(Value);
629
630 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourcePath", &Context))
631 {
632 /* The 'SetupSourcePath' value is mandatory! */
633 return ERROR_CORRUPT_TXTSETUPSIF;
634 }
635
636 /* Get pointer 'SetupSourcePath' key */
637 if (!INF_GetData(&Context, NULL, &Value))
638 {
639 /* The 'SetupSourcePath' value is mandatory! */
640 return ERROR_CORRUPT_TXTSETUPSIF;
641 }
642
643 /* Free the old source path string and create the new one */
644 RtlFreeUnicodeString(&pSetupData->SourceRootDir);
645 RtlCreateUnicodeString(&pSetupData->SourceRootDir, Value);
646 INF_FreeData(Value);
647 }
648 }
649
650 /* Search for 'DefaultPath' in the 'SetupData' section */
651 pSetupData->InstallationDirectory[0] = 0;
652 if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"DefaultPath", &Context))
653 {
654 /* Get pointer 'DefaultPath' key */
655 if (!INF_GetData(&Context, NULL, &Value))
656 return ERROR_CORRUPT_TXTSETUPSIF;
657
658 RtlStringCchCopyW(pSetupData->InstallationDirectory,
659 ARRAYSIZE(pSetupData->InstallationDirectory),
660 Value);
661
662 INF_FreeData(Value);
663 }
664
665 return ERROR_SUCCESS;
666 }
667
668 /**
669 * @brief Find or set the active system partition.
670 **/
671 BOOLEAN
InitSystemPartition(_In_ PPARTLIST PartitionList,_In_ PPARTENTRY InstallPartition,_Out_ PPARTENTRY * pSystemPartition,_In_opt_ PFSVOL_CALLBACK FsVolCallback,_In_opt_ PVOID Context)672 InitSystemPartition(
673 /**/_In_ PPARTLIST PartitionList, /* HACK HACK! */
674 /**/_In_ PPARTENTRY InstallPartition, /* HACK HACK! */
675 /**/_Out_ PPARTENTRY* pSystemPartition, /* HACK HACK! */
676 _In_opt_ PFSVOL_CALLBACK FsVolCallback,
677 _In_opt_ PVOID Context)
678 {
679 FSVOL_OP Result;
680 PPARTENTRY SystemPartition;
681 PPARTENTRY OldActivePart;
682
683 /*
684 * If we install on a fixed disk, try to find a supported system
685 * partition on the system. Otherwise if we install on a removable disk
686 * use the install partition as the system partition.
687 */
688 if (InstallPartition->DiskEntry->MediaType == FixedMedia)
689 {
690 SystemPartition = FindSupportedSystemPartition(PartitionList,
691 FALSE,
692 InstallPartition->DiskEntry,
693 InstallPartition);
694 /* Use the original system partition as the old active partition hint */
695 OldActivePart = PartitionList->SystemPartition;
696
697 if ( SystemPartition && PartitionList->SystemPartition &&
698 (SystemPartition != PartitionList->SystemPartition) )
699 {
700 DPRINT1("We are using a different system partition!!\n");
701
702 Result = FsVolCallback(Context,
703 ChangeSystemPartition,
704 (ULONG_PTR)SystemPartition,
705 0);
706 if (Result != FSVOL_DOIT)
707 return FALSE;
708 }
709 }
710 else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia)
711 {
712 SystemPartition = InstallPartition;
713 /* Don't specify any old active partition hint */
714 OldActivePart = NULL;
715 }
716
717 if (!SystemPartition)
718 {
719 FsVolCallback(Context,
720 FSVOLNOTIFY_PARTITIONERROR,
721 ERROR_SYSTEM_PARTITION_NOT_FOUND,
722 0);
723 return FALSE;
724 }
725
726 *pSystemPartition = SystemPartition;
727
728 /*
729 * If the system partition can be created in some
730 * non-partitioned space, create it now.
731 */
732 if (!SystemPartition->IsPartitioned)
733 {
734 /* Automatically create the partition; it will be
735 * formatted later with default parameters */
736 // FIXME: Don't use the whole empty space, but a minimal size
737 // specified from the TXTSETUP.SIF or unattended setup.
738 CreatePartition(PartitionList,
739 SystemPartition,
740 0ULL,
741 0);
742 ASSERT(SystemPartition->IsPartitioned);
743 }
744
745 /* Set it as such */
746 if (!SetActivePartition(PartitionList, SystemPartition, OldActivePart))
747 {
748 DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition);
749 ASSERT(FALSE);
750 }
751
752 /*
753 * In all cases, whether or not we are going to perform a formatting,
754 * we must perform a filesystem check of the system partition.
755 */
756 if (SystemPartition->Volume)
757 SystemPartition->Volume->NeedsCheck = TRUE;
758
759 return TRUE;
760 }
761
762
763 #define IS_PATH_SEPARATOR(c) ((c) == L'\\' || (c) == L'/')
764
765 /**
766 * @brief
767 * Verify whether the given directory is suitable for ReactOS installation.
768 * Each path component must be a valid 8.3 name.
769 **/
770 BOOLEAN
IsValidInstallDirectory(_In_ PCWSTR InstallDir)771 IsValidInstallDirectory(
772 _In_ PCWSTR InstallDir)
773 {
774 PCWCH p;
775
776 /* As with the NT installer, fail if the path is empty or "\\" */
777 p = InstallDir;
778 if (!*p || (IS_PATH_SEPARATOR(*p) && !*(p + 1)))
779 return FALSE;
780
781 /* The path must contain only valid characters */
782 for (p = InstallDir; *p; ++p)
783 {
784 if (!IS_VALID_INSTALL_PATH_CHAR(*p))
785 return FALSE;
786 }
787
788 /*
789 * Loop over each path component and verify that each is a valid 8.3 name.
790 */
791 for (p = InstallDir; *p;)
792 {
793 PCWSTR Path;
794 SIZE_T Length;
795 UNICODE_STRING Name;
796 BOOLEAN IsNameLegal, SpacesInName;
797
798 /* Skip any first separator */
799 if (IS_PATH_SEPARATOR(*p))
800 ++p;
801
802 /* Now skip past the path component until we reach the next separator */
803 Path = p;
804 while (*p && !IS_PATH_SEPARATOR(*p))
805 ++p;
806 if (p == Path)
807 {
808 /* Succeed if nothing else follows this separator; otherwise
809 * it's a separator and consecutive ones are not supported */
810 return (!*p);
811 }
812
813 /* Calculate the path component length */
814 Length = p - Path;
815
816 /* As with the NT installer, fail for '.' and '..';
817 * RtlIsNameLegalDOS8Dot3() would succeed otherwise */
818 if ((Length == 1 && *Path == '.') || (Length == 2 && *Path == '.' && *(Path + 1) == '.'))
819 return FALSE;
820
821 /* As with the NT installer, allow _only ONE trailing_ dot in
822 * the path component (but not 2 or more), by reducing Length
823 * in that case; RtlIsNameLegalDOS8Dot3() would fail otherwise */
824 if (Length > 1 && *(p - 2) != L'.' && *(p - 1) == L'.')
825 --Length;
826
827 if (Length == 0)
828 return FALSE;
829
830 /* Verify that the path component is a valid 8.3 name */
831 // if (Length > 8+1+3)
832 // return FALSE;
833 Name.Length = Name.MaximumLength = (USHORT)(Length * sizeof(WCHAR));
834 Name.Buffer = (PWCHAR)Path;
835 SpacesInName = FALSE;
836 IsNameLegal = RtlIsNameLegalDOS8Dot3(&Name, NULL, &SpacesInName);
837
838 /* If it isn't legal or contain spaces, fail */
839 if (!IsNameLegal || SpacesInName)
840 {
841 DPRINT("'%wZ' is %s 8.3 filename %s spaces\n",
842 &Name,
843 (IsNameLegal ? "a valid" : "an invalid"),
844 (SpacesInName ? "with" : "without"));
845 return FALSE;
846 }
847 /* Go to the next path component */
848 }
849
850 return TRUE;
851 }
852
853
854 NTSTATUS
InitDestinationPaths(_Inout_ PUSETUP_DATA pSetupData,_In_ PCWSTR InstallationDir,_In_ PVOLENTRY Volume)855 InitDestinationPaths(
856 _Inout_ PUSETUP_DATA pSetupData,
857 _In_ PCWSTR InstallationDir,
858 _In_ PVOLENTRY Volume)
859 {
860 NTSTATUS Status;
861 PPARTENTRY PartEntry = Volume->PartEntry;
862 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
863 WCHAR PathBuffer[RTL_NUMBER_OF_FIELD(VOLINFO, DeviceName) + 1];
864
865 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
866
867 /* Create 'pSetupData->DestinationRootPath' string */
868 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
869 Status = RtlStringCchPrintfW(PathBuffer, _countof(PathBuffer),
870 L"%s\\", Volume->Info.DeviceName);
871 if (!NT_SUCCESS(Status))
872 {
873 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status);
874 return Status;
875 }
876
877 Status = RtlCreateUnicodeString(&pSetupData->DestinationRootPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
878
879 if (!NT_SUCCESS(Status))
880 {
881 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
882 return Status;
883 }
884
885 DPRINT("DestinationRootPath: %wZ\n", &pSetupData->DestinationRootPath);
886
887 // FIXME! Which variable to choose?
888 if (!InstallationDir)
889 InstallationDir = pSetupData->InstallationDirectory;
890
891 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
892 /* Create 'pSetupData->DestinationArcPath' */
893 RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
894
895 if (DiskEntry->MediaType == FixedMedia)
896 {
897 if (DiskEntry->BiosFound)
898 {
899 #if 1
900 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
901 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
902 DiskEntry->HwFixedDiskNumber,
903 PartEntry->OnDiskPartitionNumber);
904 #else
905 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
906 L"multi(%lu)disk(%lu)rdisk(%lu)partition(%lu)\\",
907 DiskEntry->HwAdapterNumber,
908 DiskEntry->HwControllerNumber,
909 DiskEntry->HwFixedDiskNumber,
910 PartEntry->OnDiskPartitionNumber);
911 #endif
912 DPRINT1("Fixed disk found by BIOS, using MULTI ARC path '%S'\n", PathBuffer);
913 }
914 else
915 {
916 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
917 L"scsi(%u)disk(%u)rdisk(%u)partition(%lu)\\",
918 DiskEntry->Port,
919 DiskEntry->Bus,
920 DiskEntry->Id,
921 PartEntry->OnDiskPartitionNumber);
922 DPRINT1("Fixed disk not found by BIOS, using SCSI ARC path '%S'\n", PathBuffer);
923 }
924 }
925 else // if (DiskEntry->MediaType == RemovableMedia)
926 {
927 #if 1
928 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
929 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
930 0, 1);
931 DPRINT1("Removable disk, using MULTI ARC path '%S'\n", PathBuffer);
932 #else
933 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
934 L"signature(%08x)disk(%u)rdisk(%u)partition(%lu)\\",
935 DiskEntry->LayoutBuffer->Signature,
936 DiskEntry->Bus,
937 DiskEntry->Id,
938 PartEntry->OnDiskPartitionNumber);
939 DPRINT1("Removable disk, using SIGNATURE ARC path '%S'\n", PathBuffer);
940 #endif
941 }
942
943 if (!NT_SUCCESS(Status))
944 {
945 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status);
946 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
947 return Status;
948 }
949
950 Status = ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallationDir);
951
952 if (!NT_SUCCESS(Status))
953 {
954 DPRINT1("ConcatPaths() failed with status 0x%08lx\n", Status);
955 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
956 return Status;
957 }
958
959 Status = RtlCreateUnicodeString(&pSetupData->DestinationArcPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
960
961 if (!NT_SUCCESS(Status))
962 {
963 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
964 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
965 return Status;
966 }
967
968 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
969 /* Create 'pSetupData->DestinationPath' string */
970 RtlFreeUnicodeString(&pSetupData->DestinationPath);
971 Status = CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
972 pSetupData->DestinationRootPath.Buffer, InstallationDir);
973
974 if (!NT_SUCCESS(Status))
975 {
976 DPRINT1("CombinePaths() failed with status 0x%08lx\n", Status);
977 RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
978 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
979 return Status;
980 }
981
982 Status = RtlCreateUnicodeString(&pSetupData->DestinationPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
983
984 if (!NT_SUCCESS(Status))
985 {
986 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
987 RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
988 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
989 return Status;
990 }
991
992 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
993 // FIXME: This is only temporary!! Must be removed later!
994 Status = RtlCreateUnicodeString(&pSetupData->InstallPath, InstallationDir) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
995
996 if (!NT_SUCCESS(Status))
997 {
998 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
999 RtlFreeUnicodeString(&pSetupData->DestinationPath);
1000 RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
1001 RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
1002 return Status;
1003 }
1004
1005 return STATUS_SUCCESS;
1006 }
1007
1008 // NTSTATUS
1009 ERROR_NUMBER
InitializeSetup(IN OUT PUSETUP_DATA pSetupData,IN ULONG InitPhase)1010 InitializeSetup(
1011 IN OUT PUSETUP_DATA pSetupData,
1012 IN ULONG InitPhase)
1013 {
1014 if (InitPhase == 0)
1015 {
1016 RtlZeroMemory(pSetupData, sizeof(*pSetupData));
1017
1018 /* Initialize error handling */
1019 pSetupData->LastErrorNumber = ERROR_SUCCESS;
1020 pSetupData->ErrorRoutine = NULL;
1021
1022 /* Initialize global unicode strings */
1023 RtlInitUnicodeString(&pSetupData->SourcePath, NULL);
1024 RtlInitUnicodeString(&pSetupData->SourceRootPath, NULL);
1025 RtlInitUnicodeString(&pSetupData->SourceRootDir, NULL);
1026 RtlInitUnicodeString(&pSetupData->DestinationArcPath, NULL);
1027 RtlInitUnicodeString(&pSetupData->DestinationPath, NULL);
1028 RtlInitUnicodeString(&pSetupData->DestinationRootPath, NULL);
1029 RtlInitUnicodeString(&pSetupData->SystemRootPath, NULL);
1030
1031 // FIXME: This is only temporary!! Must be removed later!
1032 /***/RtlInitUnicodeString(&pSetupData->InstallPath, NULL);/***/
1033
1034 //
1035 // TODO: Load and start SetupDD, and ask it for the information
1036 //
1037
1038 return ERROR_SUCCESS;
1039 }
1040 else
1041 if (InitPhase == 1)
1042 {
1043 ERROR_NUMBER Error;
1044 NTSTATUS Status;
1045
1046 /* Get the source path and source root path */
1047 Status = GetSourcePaths(&pSetupData->SourcePath,
1048 &pSetupData->SourceRootPath,
1049 &pSetupData->SourceRootDir);
1050 if (!NT_SUCCESS(Status))
1051 {
1052 DPRINT1("GetSourcePaths() failed (Status 0x%08lx)\n", Status);
1053 return ERROR_NO_SOURCE_DRIVE;
1054 }
1055 DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData->SourcePath);
1056 DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData->SourceRootPath);
1057 DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData->SourceRootDir);
1058
1059 /* Set up default values */
1060 pSetupData->DestinationDiskNumber = 0;
1061 pSetupData->DestinationPartitionNumber = 1;
1062 pSetupData->BootLoaderLocation = 2; // Default to "System partition"
1063 pSetupData->FormatPartition = 0;
1064 pSetupData->AutoPartition = 0;
1065 pSetupData->FsType = 0;
1066
1067 /* Load 'txtsetup.sif' from the installation media */
1068 Error = LoadSetupInf(pSetupData);
1069 if (Error != ERROR_SUCCESS)
1070 {
1071 DPRINT1("LoadSetupInf() failed (Error 0x%lx)\n", Error);
1072 return Error;
1073 }
1074 DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData->SourcePath);
1075 DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData->SourceRootPath);
1076 DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData->SourceRootDir);
1077
1078 /* Retrieve the target machine architecture type */
1079 // FIXME: This should be determined at runtime!!
1080 // FIXME: Allow for (pre-)installing on an architecture
1081 // different from the current one?
1082 #if defined(SARCH_XBOX)
1083 pSetupData->ArchType = ARCH_Xbox;
1084 // #elif defined(SARCH_PC98)
1085 #else // TODO: Arc, UEFI
1086 pSetupData->ArchType = (IsNEC_98 ? ARCH_NEC98x86 : ARCH_PcAT);
1087 #endif
1088
1089 return ERROR_SUCCESS;
1090 }
1091
1092 return ERROR_SUCCESS;
1093 }
1094
1095 VOID
FinishSetup(IN OUT PUSETUP_DATA pSetupData)1096 FinishSetup(
1097 IN OUT PUSETUP_DATA pSetupData)
1098 {
1099 /* Destroy the computer settings list */
1100 if (pSetupData->ComputerList != NULL)
1101 {
1102 DestroyGenericList(pSetupData->ComputerList, TRUE);
1103 pSetupData->ComputerList = NULL;
1104 }
1105
1106 /* Destroy the display settings list */
1107 if (pSetupData->DisplayList != NULL)
1108 {
1109 DestroyGenericList(pSetupData->DisplayList, TRUE);
1110 pSetupData->DisplayList = NULL;
1111 }
1112
1113 /* Destroy the keyboard settings list */
1114 if (pSetupData->KeyboardList != NULL)
1115 {
1116 DestroyGenericList(pSetupData->KeyboardList, TRUE);
1117 pSetupData->KeyboardList = NULL;
1118 }
1119
1120 /* Destroy the keyboard layout list */
1121 if (pSetupData->LayoutList != NULL)
1122 {
1123 DestroyGenericList(pSetupData->LayoutList, TRUE);
1124 pSetupData->LayoutList = NULL;
1125 }
1126
1127 /* Destroy the languages list */
1128 if (pSetupData->LanguageList != NULL)
1129 {
1130 DestroyGenericList(pSetupData->LanguageList, FALSE);
1131 pSetupData->LanguageList = NULL;
1132 }
1133
1134 /* Close the Setup INF */
1135 SpInfCloseInfFile(pSetupData->SetupInf);
1136 }
1137
1138 /*
1139 * SIDEEFFECTS
1140 * Calls RegInitializeRegistry
1141 * Calls ImportRegistryFile
1142 * Calls SetDefaultPagefile
1143 * Calls SetMountedDeviceValues
1144 */
1145 ERROR_NUMBER
UpdateRegistry(IN OUT PUSETUP_DATA pSetupData,IN BOOLEAN RepairUpdateFlag,IN PPARTLIST PartitionList,IN WCHAR DestinationDriveLetter,IN PCWSTR SelectedLanguageId,IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL,IN PFONTSUBSTSETTINGS SubstSettings OPTIONAL)1146 UpdateRegistry(
1147 IN OUT PUSETUP_DATA pSetupData,
1148 /**/IN BOOLEAN RepairUpdateFlag, /* HACK HACK! */
1149 /**/IN PPARTLIST PartitionList, /* HACK HACK! */
1150 /**/IN WCHAR DestinationDriveLetter, /* HACK HACK! */
1151 /**/IN PCWSTR SelectedLanguageId, /* HACK HACK! */
1152 IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL,
1153 IN PFONTSUBSTSETTINGS SubstSettings OPTIONAL)
1154 {
1155 ERROR_NUMBER ErrorNumber;
1156 NTSTATUS Status;
1157 INFCONTEXT InfContext;
1158 PCWSTR Action;
1159 PCWSTR File;
1160 PCWSTR Section;
1161 BOOLEAN Success;
1162 BOOLEAN ShouldRepairRegistry = FALSE;
1163 BOOLEAN Delete;
1164
1165 if (RepairUpdateFlag)
1166 {
1167 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
1168
1169 /* Verify the registry hives and check whether we need to update or repair any of them */
1170 Status = VerifyRegistryHives(&pSetupData->DestinationPath, &ShouldRepairRegistry);
1171 if (!NT_SUCCESS(Status))
1172 {
1173 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
1174 ShouldRepairRegistry = FALSE;
1175 }
1176 if (!ShouldRepairRegistry)
1177 DPRINT1("No need to repair the registry\n");
1178 }
1179
1180 DoUpdate:
1181 ErrorNumber = ERROR_SUCCESS;
1182
1183 /* Update the registry */
1184 if (StatusRoutine) StatusRoutine(RegHiveUpdate);
1185
1186 /* Initialize the registry and setup the registry hives */
1187 Status = RegInitializeRegistry(&pSetupData->DestinationPath);
1188 if (!NT_SUCCESS(Status))
1189 {
1190 DPRINT1("RegInitializeRegistry() failed\n");
1191 /********** HACK!!!!!!!!!!! **********/
1192 if (Status == STATUS_NOT_IMPLEMENTED)
1193 {
1194 /* The hack was called, return its corresponding error */
1195 return ERROR_INITIALIZE_REGISTRY;
1196 }
1197 else
1198 /*************************************/
1199 {
1200 /* Something else failed */
1201 return ERROR_CREATE_HIVE;
1202 }
1203 }
1204
1205 if (!RepairUpdateFlag || ShouldRepairRegistry)
1206 {
1207 /*
1208 * We fully setup the hives, in case we are doing a fresh installation
1209 * (RepairUpdateFlag == FALSE), or in case we are doing an update
1210 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
1211 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
1212 */
1213
1214 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible
1215 if (!Success)
1216 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific
1217
1218 if (!Success)
1219 {
1220 DPRINT1("SpInfFindFirstLine() failed\n");
1221 ErrorNumber = ERROR_FIND_REGISTRY;
1222 goto Cleanup;
1223 }
1224 }
1225 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
1226 {
1227 /*
1228 * In case we are doing an update (RepairUpdateFlag == TRUE) and
1229 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
1230 * we only update the hives.
1231 */
1232
1233 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext);
1234 if (!Success)
1235 {
1236 /* Nothing to do for update! */
1237 DPRINT1("No update needed for the registry!\n");
1238 goto Cleanup;
1239 }
1240 }
1241
1242 do
1243 {
1244 INF_GetDataField(&InfContext, 0, &Action);
1245 INF_GetDataField(&InfContext, 1, &File);
1246 INF_GetDataField(&InfContext, 2, &Section);
1247
1248 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section);
1249
1250 if (Action == NULL)
1251 {
1252 INF_FreeData(Action);
1253 INF_FreeData(File);
1254 INF_FreeData(Section);
1255 break; // Hackfix
1256 }
1257
1258 if (!_wcsicmp(Action, L"AddReg"))
1259 Delete = FALSE;
1260 else if (!_wcsicmp(Action, L"DelReg"))
1261 Delete = TRUE;
1262 else
1263 {
1264 DPRINT1("Unrecognized registry INF action '%S'\n", Action);
1265 INF_FreeData(Action);
1266 INF_FreeData(File);
1267 INF_FreeData(Section);
1268 continue;
1269 }
1270
1271 INF_FreeData(Action);
1272
1273 if (StatusRoutine) StatusRoutine(ImportRegHive, File);
1274
1275 if (!ImportRegistryFile(pSetupData->SourcePath.Buffer,
1276 File, Section,
1277 pSetupData->LanguageId, Delete))
1278 {
1279 DPRINT1("Importing %S failed\n", File);
1280 INF_FreeData(File);
1281 INF_FreeData(Section);
1282 ErrorNumber = ERROR_IMPORT_HIVE;
1283 goto Cleanup;
1284 }
1285 } while (SpInfFindNextLine(&InfContext, &InfContext));
1286
1287 if (!RepairUpdateFlag || ShouldRepairRegistry)
1288 {
1289 /* See the explanation for this test above */
1290
1291 PGENERIC_LIST_ENTRY Entry;
1292 PCWSTR LanguageId; // LocaleID;
1293
1294 Entry = GetCurrentListEntry(pSetupData->DisplayList);
1295 ASSERT(Entry);
1296 pSetupData->DisplayType = ((PGENENTRY)GetListEntryData(Entry))->Id;
1297 ASSERT(pSetupData->DisplayType);
1298
1299 /* Update display registry settings */
1300 if (StatusRoutine) StatusRoutine(DisplaySettingsUpdate);
1301 if (!ProcessDisplayRegistry(pSetupData->SetupInf, pSetupData->DisplayType))
1302 {
1303 ErrorNumber = ERROR_UPDATE_DISPLAY_SETTINGS;
1304 goto Cleanup;
1305 }
1306
1307 Entry = GetCurrentListEntry(pSetupData->LanguageList);
1308 ASSERT(Entry);
1309 LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id;
1310 ASSERT(LanguageId);
1311
1312 /* Set the locale */
1313 if (StatusRoutine) StatusRoutine(LocaleSettingsUpdate);
1314 if (!ProcessLocaleRegistry(/*pSetupData->*/LanguageId))
1315 {
1316 ErrorNumber = ERROR_UPDATE_LOCALESETTINGS;
1317 goto Cleanup;
1318 }
1319
1320 /* Add the keyboard layouts for the given language (without user override) */
1321 if (StatusRoutine) StatusRoutine(KeybLayouts);
1322 if (!AddKeyboardLayouts(SelectedLanguageId))
1323 {
1324 ErrorNumber = ERROR_ADDING_KBLAYOUTS;
1325 goto Cleanup;
1326 }
1327
1328 if (!IsUnattendedSetup)
1329 {
1330 Entry = GetCurrentListEntry(pSetupData->LayoutList);
1331 ASSERT(Entry);
1332 pSetupData->LayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id;
1333 ASSERT(pSetupData->LayoutId);
1334
1335 /* Update keyboard layout settings with user-overridden values */
1336 // FIXME: Wouldn't it be better to do it all at once
1337 // with the AddKeyboardLayouts() step?
1338 if (StatusRoutine) StatusRoutine(KeybSettingsUpdate);
1339 if (!ProcessKeyboardLayoutRegistry(pSetupData->LayoutId, SelectedLanguageId))
1340 {
1341 ErrorNumber = ERROR_UPDATE_KBSETTINGS;
1342 goto Cleanup;
1343 }
1344 }
1345
1346 /* Set GeoID */
1347 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId)))
1348 {
1349 ErrorNumber = ERROR_UPDATE_GEOID;
1350 goto Cleanup;
1351 }
1352
1353 /* Add codepage information to registry */
1354 if (StatusRoutine) StatusRoutine(CodePageInfoUpdate);
1355 if (!AddCodePage(SelectedLanguageId))
1356 {
1357 ErrorNumber = ERROR_ADDING_CODEPAGE;
1358 goto Cleanup;
1359 }
1360
1361 /* Set the default pagefile entry */
1362 SetDefaultPagefile(DestinationDriveLetter);
1363
1364 /* Update the mounted devices list */
1365 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
1366 SetMountedDeviceValues(PartitionList);
1367 }
1368
1369 #ifdef __REACTOS__
1370 if (SubstSettings)
1371 {
1372 /* HACK */
1373 DoRegistryFontFixup(SubstSettings, wcstoul(SelectedLanguageId, NULL, 16));
1374 }
1375 #endif
1376
1377 Cleanup:
1378 //
1379 // TODO: Unload all the registry stuff, perform cleanup,
1380 // and copy the created hive files into .sav files.
1381 //
1382 RegCleanupRegistry(&pSetupData->DestinationPath);
1383
1384 /*
1385 * Check whether we were in update/repair mode but we were actually
1386 * repairing the registry hives. If so, we have finished repairing them,
1387 * and we now reset the flag and run the proper registry update.
1388 * Otherwise we have finished the registry update!
1389 */
1390 if (RepairUpdateFlag && ShouldRepairRegistry)
1391 {
1392 ShouldRepairRegistry = FALSE;
1393 goto DoUpdate;
1394 }
1395
1396 return ErrorNumber;
1397 }
1398
1399 /* EOF */
1400