diff -r 000000000000 -r ba25891c3a9e secureswitools/swisistools/source/interpretsislib/installer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/secureswitools/swisistools/source/interpretsislib/installer.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,1559 @@ +/* +* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#pragma warning (disable: 4786) + +#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + +#include "dbhelper.h" + +#endif //SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK +#include +#include +#include +#include +#include +#include +#include + +// SisX Library +#include "sisdependency.h" +#include "sisversionrange.h" +#include "sisversion.h" +#include "sisprerequisites.h" +#include "sisfiledescription.h" +#include "sisstring.h" +#include "sishash.h" + +// User includes +#include "stringutils.h" +#include "parameterlist.h" +#include "rommanager.h" +#include "configmanager.h" +#include "errors.h" +#include "is_utils.h" +#include "installer.h" +#include "sisregistryobject.h" +#include "adornedutilities.h" + +// Constants +const char KRomDriveLetter = 'z'; +const TUint32 KSwiDaemonUid = 0x10202DCE; +const std::wstring KSysBinPath = L"\\sys\\bin\\"; + +TInt CheckWildCard(TInt aVal, TInt aReplace) +{ + return + aVal == -1 + ? aReplace + : aVal; +} + +bool InRange(const Version& aVersion, const CSISVersionRange& aRange) +{ + Version from( + CheckWildCard(aRange.FromVersion().Major(), aVersion.GetMajor()), + CheckWildCard(aRange.FromVersion().Minor(), aVersion.GetMinor()), + CheckWildCard(aRange.FromVersion().Build(), aVersion.GetBuild())); + + if(!aRange.ToVersion().WasteOfSpace()) + { + Version to( + CheckWildCard(aRange.ToVersion().Major(), aVersion.GetMajor()), + CheckWildCard(aRange.ToVersion().Minor(), aVersion.GetMinor()), + CheckWildCard(aRange.ToVersion().Build(), aVersion.GetBuild())); + + if (aVersion == from || + aVersion == to) + { + return true; + } + + return (aVersion > from && aVersion < to); + } + else + { + return (aVersion >= from); + } +} + + +Installer::Installer( SisRegistry& aReg, const CParameterList& aParamList, RomManager& aRomManager, ConfigManager& aConfigManager ) +: iParamList(aParamList), iRegistry(aReg), iRomManager( aRomManager ), iConfigManager( aConfigManager ), + iExpressionEnvironment( NULL ), iExpressionEvaluator( NULL ) +{ +} + +TInt Installer::Install(const CParameterList::SISFileList& aList) +{ + TInt result = 0; + CParameterList::SISFileList sisFiles; + + // Get the SIS files + for (CParameterList::SISFileList::const_iterator curr = aList.begin(); curr != aList.end(); ++curr) + { + std::wstring shortName(curr->iFileName); + + // Ensure formatting is correct + if ( StringUtils::IsLastCharacter( shortName, KDirectorySeparator[ 0 ] ) || + StringUtils::IsLastCharacter( shortName, L'/' ) ) + { + shortName.erase(shortName.length()-1,1); + } + + if ( IsDirectory(shortName) ) + { + std::list contents; + GetDirContents(shortName, contents); + + for (std::list::iterator currStr = contents.begin(); currStr != contents.end(); ++currStr) + { + if ((currStr->find(L".SIS",0) != std::wstring::npos) + || (currStr->find(L".sis",0) != std::wstring::npos)) + { + InstallSISFile sisFileName(shortName + KDirectorySeparator + *currStr, + curr->iTargetDrive, curr->iGenerateStub, + curr->iNonRemovable, curr->iNotRegister, curr->iSUFlag); + + sisFiles.push_back(sisFileName); + } + } + + if (sisFiles.empty()) + { + LWARN(L"No .SIS files found in directory" << shortName); + } + } + else if ((shortName.find(L".SIS",0) != std::wstring::npos) + || (shortName.find(L".sis",0) != std::wstring::npos)) + { + InstallSISFile sisFileName(shortName, curr->iTargetDrive, curr->iGenerateStub, + curr->iNonRemovable, curr->iNotRegister, curr->iSUFlag); + + sisFiles.push_back(sisFileName); + } + else + { + LWARN(L"Invalid SIS file: " << shortName); + } + } + + bool installed = false; + + do + { + installed = false; + iMissing.clear(); + CParameterList::SISFileList::iterator curr = sisFiles.begin(); + + while (curr != sisFiles.end()) + { + // install it + try + { + LINFO(L"*** Installing " << (curr->iFileName) << L" ***"); + + SanitiseSISFileAttributes(*curr); + + result = Install(*curr); + + if ( result == SUCCESS) + { + LINFO(L""); + LINFO(L"*** Installed " << (curr->iFileName) << L" ***"); + + installed = true; + curr = sisFiles.erase(curr); + } + else + { + LERROR(L"Failed to install " << (curr->iFileName)); + ++curr; + } + } + catch(CSISException e) + { + // catch problems with individual sis files + LERROR(L"Unable to install " << (curr->iFileName)); + LINFO(e.widewhat()); + curr = sisFiles.erase(curr); + if (result == 0) + result = FILE_ERROR; + } + catch (InterpretSisError& e) + { + LERROR(L"Failed installing " << (curr->iFileName)); + LERROR(L"\t" << Utf8ToUcs2(e.what())); + curr = sisFiles.erase(curr); + + if (result == 0) + result = e.GetErrorCode(); + } + } + } + while (installed); + + if (result == 0 && !iMissing.empty()) + result = MISSING_DEPENDENCY; + + if(iParamList.RegistryVersionExists()) + { + // Backup.lst regenerated at SisRegistry startup + iRegistry.RemoveBackupLst(); + } + return result; + +} + + +void Installer::SanitiseSISFileAttributes(const InstallSISFile& aInstallSISFile) +{ + SisFile file(aInstallSISFile.iFileName); + + int targetDrive = aInstallSISFile.iTargetDrive; + + if (!iConfigManager.IsTargetDrivePresent(targetDrive)) + { + std::wstring shortName(aInstallSISFile.iFileName); + + throw InterpretSisError(L"The installing target drive for " + shortName + + L" is not defined", CMDLINE_ERROR); + } + + if (aInstallSISFile.iGenerateStub && !iConfigManager.IsTargetDriveExt(targetDrive)) + { + std::wstring shortName(aInstallSISFile.iFileName); + + throw InterpretSisError(L"The stub SIS file for " + shortName + + L" cannot be created to an internal drive", CMDLINE_ERROR); + } + + if (aInstallSISFile.iGenerateStub && file.GetInstallType() == CSISInfo::EInstPartialUpgrade) + { + std::wstring shortName(aInstallSISFile.iFileName); + + throw InterpretSisError(L"Generating stub SIS file for " + shortName + + L" (PU type) is not supported", SIS_NOT_SUPPORTED); + } +} + + +TInt Installer::Install(const InstallSISFile& aInstallSISFile) +{ + SisFile file(aInstallSISFile.iFileName); + + // Setup the expression evaluator + SetupExpressionEnvironment( file, GetSisRegistry(), iRomManager ); + + // check presence of embedded sis files and + // display a warning if they are not installed before + if (file.HasEmbedded()) + { + CheckEmbedded(file); + } + + // check file is acceptable + file.CheckValid(); + + if (!DependenciesOk(file)) + { + return MISSING_DEPENDENCY; + } + + if (!IsValidUpgrade(file, aInstallSISFile.iSUFlag)) + { + return INVALID_UPGRADE; + } + + InstallableFiles installable; + GetInstallableFiles(file, installable, *iExpressionEvaluator, aInstallSISFile.iTargetDrive); + + // Uninstall the same package (if found) prior to any installation + UninstallPkg(file); + + CheckDestinations(file, installable, aInstallSISFile); + + InstallFiles(installable, iParamList.SystemDriveLetter()); + + UpdateRegistry(file, installable, aInstallSISFile, aInstallSISFile.iSUFlag); + + if (aInstallSISFile.iGenerateStub) + { + CreateStubSisFile(aInstallSISFile, file); + } + + FreeInstallableFiles(installable); + + return SUCCESS; +} + +/** + Prepares a list of ROM files which are allowed to be eclipsed from the right + source according to the SIS file upgrade type. + + If a SIS file wants to eclipse a file in ROM, it will fail unless there is an + associated stub SIS file present in the ROM that can be used by the Installer to + identify the replacement file as a valid upgrade of the original. + */ +void Installer::PrepareEclipsableFilesList(const SisFile& aSis) +{ + iEclipsableRomFiles.clear(); + iEclipsableOverwriteFiles.clear(); + + TUint32 pkgUid = aSis.GetPackageUid(); + + // upgrade SIS file attributes + bool puInstallation = aSis.GetInstallType() == CSISInfo::EInstPartialUpgrade; + bool spInstallation = aSis.GetInstallType() == CSISInfo::EInstAugmentation; + + // base package + const SisRegistryObject& registryEntry = iRegistry.GetRegistryObject(pkgUid); + bool currentPkgIsInRom = registryEntry.GetInRom(); + bool stubExistsInRom = iRegistry.IsRomStubPackage(pkgUid); + + // SA+RU, PU and SP are all allowed to eclipse ROM files. There must + // exist a valid ROM stub in order to populate the eclipsable files list. + if (IsValidEclipsingUpgrade(aSis, registryEntry)) + { + // when an upgrade happens over an upgrade which has already upgraded the + // ROM based pacakge (i.e. ROM Stub -> SA+RU -> PU), don't populate the + // eclipsable files from the SIS registry entry which may be in-complete. + // Directly populate the eclipsable files list from the corresponding stub + // SIS file. + if (!currentPkgIsInRom && stubExistsInRom && (puInstallation || spInstallation)) + { + iRegistry.GetStubFileEntries(pkgUid, iEclipsableRomFiles); + } + else + { + const FileDescriptions& files = registryEntry.GetFileDescriptions(); + FileDescriptions::const_iterator curr = files.begin(); + FileDescriptions::const_iterator end = files.end(); + + for ( ; curr != end ; ++curr) + { + std::wstring target((*curr)->GetTarget()); + iEclipsableRomFiles.push_back(target); + } + } + } +} + +/** + Non-SU packages can Eclipse iff: + a) The package uids match and + b) The package to be installed is immediate Upgrade to ROM (SP or PU over ROM) + (SA is allowed based on next condition) + c) (or) The package to be installed is (SA+RU type or PU or SP type) and it has a matching ROM stub SIS file + are allowed to eclipse files. + */ +bool Installer::IsValidEclipsingUpgrade(const SisFile& aSis, const SisRegistryObject& registryEntry) +{ + TUint32 pkgUid = aSis.GetPackageUid(); + + // case a) + if (pkgUid != registryEntry.GetUid()) + return false; + + bool stubExistsInRom = iRegistry.IsRomStubPackage(pkgUid); + bool isBaseInRom = registryEntry.GetInRom(); + bool saInstall = aSis.GetInstallType() == CSISInfo::EInstInstallation; + bool reg51 = true; + if(iParamList.RegistryVersionExists()) + { + int regMajor = iParamList.RegistryMajorVersion(); + int regMinor = iParamList.RegistryMinorVersion(); + bool reg51 = (regMajor >= SisRegistry::KSisRegistryMajorVersion) && + (regMinor >= SisRegistry::KSisRegistryMinorVersion); + } + // RU flag was introduce when the SISRegistry was 5.1, otherwise, treat it as normal SA file + bool romUpgradeFlag = (aSis.GetInstallFlags() & CSISInfo::EInstFlagROMUpgrade) && reg51; + bool romUpgradableSA = saInstall && romUpgradeFlag; + bool puInstall = aSis.GetInstallType() == CSISInfo::EInstPartialUpgrade; + bool spInstall = aSis.GetInstallType() == CSISInfo::EInstAugmentation; + + // case b) + if (isBaseInRom && !saInstall) + return true; + + // case c) + return (stubExistsInRom && (romUpgradableSA || puInstall || spInstall)); +} + +void Installer::UninstallPkg(const SisFile& aSis) +{ + TUint32 uid = aSis.GetPackageUid(); + TUint32 installType = aSis.GetInstallType(); + + // Check to see the SA is installed, otherwise, RemovePkg() will throw an exception + if (iRegistry.IsInstalled(uid) && (installType == CSISInfo::EInstInstallation)) + { + LINFO(L"Removing package \"" << aSis.GetPackageName() << L"\" prior to re-installation"); + + // Remove all installed files for this Uid's packages and all the SisRegistry Entries + iRegistry.RemovePkg(uid, true); + } + + if (installType == CSISInfo::EInstAugmentation) + { + // Clean up the installed files from the specified SP package and the SisRegistry Entry + iRegistry.RemoveEntry(uid, aSis.GetPackageName(), aSis.GetVendorName()); + } + + // Regenerate the ROM stub registry entries for eclipsing check later. + iRegistry.GenerateStubRegistry(); +} + + +struct CheckDependencyMet +{ + CheckDependencyMet( + Installer& aInstaller, + std::vector& aMissing) + : iInstaller(aInstaller), + iMissingDependencies(aMissing) + {} + + void operator()(const CSISDependency* dep) + { + if (!iInstaller.CheckDependency(dep)) + { + iMissingDependencies.push_back(SisRegistryDependency(*dep)); + } + } + Installer& iInstaller; + std::vector& iMissingDependencies; +}; + +bool Installer::CheckDependency(const CSISDependency* aDep) +{ + bool result = false; + + try + { + const SisRegistryObject& pkg = + iRegistry.GetRegistryObject(aDep->SisUID().UID1()); + + const CSISVersionRange& range = aDep->VersionRange(); + if (!range.WasteOfSpace() && InRange(pkg.GetVersion(), range)) + { + result = true; + } + else + { + result = false; + } + } + + catch(...) + { + result = false; + } + return result ; +} + +bool Installer::DependenciesOk(const SisFile& aFile) + { + const CSISPrerequisites* reqs = aFile.GetDependencies(); + const CSISPrerequisites::TDependencyList& deps = reqs->DependencyList(); + + CheckDependencyMet checkDependencyMet(*this, iMissing[aFile.GetPackageName()]); + for(int i = 0; i < deps.size(); ++i) + { + checkDependencyMet(&deps[i]); + } + + return iMissing[aFile.GetPackageName()].size() == 0; + } + + +bool Installer::IsValidUpgrade(const SisFile& aFile, bool aSUFlag) +{ + TUint32 pkg = aFile.GetPackageUid(); + TUint32 installFlags = aFile.GetInstallFlags(); + bool RUFlag = ((installFlags & CSISInfo::EInstFlagROMUpgrade) && CSISInfo::EInstFlagROMUpgrade); + + if(iParamList.RegistryVersionExists()) + { + int regMajor = iParamList.RegistryMajorVersion(); + int regMinor = iParamList.RegistryMinorVersion(); + bool reg51 = (regMajor >= SisRegistry::KSisRegistryMajorVersion) && + (regMinor >= SisRegistry::KSisRegistryMinorVersion); + // RU flag was introduce when the SISRegistry was 5.1, otherwise, treat it as normal SA file + RUFlag = RUFlag && reg51; + } + if ( aSUFlag && !RUFlag) + { + std::stringstream err; + err << "Illegal system upgrade (SU) of ROM package 0x" << std::hex << pkg << " without setting the RU flag"; + throw InterpretSisError(err.str(), ATTEMPT_TO_UPGRADE_ROM_PKG); + } + + // Check is this package has been installed before + + TUint32 installType = aFile.GetInstallType(); + + if (iRegistry.IsInstalled(pkg)) + { + ValidateRegistry(aFile,pkg,installFlags,RUFlag); + } + else if (installType == CSISInfo::EInstAugmentation || installType == CSISInfo::EInstPartialUpgrade) + { + // Installing SP and PU without the base package + std::stringstream err; + err << "Could not perform upgrade - the base package 0x" << std::hex + << pkg << " is missing"; + + throw InterpretSisError(err.str(), MISSING_BASE_PACKAGE); + } + + return true; + } + +void Installer::ValidateRegistry(const SisFile& aFile, TUint32 aPckgUid, TUint32 aInstallFlags, bool aRUFlag) + { + bool isSisNonRemovable = aInstallFlags & CSISInfo::EInstFlagNonRemovable; + bool isBaseRemovable = false; + bool inRom = false; + bool isPreInstalled = false; + TUint32 uid = 0; + std::wstring packageName; + + InitializeRegistryDetails(aPckgUid, isBaseRemovable, inRom, isPreInstalled, uid, packageName ); + + // Check is this package has been installed before + TUint32 installType = aFile.GetInstallType(); + + if (installType == CSISInfo::EInstInstallation) + { + if (inRom && !aRUFlag) + { + std::stringstream err; + err << "Illegal SA upgrade to ROM package 0x" << std::hex << aPckgUid; + throw InterpretSisError(err.str(), ATTEMPT_TO_UPGRADE_ROM_PKG); + } + // This is not a ROM base package, check is there a SIS stub base package present + else if (iRegistry.IsRomStubPackage(aPckgUid) && !aRUFlag) + { + std::stringstream err; + err << "Indirect SA upgrade to ROM package 0x" << std::hex << aPckgUid + << " missing RU flag"; + throw InterpretSisError(err.str(), ATTEMPT_TO_UPGRADE_ROM_PKG); + } + } + else if (installType == CSISInfo::EInstAugmentation) + { + if (isBaseRemovable && isSisNonRemovable) + { + std::stringstream err; + err << "Not allowed to install SP + NR to the removable base package 0x" << std::hex << aPckgUid; + + throw InterpretSisError(err.str(), INVALID_UPGRADE); + } + + if (packageName == aFile.GetPackageName() && uid == aFile.GetPackageUid()) + { + std::stringstream err; + err << "Cannot augment package 0x" << std::hex << aFile.GetPackageUid() << " - package names match"; + + throw InterpretSisError(err.str(), MISSING_BASE_PACKAGE); + } + } + else if (installType == CSISInfo::EInstPartialUpgrade) + { + // Do not allow partial upgrades to preinstalled applications + if (isPreInstalled) + { + std::stringstream err; + err << "Cannot install PU (0x" << std::hex << aPckgUid << ") to a PA"; + + throw InterpretSisError(err.str(), INVALID_UPGRADE); + } + + // Partial Upgrade can only be installed to a base package of the same install flag type. + // The only exception is a ROM stub which is upgradable and non-removable by definition. + if ((isBaseRemovable == isSisNonRemovable) && !inRom ) + { + std::stringstream err; + err << "Cannot install PU (0x" << std::hex << aPckgUid << ") to a base package with a different removable flag type"; + + throw InterpretSisError(err.str(), INVALID_UPGRADE); + } + } + else if (installType == CSISInfo::EInstPreInstalledApp) + { + std::stringstream err; + err << "Cannot install PA (0x" << std::hex << aPckgUid << ") over top of another package"; + + throw InterpretSisError(err.str(), INVALID_UPGRADE); + } + } + +void Installer::InitializeRegistryDetails( const TUint32 aPckgUid, bool& aIsBaseRemovable, + bool& aInRom, bool& aIsPreInstalled, + TUint32& aUid, std::wstring& aPackageName + ) + { + if(iParamList.RegistryVersionExists() ) + { + const SisRegistryObject& obj = iRegistry.GetRegistryObject(aPckgUid); + aIsBaseRemovable = obj.GetIsRemovable(); + aInRom = obj.GetInRom(); + aIsPreInstalled = obj.IsPreInstalled(); + aUid = obj.GetUid(); + aPackageName = obj.GetPackageName(); + } + #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + else + { + const DbHelper* dbHelper( iRegistry.GetDbHelper()); + TInt32 componentId = dbHelper->GetComponentId(aPckgUid); + aIsBaseRemovable = dbHelper->GetIsRemovable(componentId); + aInRom = dbHelper->GetInRom(componentId); + if(dbHelper->GetInstallType(componentId) == CSISInfo::EInstPreInstalledApp ) + { + aIsPreInstalled = true; + } + aUid = dbHelper->GetUid(componentId); + aPackageName = dbHelper->GetPackageName(componentId); + } + #endif // SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + } + +bool Installer::GetInstallableFiles(const SisFile& aFile, InstallableFiles& aList, ExpressionEvaluator& aEvaluator, + int aInstallingDrive) +{ + return aFile.GetInstallableFiles(aList, aEvaluator, + iConfigManager.GetLocalDrivePath(aInstallingDrive), aInstallingDrive); +} + + +struct InstallFile +{ + InstallFile(const std::wstring& aCDrive, const int aSystemDrive) + : iSystemDrivePath(aCDrive), iSystemDrive(aSystemDrive) {} + + const std::wstring& iSystemDrivePath; + const int iSystemDrive; + + void operator()(const InstallableFile* aFile) + { + std::fstream output; + std::wstring target(aFile->GetTarget()); + std::wstring localTarget(aFile->GetLocalTarget()); + + bool fileNullOption = (aFile->FileDescription()->Operation() == CSISFileDescription::EOpNull); + + if (!target.length()) + { + LINFO(L"Skipping file with empty destination filename"); + } + else + { + // Unicode characters can not be displayed on DOS prompt + std::string temporary = Ucs2ToUtf8(target); + std::wstring targetDisplay = Utf8ToUcs2( temporary ); + LINFO(L"Installing file: " << targetDisplay); + + std::wstring targetDirectory = localTarget.substr( 0, localTarget.rfind( KDirectorySeparator ) ); + const unsigned char* buffer = NULL; + TUint32 len; + + if (aFile->IsStub()) // PA + { + // check the presence of file at target location + if (!FileExists(localTarget)) + { + throw InterpretSisError(L"PA Install error - No target file- "+target, PA_NO_TARGET_FILE); + } + } + else // SA + { + // if the FN option specified, leave the file creation + if (fileNullOption) + { + LINFO(L"File " << target << L" contains \"Delete-File-On-Uninstall\" option." ); + } + else + { + if ( !MakeDir( targetDirectory ) ) + { + throw InterpretSisError(L"Directory Creation Error - "+targetDirectory, + DIRECTORY_CREATION_ERROR); + } + + HANDLE hFile = MakeSISOpenFile(localTarget.c_str(), GENERIC_WRITE, CREATE_ALWAYS); + if( INVALID_HANDLE_VALUE == hFile ) + { + throw InterpretSisError(L"FileOpenError - "+target, FILE_ERROR); + } + buffer = aFile->FileData()->Data(); + len = aFile->FileData()->UncompressedSize(); + DWORD bytesWritten; + BOOL error = WriteFile(hFile, buffer, len, &bytesWritten, NULL); + if( error != TRUE ) + { + throw InterpretSisError(L"FileWriteError - "+target, FILE_ERROR); + } + CloseHandle(hFile); + } + } + + if (aFile->IsExecutable() && !fileNullOption) + { + // register the hash + std::wstring basename = localTarget.substr( localTarget.rfind( KDirectorySeparator ) + 1 ); + std::wstring hashdir = iSystemDrivePath + L"\\sys\\hash\\"; + std::wstring reghashdir = L"$:\\sys\\hash\\"; + + if ( !MakeDir( hashdir ) ) + { + throw InterpretSisError(L"Directory Creation Error - "+hashdir, + DIRECTORY_CREATION_ERROR); + } + + // hash file is always created on the system drive + reghashdir[0] = iSystemDrive; + + LINFO(L"\tCreating hash: " << reghashdir << basename); + + std::wstring hash = hashdir + basename; + HANDLE hFile = MakeSISOpenFile(hash.c_str(), GENERIC_WRITE, CREATE_ALWAYS); + if( INVALID_HANDLE_VALUE == hFile ) + { + throw InterpretSisError(L"FileOpenError - " + hashdir + basename, FILE_ERROR); + } + + buffer = aFile->FileDescription()->Hash().Blob().Data(); + len = aFile->FileDescription()->Hash().Blob().Size(); + DWORD bytesWritten; + BOOL error = WriteFile(hFile, buffer, len, &bytesWritten, NULL); + if( error != TRUE ) + { + throw InterpretSisError(L"FileWriteError - " + hashdir + basename, FILE_ERROR); + } + CloseHandle(hFile); + } + } + } +}; + + +void Installer::InstallFiles(const InstallableFiles& aList, const int aInstallDrive) +{ + std::wstring localTargetPath = iConfigManager.GetLocalDrivePath(aInstallDrive); + + std::for_each(aList.begin(), aList.end(), InstallFile(localTargetPath, aInstallDrive)); +} + + +void Installer::UpdateRegistry(const SisFile& aFile, const InstallableFiles& aList, + const InstallSISFile& aInstallSISFile, const bool aSUFlag) +{ + if (aFile.GetInstallType() == CSISInfo::EInstPartialUpgrade) + { + iRegistry.UpdateRegistryEntry(aFile, aList, aInstallSISFile); + } + else if (!aInstallSISFile.iNotRegister) + { + iRegistry.AddRegistryEntry(aFile, aList, aInstallSISFile); + } +} + +/** This function takes a fully qualified name and searches the filesystem through for all possible adorned filename matches. + Besides that it calculates the unadorned version of the input filename as well and return it through the corresponding given + input reference variable. + @param aTarget the fully qualified filename (full path and name) + @param aUnadornedName the calulated unadorned name is returned through this variable(full path and unadorned name calculated from aTarget) + @param aAdornedFileNamesFound all the found adorned name matches are returned through this list +*/ +void Installer::AdornedProcessingOfFile(const std::wstring& aTarget, std::wstring& aUnadornedName, + std::list& aAdornedFileNamesFound) +{ + std::wstring targetNameAndExt(StringUtils::NameAndExt(aTarget)); + std::wstring targetDriveAndPath(StringUtils::DriveAndPath(aTarget)); + + std::wstring unadornedName; + std::wstring searchNameWild; + + // create the unadorned version of the target file e.g. c:\sys\bin\a.dll + GetUnadornedFileName(targetNameAndExt, unadornedName); + aUnadornedName = targetDriveAndPath; + aUnadornedName.append(unadornedName); + + // create a wildcard version of the target file e.g. c:\sys\bin\a{????????}.dll + GenerateSearchNameWild(targetNameAndExt, searchNameWild); + + const DrivesMap& driveMap = iConfigManager.GetDrivesMap(); + FindAllAdornedVariants(searchNameWild, KSysBinPath, aAdornedFileNamesFound, driveMap); + + // find all adorned variants in the ROM/ROFS logs + if (iParamList.IsFlagSet(CParameterList::EFlagsRomRofsLogFilesSet)) + { + std::wstring romSearchNameWild = L"z:\\sys\\bin\\"; + romSearchNameWild.append(searchNameWild); + iRomManager.FindAllAdornedVariants(romSearchNameWild, aAdornedFileNamesFound); + } +} + +/** + This function ensures the SIS file to be installed does not illegally + eclipse a file already installed in the ROM. + @param aFile the SIS file to be installed + @param aTarget the fully qualified filename (full path and name) + @param aInstallableFile the current installing files properties + @param aSUFlag specifies if the installing SIS file has been signed by a SU certificate +*/ +bool Installer::ValidEclipse(const SisFile& aFile, const std::wstring& aTarget, const InstallableFile& aInstallableFile, bool aSUFlag) +{ + bool result = true; + std::wstring searchNameUnadorned = L""; + std::wstring localDir = L""; + std::list adornedFileNamesFound; + + int targetDisk = tolower(aTarget[0]); + const DrivesMap& driveMap = iConfigManager.GetDrivesMap(); + + int count = driveMap.size(); + + // check for adorned (versioned) files e.g. dummy{12345678}.dll + if (aTarget.find(KSysBinPath) != std::wstring::npos) + { + AdornedProcessingOfFile(aTarget, searchNameUnadorned, adornedFileNamesFound); + } + else + { + searchNameUnadorned = aTarget; + } + + DrivesMap::const_iterator it = driveMap.begin(); + DrivesMap::const_iterator end = driveMap.end(); + + // search on all of defined drives (including the ROM and system drive) for + // the target file + for ( ; it != end ; ++it) + { + // drive letter + int disk = tolower(it->first); + searchNameUnadorned[0] = disk; + std::wstring unadornedLocalPath(searchNameUnadorned); + + // check if adorned file version is found on this disk + bool adornedFound = false; + + std::list::iterator index = adornedFileNamesFound.begin(); + std::list::iterator adornedEnd = adornedFileNamesFound.end(); + int nrOfAdornedFilenamesFound = adornedFileNamesFound.size(); + + for ( ; index != adornedEnd ; ++index) + { + std::wstring adornedFile = *index; + int drive = tolower(adornedFile[0]); + if (drive == disk) + { + adornedFound = true; + break; + } + } + + // the actual directory + localDir = it->second->iDir; + bool unadornedFound; + + // check to see if we are using ROM/ROFS files to represent the z drive. + // If so, check to see if the ROM file exists in the logs. + if (disk == 'z' && localDir.empty()) + { + unadornedFound = iRomManager.RomFileExists(searchNameUnadorned); + } + else + { + // convert to the local path and see if the file exists on the current drive + ConvertToLocalPath( unadornedLocalPath, localDir ); + unadornedFound = FileExists(unadornedLocalPath); + } + + bool matchFound = unadornedFound || adornedFound; + if (!matchFound) + continue; + + bool processEclipsingSuspectsFoundOnThisDrive = false; + + // The logic varies whether we find an eclipsable/overwritable file on: (1) The same disk as the one we are installing to + // (2) The Z drive (ROM), (3) Any other drive + if (disk == targetDisk) // case (1) + { + bool isOverwrite = FileExists(aInstallableFile.GetLocalTarget()); + + // there are 3 possible cases: (1.1) We are correctly overwriting the already present file (a PU), + // (1.2) We are incorrectly overwriting the file present, (1.3) We are eclipsing the file (if one of the file names is adorned) + if (isOverwrite) + { + // case 1.1 and 1.2 are handled here - overwrite the file if we have the right to do so. + HandleFileOverwriting(aFile, aTarget, aSUFlag); + } + else + { + // case 1.3 is handled here: + // we have found a matching filename (either unadorned or adorned); add it to the eclipsing suspects + processEclipsingSuspectsFoundOnThisDrive = true; + } + } + else if (disk == 'z') // case (2) + { + // we are eclipsing a ROM file, check if this is authorised: + // see implementation of IsEclipsable() + if (!IsEclipsable(searchNameUnadorned, aSUFlag)) + { + result = false; + break; + } + } + else // case (3) + { + processEclipsingSuspectsFoundOnThisDrive = true; + } + + // now check to see whether the unadorned or the adorned filename found on + // this drive should be added to iEclipsableOverwriteFiles. + if (processEclipsingSuspectsFoundOnThisDrive && unadornedFound) + { + iEclipsableOverwriteFiles.push_back(searchNameUnadorned); + } + + if (processEclipsingSuspectsFoundOnThisDrive && adornedFound) + { + nrOfAdornedFilenamesFound = adornedFileNamesFound.size(); + std::list::iterator index = adornedFileNamesFound.begin(); + std::list::iterator adornedEnd = adornedFileNamesFound.end(); + + // add the adorned filenames found to the list of eclipsable/overwrite candidates + for ( ; index != adornedEnd ; ++index) + { + std::wstring adornedFile = *index; + int drive = tolower(adornedFile[0]); + if (drive == disk) + { + iEclipsableOverwriteFiles.push_back(adornedFile); + } + } + } + } + // end of loop + + // the final step is to try and remove all the files from iEclipsableOverwriteFiles that + // will prevent this SIS file from installing. + if (result && (iEclipsableOverwriteFiles.size() > 0)) + { + FilterNonBlockingFilesOfFilename(aFile, aTarget); + } + + return result; +} + +/** Checks the list of eclipsable candidate files against those that are owned by the + installing package (if any). Blocking files are removed if a match is found. + @param aFile the SIS file to be installed + @param aTarget the fully qualified filename (full path and name) +*/ +void Installer::FilterNonBlockingFilesOfFilename(const SisFile& aFile, const std::wstring& aTarget) +{ + // if the package aleady exists + TUint32 pkgUid = aFile.GetPackageUid(); + if (iRegistry.IsInstalled(pkgUid)) + { + const SisRegistryObject& registryEntry = iRegistry.GetRegistryObject(pkgUid); + const FileDescriptions& installedFiles = registryEntry.GetFileDescriptions(); + + FileDescriptions::const_iterator inCurr = installedFiles.begin(); + FileDescriptions::const_iterator inEnd = installedFiles.end(); + + for ( ; inCurr != inEnd ; ++inCurr) + { + std::wstring baseFile((*inCurr)->GetTarget()); + + std::list::iterator eCurr = iEclipsableOverwriteFiles.begin(); + std::list::iterator eEnd = iEclipsableOverwriteFiles.end(); + + for ( ; eCurr != eEnd; ++eCurr) + { + std::wstring eclipseFile(*eCurr); + + // the installed base package owns the eclipse/overwrite candidate + if (FoldedCompare(baseFile, eclipseFile) == 0) + { + // we are installing a new adorned variant of a file, so remove the blocking + // file from the list + if (StringUtils::NameAndExt(baseFile) != StringUtils::NameAndExt(aTarget)) + { + eCurr = iEclipsableOverwriteFiles.erase(eCurr); + } + } + } + } + } +} + +/** This function examines the list of ROM files we may eclipse to see if the supplied name is among them. + Here we have 2 options: + 1) file is not to be installed to \sys\bin\ + in this case we don't invoke special handling of adorned filenames so we are only + interested in if that particular file is allowed to be eclipsed + 2) file is to be installed to \sys\bin therefore we have to handle adorned filenames. + Eclipsing is allowed if the filename that we are trying to install is a variant of any ROM filename + marked as eclipsable i.e: if we are trying to install c:\sys\bin\A{000A0001}.dll + and we have z:\sys\bin\A.dll as an eclipsable file or any z:\sys\bin\A{????????}.dll + then we are allowed to eclipse. + @param aRomFile fully qualified filename in ROM that is to be checked for eclipising (i.e: z:\sys\bin\some.dll) + @param aSUFlag specifies if the installing SIS file has been signed by a SU certificate +*/ +bool Installer::IsEclipsable(std::wstring& aRomFile, bool aSUFlag) +{ + // SA/SP/PU sis + RU flag + signed by SU root cert is allowed + if (aSUFlag) + return true; + + bool isEclipsable = false; + bool goesToSysBin = (aRomFile.compare(KSysBinPath) != std::wstring::npos); + + // go through the list of ROM files which are allowed to be eclipsed + std::list::const_iterator end = iEclipsableRomFiles.end(); + for (std::list::const_iterator curr = iEclipsableRomFiles.begin() ; + curr != end; ++curr) + { + std::wstring eclipsableRomFile = *curr; + + // support wildcard characters in ROM stub files + if (StringUtils::WildcardCompare(eclipsableRomFile,aRomFile)) // case 1 + { + isEclipsable = true; + break; + } + else if (goesToSysBin) // case 2 + { + if (IsAdornedVariationOf(eclipsableRomFile,aRomFile)) + { + isEclipsable = true; + break; + } + } + } + + return isEclipsable; +} + +/** This function handles overwriting scenarios (i.e: we are trying to install c:\somedir\somename.ext however it already exists) + In this case we have 2 possibilities: + 1) We are correctly overwriting the already present file (a PU) + 2) We are incorrectly overwriting the file present + @param aFile the SIS file to be installed + @param aTarget The fully qualified filename (full path and name) + @param aSUFlag specifies if the installing SIS file has been signed by a SU certificate +*/ +void Installer::HandleFileOverwriting(const SisFile& aFile, const std::wstring& aTarget, bool aSUFlag) +{ + // find out which package this file belongs to + TUint32 owningUid = 0; + const SisRegistryObject* owningObj = iRegistry.OwningPackage(aTarget,owningUid); + bool isSp = aFile.GetInstallType() == CSISInfo::EInstAugmentation; + bool isPu = aFile.GetInstallType() == CSISInfo::EInstPartialUpgrade; + bool isSa = aFile.GetInstallType() == CSISInfo::EInstInstallation; + + // no package owns this file. Always allow orphaned file overwriting! + if (owningUid == 0) + { + // do not display a warning if the installing file is a PA. The user + // needs to copy the installing files to the installing directory + // prior to installing the SIS file. + std::string tempTarget = Ucs2ToUtf8(aTarget); + std::wstring targetDisplay = Utf8ToUcs2( tempTarget ); + if (aFile.GetInstallType() == CSISInfo::EInstPreInstalledApp) + { + LINFO(targetDisplay << L" found for PA installation"); + } + else + { + LWARN(targetDisplay << L" overwrites orphaned file"); + } + } + else if (aFile.GetPackageUid() == owningUid) + { + // SP can not overwrite a file in the base pkg + if (isSp) + { + std::wostringstream os; + os << aTarget << L" overwrites file from base package 0x" << std::hex << owningUid << L" \"" << owningObj->GetPackageName() << L"\"" << std::endl; + iProblemFiles.append(os.str()); + iError = ECLIPSING_VIOLATION; + } + } + else + { + // SP can not overwrite a file belonging to a different base pkg + // PU/SA can not overwrite a file belonging to a different base pkg unless it has been signed by + // a SU cert + if (isSp || (!aSUFlag && (isPu || isSa))) + { + std::wostringstream os; + os << aTarget << L" overwrites file from base package 0x" << std::hex << owningUid << L" \"" << owningObj->GetPackageName() << L"\"" << std::endl; + iProblemFiles.append(os.str()); + iError = ECLIPSING_VIOLATION; + } + else + { + LWARN(aTarget << L" overwrites file from base package 0x" << std::hex << owningUid << L" \"" << owningObj->GetPackageName() << L"\""); + } + } +} + +void Installer::WarnEclipseOverWrite(const SisFile& aFile) +{ + // we still have some blocking files left after we have checked the destination + // of the installing file. + if (iEclipsableOverwriteFiles.size()>0) + { + // InterpretSIS allows orphan file eclipsing/overwriting + std::list::const_iterator curr = iEclipsableOverwriteFiles.begin(); + std::list::const_iterator end = iEclipsableOverwriteFiles.end(); + + for ( ; curr != end; ++curr) + { + std::wstring eclipseFile(*curr); + + TUint32 owningUid = 0; + const SisRegistryObject* owningObj = iRegistry.OwningPackage(eclipseFile, owningUid); + + // always allow orphaned file overwriting + if (owningUid == 0) + { + LWARN(eclipseFile << L" eclipses orphaned file."); + } + else + { + // SP/PU can not overwrite a file belonging to a different base pkg or + // SP/PU can not eclipse a base package which is not in the ROM. + std::wostringstream os; + os << eclipseFile << L" eclipses file from package 0x" << std::hex << owningUid << L" \"" << owningObj->GetPackageName() << L"\"" << std::endl; + iProblemFiles.append(os.str()); + iError = ECLIPSING_VIOLATION; + continue; + } + } + } +} + +void Installer::CheckDestinations(const SisFile& aFile, InstallableFiles& aFiles, + const InstallSISFile& aInstallSISFile) +{ + bool suFlag = aInstallSISFile.iSUFlag; + + // if the -e option or InstallSISFile::iNotRegister is set, disable the eclipsing checks + bool isEclipseAllowed = (iParamList.IsFlagSet(CParameterList::EFlagsDisableZDriveChecksSet)) || aInstallSISFile.iNotRegister; + + iError = SUCCESS; + + Sids sids; + GetSidsFromInstallable(aFiles, sids); + + const std::wstring privatePath = L":\\private\\"; + const std::wstring sysPath = L":\\sys\\"; + const std::wstring sysBinPath = L":\\sys\\bin\\"; + const std::wstring resourcePath = L":\\resource\\"; + const std::wstring exeType = L".exe"; + + int num_of_files = aFiles.size(); + TUint32 pkgUid = aFile.GetPackageUid(); + TUint32 installType = aFile.GetInstallType(); + std::list stubFileEntries; + + iRegistry.GetStubFileEntries(pkgUid, stubFileEntries); + + // if a base package exists, check to see if it chains back to a ROM stub. If so, populate + // iEclipsableRomFiles with the files owned by the ROM stub. Only ROM files can be eclipsed. + // + // if the package has been signed by a SU cert, then there is no need to generate the eclipsable + // file list - it is allowed to eclipse any file in the ROM. + if (iRegistry.IsInstalled(pkgUid) && !suFlag) + { + PrepareEclipsableFilesList(aFile); + } + + // loop through the files to be installed + for( int ii=num_of_files-1; ii>=0; ii-- ) + { + const InstallableFile* file = aFiles[ ii ]; + const CSISFileDescription* sisDescription = file->FileDescription(); + + // file to be installed + std::wstring target( file->GetTarget() ); + + if (sisDescription->Operation() == CSISFileDescription::EOpText) + break; + if (sisDescription->Operation() == CSISFileDescription::EOpNull) + { + // a FN file can not remove a file from \sys or \resource + if ((target.find(sysPath,0) != std::wstring::npos) || (target.find(resourcePath,0) != std::wstring::npos)) + { + // eclipsing problem + std::wostringstream os; + os << L"FN file \"" << target << L"\" can not remove a file from \\sys or \\resource" << std::endl; + iProblemFiles.append(os.str()); + iError = DATA_CAGE_VIOLATION; + continue; + } + } + else + { + std::wstring realTarget(file->GetLocalTarget()); + + std::wstring romTarget(target); + romTarget[0] = KRomDriveLetter; + + // check to see if we are legally allowed to eclipse a ROM file + if (!isEclipseAllowed) + { + if (!ValidEclipse(aFile, target, *file, suFlag)) + { + // eclipsing problem + std::wostringstream os; + os << target << L" eclipses file from ROM" << std::endl; + iProblemFiles.append(os.str()); + iError = ECLIPSING_VIOLATION; + continue; + } + } + + // additional platsec checks + if (target.find(privatePath) != std::wstring::npos) + { + // add an extra one for the drive letter + TInt start = privatePath.size()+1; + TInt end = target.find( KDirectorySeparator[ 0 ], start); + + std::wistringstream uidStr(target.substr(start,end-start)); + + TUint32 sid = 0; + uidStr >> std::hex >> sid; + + if (sid == 0) + break; + + // if a file in a private directory is registered, check to see if + // it belongs to this package + if (std::find(sids.begin(), sids.end(), sid) == sids.end()) + { + TUint32 sidOwnerPkgUId = KNullUid; + + if (iRegistry.SidExists(sid)) + { + if(iParamList.RegistryVersionExists()) + { + // SID belongs to some package, lets find out its UID + const SisRegistryPackage& sisRegistryPkg = iRegistry.SidToPackage(sid); + + sidOwnerPkgUId = sisRegistryPkg.GetUid(); + } + else + { +#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + sidOwnerPkgUId = iRegistry.GetUid(sid); +#endif //SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + } + } + + if (sidOwnerPkgUId != pkgUid) + { + // this package is trying to write to a SID's private directory + // which does not belong to this package + + const int KUidStringLength = 8; + std::wstring importPath = privatePath; + + importPath.append( uidStr.str() + L"\\import" ); + + if ((target.find(importPath,0) == std::wstring::npos) && !suFlag) + { + // only SA with RU + SU and PU with RU + SU flag can override other private directory + std::wostringstream os; + os << target << L" cannot be written to a private directory which " + << L"does not belong to any exe in this package" << std::endl; + iProblemFiles.append(os.str()); + iError = DATA_CAGE_VIOLATION; + continue; + } + } + } + } + else if (file->IsExecutable()) + { + TUint32 sid = file->Sid(); + + std::wstring romFileWithDuplicateSid(L""); + bool sidExistsInRom = iRomManager.SidExistsInRom(romFileWithDuplicateSid, sid); + bool sidExistsInRegistry = iRegistry.SidExists(sid); + + if (sidExistsInRegistry && file->IsExe()) + { + // the .EXE which owns the SID + std::wstring owningSidFile; + iRegistry.SidToFileName(sid,owningSidFile); + + bool owningPkgInRom = false; + bool samePkgUid = false; + TUint32 owningPkg = 0; + if(iParamList.RegistryVersionExists()) + { + // the SisRegistryObject which owns the .EXE + + const SisRegistryObject* owningObj = iRegistry.OwningPackage(owningSidFile,owningPkg); + + owningPkgInRom = owningObj->GetInRom(); + samePkgUid = (owningPkg == pkgUid); + } + else + { + #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + owningPkg = iRegistry.GetUid(owningSidFile); + owningPkgInRom = iRegistry.GetInRom(owningPkg); + samePkgUid = (owningPkg == pkgUid); + #endif //SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + } + std::wstring targetName = StringUtils::NameAndExt(file->GetTarget()); + std::wstring owningSidFileName = StringUtils::NameAndExt(owningSidFile); + + bool sameTargetName = (FoldedCompare(targetName,owningSidFileName) == 0); + bool romStubExists = iRegistry.IsRomStubPackage(pkgUid); + bool validInstallType = (installType == CSISInfo::EInstInstallation || installType == CSISInfo::EInstPartialUpgrade || installType == CSISInfo::EInstAugmentation); + + // allow SID eclipsing in the following scenarios: + // 1) SIS file has been signed by a SU cert + // 2) eclipsing checks have been disabled by the user (using -e) + // 3) SP/PU/SA+RU eclipsing of a ROM stub + bool allowSidEclipse = false; + + // case 1 and 2 + if (suFlag || isEclipseAllowed) + allowSidEclipse = true; + + // case 3 + if (validInstallType && sameTargetName && samePkgUid && (owningPkgInRom || romStubExists)) + { + allowSidEclipse = true; + } + + if (!allowSidEclipse) + { + std::wostringstream os; + + os << L"The existing file " << owningSidFile << L" already has the SID 0x" << std::hex << sid + << std::dec << L", cannot install " << target << std::endl; + iProblemFiles.append(os.str()); + iError = DUPLICATE_SID; + continue; + } + } + // .EXE exists in the ROM, but no ROM stub has ownership of it + else if (sidExistsInRom) + { + // A ROM stub could have referenced this .EXE using wildcards - in this case the SID will not + // be registered in the SIS registry. + bool isInstalled = iRegistry.IsInstalled(pkgUid); + bool ownedByRomStub = false; + if (isInstalled) + { + if (iRegistry.IsRomStubPackage(pkgUid)) + { + CSISController* sisController = iRegistry.GetStubController(pkgUid); + TFileDescList fileDesList; + sisController->InstallBlock().GetFileList(fileDesList); + for(TFileDescListConstIter iter = fileDesList.begin(); iter != fileDesList.end(); ++iter) + { + const CSISFileDescription* fD = *iter; + + std::wstring romStubTarget(fD->Target().GetString()); + + if (StringUtils::WildcardCompare(romStubTarget,romFileWithDuplicateSid)) + { + ownedByRomStub = true; + break; + } + } + } + } + + bool allowSidEclipse = false; + + if (suFlag || isEclipseAllowed) + allowSidEclipse = true; + + if (!allowSidEclipse && !ownedByRomStub) + { + std::wostringstream os; + + os << L"A ROM file already has the SID 0x" << std::hex << file->Sid() + << std::dec << L", cannot install " << target << std::endl; + iProblemFiles.append(os.str()); + iError = DUPLICATE_SID; + continue; + } + } + } + else if (realTarget.find(sysBinPath) != std::wstring::npos) + { + std::wostringstream os; + os << target << L" cannot be installed to a data caged area" << std::endl; + iProblemFiles.append(os.str()); + iError = DATA_CAGE_VIOLATION; + continue; + } + } + } + + // we still may have blocking files left. Handle them here. + WarnEclipseOverWrite(aFile); + + iEclipsableOverwriteFiles.clear(); + iEclipsableRomFiles.clear(); + + if (!iProblemFiles.empty()) + { + std::string x; + throw InvalidSis("", Ucs2ToUtf8(iProblemFiles,x), iError); + } +} + +void Installer::SetupExpressionEnvironment(const SisFile& aFile, const SisRegistry& aSisRegistry, RomManager& aRomManager ) +{ + delete iExpressionEnvironment; + iExpressionEnvironment = new ExpressionEnvironment( aFile, + aSisRegistry, + iRomManager, + iConfigManager, + iParamList.SystemDrivePath() ); + + delete iExpressionEvaluator; + iExpressionEvaluator = new ExpressionEvaluator( *iExpressionEnvironment ); +} + +void Installer::CheckEmbedded(const SisFile& aFile) +{ + PackageUids pkgs = aFile.GetEmbeddedPackageUids(); + + for (PackageUids::const_iterator curr = pkgs.begin() ; + curr != pkgs.end() ; + ++curr) + { + if (!iRegistry.IsInstalled(*curr)) + { + + LWARN(L" Embedded Package not installed: UID " << std::hex << *curr ); + } + } +} + + +void Installer::CreateStubSisFile(const InstallSISFile& aInstallSISFile, SisFile& aSis) +{ + int targetDrive = aInstallSISFile.iTargetDrive; + std::wstring drivePath = iConfigManager.GetLocalDrivePath(targetDrive); + + drivePath.append(L"\\private\\"); + + // build SwiDaemon Pathname + std::wstring ctrl = StringUtils::MakePathFromSID(drivePath, KSwiDaemonUid); + + if ( !MakeDir( ctrl ) ) + { + throw InterpretSisError(L"Directory Creation Error - "+ctrl, DIRECTORY_CREATION_ERROR); + } + + std::wstringstream s; + s << std::hex << aSis.GetPackageUid(); + + ctrl.append(s.str()); + + + switch(aSis.GetInstallType()) + { + case CSISInfo::EInstInstallation: + case CSISInfo::EInstPreInstalledApp: + { + // If an Installation type is SA/PA then append _0 after the stub UID. + ctrl.append(L"_0"); + break; + } + + case CSISInfo::EInstAugmentation: + { + // If an Installation type is SP then append an index after the stub UID. + + int num = 0; + + ctrl.append( L"_"); + + if (aInstallSISFile.iNotRegister) + { + // In this case, we can only assume all the previous SP installations + // (of a particular package) are consistently installed to the same target + // drive and all of the SP installation's attribute are set to either + // +mcardalone OR +mcardalonenr. Otherwise, the generated index will be wrong. + + // Get the index from the daemon folder + num = GetAugmentationsNumber(ctrl); + } + else + { + // In this case, we can only assume all the previous SP installations + // (of a particular package) is consistent with attributes set to either + // +mcard OR +mcardnr. Otherwise, the generated index will be wrong. + + // Get the index from the sisregistry entries + num = iRegistry.GetAugmentationsNumber(aSis.GetPackageUid()); + } + + std::wstringstream s2; + s2 << std::hex << num; + ctrl.append( s2.str() ); + break; + } + + default: + { + std::wstring err(L"SIS file cannot be propagated: "); + err.append(aInstallSISFile.iFileName); + throw InterpretSisError(err, SIS_NOT_SUPPORTED); + } + } + + ctrl.append(L".sis"); + + // Display the target SIS file. Format the stub SIS file string so it displays correctly. + std::wstring ctrlDrive(L"$:"); + ctrlDrive[0] = targetDrive; + std::wstring ctrlTarget = ctrl.substr(iConfigManager.GetLocalDrivePath(targetDrive).length(),ctrl.length()); + ctrlDrive.append(ctrlTarget); + + LINFO(L"\tCreating stub: " << ctrlDrive); + + aSis.MakeSISStub(ctrl); + // If the NR flag is set, change the file attribute to RO + if (aInstallSISFile.iNonRemovable) + { + _wchmod(ctrl.c_str(),_S_IREAD); + } +}