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