2017-08-09 20:39:45 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS Setup Library
|
|
|
|
* FILE: base/setup/lib/setuplib.c
|
|
|
|
* PURPOSE: Setup Library - Main initialization helpers
|
|
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "filesup.h"
|
|
|
|
#include "infsupp.h"
|
|
|
|
#include "inicache.h"
|
|
|
|
|
|
|
|
#include "setuplib.h"
|
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CheckUnattendedSetup(
|
|
|
|
IN OUT PUSETUP_DATA pSetupData)
|
|
|
|
{
|
|
|
|
INFCONTEXT Context;
|
|
|
|
HINF UnattendInf;
|
|
|
|
UINT ErrorLine;
|
|
|
|
INT IntValue;
|
2018-01-06 15:47:37 +00:00
|
|
|
PCWSTR Value;
|
2017-08-09 20:39:45 +00:00
|
|
|
WCHAR UnattendInfPath[MAX_PATH];
|
|
|
|
|
|
|
|
CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
|
|
|
|
pSetupData->SourcePath.Buffer, L"unattend.inf");
|
|
|
|
|
2017-08-25 09:19:44 +00:00
|
|
|
DPRINT("UnattendInf path: '%S'\n", UnattendInfPath);
|
|
|
|
|
2017-08-09 20:39:45 +00:00
|
|
|
if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
|
|
|
|
{
|
|
|
|
DPRINT("Does not exist: %S\n", UnattendInfPath);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load 'unattend.inf' from installation media */
|
2018-01-06 15:47:37 +00:00
|
|
|
UnattendInf = SpInfOpenInfFile(UnattendInfPath,
|
|
|
|
NULL,
|
|
|
|
INF_STYLE_OLDNT,
|
|
|
|
pSetupData->LanguageId,
|
|
|
|
&ErrorLine);
|
2017-08-09 20:39:45 +00:00
|
|
|
if (UnattendInf == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT("SpInfOpenInfFile() failed\n");
|
2017-08-09 20:39:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open 'Unattend' section */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"Signature", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT("SpInfFindFirstLine() failed for section 'Unattend'\n");
|
2017-08-09 20:39:45 +00:00
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get pointer 'Signature' key */
|
|
|
|
if (!INF_GetData(&Context, NULL, &Value))
|
|
|
|
{
|
|
|
|
DPRINT("INF_GetData() failed for key 'Signature'\n");
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check 'Signature' string */
|
|
|
|
if (_wcsicmp(Value, L"$ReactOS$") != 0)
|
|
|
|
{
|
|
|
|
DPRINT("Signature not $ReactOS$\n");
|
|
|
|
INF_FreeData(Value);
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
INF_FreeData(Value);
|
|
|
|
|
|
|
|
/* Check if Unattend setup is enabled */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
|
|
|
DPRINT("Can't find key 'UnattendSetupEnabled'\n");
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!INF_GetData(&Context, NULL, &Value))
|
|
|
|
{
|
|
|
|
DPRINT("Can't read key 'UnattendSetupEnabled'\n");
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_wcsicmp(Value, L"yes") != 0)
|
|
|
|
{
|
|
|
|
DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
|
|
|
|
INF_FreeData(Value);
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
INF_FreeData(Value);
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'DestinationDiskNumber' */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT("SpInfFindFirstLine() failed for key 'DestinationDiskNumber'\n");
|
2017-08-09 20:39:45 +00:00
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfGetIntField(&Context, 1, &IntValue))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT("SpInfGetIntField() failed for key 'DestinationDiskNumber'\n");
|
2017-08-09 20:39:45 +00:00
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
pSetupData->DestinationDiskNumber = (LONG)IntValue;
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'DestinationPartitionNumber' */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT("SpInfFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
|
2017-08-09 20:39:45 +00:00
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfGetIntField(&Context, 1, &IntValue))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT("SpInfGetIntField() failed for key 'DestinationPartitionNumber'\n");
|
2017-08-09 20:39:45 +00:00
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
pSetupData->DestinationPartitionNumber = (LONG)IntValue;
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'InstallationDirectory' (optional) */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2023-12-16 11:52:39 +00:00
|
|
|
if (INF_GetData(&Context, NULL, &Value))
|
|
|
|
{
|
|
|
|
RtlStringCchCopyW(pSetupData->InstallationDirectory,
|
|
|
|
ARRAYSIZE(pSetupData->InstallationDirectory),
|
|
|
|
Value);
|
|
|
|
INF_FreeData(Value);
|
|
|
|
}
|
|
|
|
else
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
|
|
|
DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IsUnattendedSetup = TRUE;
|
|
|
|
DPRINT("Running unattended setup\n");
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'BootLoaderLocation' (optional) */
|
2023-11-02 14:22:02 +00:00
|
|
|
if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"BootLoaderLocation", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfGetIntField(&Context, 1, &IntValue))
|
2023-11-02 14:22:02 +00:00
|
|
|
pSetupData->BootLoaderLocation = IntValue;
|
2017-08-09 20:39:45 +00:00
|
|
|
}
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'FormatPartition' (optional) */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FormatPartition", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfGetIntField(&Context, 1, &IntValue))
|
2017-08-09 20:39:45 +00:00
|
|
|
pSetupData->FormatPartition = IntValue;
|
|
|
|
}
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'AutoPartition' (optional) */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"AutoPartition", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfGetIntField(&Context, 1, &IntValue))
|
2017-08-09 20:39:45 +00:00
|
|
|
pSetupData->AutoPartition = IntValue;
|
|
|
|
}
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'LocaleID' (optional) */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"LocaleID", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
|
|
|
if (INF_GetData(&Context, NULL, &Value))
|
|
|
|
{
|
|
|
|
LONG Id = wcstol(Value, NULL, 16);
|
2017-09-03 20:05:11 +00:00
|
|
|
RtlStringCchPrintfW(pSetupData->LocaleID,
|
|
|
|
ARRAYSIZE(pSetupData->LocaleID),
|
|
|
|
L"%08lx", Id);
|
2017-08-09 20:39:45 +00:00
|
|
|
INF_FreeData(Value);
|
2023-12-16 11:52:39 +00:00
|
|
|
}
|
2017-08-09 20:39:45 +00:00
|
|
|
}
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Search for 'FsType' (optional) */
|
2018-12-28 19:34:48 +00:00
|
|
|
if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FsType", &Context))
|
|
|
|
{
|
|
|
|
if (SpInfGetIntField(&Context, 1, &IntValue))
|
|
|
|
pSetupData->FsType = IntValue;
|
|
|
|
}
|
|
|
|
|
2017-08-09 20:39:45 +00:00
|
|
|
Quit:
|
2018-01-06 15:47:37 +00:00
|
|
|
SpInfCloseInfFile(UnattendInf);
|
2017-08-09 20:39:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
InstallSetupInfFile(
|
|
|
|
IN OUT PUSETUP_DATA pSetupData)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PINICACHE IniCache;
|
|
|
|
|
|
|
|
#if 0 // HACK FIXME!
|
|
|
|
PINICACHE UnattendCache;
|
|
|
|
PINICACHEITERATOR Iterator;
|
|
|
|
#else
|
2017-12-23 19:17:38 +00:00
|
|
|
// WCHAR CrLf[] = {L'\r', L'\n'};
|
|
|
|
CHAR CrLf[] = {'\r', '\n'};
|
2017-08-09 20:39:45 +00:00
|
|
|
HANDLE FileHandle, UnattendFileHandle, SectionHandle;
|
|
|
|
FILE_STANDARD_INFORMATION FileInfo;
|
|
|
|
ULONG FileSize;
|
|
|
|
PVOID ViewBase;
|
|
|
|
UNICODE_STRING FileName;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
#endif
|
|
|
|
|
2024-04-23 19:09:36 +00:00
|
|
|
PINI_SECTION IniSection;
|
2017-08-09 20:39:45 +00:00
|
|
|
WCHAR PathBuffer[MAX_PATH];
|
|
|
|
WCHAR UnattendInfPath[MAX_PATH];
|
|
|
|
|
|
|
|
/* Create a $winnt$.inf file with default entries */
|
|
|
|
IniCache = IniCacheCreate();
|
|
|
|
if (!IniCache)
|
|
|
|
return;
|
|
|
|
|
2024-04-23 19:09:36 +00:00
|
|
|
IniSection = IniAddSection(IniCache, L"SetupParams");
|
2017-08-09 20:39:45 +00:00
|
|
|
if (IniSection)
|
|
|
|
{
|
|
|
|
/* Key "skipmissingfiles" */
|
2017-09-03 20:05:11 +00:00
|
|
|
// RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
// L"\"%s\"", L"WinNt5.2");
|
2024-04-23 19:09:36 +00:00
|
|
|
// IniAddKey(IniSection, L"Version", PathBuffer);
|
2017-08-09 20:39:45 +00:00
|
|
|
}
|
|
|
|
|
2024-04-23 19:09:36 +00:00
|
|
|
IniSection = IniAddSection(IniCache, L"Data");
|
2017-08-09 20:39:45 +00:00
|
|
|
if (IniSection)
|
|
|
|
{
|
2017-09-03 20:05:11 +00:00
|
|
|
RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"\"%s\"", IsUnattendedSetup ? L"yes" : L"no");
|
2024-04-23 19:09:36 +00:00
|
|
|
IniAddKey(IniSection, L"UnattendedInstall", PathBuffer);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
|
|
|
// "floppylessbootpath" (yes/no)
|
|
|
|
|
2017-09-03 20:05:11 +00:00
|
|
|
RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"\"%s\"", L"winnt");
|
2024-04-23 19:09:36 +00:00
|
|
|
IniAddKey(IniSection, L"ProductType", PathBuffer);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
2017-09-03 20:05:11 +00:00
|
|
|
RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"\"%s\\\"", pSetupData->SourceRootPath.Buffer);
|
2024-04-23 19:09:36 +00:00
|
|
|
IniAddKey(IniSection, L"SourcePath", PathBuffer);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
|
|
|
// "floppyless" ("0")
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
/* TODO: Append the standard unattend.inf file */
|
2017-08-25 09:19:44 +00:00
|
|
|
CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
|
|
|
|
pSetupData->SourcePath.Buffer, L"unattend.inf");
|
2017-08-09 20:39:45 +00:00
|
|
|
if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
|
|
|
|
{
|
|
|
|
DPRINT("Does not exist: %S\n", UnattendInfPath);
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = IniCacheLoad(&UnattendCache, UnattendInfPath, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath);
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
IniCacheDestroy(UnattendCache);
|
|
|
|
|
|
|
|
Quit:
|
|
|
|
CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
|
|
|
|
pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf");
|
|
|
|
IniCacheSave(IniCache, PathBuffer);
|
|
|
|
IniCacheDestroy(IniCache);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
|
|
|
|
pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf");
|
|
|
|
IniCacheSave(IniCache, PathBuffer);
|
|
|
|
IniCacheDestroy(IniCache);
|
|
|
|
|
|
|
|
/* TODO: Append the standard unattend.inf file */
|
|
|
|
CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
|
|
|
|
pSetupData->SourcePath.Buffer, L"unattend.inf");
|
|
|
|
if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
|
|
|
|
{
|
|
|
|
DPRINT("Does not exist: %S\n", UnattendInfPath);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&FileName, PathBuffer);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&FileName,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
|
|
FILE_APPEND_DATA | SYNCHRONIZE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ,
|
|
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Cannot load %S as an INI file!\n", PathBuffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Query the file size */
|
|
|
|
Status = NtQueryInformationFile(FileHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
&FileInfo,
|
|
|
|
sizeof(FileInfo),
|
|
|
|
FileStandardInformation);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
|
|
|
|
FileInfo.EndOfFile.QuadPart = 0ULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = OpenAndMapFile(NULL,
|
|
|
|
UnattendInfPath,
|
|
|
|
&UnattendFileHandle,
|
2024-05-04 10:35:24 +00:00
|
|
|
&FileSize,
|
2017-08-09 20:39:45 +00:00
|
|
|
&SectionHandle,
|
|
|
|
&ViewBase,
|
|
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Cannot load %S !\n", UnattendInfPath);
|
|
|
|
NtClose(FileHandle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write to the INI file */
|
|
|
|
|
|
|
|
/* "\r\n" */
|
|
|
|
Status = NtWriteFile(FileHandle,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&IoStatusBlock,
|
|
|
|
(PVOID)CrLf,
|
2017-12-23 19:17:38 +00:00
|
|
|
sizeof(CrLf),
|
2017-08-09 20:39:45 +00:00
|
|
|
&FileInfo.EndOfFile,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtWriteFile(FileHandle,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&IoStatusBlock,
|
|
|
|
ViewBase,
|
|
|
|
FileSize,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, unmap and close the file */
|
2017-08-23 12:20:15 +00:00
|
|
|
UnMapAndCloseFile(UnattendFileHandle, SectionHandle, ViewBase);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
|
|
|
NtClose(FileHandle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
GetSourcePaths(
|
|
|
|
OUT PUNICODE_STRING SourcePath,
|
|
|
|
OUT PUNICODE_STRING SourceRootPath,
|
|
|
|
OUT PUNICODE_STRING SourceRootDir)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2018-01-07 00:35:48 +00:00
|
|
|
HANDLE LinkHandle;
|
2017-08-25 09:19:44 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UCHAR ImageFileBuffer[sizeof(UNICODE_STRING) + MAX_PATH * sizeof(WCHAR)];
|
|
|
|
PUNICODE_STRING InstallSourcePath = (PUNICODE_STRING)&ImageFileBuffer;
|
|
|
|
WCHAR SystemRootBuffer[MAX_PATH] = L"";
|
|
|
|
UNICODE_STRING SystemRootPath = RTL_CONSTANT_STRING(L"\\SystemRoot");
|
|
|
|
ULONG BufferSize;
|
2017-08-09 20:39:45 +00:00
|
|
|
PWCHAR Ptr;
|
|
|
|
|
2020-12-20 15:21:27 +00:00
|
|
|
// FIXME: commented out to allow installation from USB
|
|
|
|
#if 0
|
2017-08-25 09:19:44 +00:00
|
|
|
/* Determine the installation source path via the full path of the installer */
|
|
|
|
RtlInitEmptyUnicodeString(InstallSourcePath,
|
|
|
|
(PWSTR)((ULONG_PTR)ImageFileBuffer + sizeof(UNICODE_STRING)),
|
|
|
|
sizeof(ImageFileBuffer) - sizeof(UNICODE_STRING)
|
|
|
|
/* Reserve space for a NULL terminator */ - sizeof(UNICODE_NULL));
|
|
|
|
BufferSize = sizeof(ImageFileBuffer);
|
|
|
|
Status = NtQueryInformationProcess(NtCurrentProcess(),
|
|
|
|
ProcessImageFileName,
|
|
|
|
InstallSourcePath,
|
|
|
|
BufferSize,
|
|
|
|
NULL);
|
|
|
|
// STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ?
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
/* Manually NULL-terminate */
|
|
|
|
InstallSourcePath->Buffer[InstallSourcePath->Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
|
|
|
|
/* Strip the trailing file name */
|
|
|
|
Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR);
|
|
|
|
if (Ptr)
|
|
|
|
*Ptr = UNICODE_NULL;
|
|
|
|
InstallSourcePath->Length = wcslen(InstallSourcePath->Buffer) * sizeof(WCHAR);
|
2020-12-20 15:21:27 +00:00
|
|
|
#endif
|
2017-08-25 09:19:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now resolve the full path to \SystemRoot. In case it prefixes
|
|
|
|
* the installation source path determined from the full path of
|
|
|
|
* the installer, we use instead the resolved \SystemRoot as the
|
|
|
|
* installation source path.
|
|
|
|
* Otherwise, we use instead the path from the full installer path.
|
|
|
|
*/
|
|
|
|
|
2017-08-09 20:39:45 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
2017-08-25 09:19:44 +00:00
|
|
|
&SystemRootPath,
|
2017-08-09 20:39:45 +00:00
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
2018-01-07 00:35:48 +00:00
|
|
|
Status = NtOpenSymbolicLinkObject(&LinkHandle,
|
2017-08-25 09:19:44 +00:00
|
|
|
SYMBOLIC_LINK_QUERY,
|
2017-08-09 20:39:45 +00:00
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2017-08-25 09:19:44 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We failed at opening the \SystemRoot link (usually due to wrong
|
|
|
|
* access rights). Do not consider this as a fatal error, but use
|
|
|
|
* instead the image file path as the installation source path.
|
|
|
|
*/
|
|
|
|
DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed with Status 0x%08lx\n",
|
|
|
|
&SystemRootPath, Status);
|
|
|
|
goto InitPaths;
|
|
|
|
}
|
2017-08-09 20:39:45 +00:00
|
|
|
|
2017-08-25 09:19:44 +00:00
|
|
|
RtlInitEmptyUnicodeString(&SystemRootPath,
|
|
|
|
SystemRootBuffer,
|
|
|
|
sizeof(SystemRootBuffer));
|
2017-08-09 20:39:45 +00:00
|
|
|
|
2018-01-07 00:35:48 +00:00
|
|
|
/* Resolve the link and close its handle */
|
|
|
|
Status = NtQuerySymbolicLinkObject(LinkHandle,
|
2017-08-25 09:19:44 +00:00
|
|
|
&SystemRootPath,
|
|
|
|
&BufferSize);
|
2018-01-07 00:35:48 +00:00
|
|
|
NtClose(LinkHandle);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
2017-08-25 09:19:44 +00:00
|
|
|
return Status; // Unexpected error
|
|
|
|
|
|
|
|
/* Check whether the resolved \SystemRoot is a prefix of the image file path */
|
2020-12-20 15:21:27 +00:00
|
|
|
// FIXME: commented out to allow installation from USB
|
|
|
|
// if (RtlPrefixUnicodeString(&SystemRootPath, InstallSourcePath, TRUE))
|
2017-08-25 09:19:44 +00:00
|
|
|
{
|
|
|
|
/* Yes it is, so we use instead SystemRoot as the installation source path */
|
|
|
|
InstallSourcePath = &SystemRootPath;
|
|
|
|
}
|
2017-08-09 20:39:45 +00:00
|
|
|
|
2017-08-25 09:19:44 +00:00
|
|
|
|
|
|
|
InitPaths:
|
|
|
|
/*
|
|
|
|
* Retrieve the different source path components
|
|
|
|
*/
|
|
|
|
RtlCreateUnicodeString(SourcePath, InstallSourcePath->Buffer);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
|
|
|
/* Strip trailing directory */
|
2017-08-25 09:19:44 +00:00
|
|
|
Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR);
|
2017-08-09 20:39:45 +00:00
|
|
|
if (Ptr)
|
|
|
|
{
|
|
|
|
RtlCreateUnicodeString(SourceRootDir, Ptr);
|
|
|
|
*Ptr = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RtlCreateUnicodeString(SourceRootDir, L"");
|
|
|
|
}
|
|
|
|
|
2017-08-25 09:19:44 +00:00
|
|
|
RtlCreateUnicodeString(SourceRootPath, InstallSourcePath->Buffer);
|
2017-08-09 20:39:45 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ERROR_NUMBER
|
|
|
|
LoadSetupInf(
|
|
|
|
IN OUT PUSETUP_DATA pSetupData)
|
|
|
|
{
|
|
|
|
INFCONTEXT Context;
|
|
|
|
UINT ErrorLine;
|
|
|
|
INT IntValue;
|
2018-01-06 15:47:37 +00:00
|
|
|
PCWSTR Value;
|
2017-08-09 20:39:45 +00:00
|
|
|
WCHAR FileNameBuffer[MAX_PATH];
|
|
|
|
|
|
|
|
CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2,
|
|
|
|
pSetupData->SourcePath.Buffer, L"txtsetup.sif");
|
|
|
|
|
2017-08-25 09:19:44 +00:00
|
|
|
DPRINT("SetupInf path: '%S'\n", FileNameBuffer);
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
pSetupData->SetupInf =
|
2018-01-06 15:47:37 +00:00
|
|
|
SpInfOpenInfFile(FileNameBuffer,
|
|
|
|
NULL,
|
2018-01-15 17:09:53 +00:00
|
|
|
INF_STYLE_WIN4,
|
2018-01-06 15:47:37 +00:00
|
|
|
pSetupData->LanguageId,
|
|
|
|
&ErrorLine);
|
2018-01-05 01:51:51 +00:00
|
|
|
if (pSetupData->SetupInf == INVALID_HANDLE_VALUE)
|
2017-08-09 20:39:45 +00:00
|
|
|
return ERROR_LOAD_TXTSETUPSIF;
|
|
|
|
|
|
|
|
/* Open 'Version' section */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Version", L"Signature", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
|
|
|
|
/* Get pointer 'Signature' key */
|
|
|
|
if (!INF_GetData(&Context, NULL, &Value))
|
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
|
|
|
|
/* Check 'Signature' string */
|
2018-01-15 17:09:53 +00:00
|
|
|
if (_wcsicmp(Value, L"$ReactOS$") != 0 &&
|
|
|
|
_wcsicmp(Value, L"$Windows NT$") != 0)
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
|
|
|
INF_FreeData(Value);
|
|
|
|
return ERROR_SIGNATURE_TXTSETUPSIF;
|
|
|
|
}
|
|
|
|
|
|
|
|
INF_FreeData(Value);
|
|
|
|
|
|
|
|
/* Open 'DiskSpaceRequirements' section */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(pSetupData->SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
|
|
|
|
pSetupData->RequiredPartitionDiskSpace = ~0;
|
|
|
|
|
|
|
|
/* Get the 'FreeSysPartDiskSpace' value */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfGetIntField(&Context, 1, &IntValue))
|
2017-08-09 20:39:45 +00:00
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
|
|
|
|
pSetupData->RequiredPartitionDiskSpace = (ULONG)IntValue;
|
|
|
|
|
|
|
|
//
|
2018-01-05 01:51:51 +00:00
|
|
|
// Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif
|
2017-08-09 20:39:45 +00:00
|
|
|
// See CORE-9023
|
2018-01-05 01:51:51 +00:00
|
|
|
// Support for that should also be added in setupldr.
|
2017-08-09 20:39:45 +00:00
|
|
|
//
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
/* Update the Setup Source paths */
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourceDevice", &Context))
|
2018-01-05 01:51:51 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Get optional pointer 'SetupSourceDevice' key, its presence
|
|
|
|
* will dictate whether we also need 'SetupSourcePath'.
|
|
|
|
*/
|
|
|
|
if (INF_GetData(&Context, NULL, &Value))
|
|
|
|
{
|
|
|
|
/* Free the old source root path string and create the new one */
|
|
|
|
RtlFreeUnicodeString(&pSetupData->SourceRootPath);
|
|
|
|
RtlCreateUnicodeString(&pSetupData->SourceRootPath, Value);
|
|
|
|
INF_FreeData(Value);
|
|
|
|
|
2018-01-06 15:47:37 +00:00
|
|
|
if (!SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourcePath", &Context))
|
2018-01-05 01:51:51 +00:00
|
|
|
{
|
|
|
|
/* The 'SetupSourcePath' value is mandatory! */
|
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get pointer 'SetupSourcePath' key */
|
|
|
|
if (!INF_GetData(&Context, NULL, &Value))
|
|
|
|
{
|
|
|
|
/* The 'SetupSourcePath' value is mandatory! */
|
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the old source path string and create the new one */
|
|
|
|
RtlFreeUnicodeString(&pSetupData->SourceRootDir);
|
|
|
|
RtlCreateUnicodeString(&pSetupData->SourceRootDir, Value);
|
|
|
|
INF_FreeData(Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 20:39:45 +00:00
|
|
|
/* Search for 'DefaultPath' in the 'SetupData' section */
|
2018-01-05 01:51:51 +00:00
|
|
|
pSetupData->InstallationDirectory[0] = 0;
|
2018-01-06 15:47:37 +00:00
|
|
|
if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"DefaultPath", &Context))
|
2017-08-09 20:39:45 +00:00
|
|
|
{
|
|
|
|
/* Get pointer 'DefaultPath' key */
|
|
|
|
if (!INF_GetData(&Context, NULL, &Value))
|
|
|
|
return ERROR_CORRUPT_TXTSETUPSIF;
|
|
|
|
|
2017-09-03 20:05:11 +00:00
|
|
|
RtlStringCchCopyW(pSetupData->InstallationDirectory,
|
|
|
|
ARRAYSIZE(pSetupData->InstallationDirectory),
|
|
|
|
Value);
|
|
|
|
|
2017-08-09 20:39:45 +00:00
|
|
|
INF_FreeData(Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-11-23 03:38:51 +00:00
|
|
|
/**
|
|
|
|
* @brief Find or set the active system partition.
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
InitSystemPartition(
|
|
|
|
/**/_In_ PPARTLIST PartitionList, /* HACK HACK! */
|
|
|
|
/**/_In_ PPARTENTRY InstallPartition, /* HACK HACK! */
|
|
|
|
/**/_Out_ PPARTENTRY* pSystemPartition, /* HACK HACK! */
|
|
|
|
_In_opt_ PFSVOL_CALLBACK FsVolCallback,
|
|
|
|
_In_opt_ PVOID Context)
|
|
|
|
{
|
|
|
|
FSVOL_OP Result;
|
|
|
|
PPARTENTRY SystemPartition;
|
|
|
|
PPARTENTRY OldActivePart;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we install on a fixed disk, try to find a supported system
|
|
|
|
* partition on the system. Otherwise if we install on a removable disk
|
|
|
|
* use the install partition as the system partition.
|
|
|
|
*/
|
|
|
|
if (InstallPartition->DiskEntry->MediaType == FixedMedia)
|
|
|
|
{
|
|
|
|
SystemPartition = FindSupportedSystemPartition(PartitionList,
|
|
|
|
FALSE,
|
|
|
|
InstallPartition->DiskEntry,
|
|
|
|
InstallPartition);
|
|
|
|
/* Use the original system partition as the old active partition hint */
|
|
|
|
OldActivePart = PartitionList->SystemPartition;
|
|
|
|
|
|
|
|
if ( SystemPartition && PartitionList->SystemPartition &&
|
|
|
|
(SystemPartition != PartitionList->SystemPartition) )
|
|
|
|
{
|
|
|
|
DPRINT1("We are using a different system partition!!\n");
|
|
|
|
|
|
|
|
Result = FsVolCallback(Context,
|
|
|
|
ChangeSystemPartition,
|
|
|
|
(ULONG_PTR)SystemPartition,
|
|
|
|
0);
|
|
|
|
if (Result != FSVOL_DOIT)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia)
|
|
|
|
{
|
|
|
|
SystemPartition = InstallPartition;
|
|
|
|
/* Don't specify any old active partition hint */
|
|
|
|
OldActivePart = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SystemPartition)
|
|
|
|
{
|
|
|
|
FsVolCallback(Context,
|
|
|
|
FSVOLNOTIFY_PARTITIONERROR,
|
|
|
|
ERROR_SYSTEM_PARTITION_NOT_FOUND,
|
|
|
|
0);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pSystemPartition = SystemPartition;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the system partition can be created in some
|
|
|
|
* non-partitioned space, create it now.
|
|
|
|
*/
|
|
|
|
if (!SystemPartition->IsPartitioned)
|
|
|
|
{
|
|
|
|
/* Automatically create the partition; it will be
|
|
|
|
* formatted later with default parameters */
|
|
|
|
// FIXME: Don't use the whole empty space, but a minimal size
|
|
|
|
// specified from the TXTSETUP.SIF or unattended setup.
|
|
|
|
CreatePartition(PartitionList,
|
|
|
|
SystemPartition,
|
|
|
|
0ULL,
|
|
|
|
0);
|
|
|
|
ASSERT(SystemPartition->IsPartitioned);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set it as such */
|
|
|
|
if (!SetActivePartition(PartitionList, SystemPartition, OldActivePart))
|
|
|
|
{
|
|
|
|
DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition);
|
|
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In all cases, whether or not we are going to perform a formatting,
|
|
|
|
* we must perform a filesystem check of the system partition.
|
|
|
|
*/
|
[SETUPLIB][REACTOS][USETUP] Split FS-volume-specific functionality from partitions (#7258)
CORE-13525
This greatly helps in reducing code complexity in some areas: code that
previously iterated over all partitions of a given disk, just to find
which ones were partitioned and contained a valid file system, now just
have to iterate over mounted volumes.
See in particular, `lib/utils/osdetect.c` and `lib/fsutil.c` .
- Remove FORMATSTATE "Preformatted" enum value;
- Cleanup osdetect code after introducing Volume support;
- Some simplifications for FormatState.
- Differentiate between 'new' partition and 'new' volume:
* "New" partition: it has been created and added in the cached list,
but not yet actually written into the disk.
* "New" volume: newly-created volume (may be backed by a partition or
not), not yet formatted. May exist on either new, or not new partition,
or elsewhere.
- Cache partition and volume NT device names.
These do not change across repartitioning operations, as long as the
partition or the filesystem volume hasn't been deleted/recreated.
This avoids doing \Device\Harddisk%u\Partition%u sprintf's everytime
we need to retrieve the given partition or volume device name.
When a partition/fileysystem volume is "virtually" created (i.e. in
the partition list, but not yet committed to disk and exposed to the
OS), no device partition number and device name are available yet.
In particular, validate that no manipulation of \Device\HarddiskM\Partition0
(i.e. the whole disk) is being made.
2024-05-18 21:09:16 +00:00
|
|
|
if (SystemPartition->Volume)
|
|
|
|
SystemPartition->Volume->NeedsCheck = TRUE;
|
2020-11-23 03:38:51 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
|
|
|
|
#define IS_PATH_SEPARATOR(c) ((c) == L'\\' || (c) == L'/')
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
* Verify whether the given directory is suitable for ReactOS installation.
|
|
|
|
* Each path component must be a valid 8.3 name.
|
|
|
|
**/
|
2024-07-25 16:57:23 +00:00
|
|
|
BOOLEAN
|
|
|
|
IsValidInstallDirectory(
|
|
|
|
_In_ PCWSTR InstallDir)
|
|
|
|
{
|
2024-07-25 16:57:23 +00:00
|
|
|
PCWCH p;
|
|
|
|
|
|
|
|
/* As with the NT installer, fail if the path is empty or "\\" */
|
|
|
|
p = InstallDir;
|
|
|
|
if (!*p || (IS_PATH_SEPARATOR(*p) && !*(p + 1)))
|
|
|
|
return FALSE;
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2024-08-11 19:04:18 +00:00
|
|
|
/* The path must contain only valid characters */
|
2024-07-25 16:57:23 +00:00
|
|
|
for (p = InstallDir; *p; ++p)
|
|
|
|
{
|
|
|
|
if (!IS_VALID_INSTALL_PATH_CHAR(*p))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
/*
|
|
|
|
* Loop over each path component and verify that each is a valid 8.3 name.
|
|
|
|
*/
|
|
|
|
for (p = InstallDir; *p;)
|
|
|
|
{
|
|
|
|
PCWSTR Path;
|
|
|
|
SIZE_T Length;
|
|
|
|
UNICODE_STRING Name;
|
|
|
|
BOOLEAN IsNameLegal, SpacesInName;
|
|
|
|
|
|
|
|
/* Skip any first separator */
|
|
|
|
if (IS_PATH_SEPARATOR(*p))
|
|
|
|
++p;
|
|
|
|
|
|
|
|
/* Now skip past the path component until we reach the next separator */
|
|
|
|
Path = p;
|
|
|
|
while (*p && !IS_PATH_SEPARATOR(*p))
|
|
|
|
++p;
|
|
|
|
if (p == Path)
|
|
|
|
{
|
|
|
|
/* Succeed if nothing else follows this separator; otherwise
|
|
|
|
* it's a separator and consecutive ones are not supported */
|
|
|
|
return (!*p);
|
|
|
|
}
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
/* Calculate the path component length */
|
|
|
|
Length = p - Path;
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
/* As with the NT installer, fail for '.' and '..';
|
|
|
|
* RtlIsNameLegalDOS8Dot3() would succeed otherwise */
|
|
|
|
if ((Length == 1 && *Path == '.') || (Length == 2 && *Path == '.' && *(Path + 1) == '.'))
|
|
|
|
return FALSE;
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
/* As with the NT installer, allow _only ONE trailing_ dot in
|
|
|
|
* the path component (but not 2 or more), by reducing Length
|
|
|
|
* in that case; RtlIsNameLegalDOS8Dot3() would fail otherwise */
|
|
|
|
if (Length > 1 && *(p - 2) != L'.' && *(p - 1) == L'.')
|
|
|
|
--Length;
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
if (Length == 0)
|
2024-07-25 16:57:23 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
/* Verify that the path component is a valid 8.3 name */
|
|
|
|
// if (Length > 8+1+3)
|
|
|
|
// return FALSE;
|
|
|
|
Name.Length = Name.MaximumLength = (USHORT)(Length * sizeof(WCHAR));
|
|
|
|
Name.Buffer = (PWCHAR)Path;
|
|
|
|
SpacesInName = FALSE;
|
|
|
|
IsNameLegal = RtlIsNameLegalDOS8Dot3(&Name, NULL, &SpacesInName);
|
|
|
|
|
|
|
|
/* If it isn't legal or contain spaces, fail */
|
|
|
|
if (!IsNameLegal || SpacesInName)
|
2024-07-25 16:57:23 +00:00
|
|
|
{
|
2024-07-25 16:57:23 +00:00
|
|
|
DPRINT("'%wZ' is %s 8.3 filename %s spaces\n",
|
|
|
|
&Name,
|
|
|
|
(IsNameLegal ? "a valid" : "an invalid"),
|
|
|
|
(SpacesInName ? "with" : "without"));
|
|
|
|
return FALSE;
|
2024-07-25 16:57:23 +00:00
|
|
|
}
|
2024-07-25 16:57:23 +00:00
|
|
|
/* Go to the next path component */
|
2024-07-25 16:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2024-07-25 16:57:23 +00:00
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
NTSTATUS
|
|
|
|
InitDestinationPaths(
|
[SETUPLIB][REACTOS][USETUP] Split FS-volume-specific functionality from partitions (#7258)
CORE-13525
This greatly helps in reducing code complexity in some areas: code that
previously iterated over all partitions of a given disk, just to find
which ones were partitioned and contained a valid file system, now just
have to iterate over mounted volumes.
See in particular, `lib/utils/osdetect.c` and `lib/fsutil.c` .
- Remove FORMATSTATE "Preformatted" enum value;
- Cleanup osdetect code after introducing Volume support;
- Some simplifications for FormatState.
- Differentiate between 'new' partition and 'new' volume:
* "New" partition: it has been created and added in the cached list,
but not yet actually written into the disk.
* "New" volume: newly-created volume (may be backed by a partition or
not), not yet formatted. May exist on either new, or not new partition,
or elsewhere.
- Cache partition and volume NT device names.
These do not change across repartitioning operations, as long as the
partition or the filesystem volume hasn't been deleted/recreated.
This avoids doing \Device\Harddisk%u\Partition%u sprintf's everytime
we need to retrieve the given partition or volume device name.
When a partition/fileysystem volume is "virtually" created (i.e. in
the partition list, but not yet committed to disk and exposed to the
OS), no device partition number and device name are available yet.
In particular, validate that no manipulation of \Device\HarddiskM\Partition0
(i.e. the whole disk) is being made.
2024-05-18 21:09:16 +00:00
|
|
|
_Inout_ PUSETUP_DATA pSetupData,
|
|
|
|
_In_ PCWSTR InstallationDir,
|
|
|
|
_In_ PVOLENTRY Volume)
|
2018-01-05 01:51:51 +00:00
|
|
|
{
|
2019-02-10 15:43:51 +00:00
|
|
|
NTSTATUS Status;
|
[SETUPLIB][REACTOS][USETUP] Split FS-volume-specific functionality from partitions (#7258)
CORE-13525
This greatly helps in reducing code complexity in some areas: code that
previously iterated over all partitions of a given disk, just to find
which ones were partitioned and contained a valid file system, now just
have to iterate over mounted volumes.
See in particular, `lib/utils/osdetect.c` and `lib/fsutil.c` .
- Remove FORMATSTATE "Preformatted" enum value;
- Cleanup osdetect code after introducing Volume support;
- Some simplifications for FormatState.
- Differentiate between 'new' partition and 'new' volume:
* "New" partition: it has been created and added in the cached list,
but not yet actually written into the disk.
* "New" volume: newly-created volume (may be backed by a partition or
not), not yet formatted. May exist on either new, or not new partition,
or elsewhere.
- Cache partition and volume NT device names.
These do not change across repartitioning operations, as long as the
partition or the filesystem volume hasn't been deleted/recreated.
This avoids doing \Device\Harddisk%u\Partition%u sprintf's everytime
we need to retrieve the given partition or volume device name.
When a partition/fileysystem volume is "virtually" created (i.e. in
the partition list, but not yet committed to disk and exposed to the
OS), no device partition number and device name are available yet.
In particular, validate that no manipulation of \Device\HarddiskM\Partition0
(i.e. the whole disk) is being made.
2024-05-18 21:09:16 +00:00
|
|
|
PPARTENTRY PartEntry = Volume->PartEntry;
|
2019-03-05 00:42:33 +00:00
|
|
|
PDISKENTRY DiskEntry = PartEntry->DiskEntry;
|
[SETUPLIB][REACTOS][USETUP] Split FS-volume-specific functionality from partitions (#7258)
CORE-13525
This greatly helps in reducing code complexity in some areas: code that
previously iterated over all partitions of a given disk, just to find
which ones were partitioned and contained a valid file system, now just
have to iterate over mounted volumes.
See in particular, `lib/utils/osdetect.c` and `lib/fsutil.c` .
- Remove FORMATSTATE "Preformatted" enum value;
- Cleanup osdetect code after introducing Volume support;
- Some simplifications for FormatState.
- Differentiate between 'new' partition and 'new' volume:
* "New" partition: it has been created and added in the cached list,
but not yet actually written into the disk.
* "New" volume: newly-created volume (may be backed by a partition or
not), not yet formatted. May exist on either new, or not new partition,
or elsewhere.
- Cache partition and volume NT device names.
These do not change across repartitioning operations, as long as the
partition or the filesystem volume hasn't been deleted/recreated.
This avoids doing \Device\Harddisk%u\Partition%u sprintf's everytime
we need to retrieve the given partition or volume device name.
When a partition/fileysystem volume is "virtually" created (i.e. in
the partition list, but not yet committed to disk and exposed to the
OS), no device partition number and device name are available yet.
In particular, validate that no manipulation of \Device\HarddiskM\Partition0
(i.e. the whole disk) is being made.
2024-05-18 21:09:16 +00:00
|
|
|
WCHAR PathBuffer[RTL_NUMBER_OF_FIELD(VOLINFO, DeviceName) + 1];
|
2018-01-05 01:51:51 +00:00
|
|
|
|
2019-02-24 18:04:57 +00:00
|
|
|
ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
/* Create 'pSetupData->DestinationRootPath' string */
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
[SETUPLIB][REACTOS][USETUP] Split FS-volume-specific functionality from partitions (#7258)
CORE-13525
This greatly helps in reducing code complexity in some areas: code that
previously iterated over all partitions of a given disk, just to find
which ones were partitioned and contained a valid file system, now just
have to iterate over mounted volumes.
See in particular, `lib/utils/osdetect.c` and `lib/fsutil.c` .
- Remove FORMATSTATE "Preformatted" enum value;
- Cleanup osdetect code after introducing Volume support;
- Some simplifications for FormatState.
- Differentiate between 'new' partition and 'new' volume:
* "New" partition: it has been created and added in the cached list,
but not yet actually written into the disk.
* "New" volume: newly-created volume (may be backed by a partition or
not), not yet formatted. May exist on either new, or not new partition,
or elsewhere.
- Cache partition and volume NT device names.
These do not change across repartitioning operations, as long as the
partition or the filesystem volume hasn't been deleted/recreated.
This avoids doing \Device\Harddisk%u\Partition%u sprintf's everytime
we need to retrieve the given partition or volume device name.
When a partition/fileysystem volume is "virtually" created (i.e. in
the partition list, but not yet committed to disk and exposed to the
OS), no device partition number and device name are available yet.
In particular, validate that no manipulation of \Device\HarddiskM\Partition0
(i.e. the whole disk) is being made.
2024-05-18 21:09:16 +00:00
|
|
|
Status = RtlStringCchPrintfW(PathBuffer, _countof(PathBuffer),
|
|
|
|
L"%s\\", Volume->Info.DeviceName);
|
2019-02-10 15:43:51 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = RtlCreateUnicodeString(&pSetupData->DestinationRootPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
DPRINT("DestinationRootPath: %wZ\n", &pSetupData->DestinationRootPath);
|
|
|
|
|
2018-01-06 15:47:37 +00:00
|
|
|
// FIXME! Which variable to choose?
|
|
|
|
if (!InstallationDir)
|
|
|
|
InstallationDir = pSetupData->InstallationDirectory;
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
/** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
|
|
|
|
/* Create 'pSetupData->DestinationArcPath' */
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
|
[SETUPLIB][USETUP] Improve disk HW numbering, removable disk support, and "super-floppy" partitioning.
Nowadays more and more people try to install ReactOS from removable
drives (e.g. USB sticks) onto fixed HDDs, or try to install it into
USB sticks too.
Both fixed and removable drives, as well as partitions on these, are
represented in NT using the same device name format:
\Device\HarddiskM\PartitionN ,
with an increasing disk number M. Using this number for building the
corresponding firmware-specific ARC multi(x)disk(y)rdisk(z) path used
by the NT/ROS loader (FreeLdr, ...) is then prone to error since there
may have been removable drives inserted and accounted for in the
calculation of the disk number. These drives must be correctly
subtracted in order to generate the correct ARC path, valid once all
the removable drives have been ejected (which should also be the
situation seen from the BIOS when booting up, except of course if you
boot on a USB stick).
This problem is now solved. Note that it matters only for the disks
that have also been enumerated by the firmware (BIOS; Int 13h). We
don't have to care about the other drives, since the ARC path will be
of a different format and will not use the disk number (instead, the
SCSI coordinates are used).
We also try to enumerate all the disks found in all the possible disk
adapters and controllers enumerated in the Hardware registry tree
(and that are visible by FreeLdr) in order to cover all.
Finally, we detect whether a disk reports as a "super-floppy", i.e.
an unpartitioned disk with a valid VBR. This is indeed how a standard
floppy disk looks like, or how USB sticks are partitioned on Windows.
Such disk is reported has having only one single partition starting at
the beginning of the disk, with partition number == 0, its type being
FAT16 non-bootable.
This allows us to forbid creating any new partitions on such disks.
Note that accessing either \Device\HarddiskN\Partition0 or Partition1
on such a disk returns the same data.
Note also that on the contrary, regular MBR-partitioned disks would
report at least four partitions entries, instead of just one.
The other improvements are:
- Do *NOT* write any MBR on a disk partitioned as "super-floppy".
CORE-13703
- Fix the computed disk identifier, of format: %08x-%08x-%c .
The numbers are respectively the checksum of the first sector, and
the disk signature. The terminating letter is A or X, depending
whether the first sector ends with 0x55AA/0xAA55 or not (see also
commit 5053f1f5).
- Warn if the user attempts to install ReactOS on a disk that is not
visible by the firmware of his computer, because it may not be
bootable.
2019-03-11 23:13:25 +00:00
|
|
|
|
|
|
|
if (DiskEntry->MediaType == FixedMedia)
|
|
|
|
{
|
|
|
|
if (DiskEntry->BiosFound)
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
|
|
|
|
DiskEntry->HwFixedDiskNumber,
|
|
|
|
PartEntry->OnDiskPartitionNumber);
|
|
|
|
#else
|
|
|
|
Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"multi(%lu)disk(%lu)rdisk(%lu)partition(%lu)\\",
|
|
|
|
DiskEntry->HwAdapterNumber,
|
|
|
|
DiskEntry->HwControllerNumber,
|
|
|
|
DiskEntry->HwFixedDiskNumber,
|
|
|
|
PartEntry->OnDiskPartitionNumber);
|
|
|
|
#endif
|
|
|
|
DPRINT1("Fixed disk found by BIOS, using MULTI ARC path '%S'\n", PathBuffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"scsi(%u)disk(%u)rdisk(%u)partition(%lu)\\",
|
|
|
|
DiskEntry->Port,
|
|
|
|
DiskEntry->Bus,
|
|
|
|
DiskEntry->Id,
|
|
|
|
PartEntry->OnDiskPartitionNumber);
|
|
|
|
DPRINT1("Fixed disk not found by BIOS, using SCSI ARC path '%S'\n", PathBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // if (DiskEntry->MediaType == RemovableMedia)
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
|
|
|
|
0, 1);
|
|
|
|
DPRINT1("Removable disk, using MULTI ARC path '%S'\n", PathBuffer);
|
|
|
|
#else
|
|
|
|
Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
|
|
L"signature(%08x)disk(%u)rdisk(%u)partition(%lu)\\",
|
|
|
|
DiskEntry->LayoutBuffer->Signature,
|
|
|
|
DiskEntry->Bus,
|
|
|
|
DiskEntry->Id,
|
|
|
|
PartEntry->OnDiskPartitionNumber);
|
|
|
|
DPRINT1("Removable disk, using SIGNATURE ARC path '%S'\n", PathBuffer);
|
|
|
|
#endif
|
|
|
|
}
|
2019-02-10 15:43:51 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallationDir);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("ConcatPaths() failed with status 0x%08lx\n", Status);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = RtlCreateUnicodeString(&pSetupData->DestinationArcPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
|
|
|
return Status;
|
|
|
|
}
|
2018-01-05 01:51:51 +00:00
|
|
|
|
|
|
|
/** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
|
|
|
|
/* Create 'pSetupData->DestinationPath' string */
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationPath);
|
2019-02-10 15:43:51 +00:00
|
|
|
Status = CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
|
|
|
|
pSetupData->DestinationRootPath.Buffer, InstallationDir);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("CombinePaths() failed with status 0x%08lx\n", Status);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
|
[SETUPLIB][USETUP] Improve disk HW numbering, removable disk support, and "super-floppy" partitioning.
Nowadays more and more people try to install ReactOS from removable
drives (e.g. USB sticks) onto fixed HDDs, or try to install it into
USB sticks too.
Both fixed and removable drives, as well as partitions on these, are
represented in NT using the same device name format:
\Device\HarddiskM\PartitionN ,
with an increasing disk number M. Using this number for building the
corresponding firmware-specific ARC multi(x)disk(y)rdisk(z) path used
by the NT/ROS loader (FreeLdr, ...) is then prone to error since there
may have been removable drives inserted and accounted for in the
calculation of the disk number. These drives must be correctly
subtracted in order to generate the correct ARC path, valid once all
the removable drives have been ejected (which should also be the
situation seen from the BIOS when booting up, except of course if you
boot on a USB stick).
This problem is now solved. Note that it matters only for the disks
that have also been enumerated by the firmware (BIOS; Int 13h). We
don't have to care about the other drives, since the ARC path will be
of a different format and will not use the disk number (instead, the
SCSI coordinates are used).
We also try to enumerate all the disks found in all the possible disk
adapters and controllers enumerated in the Hardware registry tree
(and that are visible by FreeLdr) in order to cover all.
Finally, we detect whether a disk reports as a "super-floppy", i.e.
an unpartitioned disk with a valid VBR. This is indeed how a standard
floppy disk looks like, or how USB sticks are partitioned on Windows.
Such disk is reported has having only one single partition starting at
the beginning of the disk, with partition number == 0, its type being
FAT16 non-bootable.
This allows us to forbid creating any new partitions on such disks.
Note that accessing either \Device\HarddiskN\Partition0 or Partition1
on such a disk returns the same data.
Note also that on the contrary, regular MBR-partitioned disks would
report at least four partitions entries, instead of just one.
The other improvements are:
- Do *NOT* write any MBR on a disk partitioned as "super-floppy".
CORE-13703
- Fix the computed disk identifier, of format: %08x-%08x-%c .
The numbers are respectively the checksum of the first sector, and
the disk signature. The terminating letter is A or X, depending
whether the first sector ends with 0x55AA/0xAA55 or not (see also
commit 5053f1f5).
- Warn if the user attempts to install ReactOS on a disk that is not
visible by the firmware of his computer, because it may not be
bootable.
2019-03-11 23:13:25 +00:00
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
2019-02-10 15:43:51 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = RtlCreateUnicodeString(&pSetupData->DestinationPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
|
[SETUPLIB][USETUP] Improve disk HW numbering, removable disk support, and "super-floppy" partitioning.
Nowadays more and more people try to install ReactOS from removable
drives (e.g. USB sticks) onto fixed HDDs, or try to install it into
USB sticks too.
Both fixed and removable drives, as well as partitions on these, are
represented in NT using the same device name format:
\Device\HarddiskM\PartitionN ,
with an increasing disk number M. Using this number for building the
corresponding firmware-specific ARC multi(x)disk(y)rdisk(z) path used
by the NT/ROS loader (FreeLdr, ...) is then prone to error since there
may have been removable drives inserted and accounted for in the
calculation of the disk number. These drives must be correctly
subtracted in order to generate the correct ARC path, valid once all
the removable drives have been ejected (which should also be the
situation seen from the BIOS when booting up, except of course if you
boot on a USB stick).
This problem is now solved. Note that it matters only for the disks
that have also been enumerated by the firmware (BIOS; Int 13h). We
don't have to care about the other drives, since the ARC path will be
of a different format and will not use the disk number (instead, the
SCSI coordinates are used).
We also try to enumerate all the disks found in all the possible disk
adapters and controllers enumerated in the Hardware registry tree
(and that are visible by FreeLdr) in order to cover all.
Finally, we detect whether a disk reports as a "super-floppy", i.e.
an unpartitioned disk with a valid VBR. This is indeed how a standard
floppy disk looks like, or how USB sticks are partitioned on Windows.
Such disk is reported has having only one single partition starting at
the beginning of the disk, with partition number == 0, its type being
FAT16 non-bootable.
This allows us to forbid creating any new partitions on such disks.
Note that accessing either \Device\HarddiskN\Partition0 or Partition1
on such a disk returns the same data.
Note also that on the contrary, regular MBR-partitioned disks would
report at least four partitions entries, instead of just one.
The other improvements are:
- Do *NOT* write any MBR on a disk partitioned as "super-floppy".
CORE-13703
- Fix the computed disk identifier, of format: %08x-%08x-%c .
The numbers are respectively the checksum of the first sector, and
the disk signature. The terminating letter is A or X, depending
whether the first sector ends with 0x55AA/0xAA55 or not (see also
commit 5053f1f5).
- Warn if the user attempts to install ReactOS on a disk that is not
visible by the firmware of his computer, because it may not be
bootable.
2019-03-11 23:13:25 +00:00
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
2019-02-10 15:43:51 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2018-01-05 01:51:51 +00:00
|
|
|
|
|
|
|
/** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
|
|
|
|
// FIXME: This is only temporary!! Must be removed later!
|
2019-02-10 15:43:51 +00:00
|
|
|
Status = RtlCreateUnicodeString(&pSetupData->InstallPath, InstallationDir) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationPath);
|
[SETUPLIB][USETUP] Improve disk HW numbering, removable disk support, and "super-floppy" partitioning.
Nowadays more and more people try to install ReactOS from removable
drives (e.g. USB sticks) onto fixed HDDs, or try to install it into
USB sticks too.
Both fixed and removable drives, as well as partitions on these, are
represented in NT using the same device name format:
\Device\HarddiskM\PartitionN ,
with an increasing disk number M. Using this number for building the
corresponding firmware-specific ARC multi(x)disk(y)rdisk(z) path used
by the NT/ROS loader (FreeLdr, ...) is then prone to error since there
may have been removable drives inserted and accounted for in the
calculation of the disk number. These drives must be correctly
subtracted in order to generate the correct ARC path, valid once all
the removable drives have been ejected (which should also be the
situation seen from the BIOS when booting up, except of course if you
boot on a USB stick).
This problem is now solved. Note that it matters only for the disks
that have also been enumerated by the firmware (BIOS; Int 13h). We
don't have to care about the other drives, since the ARC path will be
of a different format and will not use the disk number (instead, the
SCSI coordinates are used).
We also try to enumerate all the disks found in all the possible disk
adapters and controllers enumerated in the Hardware registry tree
(and that are visible by FreeLdr) in order to cover all.
Finally, we detect whether a disk reports as a "super-floppy", i.e.
an unpartitioned disk with a valid VBR. This is indeed how a standard
floppy disk looks like, or how USB sticks are partitioned on Windows.
Such disk is reported has having only one single partition starting at
the beginning of the disk, with partition number == 0, its type being
FAT16 non-bootable.
This allows us to forbid creating any new partitions on such disks.
Note that accessing either \Device\HarddiskN\Partition0 or Partition1
on such a disk returns the same data.
Note also that on the contrary, regular MBR-partitioned disks would
report at least four partitions entries, instead of just one.
The other improvements are:
- Do *NOT* write any MBR on a disk partitioned as "super-floppy".
CORE-13703
- Fix the computed disk identifier, of format: %08x-%08x-%c .
The numbers are respectively the checksum of the first sector, and
the disk signature. The terminating letter is A or X, depending
whether the first sector ends with 0x55AA/0xAA55 or not (see also
commit 5053f1f5).
- Warn if the user attempts to install ReactOS on a disk that is not
visible by the firmware of his computer, because it may not be
bootable.
2019-03-11 23:13:25 +00:00
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationArcPath);
|
|
|
|
RtlFreeUnicodeString(&pSetupData->DestinationRootPath);
|
2019-02-10 15:43:51 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2018-01-05 01:51:51 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NTSTATUS
|
|
|
|
ERROR_NUMBER
|
|
|
|
InitializeSetup(
|
|
|
|
IN OUT PUSETUP_DATA pSetupData,
|
|
|
|
IN ULONG InitPhase)
|
|
|
|
{
|
|
|
|
if (InitPhase == 0)
|
|
|
|
{
|
|
|
|
RtlZeroMemory(pSetupData, sizeof(*pSetupData));
|
|
|
|
|
2018-10-28 21:51:33 +00:00
|
|
|
/* Initialize error handling */
|
|
|
|
pSetupData->LastErrorNumber = ERROR_SUCCESS;
|
|
|
|
pSetupData->ErrorRoutine = NULL;
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
/* Initialize global unicode strings */
|
|
|
|
RtlInitUnicodeString(&pSetupData->SourcePath, NULL);
|
|
|
|
RtlInitUnicodeString(&pSetupData->SourceRootPath, NULL);
|
|
|
|
RtlInitUnicodeString(&pSetupData->SourceRootDir, NULL);
|
|
|
|
RtlInitUnicodeString(&pSetupData->DestinationArcPath, NULL);
|
|
|
|
RtlInitUnicodeString(&pSetupData->DestinationPath, NULL);
|
|
|
|
RtlInitUnicodeString(&pSetupData->DestinationRootPath, NULL);
|
|
|
|
RtlInitUnicodeString(&pSetupData->SystemRootPath, NULL);
|
|
|
|
|
|
|
|
// FIXME: This is only temporary!! Must be removed later!
|
|
|
|
/***/RtlInitUnicodeString(&pSetupData->InstallPath, NULL);/***/
|
|
|
|
|
|
|
|
//
|
|
|
|
// TODO: Load and start SetupDD, and ask it for the information
|
|
|
|
//
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (InitPhase == 1)
|
|
|
|
{
|
|
|
|
ERROR_NUMBER Error;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
/* Get the source path and source root path */
|
|
|
|
//
|
|
|
|
// NOTE: Sometimes the source path may not be in SystemRoot !!
|
|
|
|
// (and this is the case when using the 1st-stage GUI setup!)
|
|
|
|
//
|
|
|
|
Status = GetSourcePaths(&pSetupData->SourcePath,
|
|
|
|
&pSetupData->SourceRootPath,
|
|
|
|
&pSetupData->SourceRootDir);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2023-11-16 22:22:12 +00:00
|
|
|
DPRINT1("GetSourcePaths() failed (Status 0x%08lx)\n", Status);
|
2018-01-05 01:51:51 +00:00
|
|
|
return ERROR_NO_SOURCE_DRIVE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Example of output:
|
|
|
|
* SourcePath: '\Device\CdRom0\I386'
|
|
|
|
* SourceRootPath: '\Device\CdRom0'
|
|
|
|
* SourceRootDir: '\I386'
|
|
|
|
*/
|
|
|
|
DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData->SourcePath);
|
|
|
|
DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData->SourceRootPath);
|
|
|
|
DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData->SourceRootDir);
|
|
|
|
|
2023-12-16 11:52:39 +00:00
|
|
|
/* Set up default values */
|
|
|
|
pSetupData->DestinationDiskNumber = 0;
|
|
|
|
pSetupData->DestinationPartitionNumber = 1;
|
|
|
|
pSetupData->BootLoaderLocation = 2; // Default to "System partition"
|
|
|
|
pSetupData->FormatPartition = 0;
|
|
|
|
pSetupData->AutoPartition = 0;
|
|
|
|
pSetupData->FsType = 0;
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
/* Load 'txtsetup.sif' from the installation media */
|
|
|
|
Error = LoadSetupInf(pSetupData);
|
|
|
|
if (Error != ERROR_SUCCESS)
|
|
|
|
{
|
2023-11-16 22:22:12 +00:00
|
|
|
DPRINT1("LoadSetupInf() failed (Error 0x%lx)\n", Error);
|
2018-01-05 01:51:51 +00:00
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData->SourcePath);
|
|
|
|
DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData->SourceRootPath);
|
|
|
|
DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData->SourceRootDir);
|
|
|
|
|
2024-07-20 20:15:47 +00:00
|
|
|
/* Retrieve the target machine architecture type */
|
|
|
|
// FIXME: This should be determined at runtime!!
|
|
|
|
// FIXME: Allow for (pre-)installing on an architecture
|
|
|
|
// different from the current one?
|
|
|
|
#if defined(SARCH_XBOX)
|
|
|
|
pSetupData->ArchType = ARCH_Xbox;
|
|
|
|
// #elif defined(SARCH_PC98)
|
|
|
|
#else // TODO: Arc, UEFI
|
|
|
|
pSetupData->ArchType = (IsNEC_98 ? ARCH_NEC98x86 : ARCH_PcAT);
|
|
|
|
#endif
|
|
|
|
|
2018-01-05 01:51:51 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FinishSetup(
|
|
|
|
IN OUT PUSETUP_DATA pSetupData)
|
|
|
|
{
|
|
|
|
/* Destroy the computer settings list */
|
|
|
|
if (pSetupData->ComputerList != NULL)
|
|
|
|
{
|
|
|
|
DestroyGenericList(pSetupData->ComputerList, TRUE);
|
|
|
|
pSetupData->ComputerList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy the display settings list */
|
|
|
|
if (pSetupData->DisplayList != NULL)
|
|
|
|
{
|
|
|
|
DestroyGenericList(pSetupData->DisplayList, TRUE);
|
|
|
|
pSetupData->DisplayList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy the keyboard settings list */
|
|
|
|
if (pSetupData->KeyboardList != NULL)
|
|
|
|
{
|
|
|
|
DestroyGenericList(pSetupData->KeyboardList, TRUE);
|
|
|
|
pSetupData->KeyboardList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy the keyboard layout list */
|
|
|
|
if (pSetupData->LayoutList != NULL)
|
|
|
|
{
|
|
|
|
DestroyGenericList(pSetupData->LayoutList, TRUE);
|
|
|
|
pSetupData->LayoutList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy the languages list */
|
|
|
|
if (pSetupData->LanguageList != NULL)
|
|
|
|
{
|
|
|
|
DestroyGenericList(pSetupData->LanguageList, FALSE);
|
|
|
|
pSetupData->LanguageList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the Setup INF */
|
2018-01-06 15:47:37 +00:00
|
|
|
SpInfCloseInfFile(pSetupData->SetupInf);
|
2018-01-05 01:51:51 +00:00
|
|
|
}
|
|
|
|
|
2017-09-03 16:17:27 +00:00
|
|
|
/*
|
|
|
|
* SIDEEFFECTS
|
|
|
|
* Calls RegInitializeRegistry
|
|
|
|
* Calls ImportRegistryFile
|
|
|
|
* Calls SetDefaultPagefile
|
|
|
|
* Calls SetMountedDeviceValues
|
|
|
|
*/
|
|
|
|
ERROR_NUMBER
|
|
|
|
UpdateRegistry(
|
|
|
|
IN OUT PUSETUP_DATA pSetupData,
|
|
|
|
/**/IN BOOLEAN RepairUpdateFlag, /* HACK HACK! */
|
|
|
|
/**/IN PPARTLIST PartitionList, /* HACK HACK! */
|
|
|
|
/**/IN WCHAR DestinationDriveLetter, /* HACK HACK! */
|
|
|
|
/**/IN PCWSTR SelectedLanguageId, /* HACK HACK! */
|
2020-02-14 01:47:20 +00:00
|
|
|
IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL,
|
|
|
|
IN PFONTSUBSTSETTINGS SubstSettings OPTIONAL)
|
2017-09-03 16:17:27 +00:00
|
|
|
{
|
|
|
|
ERROR_NUMBER ErrorNumber;
|
|
|
|
NTSTATUS Status;
|
|
|
|
INFCONTEXT InfContext;
|
2018-01-06 15:47:37 +00:00
|
|
|
PCWSTR Action;
|
|
|
|
PCWSTR File;
|
|
|
|
PCWSTR Section;
|
2017-09-03 16:17:27 +00:00
|
|
|
BOOLEAN Success;
|
|
|
|
BOOLEAN ShouldRepairRegistry = FALSE;
|
|
|
|
BOOLEAN Delete;
|
|
|
|
|
|
|
|
if (RepairUpdateFlag)
|
|
|
|
{
|
|
|
|
DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
|
|
|
|
|
|
|
|
/* Verify the registry hives and check whether we need to update or repair any of them */
|
|
|
|
Status = VerifyRegistryHives(&pSetupData->DestinationPath, &ShouldRepairRegistry);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
|
|
|
|
ShouldRepairRegistry = FALSE;
|
|
|
|
}
|
|
|
|
if (!ShouldRepairRegistry)
|
|
|
|
DPRINT1("No need to repair the registry\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
DoUpdate:
|
|
|
|
ErrorNumber = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
/* Update the registry */
|
|
|
|
if (StatusRoutine) StatusRoutine(RegHiveUpdate);
|
|
|
|
|
|
|
|
/* Initialize the registry and setup the registry hives */
|
|
|
|
Status = RegInitializeRegistry(&pSetupData->DestinationPath);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RegInitializeRegistry() failed\n");
|
|
|
|
/********** HACK!!!!!!!!!!! **********/
|
|
|
|
if (Status == STATUS_NOT_IMPLEMENTED)
|
|
|
|
{
|
|
|
|
/* The hack was called, return its corresponding error */
|
|
|
|
return ERROR_INITIALIZE_REGISTRY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/*************************************/
|
|
|
|
{
|
|
|
|
/* Something else failed */
|
|
|
|
return ERROR_CREATE_HIVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!RepairUpdateFlag || ShouldRepairRegistry)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We fully setup the hives, in case we are doing a fresh installation
|
|
|
|
* (RepairUpdateFlag == FALSE), or in case we are doing an update
|
|
|
|
* (RepairUpdateFlag == TRUE) BUT we have some registry hives to
|
|
|
|
* "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
|
|
|
|
*/
|
|
|
|
|
2018-01-07 00:35:48 +00:00
|
|
|
Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible
|
2017-09-03 16:17:27 +00:00
|
|
|
if (!Success)
|
2018-01-07 00:35:48 +00:00
|
|
|
Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific
|
2017-09-03 16:17:27 +00:00
|
|
|
|
|
|
|
if (!Success)
|
|
|
|
{
|
2018-01-06 15:47:37 +00:00
|
|
|
DPRINT1("SpInfFindFirstLine() failed\n");
|
2017-09-03 16:17:27 +00:00
|
|
|
ErrorNumber = ERROR_FIND_REGISTRY;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // if (RepairUpdateFlag && !ShouldRepairRegistry)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In case we are doing an update (RepairUpdateFlag == TRUE) and
|
|
|
|
* NO registry hives need a repair (ShouldRepairRegistry == FALSE),
|
|
|
|
* we only update the hives.
|
|
|
|
*/
|
|
|
|
|
2018-01-07 00:35:48 +00:00
|
|
|
Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext);
|
2017-09-03 16:17:27 +00:00
|
|
|
if (!Success)
|
|
|
|
{
|
|
|
|
/* Nothing to do for update! */
|
|
|
|
DPRINT1("No update needed for the registry!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
INF_GetDataField(&InfContext, 0, &Action);
|
|
|
|
INF_GetDataField(&InfContext, 1, &File);
|
|
|
|
INF_GetDataField(&InfContext, 2, &Section);
|
|
|
|
|
|
|
|
DPRINT("Action: %S File: %S Section %S\n", Action, File, Section);
|
|
|
|
|
|
|
|
if (Action == NULL)
|
|
|
|
{
|
|
|
|
INF_FreeData(Action);
|
|
|
|
INF_FreeData(File);
|
|
|
|
INF_FreeData(Section);
|
|
|
|
break; // Hackfix
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_wcsicmp(Action, L"AddReg"))
|
|
|
|
Delete = FALSE;
|
|
|
|
else if (!_wcsicmp(Action, L"DelReg"))
|
|
|
|
Delete = TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("Unrecognized registry INF action '%S'\n", Action);
|
|
|
|
INF_FreeData(Action);
|
|
|
|
INF_FreeData(File);
|
|
|
|
INF_FreeData(Section);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
INF_FreeData(Action);
|
|
|
|
|
|
|
|
if (StatusRoutine) StatusRoutine(ImportRegHive, File);
|
|
|
|
|
|
|
|
if (!ImportRegistryFile(pSetupData->SourcePath.Buffer,
|
|
|
|
File, Section,
|
|
|
|
pSetupData->LanguageId, Delete))
|
|
|
|
{
|
|
|
|
DPRINT1("Importing %S failed\n", File);
|
|
|
|
INF_FreeData(File);
|
|
|
|
INF_FreeData(Section);
|
|
|
|
ErrorNumber = ERROR_IMPORT_HIVE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
2018-01-06 15:47:37 +00:00
|
|
|
} while (SpInfFindNextLine(&InfContext, &InfContext));
|
2017-09-03 16:17:27 +00:00
|
|
|
|
|
|
|
if (!RepairUpdateFlag || ShouldRepairRegistry)
|
|
|
|
{
|
|
|
|
/* See the explanation for this test above */
|
|
|
|
|
2024-02-15 22:10:55 +00:00
|
|
|
PGENERIC_LIST_ENTRY Entry;
|
|
|
|
PCWSTR LanguageId; // LocaleID;
|
|
|
|
|
|
|
|
Entry = GetCurrentListEntry(pSetupData->DisplayList);
|
|
|
|
ASSERT(Entry);
|
|
|
|
pSetupData->DisplayType = ((PGENENTRY)GetListEntryData(Entry))->Id;
|
|
|
|
ASSERT(pSetupData->DisplayType);
|
|
|
|
|
2017-09-03 16:17:27 +00:00
|
|
|
/* Update display registry settings */
|
|
|
|
if (StatusRoutine) StatusRoutine(DisplaySettingsUpdate);
|
2024-02-15 22:10:55 +00:00
|
|
|
if (!ProcessDisplayRegistry(pSetupData->SetupInf, pSetupData->DisplayType))
|
2017-09-03 16:17:27 +00:00
|
|
|
{
|
|
|
|
ErrorNumber = ERROR_UPDATE_DISPLAY_SETTINGS;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2024-02-15 22:10:55 +00:00
|
|
|
Entry = GetCurrentListEntry(pSetupData->LanguageList);
|
|
|
|
ASSERT(Entry);
|
|
|
|
LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id;
|
|
|
|
ASSERT(LanguageId);
|
|
|
|
|
2017-09-03 16:17:27 +00:00
|
|
|
/* Set the locale */
|
|
|
|
if (StatusRoutine) StatusRoutine(LocaleSettingsUpdate);
|
2024-02-15 22:10:55 +00:00
|
|
|
if (!ProcessLocaleRegistry(/*pSetupData->*/LanguageId))
|
2017-09-03 16:17:27 +00:00
|
|
|
{
|
|
|
|
ErrorNumber = ERROR_UPDATE_LOCALESETTINGS;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2024-02-15 22:10:55 +00:00
|
|
|
/* Add the keyboard layouts for the given language (without user override) */
|
2017-09-03 16:17:27 +00:00
|
|
|
if (StatusRoutine) StatusRoutine(KeybLayouts);
|
|
|
|
if (!AddKeyboardLayouts(SelectedLanguageId))
|
|
|
|
{
|
|
|
|
ErrorNumber = ERROR_ADDING_KBLAYOUTS;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsUnattendedSetup)
|
|
|
|
{
|
2024-02-15 22:10:55 +00:00
|
|
|
Entry = GetCurrentListEntry(pSetupData->LayoutList);
|
|
|
|
ASSERT(Entry);
|
|
|
|
pSetupData->LayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id;
|
|
|
|
ASSERT(pSetupData->LayoutId);
|
|
|
|
|
|
|
|
/* Update keyboard layout settings with user-overridden values */
|
|
|
|
// FIXME: Wouldn't it be better to do it all at once
|
|
|
|
// with the AddKeyboardLayouts() step?
|
2017-09-03 16:17:27 +00:00
|
|
|
if (StatusRoutine) StatusRoutine(KeybSettingsUpdate);
|
2024-02-15 22:10:55 +00:00
|
|
|
if (!ProcessKeyboardLayoutRegistry(pSetupData->LayoutId, SelectedLanguageId))
|
2017-09-03 16:17:27 +00:00
|
|
|
{
|
|
|
|
ErrorNumber = ERROR_UPDATE_KBSETTINGS;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-15 22:10:55 +00:00
|
|
|
/* Set GeoID */
|
|
|
|
if (!SetGeoID(MUIGetGeoID(SelectedLanguageId)))
|
|
|
|
{
|
|
|
|
ErrorNumber = ERROR_UPDATE_GEOID;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2017-09-03 16:17:27 +00:00
|
|
|
/* Add codepage information to registry */
|
|
|
|
if (StatusRoutine) StatusRoutine(CodePageInfoUpdate);
|
|
|
|
if (!AddCodePage(SelectedLanguageId))
|
|
|
|
{
|
|
|
|
ErrorNumber = ERROR_ADDING_CODEPAGE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the default pagefile entry */
|
|
|
|
SetDefaultPagefile(DestinationDriveLetter);
|
|
|
|
|
|
|
|
/* Update the mounted devices list */
|
|
|
|
// FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
|
|
|
|
SetMountedDeviceValues(PartitionList);
|
|
|
|
}
|
|
|
|
|
2020-02-14 01:47:20 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
if (SubstSettings)
|
|
|
|
{
|
|
|
|
/* HACK */
|
|
|
|
DoRegistryFontFixup(SubstSettings, wcstoul(SelectedLanguageId, NULL, 16));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-09-03 16:17:27 +00:00
|
|
|
Cleanup:
|
|
|
|
//
|
|
|
|
// TODO: Unload all the registry stuff, perform cleanup,
|
|
|
|
// and copy the created hive files into .sav files.
|
|
|
|
//
|
|
|
|
RegCleanupRegistry(&pSetupData->DestinationPath);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check whether we were in update/repair mode but we were actually
|
|
|
|
* repairing the registry hives. If so, we have finished repairing them,
|
|
|
|
* and we now reset the flag and run the proper registry update.
|
|
|
|
* Otherwise we have finished the registry update!
|
|
|
|
*/
|
|
|
|
if (RepairUpdateFlag && ShouldRepairRegistry)
|
|
|
|
{
|
|
|
|
ShouldRepairRegistry = FALSE;
|
|
|
|
goto DoUpdate;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ErrorNumber;
|
|
|
|
}
|
|
|
|
|
2017-08-09 20:39:45 +00:00
|
|
|
/* EOF */
|