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)
10 /* INCLUDES *****************************************************************/
23 /* GLOBALS ******************************************************************/
25 /* FUNCTIONS ****************************************************************/
29 IN OUT PUSETUP_DATA pSetupData
)
36 WCHAR UnattendInfPath
[MAX_PATH
];
38 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
39 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
41 DPRINT("UnattendInf path: '%S'\n", UnattendInfPath
);
43 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
45 DPRINT("Does not exist: %S\n", UnattendInfPath
);
49 /* Load 'unattend.inf' from installation media */
50 UnattendInf
= SpInfOpenInfFile(UnattendInfPath
,
53 pSetupData
->LanguageId
,
55 if (UnattendInf
== INVALID_HANDLE_VALUE
)
57 DPRINT("SpInfOpenInfFile() failed\n");
61 /* Open 'Unattend' section */
62 if (!SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
64 DPRINT("SpInfFindFirstLine() failed for section 'Unattend'\n");
68 /* Get pointer 'Signature' key */
69 if (!INF_GetData(&Context
, NULL
, &Value
))
71 DPRINT("INF_GetData() failed for key 'Signature'\n");
75 /* Check 'Signature' string */
76 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
78 DPRINT("Signature not $ReactOS$\n");
85 /* Check if Unattend setup is enabled */
86 if (!SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
88 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
92 if (!INF_GetData(&Context
, NULL
, &Value
))
94 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
98 if (_wcsicmp(Value
, L
"yes") != 0)
100 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
107 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
108 if (!SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
110 DPRINT("SpInfFindFirstLine() failed for key 'DestinationDiskNumber'\n");
114 if (!SpInfGetIntField(&Context
, 1, &IntValue
))
116 DPRINT("SpInfGetIntField() failed for key 'DestinationDiskNumber'\n");
120 pSetupData
->DestinationDiskNumber
= (LONG
)IntValue
;
122 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
123 if (!SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
125 DPRINT("SpInfFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
129 if (!SpInfGetIntField(&Context
, 1, &IntValue
))
131 DPRINT("SpInfGetIntField() failed for key 'DestinationPartitionNumber'\n");
135 pSetupData
->DestinationPartitionNumber
= (LONG
)IntValue
;
137 /* Search for 'InstallationDirectory' in the 'Unattend' section (optional) */
138 if (SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
140 /* Get pointer 'InstallationDirectory' key */
141 if (!INF_GetData(&Context
, NULL
, &Value
))
143 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
147 RtlStringCchCopyW(pSetupData
->InstallationDirectory
,
148 ARRAYSIZE(pSetupData
->InstallationDirectory
),
154 IsUnattendedSetup
= TRUE
;
155 DPRINT("Running unattended setup\n");
157 /* Search for 'MBRInstallType' in the 'Unattend' section */
158 pSetupData
->MBRInstallType
= -1;
159 if (SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
161 if (SpInfGetIntField(&Context
, 1, &IntValue
))
163 pSetupData
->MBRInstallType
= IntValue
;
167 /* Search for 'FormatPartition' in the 'Unattend' section */
168 pSetupData
->FormatPartition
= 0;
169 if (SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
171 if (SpInfGetIntField(&Context
, 1, &IntValue
))
173 pSetupData
->FormatPartition
= IntValue
;
177 pSetupData
->AutoPartition
= 0;
178 if (SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
180 if (SpInfGetIntField(&Context
, 1, &IntValue
))
182 pSetupData
->AutoPartition
= IntValue
;
186 /* Search for LocaleID in the 'Unattend' section */
187 if (SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
189 if (INF_GetData(&Context
, NULL
, &Value
))
191 LONG Id
= wcstol(Value
, NULL
, 16);
192 RtlStringCchPrintfW(pSetupData
->LocaleID
,
193 ARRAYSIZE(pSetupData
->LocaleID
),
199 /* Search for FsType in the 'Unattend' section */
200 pSetupData
->FsType
= 0;
201 if (SpInfFindFirstLine(UnattendInf
, L
"Unattend", L
"FsType", &Context
))
203 if (SpInfGetIntField(&Context
, 1, &IntValue
))
205 pSetupData
->FsType
= IntValue
;
210 SpInfCloseInfFile(UnattendInf
);
215 IN OUT PUSETUP_DATA pSetupData
)
221 PINICACHE UnattendCache
;
222 PINICACHEITERATOR Iterator
;
224 // WCHAR CrLf[] = {L'\r', L'\n'};
225 CHAR CrLf
[] = {'\r', '\n'};
226 HANDLE FileHandle
, UnattendFileHandle
, SectionHandle
;
227 FILE_STANDARD_INFORMATION FileInfo
;
230 UNICODE_STRING FileName
;
231 OBJECT_ATTRIBUTES ObjectAttributes
;
232 IO_STATUS_BLOCK IoStatusBlock
;
235 PINICACHESECTION IniSection
;
236 WCHAR PathBuffer
[MAX_PATH
];
237 WCHAR UnattendInfPath
[MAX_PATH
];
239 /* Create a $winnt$.inf file with default entries */
240 IniCache
= IniCacheCreate();
244 IniSection
= IniCacheAppendSection(IniCache
, L
"SetupParams");
247 /* Key "skipmissingfiles" */
248 // RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
249 // L"\"%s\"", L"WinNt5.2");
250 // IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
251 // L"Version", PathBuffer);
254 IniSection
= IniCacheAppendSection(IniCache
, L
"Data");
257 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
258 L
"\"%s\"", IsUnattendedSetup
? L
"yes" : L
"no");
259 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
260 L
"UnattendedInstall", PathBuffer
);
262 // "floppylessbootpath" (yes/no)
264 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
265 L
"\"%s\"", L
"winnt");
266 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
267 L
"ProductType", PathBuffer
);
269 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
270 L
"\"%s\\\"", pSetupData
->SourceRootPath
.Buffer
);
271 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
272 L
"SourcePath", PathBuffer
);
274 // "floppyless" ("0")
279 /* TODO: Append the standard unattend.inf file */
280 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
281 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
282 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
284 DPRINT("Does not exist: %S\n", UnattendInfPath
);
288 Status
= IniCacheLoad(&UnattendCache
, UnattendInfPath
, FALSE
);
289 if (!NT_SUCCESS(Status
))
291 DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath
);
295 IniCacheDestroy(UnattendCache
);
298 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
299 pSetupData
->DestinationPath
.Buffer
, L
"System32\\$winnt$.inf");
300 IniCacheSave(IniCache
, PathBuffer
);
301 IniCacheDestroy(IniCache
);
305 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
306 pSetupData
->DestinationPath
.Buffer
, L
"System32\\$winnt$.inf");
307 IniCacheSave(IniCache
, PathBuffer
);
308 IniCacheDestroy(IniCache
);
310 /* TODO: Append the standard unattend.inf file */
311 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
312 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
313 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
315 DPRINT("Does not exist: %S\n", UnattendInfPath
);
319 RtlInitUnicodeString(&FileName
, PathBuffer
);
320 InitializeObjectAttributes(&ObjectAttributes
,
322 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
325 Status
= NtOpenFile(&FileHandle
,
326 FILE_APPEND_DATA
| SYNCHRONIZE
,
330 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
331 if (!NT_SUCCESS(Status
))
333 DPRINT1("Cannot load %S as an INI file!\n", PathBuffer
);
337 /* Query the file size */
338 Status
= NtQueryInformationFile(FileHandle
,
342 FileStandardInformation
);
343 if (!NT_SUCCESS(Status
))
345 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
346 FileInfo
.EndOfFile
.QuadPart
= 0ULL;
349 Status
= OpenAndMapFile(NULL
,
356 if (!NT_SUCCESS(Status
))
358 DPRINT1("Cannot load %S !\n", UnattendInfPath
);
363 /* Write to the INI file */
366 Status
= NtWriteFile(FileHandle
,
376 Status
= NtWriteFile(FileHandle
,
385 if (!NT_SUCCESS(Status
))
387 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
390 /* Finally, unmap and close the file */
391 UnMapAndCloseFile(UnattendFileHandle
, SectionHandle
, ViewBase
);
399 OUT PUNICODE_STRING SourcePath
,
400 OUT PUNICODE_STRING SourceRootPath
,
401 OUT PUNICODE_STRING SourceRootDir
)
405 OBJECT_ATTRIBUTES ObjectAttributes
;
406 UCHAR ImageFileBuffer
[sizeof(UNICODE_STRING
) + MAX_PATH
* sizeof(WCHAR
)];
407 PUNICODE_STRING InstallSourcePath
= (PUNICODE_STRING
)&ImageFileBuffer
;
408 WCHAR SystemRootBuffer
[MAX_PATH
] = L
"";
409 UNICODE_STRING SystemRootPath
= RTL_CONSTANT_STRING(L
"\\SystemRoot");
413 /* Determine the installation source path via the full path of the installer */
414 RtlInitEmptyUnicodeString(InstallSourcePath
,
415 (PWSTR
)((ULONG_PTR
)ImageFileBuffer
+ sizeof(UNICODE_STRING
)),
416 sizeof(ImageFileBuffer
) - sizeof(UNICODE_STRING
)
417 /* Reserve space for a NULL terminator */ - sizeof(UNICODE_NULL
));
418 BufferSize
= sizeof(ImageFileBuffer
);
419 Status
= NtQueryInformationProcess(NtCurrentProcess(),
420 ProcessImageFileName
,
424 // STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ?
425 if (!NT_SUCCESS(Status
))
428 /* Manually NULL-terminate */
429 InstallSourcePath
->Buffer
[InstallSourcePath
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
431 /* Strip the trailing file name */
432 Ptr
= wcsrchr(InstallSourcePath
->Buffer
, OBJ_NAME_PATH_SEPARATOR
);
435 InstallSourcePath
->Length
= wcslen(InstallSourcePath
->Buffer
) * sizeof(WCHAR
);
439 * Now resolve the full path to \SystemRoot. In case it prefixes
440 * the installation source path determined from the full path of
441 * the installer, we use instead the resolved \SystemRoot as the
442 * installation source path.
443 * Otherwise, we use instead the path from the full installer path.
446 InitializeObjectAttributes(&ObjectAttributes
,
448 OBJ_CASE_INSENSITIVE
,
452 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
455 if (!NT_SUCCESS(Status
))
458 * We failed at opening the \SystemRoot link (usually due to wrong
459 * access rights). Do not consider this as a fatal error, but use
460 * instead the image file path as the installation source path.
462 DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed with Status 0x%08lx\n",
463 &SystemRootPath
, Status
);
467 RtlInitEmptyUnicodeString(&SystemRootPath
,
469 sizeof(SystemRootBuffer
));
471 /* Resolve the link and close its handle */
472 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
477 if (!NT_SUCCESS(Status
))
478 return Status
; // Unexpected error
480 /* Check whether the resolved \SystemRoot is a prefix of the image file path */
481 if (RtlPrefixUnicodeString(&SystemRootPath
, InstallSourcePath
, TRUE
))
483 /* Yes it is, so we use instead SystemRoot as the installation source path */
484 InstallSourcePath
= &SystemRootPath
;
490 * Retrieve the different source path components
492 RtlCreateUnicodeString(SourcePath
, InstallSourcePath
->Buffer
);
494 /* Strip trailing directory */
495 Ptr
= wcsrchr(InstallSourcePath
->Buffer
, OBJ_NAME_PATH_SEPARATOR
);
498 RtlCreateUnicodeString(SourceRootDir
, Ptr
);
503 RtlCreateUnicodeString(SourceRootDir
, L
"");
506 RtlCreateUnicodeString(SourceRootPath
, InstallSourcePath
->Buffer
);
508 return STATUS_SUCCESS
;
513 IN OUT PUSETUP_DATA pSetupData
)
519 WCHAR FileNameBuffer
[MAX_PATH
];
521 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2,
522 pSetupData
->SourcePath
.Buffer
, L
"txtsetup.sif");
524 DPRINT("SetupInf path: '%S'\n", FileNameBuffer
);
526 pSetupData
->SetupInf
=
527 SpInfOpenInfFile(FileNameBuffer
,
530 pSetupData
->LanguageId
,
532 if (pSetupData
->SetupInf
== INVALID_HANDLE_VALUE
)
533 return ERROR_LOAD_TXTSETUPSIF
;
535 /* Open 'Version' section */
536 if (!SpInfFindFirstLine(pSetupData
->SetupInf
, L
"Version", L
"Signature", &Context
))
537 return ERROR_CORRUPT_TXTSETUPSIF
;
539 /* Get pointer 'Signature' key */
540 if (!INF_GetData(&Context
, NULL
, &Value
))
541 return ERROR_CORRUPT_TXTSETUPSIF
;
543 /* Check 'Signature' string */
544 if (_wcsicmp(Value
, L
"$ReactOS$") != 0 &&
545 _wcsicmp(Value
, L
"$Windows NT$") != 0)
548 return ERROR_SIGNATURE_TXTSETUPSIF
;
553 /* Open 'DiskSpaceRequirements' section */
554 if (!SpInfFindFirstLine(pSetupData
->SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
555 return ERROR_CORRUPT_TXTSETUPSIF
;
557 pSetupData
->RequiredPartitionDiskSpace
= ~0;
559 /* Get the 'FreeSysPartDiskSpace' value */
560 if (!SpInfGetIntField(&Context
, 1, &IntValue
))
561 return ERROR_CORRUPT_TXTSETUPSIF
;
563 pSetupData
->RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
566 // Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif
568 // Support for that should also be added in setupldr.
571 /* Update the Setup Source paths */
572 if (SpInfFindFirstLine(pSetupData
->SetupInf
, L
"SetupData", L
"SetupSourceDevice", &Context
))
575 * Get optional pointer 'SetupSourceDevice' key, its presence
576 * will dictate whether we also need 'SetupSourcePath'.
578 if (INF_GetData(&Context
, NULL
, &Value
))
580 /* Free the old source root path string and create the new one */
581 RtlFreeUnicodeString(&pSetupData
->SourceRootPath
);
582 RtlCreateUnicodeString(&pSetupData
->SourceRootPath
, Value
);
585 if (!SpInfFindFirstLine(pSetupData
->SetupInf
, L
"SetupData", L
"SetupSourcePath", &Context
))
587 /* The 'SetupSourcePath' value is mandatory! */
588 return ERROR_CORRUPT_TXTSETUPSIF
;
591 /* Get pointer 'SetupSourcePath' key */
592 if (!INF_GetData(&Context
, NULL
, &Value
))
594 /* The 'SetupSourcePath' value is mandatory! */
595 return ERROR_CORRUPT_TXTSETUPSIF
;
598 /* Free the old source path string and create the new one */
599 RtlFreeUnicodeString(&pSetupData
->SourceRootDir
);
600 RtlCreateUnicodeString(&pSetupData
->SourceRootDir
, Value
);
605 /* Search for 'DefaultPath' in the 'SetupData' section */
606 pSetupData
->InstallationDirectory
[0] = 0;
607 if (SpInfFindFirstLine(pSetupData
->SetupInf
, L
"SetupData", L
"DefaultPath", &Context
))
609 /* Get pointer 'DefaultPath' key */
610 if (!INF_GetData(&Context
, NULL
, &Value
))
611 return ERROR_CORRUPT_TXTSETUPSIF
;
613 RtlStringCchCopyW(pSetupData
->InstallationDirectory
,
614 ARRAYSIZE(pSetupData
->InstallationDirectory
),
620 return ERROR_SUCCESS
;
624 InitDestinationPaths(
625 IN OUT PUSETUP_DATA pSetupData
,
626 IN PCWSTR InstallationDir
,
627 IN PDISKENTRY DiskEntry
, // FIXME: HACK!
628 IN PPARTENTRY PartEntry
) // FIXME: HACK!
630 WCHAR PathBuffer
[MAX_PATH
];
633 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
635 /* Create 'pSetupData->DestinationRootPath' string */
636 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
637 Status
= RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
638 L
"\\Device\\Harddisk%lu\\Partition%lu\\",
639 DiskEntry
->DiskNumber
,
640 PartEntry
->PartitionNumber
);
642 if (!NT_SUCCESS(Status
))
644 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status
);
648 Status
= RtlCreateUnicodeString(&pSetupData
->DestinationRootPath
, PathBuffer
) ? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
650 if (!NT_SUCCESS(Status
))
652 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status
);
656 DPRINT("DestinationRootPath: %wZ\n", &pSetupData
->DestinationRootPath
);
658 // FIXME! Which variable to choose?
659 if (!InstallationDir
)
660 InstallationDir
= pSetupData
->InstallationDirectory
;
662 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
663 /* Create 'pSetupData->DestinationArcPath' */
664 RtlFreeUnicodeString(&pSetupData
->DestinationArcPath
);
665 Status
= RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
666 L
"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
667 DiskEntry
->BiosDiskNumber
,
668 PartEntry
->OnDiskPartitionNumber
);
670 if (!NT_SUCCESS(Status
))
672 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status
);
673 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
677 Status
= ConcatPaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 1, InstallationDir
);
679 if (!NT_SUCCESS(Status
))
681 DPRINT1("ConcatPaths() failed with status 0x%08lx\n", Status
);
682 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
686 Status
= RtlCreateUnicodeString(&pSetupData
->DestinationArcPath
, PathBuffer
) ? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
688 if (!NT_SUCCESS(Status
))
690 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status
);
691 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
695 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
696 /* Create 'pSetupData->DestinationPath' string */
697 RtlFreeUnicodeString(&pSetupData
->DestinationPath
);
698 Status
= CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
699 pSetupData
->DestinationRootPath
.Buffer
, InstallationDir
);
701 if (!NT_SUCCESS(Status
))
703 DPRINT1("CombinePaths() failed with status 0x%08lx\n", Status
);
704 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
705 RtlFreeUnicodeString(&pSetupData
->DestinationArcPath
);
709 Status
= RtlCreateUnicodeString(&pSetupData
->DestinationPath
, PathBuffer
) ? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
711 if (!NT_SUCCESS(Status
))
713 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status
);
714 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
715 RtlFreeUnicodeString(&pSetupData
->DestinationArcPath
);
719 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
720 // FIXME: This is only temporary!! Must be removed later!
721 Status
= RtlCreateUnicodeString(&pSetupData
->InstallPath
, InstallationDir
) ? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
723 if (!NT_SUCCESS(Status
))
725 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status
);
726 RtlFreeUnicodeString(&pSetupData
->DestinationRootPath
);
727 RtlFreeUnicodeString(&pSetupData
->DestinationArcPath
);
728 RtlFreeUnicodeString(&pSetupData
->DestinationPath
);
732 return STATUS_SUCCESS
;
738 IN OUT PUSETUP_DATA pSetupData
,
743 RtlZeroMemory(pSetupData
, sizeof(*pSetupData
));
745 // pSetupData->ComputerList = NULL;
746 // pSetupData->DisplayList = NULL;
747 // pSetupData->KeyboardList = NULL;
748 // pSetupData->LayoutList = NULL;
749 // pSetupData->LanguageList = NULL;
751 /* Initialize error handling */
752 pSetupData
->LastErrorNumber
= ERROR_SUCCESS
;
753 pSetupData
->ErrorRoutine
= NULL
;
755 /* Initialize global unicode strings */
756 RtlInitUnicodeString(&pSetupData
->SourcePath
, NULL
);
757 RtlInitUnicodeString(&pSetupData
->SourceRootPath
, NULL
);
758 RtlInitUnicodeString(&pSetupData
->SourceRootDir
, NULL
);
759 RtlInitUnicodeString(&pSetupData
->DestinationArcPath
, NULL
);
760 RtlInitUnicodeString(&pSetupData
->DestinationPath
, NULL
);
761 RtlInitUnicodeString(&pSetupData
->DestinationRootPath
, NULL
);
762 RtlInitUnicodeString(&pSetupData
->SystemRootPath
, NULL
);
764 // FIXME: This is only temporary!! Must be removed later!
765 /***/RtlInitUnicodeString(&pSetupData
->InstallPath
, NULL
);/***/
768 // TODO: Load and start SetupDD, and ask it for the information
771 return ERROR_SUCCESS
;
779 /* Get the source path and source root path */
781 // NOTE: Sometimes the source path may not be in SystemRoot !!
782 // (and this is the case when using the 1st-stage GUI setup!)
784 Status
= GetSourcePaths(&pSetupData
->SourcePath
,
785 &pSetupData
->SourceRootPath
,
786 &pSetupData
->SourceRootDir
);
787 if (!NT_SUCCESS(Status
))
789 DPRINT1("GetSourcePaths() failed (Status 0x%08lx)", Status
);
790 return ERROR_NO_SOURCE_DRIVE
;
794 * SourcePath: '\Device\CdRom0\I386'
795 * SourceRootPath: '\Device\CdRom0'
796 * SourceRootDir: '\I386'
798 DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData
->SourcePath
);
799 DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData
->SourceRootPath
);
800 DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData
->SourceRootDir
);
802 /* Load 'txtsetup.sif' from the installation media */
803 Error
= LoadSetupInf(pSetupData
);
804 if (Error
!= ERROR_SUCCESS
)
806 DPRINT1("LoadSetupInf() failed (Error 0x%lx)", Error
);
809 DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData
->SourcePath
);
810 DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData
->SourceRootPath
);
811 DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData
->SourceRootDir
);
813 return ERROR_SUCCESS
;
816 return ERROR_SUCCESS
;
821 IN OUT PUSETUP_DATA pSetupData
)
823 /* Destroy the computer settings list */
824 if (pSetupData
->ComputerList
!= NULL
)
826 DestroyGenericList(pSetupData
->ComputerList
, TRUE
);
827 pSetupData
->ComputerList
= NULL
;
830 /* Destroy the display settings list */
831 if (pSetupData
->DisplayList
!= NULL
)
833 DestroyGenericList(pSetupData
->DisplayList
, TRUE
);
834 pSetupData
->DisplayList
= NULL
;
837 /* Destroy the keyboard settings list */
838 if (pSetupData
->KeyboardList
!= NULL
)
840 DestroyGenericList(pSetupData
->KeyboardList
, TRUE
);
841 pSetupData
->KeyboardList
= NULL
;
844 /* Destroy the keyboard layout list */
845 if (pSetupData
->LayoutList
!= NULL
)
847 DestroyGenericList(pSetupData
->LayoutList
, TRUE
);
848 pSetupData
->LayoutList
= NULL
;
851 /* Destroy the languages list */
852 if (pSetupData
->LanguageList
!= NULL
)
854 DestroyGenericList(pSetupData
->LanguageList
, FALSE
);
855 pSetupData
->LanguageList
= NULL
;
858 /* Close the Setup INF */
859 SpInfCloseInfFile(pSetupData
->SetupInf
);
864 * Calls RegInitializeRegistry
865 * Calls ImportRegistryFile
866 * Calls SetDefaultPagefile
867 * Calls SetMountedDeviceValues
871 IN OUT PUSETUP_DATA pSetupData
,
872 /**/IN BOOLEAN RepairUpdateFlag
, /* HACK HACK! */
873 /**/IN PPARTLIST PartitionList
, /* HACK HACK! */
874 /**/IN WCHAR DestinationDriveLetter
, /* HACK HACK! */
875 /**/IN PCWSTR SelectedLanguageId
, /* HACK HACK! */
876 IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL
)
878 ERROR_NUMBER ErrorNumber
;
880 INFCONTEXT InfContext
;
885 BOOLEAN ShouldRepairRegistry
= FALSE
;
888 if (RepairUpdateFlag
)
890 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
892 /* Verify the registry hives and check whether we need to update or repair any of them */
893 Status
= VerifyRegistryHives(&pSetupData
->DestinationPath
, &ShouldRepairRegistry
);
894 if (!NT_SUCCESS(Status
))
896 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status
);
897 ShouldRepairRegistry
= FALSE
;
899 if (!ShouldRepairRegistry
)
900 DPRINT1("No need to repair the registry\n");
904 ErrorNumber
= ERROR_SUCCESS
;
906 /* Update the registry */
907 if (StatusRoutine
) StatusRoutine(RegHiveUpdate
);
909 /* Initialize the registry and setup the registry hives */
910 Status
= RegInitializeRegistry(&pSetupData
->DestinationPath
);
911 if (!NT_SUCCESS(Status
))
913 DPRINT1("RegInitializeRegistry() failed\n");
914 /********** HACK!!!!!!!!!!! **********/
915 if (Status
== STATUS_NOT_IMPLEMENTED
)
917 /* The hack was called, return its corresponding error */
918 return ERROR_INITIALIZE_REGISTRY
;
921 /*************************************/
923 /* Something else failed */
924 return ERROR_CREATE_HIVE
;
928 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
931 * We fully setup the hives, in case we are doing a fresh installation
932 * (RepairUpdateFlag == FALSE), or in case we are doing an update
933 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
934 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
937 Success
= SpInfFindFirstLine(pSetupData
->SetupInf
, L
"HiveInfs.Fresh", NULL
, &InfContext
); // Windows-compatible
939 Success
= SpInfFindFirstLine(pSetupData
->SetupInf
, L
"HiveInfs.Install", NULL
, &InfContext
); // ReactOS-specific
943 DPRINT1("SpInfFindFirstLine() failed\n");
944 ErrorNumber
= ERROR_FIND_REGISTRY
;
948 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
951 * In case we are doing an update (RepairUpdateFlag == TRUE) and
952 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
953 * we only update the hives.
956 Success
= SpInfFindFirstLine(pSetupData
->SetupInf
, L
"HiveInfs.Upgrade", NULL
, &InfContext
);
959 /* Nothing to do for update! */
960 DPRINT1("No update needed for the registry!\n");
967 INF_GetDataField(&InfContext
, 0, &Action
);
968 INF_GetDataField(&InfContext
, 1, &File
);
969 INF_GetDataField(&InfContext
, 2, &Section
);
971 DPRINT("Action: %S File: %S Section %S\n", Action
, File
, Section
);
975 INF_FreeData(Action
);
977 INF_FreeData(Section
);
981 if (!_wcsicmp(Action
, L
"AddReg"))
983 else if (!_wcsicmp(Action
, L
"DelReg"))
987 DPRINT1("Unrecognized registry INF action '%S'\n", Action
);
988 INF_FreeData(Action
);
990 INF_FreeData(Section
);
994 INF_FreeData(Action
);
996 if (StatusRoutine
) StatusRoutine(ImportRegHive
, File
);
998 if (!ImportRegistryFile(pSetupData
->SourcePath
.Buffer
,
1000 pSetupData
->LanguageId
, Delete
))
1002 DPRINT1("Importing %S failed\n", File
);
1004 INF_FreeData(Section
);
1005 ErrorNumber
= ERROR_IMPORT_HIVE
;
1008 } while (SpInfFindNextLine(&InfContext
, &InfContext
));
1010 if (!RepairUpdateFlag
|| ShouldRepairRegistry
)
1012 /* See the explanation for this test above */
1014 /* Update display registry settings */
1015 if (StatusRoutine
) StatusRoutine(DisplaySettingsUpdate
);
1016 if (!ProcessDisplayRegistry(pSetupData
->SetupInf
, pSetupData
->DisplayList
))
1018 ErrorNumber
= ERROR_UPDATE_DISPLAY_SETTINGS
;
1022 /* Set the locale */
1023 if (StatusRoutine
) StatusRoutine(LocaleSettingsUpdate
);
1024 if (!ProcessLocaleRegistry(pSetupData
->LanguageList
))
1026 ErrorNumber
= ERROR_UPDATE_LOCALESETTINGS
;
1030 /* Add keyboard layouts */
1031 if (StatusRoutine
) StatusRoutine(KeybLayouts
);
1032 if (!AddKeyboardLayouts(SelectedLanguageId
))
1034 ErrorNumber
= ERROR_ADDING_KBLAYOUTS
;
1039 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId
)))
1041 ErrorNumber
= ERROR_UPDATE_GEOID
;
1045 if (!IsUnattendedSetup
)
1047 /* Update keyboard layout settings */
1048 if (StatusRoutine
) StatusRoutine(KeybSettingsUpdate
);
1049 if (!ProcessKeyboardLayoutRegistry(pSetupData
->LayoutList
, SelectedLanguageId
))
1051 ErrorNumber
= ERROR_UPDATE_KBSETTINGS
;
1056 /* Add codepage information to registry */
1057 if (StatusRoutine
) StatusRoutine(CodePageInfoUpdate
);
1058 if (!AddCodePage(SelectedLanguageId
))
1060 ErrorNumber
= ERROR_ADDING_CODEPAGE
;
1064 /* Set the default pagefile entry */
1065 SetDefaultPagefile(DestinationDriveLetter
);
1067 /* Update the mounted devices list */
1068 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
1069 SetMountedDeviceValues(PartitionList
);
1074 // TODO: Unload all the registry stuff, perform cleanup,
1075 // and copy the created hive files into .sav files.
1077 RegCleanupRegistry(&pSetupData
->DestinationPath
);
1080 * Check whether we were in update/repair mode but we were actually
1081 * repairing the registry hives. If so, we have finished repairing them,
1082 * and we now reset the flag and run the proper registry update.
1083 * Otherwise we have finished the registry update!
1085 if (RepairUpdateFlag
&& ShouldRepairRegistry
)
1087 ShouldRepairRegistry
= FALSE
;