mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 13:23:51 +00:00
![Hermès Bélusca-Maïto](/assets/img/avatar_default.png)
- BOOTDATA: Use standard INF signature string, so that they can be opened successfully using ReactOS' or Windows' setupapi.dll with the INF_STYLE_WIN4 style. - SETUPLIB: Use the correct INF_STYLE_* INF styles in SpInfOpenInfFile() calls. - REACTOS : Switch thread locale to user-specified LocaleId when calling SetupOpenInfFileW(), so that the correct localized strings are used.
837 lines
26 KiB
C
837 lines
26 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Setup Library
|
|
* FILE: base/setup/lib/install.c
|
|
* PURPOSE: Installation functions
|
|
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "filesup.h"
|
|
#include "infsupp.h"
|
|
|
|
#include "setuplib.h" // HAXX for USETUP_DATA!!
|
|
|
|
#include "install.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
static BOOL
|
|
LookupDirectoryById(
|
|
IN HINF InfHandle,
|
|
IN OUT PINFCONTEXT InfContext,
|
|
IN PCWSTR DirId,
|
|
OUT PCWSTR* pDirectory)
|
|
{
|
|
BOOL Success;
|
|
|
|
// ReactOS-specific
|
|
Success = SpInfFindFirstLine(InfHandle, L"Directories", DirId, InfContext);
|
|
if (!Success)
|
|
{
|
|
// Windows-compatible
|
|
Success = SpInfFindFirstLine(InfHandle, L"WinntDirectories", DirId, InfContext);
|
|
if (!Success)
|
|
DPRINT1("SpInfFindFirstLine() failed\n");
|
|
}
|
|
if (Success)
|
|
{
|
|
Success = INF_GetData(InfContext, NULL, pDirectory);
|
|
if (!Success)
|
|
DPRINT1("INF_GetData() failed\n");
|
|
}
|
|
|
|
if (!Success)
|
|
DPRINT1("LookupDirectoryById(%S) - directory not found!\n", DirId);
|
|
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* Note: Modeled after SetupGetSourceFileLocation(), SetupGetSourceInfo()
|
|
* and SetupGetTargetPath() APIs.
|
|
* Technically the target path is the same for a given file section,
|
|
* but here we try to remove this constraint.
|
|
*
|
|
* TXTSETUP.SIF entries syntax explained at:
|
|
* http://www.msfn.org/board/topic/125480-txtsetupsif-syntax/
|
|
*/
|
|
static NTSTATUS
|
|
GetSourceFileAndTargetLocation(
|
|
IN HINF InfHandle,
|
|
IN PINFCONTEXT InfContext OPTIONAL,
|
|
IN PCWSTR SourceFileName OPTIONAL,
|
|
OUT PCWSTR* pSourceRootPath,
|
|
OUT PCWSTR* pSourcePath,
|
|
OUT PCWSTR* pTargetDirectory,
|
|
OUT PCWSTR* pTargetFileName)
|
|
{
|
|
BOOL Success;
|
|
INFCONTEXT FileContext;
|
|
INFCONTEXT DirContext;
|
|
PCWSTR SourceRootDirId;
|
|
PCWSTR SourceRootDir;
|
|
PCWSTR SourceRelativePath;
|
|
PCWSTR TargetDirId;
|
|
PCWSTR TargetDir;
|
|
PCWSTR TargetFileName;
|
|
|
|
/* Either InfContext or SourceFileName must be specified */
|
|
if (!InfContext && !SourceFileName)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* InfContext to a file was not given, retrieve one corresponding to SourceFileName */
|
|
if (!InfContext)
|
|
{
|
|
/* Search for the SourceDisksFiles section */
|
|
|
|
/* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
|
|
Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles." INF_ARCH, SourceFileName, &FileContext);
|
|
if (!Success)
|
|
{
|
|
/* Search in the global section */
|
|
Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles", SourceFileName, &FileContext);
|
|
}
|
|
if (!Success)
|
|
{
|
|
// pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
|
|
// if (pSetupData->ErrorRoutine)
|
|
// pSetupData->ErrorRoutine(pSetupData, SectionName);
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
InfContext = &FileContext;
|
|
}
|
|
// else, InfContext != NULL and ignore SourceFileName (that may or may not be == NULL).
|
|
|
|
/*
|
|
* Getting Source File Location -- SetupGetSourceFileLocation()
|
|
*/
|
|
|
|
/* Get source root directory id */
|
|
if (!INF_GetDataField(InfContext, 1, &SourceRootDirId))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("INF_GetData() failed\n");
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
/* Lookup source root directory -- SetupGetSourceInfo() */
|
|
/* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
|
|
Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames." INF_ARCH, SourceRootDirId, &DirContext);
|
|
if (!Success)
|
|
{
|
|
/* Search in the global section */
|
|
Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames", SourceRootDirId, &DirContext);
|
|
if (!Success)
|
|
DPRINT1("SpInfFindFirstLine(\"SourceDisksNames\", \"%S\") failed\n", SourceRootDirId);
|
|
}
|
|
INF_FreeData(SourceRootDirId);
|
|
if (!Success)
|
|
{
|
|
/* FIXME: Handle error! */
|
|
// pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
|
|
// if (pSetupData->ErrorRoutine)
|
|
// pSetupData->ErrorRoutine(pSetupData, SectionName);
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
if (!INF_GetDataField(&DirContext, 4, &SourceRootDir))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("INF_GetData() failed\n");
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
/* Get optional source relative directory */
|
|
if (!INF_GetDataField(InfContext, 2, &SourceRelativePath))
|
|
{
|
|
SourceRelativePath = NULL;
|
|
}
|
|
else if (!*SourceRelativePath)
|
|
{
|
|
INF_FreeData(SourceRelativePath);
|
|
SourceRelativePath = NULL;
|
|
}
|
|
if (!SourceRelativePath)
|
|
{
|
|
/* Use WinPE directory instead */
|
|
if (INF_GetDataField(InfContext, 13, &TargetDirId))
|
|
{
|
|
/* Lookup directory */
|
|
Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &SourceRelativePath);
|
|
INF_FreeData(TargetDirId);
|
|
if (!Success)
|
|
{
|
|
SourceRelativePath = NULL;
|
|
}
|
|
else if (!*SourceRelativePath)
|
|
{
|
|
INF_FreeData(SourceRelativePath);
|
|
SourceRelativePath = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Getting Target File Location -- SetupGetTargetPath()
|
|
*/
|
|
|
|
/* Get target directory id */
|
|
if (!INF_GetDataField(InfContext, 8, &TargetDirId))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("INF_GetData() failed\n");
|
|
INF_FreeData(SourceRelativePath);
|
|
INF_FreeData(SourceRootDir);
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
/* Lookup target directory */
|
|
Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &TargetDir);
|
|
INF_FreeData(TargetDirId);
|
|
if (!Success)
|
|
{
|
|
/* FIXME: Handle error! */
|
|
INF_FreeData(SourceRelativePath);
|
|
INF_FreeData(SourceRootDir);
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
/* Get optional target file name */
|
|
if (!INF_GetDataField(InfContext, 11, &TargetFileName))
|
|
TargetFileName = NULL;
|
|
else if (!*TargetFileName)
|
|
TargetFileName = NULL;
|
|
|
|
DPRINT("GetSourceFileAndTargetLocation(%S) = "
|
|
"SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n",
|
|
SourceFileName, SourceRootDir, SourceRelativePath, TargetDir, TargetFileName);
|
|
|
|
#if 0
|
|
INF_FreeData(TargetDir);
|
|
INF_FreeData(TargetFileName);
|
|
INF_FreeData(SourceRelativePath);
|
|
INF_FreeData(SourceRootDir);
|
|
#endif
|
|
|
|
*pSourceRootPath = SourceRootDir;
|
|
*pSourcePath = SourceRelativePath;
|
|
*pTargetDirectory = TargetDir;
|
|
*pTargetFileName = TargetFileName;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS
|
|
BuildFullDirectoryPath(
|
|
IN PCWSTR RootPath,
|
|
IN PCWSTR BasePath,
|
|
IN PCWSTR RelativePath,
|
|
OUT PWSTR FullPath,
|
|
IN SIZE_T cchFullPathSize)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if ((RelativePath[0] == UNICODE_NULL) || (RelativePath[0] == L'\\' && RelativePath[1] == UNICODE_NULL))
|
|
{
|
|
/* Installation path */
|
|
DPRINT("InstallationPath: '%S'\n", RelativePath);
|
|
|
|
Status = CombinePaths(FullPath, cchFullPathSize, 2,
|
|
RootPath, BasePath);
|
|
|
|
DPRINT("InstallationPath(2): '%S'\n", FullPath);
|
|
}
|
|
else if (RelativePath[0] == L'\\')
|
|
{
|
|
/* Absolute path */
|
|
DPRINT("AbsolutePath: '%S'\n", RelativePath);
|
|
|
|
Status = CombinePaths(FullPath, cchFullPathSize, 2,
|
|
RootPath, RelativePath);
|
|
|
|
DPRINT("AbsolutePath(2): '%S'\n", FullPath);
|
|
}
|
|
else // if (RelativePath[0] != L'\\')
|
|
{
|
|
/* Path relative to the installation path */
|
|
DPRINT("RelativePath: '%S'\n", RelativePath);
|
|
|
|
Status = CombinePaths(FullPath, cchFullPathSize, 3,
|
|
RootPath, BasePath, RelativePath);
|
|
|
|
DPRINT("RelativePath(2): '%S'\n", FullPath);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
* This code enumerates the list of files in reactos.dff / reactos.inf
|
|
* that need to be extracted from reactos.cab and be installed in their
|
|
* respective directories.
|
|
*/
|
|
/*
|
|
* IMPORTANT NOTE: The INF file specification used for the .CAB in ReactOS
|
|
* is not compliant with respect to TXTSETUP.SIF syntax or the standard syntax.
|
|
*/
|
|
static BOOLEAN
|
|
AddSectionToCopyQueueCab(
|
|
IN PUSETUP_DATA pSetupData,
|
|
IN HINF InfFile,
|
|
IN PCWSTR SectionName,
|
|
IN PCWSTR SourceCabinet,
|
|
IN PCUNICODE_STRING DestinationPath)
|
|
{
|
|
BOOLEAN Success;
|
|
NTSTATUS Status;
|
|
INFCONTEXT FilesContext;
|
|
INFCONTEXT DirContext;
|
|
PCWSTR SourceFileName;
|
|
PCWSTR TargetDirId;
|
|
PCWSTR TargetDir;
|
|
PCWSTR TargetFileName;
|
|
WCHAR FileDstPath[MAX_PATH];
|
|
|
|
/* Search for the SectionName section */
|
|
if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
|
|
{
|
|
DPRINT1("AddSectionToCopyQueueCab(): Unable to find section '%S' in cabinet file\n", SectionName);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Enumerate the files in the section and add them to the file queue.
|
|
*/
|
|
do
|
|
{
|
|
/* Get source file name and target directory id */
|
|
if (!INF_GetData(&FilesContext, &SourceFileName, &TargetDirId))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("INF_GetData() failed\n");
|
|
break;
|
|
}
|
|
|
|
/* Get optional target file name */
|
|
if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
|
|
{
|
|
TargetFileName = NULL;
|
|
}
|
|
else if (!*TargetFileName)
|
|
{
|
|
INF_FreeData(TargetFileName);
|
|
TargetFileName = NULL;
|
|
}
|
|
|
|
/* Lookup target directory */
|
|
Success = LookupDirectoryById(InfFile, &DirContext, TargetDirId, &TargetDir);
|
|
INF_FreeData(TargetDirId);
|
|
if (!Success)
|
|
{
|
|
/* FIXME: Handle error! */
|
|
INF_FreeData(TargetFileName);
|
|
INF_FreeData(SourceFileName);
|
|
break;
|
|
}
|
|
|
|
DPRINT("GetSourceTargetFromCab(%S) = "
|
|
"SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n",
|
|
SourceFileName,
|
|
pSetupData->SourcePath.Buffer,
|
|
pSetupData->SourceRootDir.Buffer,
|
|
TargetDir, TargetFileName);
|
|
|
|
Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
|
|
pSetupData->DestinationPath.Buffer,
|
|
TargetDir);
|
|
UNREFERENCED_PARAMETER(Status);
|
|
DPRINT(" --> FileDstPath = '%S'\n", FileDstPath);
|
|
|
|
INF_FreeData(TargetDir);
|
|
|
|
if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue,
|
|
pSetupData->SourcePath.Buffer, // SourcePath == SourceRootPath ++ SourceRootDir
|
|
NULL,
|
|
SourceFileName,
|
|
NULL,
|
|
SourceCabinet,
|
|
NULL,
|
|
FileDstPath,
|
|
TargetFileName,
|
|
0 /* FIXME */))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("SpFileQueueCopy() failed\n");
|
|
}
|
|
|
|
INF_FreeData(TargetFileName);
|
|
INF_FreeData(SourceFileName);
|
|
|
|
} while (SpInfFindNextLine(&FilesContext, &FilesContext));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Note: Modeled after the SetupQueueCopySection() API
|
|
/*
|
|
BOOL SetupQueueCopySection(
|
|
_In_ HSPFILEQ QueueHandle,
|
|
_In_ PCTSTR SourceRootPath,
|
|
_In_ HINF InfHandle,
|
|
_In_ HINF ListInfHandle,
|
|
_In_ PCTSTR Section,
|
|
_In_ DWORD CopyStyle
|
|
);
|
|
*/
|
|
static BOOLEAN
|
|
AddSectionToCopyQueue(
|
|
IN PUSETUP_DATA pSetupData,
|
|
IN HINF InfFile,
|
|
IN PCWSTR SectionName,
|
|
IN PCUNICODE_STRING DestinationPath)
|
|
{
|
|
NTSTATUS Status;
|
|
INFCONTEXT FilesContext;
|
|
PCWSTR SourceFileName;
|
|
PCWSTR SourceRootPath;
|
|
PCWSTR SourcePath;
|
|
PCWSTR TargetDirectory;
|
|
PCWSTR TargetFileName;
|
|
WCHAR FileSrcRootPath[MAX_PATH];
|
|
WCHAR FileDstPath[MAX_PATH];
|
|
|
|
/*
|
|
* This code enumerates the list of files in txtsetup.sif
|
|
* that need to be installed in their respective directories.
|
|
*/
|
|
|
|
/* Search for the SectionName section */
|
|
if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
|
|
{
|
|
DPRINT1("AddSectionToCopyQueue(): Unable to find section '%S' in TXTSETUP.SIF\n", SectionName);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Enumerate the files in the section and add them to the file queue.
|
|
*/
|
|
do
|
|
{
|
|
/* Get source file name */
|
|
if (!INF_GetDataField(&FilesContext, 0, &SourceFileName))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("INF_GetData() failed\n");
|
|
break;
|
|
}
|
|
|
|
Status = GetSourceFileAndTargetLocation(InfFile,
|
|
&FilesContext,
|
|
SourceFileName,
|
|
&SourceRootPath, // SourceRootDir
|
|
&SourcePath,
|
|
&TargetDirectory,
|
|
&TargetFileName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Could not find source and target location for file '%S'\n", SourceFileName);
|
|
INF_FreeData(SourceFileName);
|
|
|
|
// FIXME: Another error?
|
|
pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, SectionName);
|
|
return FALSE;
|
|
// break;
|
|
}
|
|
/*
|
|
* SourcePath: '\Device\CdRom0\I386'
|
|
* SourceRootPath: '\Device\CdRom0'
|
|
* SourceRootDir: '\I386'
|
|
*/
|
|
|
|
Status = CombinePaths(FileSrcRootPath, ARRAYSIZE(FileSrcRootPath), 2,
|
|
pSetupData->SourceRootPath.Buffer,
|
|
SourceRootPath);
|
|
UNREFERENCED_PARAMETER(Status);
|
|
// DPRINT1("Could not build the full path for '%S', skipping...\n", SourceRootPath);
|
|
DPRINT(" --> FileSrcRootPath = '%S'\n", FileSrcRootPath);
|
|
|
|
INF_FreeData(SourceRootPath);
|
|
|
|
Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
|
|
pSetupData->DestinationPath.Buffer,
|
|
TargetDirectory);
|
|
UNREFERENCED_PARAMETER(Status);
|
|
// DPRINT1("Could not build the full path for '%S', skipping...\n", TargetDirectory);
|
|
DPRINT(" --> FileDstPath = '%S'\n", FileDstPath);
|
|
|
|
INF_FreeData(TargetDirectory);
|
|
|
|
if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue,
|
|
FileSrcRootPath,
|
|
SourcePath,
|
|
SourceFileName,
|
|
NULL,
|
|
NULL, // No SourceCabinet
|
|
NULL,
|
|
FileDstPath,
|
|
TargetFileName,
|
|
0 /* FIXME */))
|
|
{
|
|
/* FIXME: Handle error! */
|
|
DPRINT1("SpFileQueueCopy() failed\n");
|
|
}
|
|
|
|
INF_FreeData(TargetFileName);
|
|
INF_FreeData(SourcePath);
|
|
INF_FreeData(SourceFileName);
|
|
|
|
} while (SpInfFindNextLine(&FilesContext, &FilesContext));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN // ERROR_NUMBER
|
|
PrepareCopyInfFile(
|
|
IN OUT PUSETUP_DATA pSetupData,
|
|
IN HINF InfFile,
|
|
IN PCWSTR SourceCabinet OPTIONAL)
|
|
{
|
|
BOOLEAN Success;
|
|
NTSTATUS Status;
|
|
INFCONTEXT DirContext;
|
|
PWCHAR AdditionalSectionName = NULL;
|
|
PCWSTR DirKeyValue;
|
|
WCHAR PathBuffer[MAX_PATH];
|
|
|
|
if (SourceCabinet == NULL)
|
|
{
|
|
/* Add common files -- Search for the SourceDisksFiles section */
|
|
/* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
|
|
Success = AddSectionToCopyQueue(pSetupData, InfFile,
|
|
L"SourceDisksFiles." INF_ARCH,
|
|
&pSetupData->DestinationPath);
|
|
if (!Success)
|
|
{
|
|
DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles." INF_ARCH);
|
|
}
|
|
/* Search in the global section */
|
|
Success = AddSectionToCopyQueue(pSetupData, InfFile,
|
|
L"SourceDisksFiles",
|
|
&pSetupData->DestinationPath);
|
|
if (!Success)
|
|
{
|
|
DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles");
|
|
pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, L"SourceDisksFiles");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Add specific files depending of computer type */
|
|
if (!ProcessComputerFiles(InfFile, pSetupData->ComputerList, &AdditionalSectionName))
|
|
return FALSE;
|
|
|
|
if (AdditionalSectionName &&
|
|
!AddSectionToCopyQueue(pSetupData, InfFile,
|
|
AdditionalSectionName,
|
|
&pSetupData->DestinationPath))
|
|
{
|
|
pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, AdditionalSectionName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Process a cabinet INF */
|
|
Success = AddSectionToCopyQueueCab(pSetupData, InfFile,
|
|
L"SourceFiles",
|
|
SourceCabinet,
|
|
&pSetupData->DestinationPath);
|
|
if (!Success)
|
|
{
|
|
DPRINT1("AddSectionToCopyQueueCab(%S) failed!\n", SourceCabinet);
|
|
pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, L"SourceFiles");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Create directories */
|
|
|
|
/*
|
|
* NOTE: This is technically optional since SpFileQueueCommit()
|
|
* does that. This is however needed if one wants to create
|
|
* empty directories.
|
|
*/
|
|
|
|
/*
|
|
* FIXME:
|
|
* Copying files to pSetupData->DestinationRootPath should be done from within
|
|
* the SystemPartitionFiles section.
|
|
* At the moment we check whether we specify paths like '\foo' or '\\' for that.
|
|
* For installing to pSetupData->DestinationPath specify just '\' .
|
|
*/
|
|
|
|
/* Get destination path */
|
|
RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
|
|
pSetupData->DestinationPath.Buffer);
|
|
|
|
DPRINT("FullPath(1): '%S'\n", PathBuffer);
|
|
|
|
/* Create the install directory */
|
|
Status = SetupCreateDirectory(PathBuffer);
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
|
|
{
|
|
DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
|
|
pSetupData->LastErrorNumber = ERROR_CREATE_INSTALL_DIR;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, PathBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Search for the 'Directories' section */
|
|
// ReactOS-specific
|
|
if (!SpInfFindFirstLine(InfFile, L"Directories", NULL, &DirContext))
|
|
{
|
|
// Windows-compatible
|
|
if (!SpInfFindFirstLine(InfFile, L"WinntDirectories", NULL, &DirContext))
|
|
{
|
|
if (SourceCabinet)
|
|
pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
|
|
else
|
|
pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
|
|
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, L"Directories");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Enumerate the directory values and create the subdirectories */
|
|
do
|
|
{
|
|
if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
|
|
{
|
|
DPRINT1("break\n");
|
|
break;
|
|
}
|
|
|
|
Status = BuildFullDirectoryPath(pSetupData->DestinationRootPath.Buffer,
|
|
pSetupData->InstallPath.Buffer,
|
|
DirKeyValue,
|
|
PathBuffer,
|
|
ARRAYSIZE(PathBuffer));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Could not build the full path for '%S', skipping...\n", DirKeyValue);
|
|
INF_FreeData(DirKeyValue);
|
|
continue;
|
|
}
|
|
|
|
if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
|
|
{
|
|
/*
|
|
* Installation path -- No need to create it
|
|
* because it has been already created above.
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
/* Arbitrary path -- Create it */
|
|
Status = SetupCreateDirectory(PathBuffer);
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
|
|
{
|
|
INF_FreeData(DirKeyValue);
|
|
DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
|
|
pSetupData->LastErrorNumber = ERROR_CREATE_DIR;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, PathBuffer);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
INF_FreeData(DirKeyValue);
|
|
} while (SpInfFindNextLine(&DirContext, &DirContext));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// #define USE_CABINET_INF
|
|
|
|
BOOLEAN // ERROR_NUMBER
|
|
PrepareFileCopy(
|
|
IN OUT PUSETUP_DATA pSetupData,
|
|
IN PFILE_COPY_STATUS_ROUTINE StatusRoutine OPTIONAL)
|
|
{
|
|
HINF InfHandle;
|
|
INFCONTEXT CabinetsContext;
|
|
PCWSTR CabinetName;
|
|
UINT ErrorLine;
|
|
#if defined(__REACTOS__) && defined(USE_CABINET_INF)
|
|
ULONG InfFileSize;
|
|
PVOID InfFileData;
|
|
CABINET_CONTEXT CabinetContext;
|
|
#endif
|
|
WCHAR PathBuffer[MAX_PATH];
|
|
|
|
/* Create the file queue */
|
|
pSetupData->SetupFileQueue = (PVOID)SpFileQueueOpen();
|
|
if (pSetupData->SetupFileQueue == NULL)
|
|
{
|
|
pSetupData->LastErrorNumber = ERROR_COPY_QUEUE;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Prepare the copy of the common files that are not in installation cabinets */
|
|
if (!PrepareCopyInfFile(pSetupData, pSetupData->SetupInf, NULL))
|
|
{
|
|
/* FIXME: show an error dialog */
|
|
return FALSE;
|
|
}
|
|
|
|
/* Search for the 'Cabinets' section */
|
|
if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Cabinets", NULL, &CabinetsContext))
|
|
{
|
|
/* Skip this step and return success if no cabinet file is listed */
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Enumerate the installation cabinets listed in the
|
|
* 'Cabinets' section and parse their inf files.
|
|
*/
|
|
do
|
|
{
|
|
if (!INF_GetData(&CabinetsContext, NULL, &CabinetName))
|
|
break;
|
|
|
|
CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
|
|
pSetupData->SourcePath.Buffer, CabinetName);
|
|
|
|
#if defined(__REACTOS__) && defined(USE_CABINET_INF)
|
|
INF_FreeData(CabinetName);
|
|
|
|
CabinetInitialize(&CabinetContext);
|
|
CabinetSetEventHandlers(&CabinetContext, NULL, NULL, NULL);
|
|
CabinetSetCabinetName(&CabinetContext, PathBuffer);
|
|
|
|
if (CabinetOpen(&CabinetContext) == CAB_STATUS_SUCCESS)
|
|
{
|
|
DPRINT("Cabinet %S\n", PathBuffer);
|
|
|
|
InfFileData = CabinetGetCabinetReservedArea(&CabinetContext, &InfFileSize);
|
|
if (InfFileData == NULL)
|
|
{
|
|
CabinetCleanup(&CabinetContext);
|
|
|
|
pSetupData->LastErrorNumber = ERROR_CABINET_SCRIPT;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, PathBuffer);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Cannot open cabinet: %S.\n", PathBuffer);
|
|
CabinetCleanup(&CabinetContext);
|
|
|
|
pSetupData->LastErrorNumber = ERROR_CABINET_MISSING;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, PathBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
|
|
InfFileSize,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
pSetupData->LanguageId,
|
|
&ErrorLine);
|
|
|
|
CabinetCleanup(&CabinetContext);
|
|
#else
|
|
{
|
|
PWCHAR ptr;
|
|
|
|
/* First find the filename */
|
|
ptr = wcsrchr(PathBuffer, L'\\');
|
|
if (!ptr) ptr = PathBuffer;
|
|
|
|
/* Then find its extension */
|
|
ptr = wcsrchr(ptr, L'.');
|
|
if (!ptr)
|
|
ptr = PathBuffer + wcslen(PathBuffer);
|
|
|
|
/* Replace it by '.inf' */
|
|
wcscpy(ptr, L".inf");
|
|
|
|
InfHandle = SpInfOpenInfFile(PathBuffer,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
pSetupData->LanguageId,
|
|
&ErrorLine);
|
|
}
|
|
#endif
|
|
|
|
if (InfHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
pSetupData->LastErrorNumber = ERROR_INVALID_CABINET_INF;
|
|
if (pSetupData->ErrorRoutine)
|
|
pSetupData->ErrorRoutine(pSetupData, PathBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!PrepareCopyInfFile(pSetupData, InfHandle, CabinetName))
|
|
{
|
|
#if !(defined(__REACTOS__) && defined(USE_CABINET_INF))
|
|
SpInfCloseInfFile(InfHandle);
|
|
#endif
|
|
/* FIXME: show an error dialog */
|
|
return FALSE;
|
|
}
|
|
|
|
#if !(defined(__REACTOS__) && defined(USE_CABINET_INF))
|
|
SpInfCloseInfFile(InfHandle);
|
|
#endif
|
|
} while (SpInfFindNextLine(&CabinetsContext, &CabinetsContext));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
DoFileCopy(
|
|
IN OUT PUSETUP_DATA pSetupData,
|
|
IN PSP_FILE_CALLBACK_W MsgHandler,
|
|
IN PVOID Context OPTIONAL)
|
|
{
|
|
BOOLEAN Success;
|
|
|
|
Success = SpFileQueueCommit(NULL,
|
|
(HSPFILEQ)pSetupData->SetupFileQueue,
|
|
MsgHandler,
|
|
Context);
|
|
|
|
SpFileQueueClose((HSPFILEQ)pSetupData->SetupFileQueue);
|
|
pSetupData->SetupFileQueue = NULL;
|
|
|
|
return Success;
|
|
}
|
|
|
|
/* EOF */
|