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 *****************************************************************/
26 /* GLOBALS ******************************************************************/
28 /* FUNCTIONS ****************************************************************/
32 IN OUT PUSETUP_DATA pSetupData
)
39 WCHAR UnattendInfPath
[MAX_PATH
];
41 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
42 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
44 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
46 DPRINT("Does not exist: %S\n", UnattendInfPath
);
50 /* Load 'unattend.inf' from installation media */
51 UnattendInf
= SetupOpenInfFileExW(UnattendInfPath
,
54 pSetupData
->LanguageId
,
57 if (UnattendInf
== INVALID_HANDLE_VALUE
)
59 DPRINT("SetupOpenInfFileExW() failed\n");
63 /* Open 'Unattend' section */
64 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"Signature", &Context
))
66 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
70 /* Get pointer 'Signature' key */
71 if (!INF_GetData(&Context
, NULL
, &Value
))
73 DPRINT("INF_GetData() failed for key 'Signature'\n");
77 /* Check 'Signature' string */
78 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
80 DPRINT("Signature not $ReactOS$\n");
87 /* Check if Unattend setup is enabled */
88 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"UnattendSetupEnabled", &Context
))
90 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
94 if (!INF_GetData(&Context
, NULL
, &Value
))
96 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
100 if (_wcsicmp(Value
, L
"yes") != 0)
102 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
109 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
110 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationDiskNumber", &Context
))
112 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
116 if (!SetupGetIntField(&Context
, 1, &IntValue
))
118 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
122 pSetupData
->DestinationDiskNumber
= (LONG
)IntValue
;
124 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
125 if (!SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"DestinationPartitionNumber", &Context
))
127 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
131 if (!SetupGetIntField(&Context
, 1, &IntValue
))
133 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
137 pSetupData
->DestinationPartitionNumber
= (LONG
)IntValue
;
139 /* Search for 'InstallationDirectory' in the 'Unattend' section (optional) */
140 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"InstallationDirectory", &Context
))
142 /* Get pointer 'InstallationDirectory' key */
143 if (!INF_GetData(&Context
, NULL
, &Value
))
145 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
148 wcscpy(pSetupData
->InstallationDirectory
, Value
);
152 IsUnattendedSetup
= TRUE
;
153 DPRINT("Running unattended setup\n");
155 /* Search for 'MBRInstallType' in the 'Unattend' section */
156 pSetupData
->MBRInstallType
= -1;
157 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"MBRInstallType", &Context
))
159 if (SetupGetIntField(&Context
, 1, &IntValue
))
161 pSetupData
->MBRInstallType
= IntValue
;
165 /* Search for 'FormatPartition' in the 'Unattend' section */
166 pSetupData
->FormatPartition
= 0;
167 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"FormatPartition", &Context
))
169 if (SetupGetIntField(&Context
, 1, &IntValue
))
171 pSetupData
->FormatPartition
= IntValue
;
175 pSetupData
->AutoPartition
= 0;
176 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"AutoPartition", &Context
))
178 if (SetupGetIntField(&Context
, 1, &IntValue
))
180 pSetupData
->AutoPartition
= IntValue
;
184 /* Search for LocaleID in the 'Unattend' section */
185 if (SetupFindFirstLineW(UnattendInf
, L
"Unattend", L
"LocaleID", &Context
))
187 if (INF_GetData(&Context
, NULL
, &Value
))
189 LONG Id
= wcstol(Value
, NULL
, 16);
190 swprintf(pSetupData
->LocaleID
, L
"%08lx", Id
);
196 SetupCloseInfFile(UnattendInf
);
201 IN OUT PUSETUP_DATA pSetupData
)
207 PINICACHE UnattendCache
;
208 PINICACHEITERATOR Iterator
;
210 // PCWSTR CrLf = L"\r\n";
212 HANDLE FileHandle
, UnattendFileHandle
, SectionHandle
;
213 FILE_STANDARD_INFORMATION FileInfo
;
216 UNICODE_STRING FileName
;
217 OBJECT_ATTRIBUTES ObjectAttributes
;
218 IO_STATUS_BLOCK IoStatusBlock
;
221 PINICACHESECTION IniSection
;
222 WCHAR PathBuffer
[MAX_PATH
];
223 WCHAR UnattendInfPath
[MAX_PATH
];
225 /* Create a $winnt$.inf file with default entries */
226 IniCache
= IniCacheCreate();
230 IniSection
= IniCacheAppendSection(IniCache
, L
"SetupParams");
233 /* Key "skipmissingfiles" */
234 // StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
235 // L"\"%s\"", L"WinNt5.2");
236 // IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
237 // L"Version", PathBuffer);
240 IniSection
= IniCacheAppendSection(IniCache
, L
"Data");
243 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
244 L
"\"%s\"", IsUnattendedSetup
? L
"yes" : L
"no");
245 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
246 L
"UnattendedInstall", PathBuffer
);
248 // "floppylessbootpath" (yes/no)
250 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
251 L
"\"%s\"", L
"winnt");
252 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
253 L
"ProductType", PathBuffer
);
255 StringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
256 L
"\"%s\\\"", pSetupData
->SourceRootPath
.Buffer
);
257 IniCacheInsertKey(IniSection
, NULL
, INSERT_LAST
,
258 L
"SourcePath", PathBuffer
);
260 // "floppyless" ("0")
265 /* TODO: Append the standard unattend.inf file */
266 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2, pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
267 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
269 DPRINT("Does not exist: %S\n", UnattendInfPath
);
273 Status
= IniCacheLoad(&UnattendCache
, UnattendInfPath
, FALSE
);
274 if (!NT_SUCCESS(Status
))
276 DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath
);
280 IniCacheDestroy(UnattendCache
);
283 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
284 pSetupData
->DestinationPath
.Buffer
, L
"System32\\$winnt$.inf");
285 IniCacheSave(IniCache
, PathBuffer
);
286 IniCacheDestroy(IniCache
);
290 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 2,
291 pSetupData
->DestinationPath
.Buffer
, L
"System32\\$winnt$.inf");
292 IniCacheSave(IniCache
, PathBuffer
);
293 IniCacheDestroy(IniCache
);
295 /* TODO: Append the standard unattend.inf file */
296 CombinePaths(UnattendInfPath
, ARRAYSIZE(UnattendInfPath
), 2,
297 pSetupData
->SourcePath
.Buffer
, L
"unattend.inf");
298 if (DoesFileExist(NULL
, UnattendInfPath
) == FALSE
)
300 DPRINT("Does not exist: %S\n", UnattendInfPath
);
304 RtlInitUnicodeString(&FileName
, PathBuffer
);
305 InitializeObjectAttributes(&ObjectAttributes
,
307 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
310 Status
= NtOpenFile(&FileHandle
,
311 FILE_APPEND_DATA
| SYNCHRONIZE
,
315 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
316 if (!NT_SUCCESS(Status
))
318 DPRINT1("Cannot load %S as an INI file!\n", PathBuffer
);
322 /* Query the file size */
323 Status
= NtQueryInformationFile(FileHandle
,
327 FileStandardInformation
);
328 if (!NT_SUCCESS(Status
))
330 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
331 FileInfo
.EndOfFile
.QuadPart
= 0ULL;
334 Status
= OpenAndMapFile(NULL
,
341 if (!NT_SUCCESS(Status
))
343 DPRINT1("Cannot load %S !\n", UnattendInfPath
);
348 /* Write to the INI file */
351 Status
= NtWriteFile(FileHandle
,
357 2 * sizeof(CHAR
), // 2 * sizeof(WCHAR),
361 Status
= NtWriteFile(FileHandle
,
370 if (!NT_SUCCESS(Status
))
372 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
375 /* Finally, unmap and close the file */
376 UnMapFile(SectionHandle
, ViewBase
);
377 NtClose(UnattendFileHandle
);
387 OUT PUNICODE_STRING SourcePath
,
388 OUT PUNICODE_STRING SourceRootPath
,
389 OUT PUNICODE_STRING SourceRootDir
)
392 OBJECT_ATTRIBUTES ObjectAttributes
;
393 UNICODE_STRING LinkName
= RTL_CONSTANT_STRING(L
"\\SystemRoot");
394 UNICODE_STRING SourceName
;
395 WCHAR SourceBuffer
[MAX_PATH
] = L
"";
400 InitializeObjectAttributes(&ObjectAttributes
,
402 OBJ_CASE_INSENSITIVE
,
406 Status
= NtOpenSymbolicLinkObject(&Handle
,
407 SYMBOLIC_LINK_ALL_ACCESS
,
409 if (!NT_SUCCESS(Status
))
412 RtlInitEmptyUnicodeString(&SourceName
, SourceBuffer
, sizeof(SourceBuffer
));
414 Status
= NtQuerySymbolicLinkObject(Handle
,
419 if (!NT_SUCCESS(Status
))
422 RtlCreateUnicodeString(SourcePath
,
425 /* Strip trailing directory */
426 Ptr
= wcsrchr(SourceName
.Buffer
, OBJ_NAME_PATH_SEPARATOR
);
429 RtlCreateUnicodeString(SourceRootDir
, Ptr
);
434 RtlCreateUnicodeString(SourceRootDir
, L
"");
437 RtlCreateUnicodeString(SourceRootPath
,
440 return STATUS_SUCCESS
;
447 IN OUT PUSETUP_DATA pSetupData
)
453 WCHAR FileNameBuffer
[MAX_PATH
];
455 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2,
456 pSetupData
->SourcePath
.Buffer
, L
"txtsetup.sif");
458 *SetupInf
= SetupOpenInfFileExW(FileNameBuffer
,
461 pSetupData
->LanguageId
,
464 if (*SetupInf
== INVALID_HANDLE_VALUE
)
465 return ERROR_LOAD_TXTSETUPSIF
;
467 /* Open 'Version' section */
468 if (!SetupFindFirstLineW(*SetupInf
, L
"Version", L
"Signature", &Context
))
469 return ERROR_CORRUPT_TXTSETUPSIF
;
471 /* Get pointer 'Signature' key */
472 if (!INF_GetData(&Context
, NULL
, &Value
))
473 return ERROR_CORRUPT_TXTSETUPSIF
;
475 /* Check 'Signature' string */
476 if (_wcsicmp(Value
, L
"$ReactOS$") != 0)
479 return ERROR_SIGNATURE_TXTSETUPSIF
;
484 /* Open 'DiskSpaceRequirements' section */
485 if (!SetupFindFirstLineW(*SetupInf
, L
"DiskSpaceRequirements", L
"FreeSysPartDiskSpace", &Context
))
486 return ERROR_CORRUPT_TXTSETUPSIF
;
488 pSetupData
->RequiredPartitionDiskSpace
= ~0;
490 /* Get the 'FreeSysPartDiskSpace' value */
491 if (!SetupGetIntField(&Context
, 1, &IntValue
))
492 return ERROR_CORRUPT_TXTSETUPSIF
;
494 pSetupData
->RequiredPartitionDiskSpace
= (ULONG
)IntValue
;
497 // TODO: Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif
501 /* Search for 'DefaultPath' in the 'SetupData' section */
502 if (SetupFindFirstLineW(*SetupInf
, L
"SetupData", L
"DefaultPath", &Context
))
504 /* Get pointer 'DefaultPath' key */
505 if (!INF_GetData(&Context
, NULL
, &Value
))
506 return ERROR_CORRUPT_TXTSETUPSIF
;
508 wcscpy(pSetupData
->InstallationDirectory
, Value
);
512 return ERROR_SUCCESS
;