You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
15 KiB
431 lines
15 KiB
#include "stdinc.h"
|
|
#include "macros.h"
|
|
#include "common.h"
|
|
#include "idp.h"
|
|
#include "sxsutil.h"
|
|
|
|
#include "fusionbuffer.h"
|
|
#include "fusionheap.h"
|
|
|
|
#define FUSION_WIN32_ASSEMBLY_DUP_FILEKEY_PREFIX L"winsxs_"
|
|
#define MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME L"MsiFusionWin32AssemblyCache"
|
|
#define MSI_ASSEMBLYCACHE_DIRECTORY L"winsxs"
|
|
|
|
#define MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME L"MsiFusionWin32AssemblyManifestCache"
|
|
#define MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY L"Manifests"
|
|
|
|
#define MSI_ASSEMBLY_MANIFEST_COMPONENT_KEYNAME L"MsiFusionWin32AssemblyManifestComponent"
|
|
|
|
#define MANIFEST_FILE_EXT L".Manifest"
|
|
#define CATALOG_FILE_EXT L".cat"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Assumption : at this moment,we asusme that DuplicateFile table EXISTS
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CA_DuplicationWin32AssemblyFiles_Callback(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CStringBuffer sbDupFileKey;
|
|
CStringBuffer sbDupFileName;
|
|
CSmallStringBuffer sbExt;
|
|
bool fManifest = false;
|
|
bool fCatalog = false;
|
|
|
|
|
|
PARAMETER_CHECK_NTC(info != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszFileID != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszFileName);
|
|
|
|
|
|
sbDupFileKey.Win32Assign(FUSION_WIN32_ASSEMBLY_DUP_FILEKEY_PREFIX, wcslen(FUSION_WIN32_ASSEMBLY_DUP_FILEKEY_PREFIX));
|
|
sbDupFileKey.Win32Append(info->pszFileID, wcslen(info->pszFileID));
|
|
|
|
IFFALSE_EXIT(sbDupFileName.Win32Assign(info->pszFileName, wcslen(info->pszFileName)));
|
|
IFFALSE_EXIT(sbDupFileName.Win32GetPathExtension(sbExt));
|
|
|
|
//
|
|
//rename manifest file and catalog file
|
|
//
|
|
if ((FusionpCompareStrings(sbExt, sbExt.Cch(), L"man", wcslen(L"man"), true) == 0) ||
|
|
(FusionpCompareStrings(sbExt, sbExt.Cch(), L"manifest", wcslen(L"manifest"), true) == 0))
|
|
{
|
|
fManifest = true;
|
|
}
|
|
else
|
|
if ((FusionpCompareStrings(sbExt, sbExt.Cch(), L"cat", wcslen(L"cat"), true) == 0) ||
|
|
(FusionpCompareStrings(sbExt, sbExt.Cch(), L"catalog", wcslen(L"catalog"), true) == 0))
|
|
{
|
|
fCatalog = true;
|
|
}
|
|
|
|
if (fManifest || fCatalog)
|
|
{
|
|
PARAMETER_CHECK_NTC(info->pszAssemblyUniqueDir != NULL);
|
|
IFFALSE_EXIT(sbDupFileName.Win32Assign(info->pszAssemblyUniqueDir, wcslen(info->pszAssemblyUniqueDir)));
|
|
|
|
// reset the extension of manifest file and catalog file in order to keep the same as XP
|
|
IFFALSE_EXIT(sbDupFileName.Win32Append(fManifest? MANIFEST_FILE_EXT : CATALOG_FILE_EXT,
|
|
fManifest? wcslen(MANIFEST_FILE_EXT) : wcslen(CATALOG_FILE_EXT)));
|
|
}else
|
|
{
|
|
PARAMETER_CHECK_NTC(info->pszFileName != NULL);
|
|
IFFALSE_EXIT(sbDupFileName.Win32Assign(info->pszFileName, wcslen(info->pszFileName)));
|
|
}
|
|
|
|
// if it is a .manifest file or it is a catalog file, put it into winsxs\manifests folder,
|
|
// otherwise, put it into winsxs\x86_...._12345678
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, info->hdb,
|
|
OPT_DUPLICATEFILE,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DUPLICATEFILE,
|
|
MAKE_PCWSTR(sbDupFileKey),
|
|
MAKE_PCWSTR(info->pszComponentID),
|
|
MAKE_PCWSTR(info->pszFileID),
|
|
MAKE_PCWSTR(sbDupFileName),
|
|
(fManifest | fCatalog) ? MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME : MAKE_PCWSTR(info->pszDestFolderID)));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetXPInstalledDirectory(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info, CStringBuffer & sbAsmDir)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR sqlbuf[CA_MAX_BUF];
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
WCHAR bufName[CA_MAX_BUF];
|
|
DWORD cchName;
|
|
WCHAR bufValue[CA_MAX_BUF];
|
|
DWORD cchValue;
|
|
BOOL fWin32, fWin32Policy;
|
|
CStringBuffer sbPathBuffer;
|
|
UINT iRet;
|
|
ASSEMBLY_IDENTITY_ATTRIBUTE Attribute;
|
|
PASSEMBLY_IDENTITY AssemblyIdentity = NULL;
|
|
|
|
PARAMETER_CHECK_NTC(info != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszComponentID != NULL);
|
|
PARAMETER_CHECK_NTC(info->hdb != NULL);
|
|
|
|
IFFALSE_EXIT(::SxsCreateAssemblyIdentity(0, ASSEMBLY_IDENTITY_TYPE_DEFINITION, &AssemblyIdentity, 0, NULL));
|
|
swprintf(sqlbuf, L"SELECT Name, Value FROM MsiAssemblyName WHERE Component_='%s'", info->pszComponentID);
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info->hdb, sqlbuf, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// for each entry in MsiAssembly Table
|
|
//
|
|
iRet = MsiViewFetch(hView, &hRecord);
|
|
if (iRet == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (iRet != ERROR_SUCCESS )
|
|
SET_HRERR_AND_EXIT(iRet);
|
|
|
|
cchName = NUMBER_OF(bufName);
|
|
cchValue = NUMBER_OF(bufValue);
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 1, bufName, &cchName));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 2, bufValue, &cchValue));
|
|
|
|
Attribute.Flags = 0;
|
|
Attribute.NamespaceCch = 0;
|
|
Attribute.Namespace = NULL;
|
|
Attribute.NameCch = cchName;
|
|
Attribute.Name = bufName;
|
|
Attribute.ValueCch = cchValue;
|
|
Attribute.Value = bufValue;
|
|
|
|
//BUGBUG
|
|
// Fusion win32 required that the attribute name is case-sensitive, so, for assembly name,
|
|
// it should appear as "name" in MsiAssemblyName, however, for some historical reason,
|
|
// it appears as "Name", so, we have to force it to the right thing for win32.
|
|
//
|
|
// for other attribute in MsiAssemblyName table, there is no such problem,
|
|
//
|
|
//BUGBUG
|
|
if ((Attribute.NameCch == 4) && (_wcsicmp(Attribute.Name, L"name") == 0))
|
|
{
|
|
Attribute.Name = L"name";
|
|
}
|
|
|
|
IFFALSE_EXIT(::SxsInsertAssemblyIdentityAttribute(0, AssemblyIdentity, &Attribute));
|
|
}
|
|
|
|
IFFALSE_EXIT(SxsHashAssemblyIdentity(0, AssemblyIdentity, NULL));
|
|
|
|
//
|
|
// generate the path, something like x86_ms-sxstest-sfp_75e377300ab7b886_1.0.0.0_en_04f354da
|
|
//
|
|
IFFAILED_EXIT(ca_SxspDetermineAssemblyType(AssemblyIdentity, fWin32, fWin32Policy));
|
|
|
|
IFFAILED_EXIT(ca_SxspGenerateSxsPath(
|
|
SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT | (fWin32Policy ? SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION : 0),
|
|
SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
|
|
NULL,
|
|
0,
|
|
AssemblyIdentity,
|
|
sbPathBuffer));
|
|
|
|
|
|
IFFALSE_EXIT(sbAsmDir.Win32Assign(sbPathBuffer));
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
SxsDestroyAssemblyIdentity(AssemblyIdentity);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT IsCertainRecordExistInDirectoryTable(const MSIHANDLE & hdb, PCWSTR DirectoryKey, BOOL & fExist)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PMSIHANDLE hRecord = NULL;
|
|
PMSIHANDLE hView = NULL;
|
|
WCHAR sqlBuf[MAX_PATH];
|
|
|
|
fExist = FALSE;
|
|
|
|
swprintf(sqlBuf, ca_sqlQuery[CA_SQL_QUERY_DIRECTORY], DirectoryKey);
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlBuf, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
|
|
UINT iRet = MsiViewFetch(hView, &hRecord);
|
|
|
|
if (iRet == ERROR_SUCCESS)
|
|
{
|
|
fExist = TRUE;
|
|
}
|
|
else if (iRet == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
fExist = FALSE;
|
|
}
|
|
else
|
|
SET_HRERR_AND_EXIT(iRet);
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// add entry to Directory Table and CreateFolder Table
|
|
//
|
|
HRESULT AddFusionAssemblyDirectories(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info, CStringBuffer & sbDestFolderID)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fRecordExist = FALSE;
|
|
|
|
PARAMETER_CHECK_NTC(info != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszAssemblyUniqueDir != NULL);
|
|
PARAMETER_CHECK_NTC(info->hdb != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszComponentID != NULL);
|
|
|
|
//
|
|
// TODO: here we could make the DirectoryID more unique
|
|
//
|
|
IFFALSE_EXIT(sbDestFolderID.Win32Assign(info->pszAssemblyUniqueDir, wcslen(info->pszAssemblyUniqueDir)));
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, info->hdb,
|
|
OPT_DIRECTORY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
|
|
MAKE_PCWSTR(sbDestFolderID),
|
|
MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME),
|
|
MAKE_PCWSTR(info->pszAssemblyUniqueDir)));
|
|
|
|
//
|
|
// insert entry to CreateFolder Table
|
|
//
|
|
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, info->hdb,
|
|
OPT_CREATEFOLDER,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_CREATEFOLDER,
|
|
MAKE_PCWSTR(sbDestFolderID),
|
|
MAKE_PCWSTR(info->pszComponentID)));
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CheckWhetherUserWantMigrate(const CA_ENM_ASSEMBLY_CALLBACK_INFO * info, BOOL & fMigrateDenied)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR pwszSQL[MAX_PATH];
|
|
PMSIHANDLE hView = NULL;
|
|
PMSIHANDLE hRecord = NULL;
|
|
UINT err, iRet;
|
|
|
|
fMigrateDenied = FALSE;
|
|
|
|
// NTRAID#NTBUG9 - 589779 - 2002/03/26 - xiaoyuw
|
|
// should be replaced with _snwprintf
|
|
swprintf(pwszSQL, L"SELECT `fMigrate` FROM `%s` WHERE `Component_` = '%s'", WIN32_ASSEMBLY_MIGRATE_TABLE, info->pszComponentID);
|
|
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(info->hdb, pwszSQL, &hView));
|
|
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, NULL));
|
|
err = ::MsiViewFetch(hView, &hRecord);
|
|
switch (err) {
|
|
case ERROR_NO_MORE_ITEMS: // not exist in the table, default is migrate-enabled
|
|
break;
|
|
case ERROR_SUCCESS:
|
|
iRet = MsiRecordGetInteger(hRecord, 1);
|
|
if ( iRet == 0 )
|
|
fMigrateDenied = TRUE;
|
|
break;
|
|
default:
|
|
SET_HRERR_AND_EXIT(err);
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CA for Fusion Win32 Assembly installation on downlevel(only) :
|
|
// (1)set entries for each assembly file in DuplicateFile Table
|
|
// (2)after all done, set a RegKey so this would not be done everytime
|
|
//
|
|
HRESULT __stdcall CA_DuplicationWin32Assembly_Callback(CA_ENM_ASSEMBLY_CALLBACK_INFO * info)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CStringBuffer sbDestFolder;
|
|
CStringBuffer sbDestFolderID;
|
|
BOOL fExist = FALSE;
|
|
BOOL fMigrateDenied = FALSE;
|
|
|
|
PARAMETER_CHECK_NTC((info->dwFlags == 0) ||(info->dwFlags == CA_ENM_ASSEMBLY_CALLBACK_INFO_FLAG_IGNORE_MIGRATE_DENY_CHECK));
|
|
PARAMETER_CHECK_NTC(info->hInstall != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszComponentID != NULL);
|
|
PARAMETER_CHECK_NTC(info->pszManifestFileID != NULL);
|
|
|
|
if (! (info->dwFlags & CA_ENM_ASSEMBLY_CALLBACK_INFO_FLAG_IGNORE_MIGRATE_DENY_CHECK))
|
|
{
|
|
IFFAILED_EXIT(CheckWhetherUserWantMigrate(info, fMigrateDenied));
|
|
if (fMigrateDenied)
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// get sxs component directory in the format of x86_name_publicKeyToken_1.0.0.0_en_hashvalue
|
|
//
|
|
IFFAILED_EXIT(GetXPInstalledDirectory(info, sbDestFolder));
|
|
info->pszAssemblyUniqueDir = sbDestFolder;
|
|
|
|
//
|
|
// Create an entry for this dir in Directory Table, return DirectoryID in Directory Table
|
|
//
|
|
IFFAILED_EXIT(AddFusionAssemblyDirectories(info, sbDestFolderID));
|
|
|
|
info->pszDestFolderID = sbDestFolderID;
|
|
|
|
|
|
IFFAILED_EXIT(MSI_EnumComponentFiles(info, CA_DuplicationWin32AssemblyFiles_Callback));
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CustomAction_CopyFusionWin32AsmIntoAsmCache(MSIHANDLE hInstall)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fExist;
|
|
MSIHANDLE hdb = NULL;
|
|
|
|
#if DBG
|
|
MessageBoxA(NULL, "Enjoy the Debug", "ca_dup", MB_OK);
|
|
#endif
|
|
// Before enumerate all the assemblies, do common work right here ....
|
|
|
|
//
|
|
// (1) insert MsiAsmcache into Directory Table if not present
|
|
//
|
|
hdb = MsiGetActiveDatabase(hInstall);
|
|
INTERNAL_ERROR_CHECK_NTC(hdb != NULL);
|
|
|
|
IFFAILED_EXIT(IsCertainRecordExistInDirectoryTable(hdb, L"WindowsFolder", fExist));
|
|
if (fExist == FALSE)
|
|
{
|
|
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
|
|
OPT_DIRECTORY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
|
|
MAKE_PCWSTR(L"WindowsFolder"),
|
|
MAKE_PCWSTR(L"TARGETDIR"),
|
|
MAKE_PCWSTR(".")));
|
|
}
|
|
|
|
// adding winsxs into Directory Table
|
|
IFFAILED_EXIT(IsCertainRecordExistInDirectoryTable(hdb, MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME, fExist));
|
|
if (fExist == FALSE)
|
|
{
|
|
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
|
|
OPT_DIRECTORY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
|
|
MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME),
|
|
MAKE_PCWSTR(L"WindowsFolder"),
|
|
MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY)));
|
|
}
|
|
|
|
// adding winsxs\manifests into Directory table
|
|
IFFAILED_EXIT(IsCertainRecordExistInDirectoryTable(hdb, MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME, fExist));
|
|
if (fExist == FALSE)
|
|
{
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
|
|
OPT_DIRECTORY,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_DIRECTORY,
|
|
MAKE_PCWSTR(MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME),
|
|
MAKE_PCWSTR(MSI_ASSEMBLYCACHE_DIRECTORY_KEYNAME),
|
|
MAKE_PCWSTR(MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY)));
|
|
}
|
|
|
|
// create a component associated with this Directory too
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
|
|
OPT_COMPONENT,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_COMPONENT,
|
|
MSI_ASSEMBLY_MANIFEST_COMPONENT_KEYNAME,
|
|
MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME));
|
|
|
|
//create the folder : %windir%\winsxs\manifest
|
|
IFFAILED_EXIT(ExecuteInsertTableSQL(TEMPORARY_DB_OPT, hdb,
|
|
OPT_CREATEFOLDER,
|
|
NUMBER_OF_PARAM_TO_INSERT_TABLE_CREATEFOLDER,
|
|
MSI_ASSEMBLY_MANIFEST_CACHE_DIRECTORY_KEYNAME,
|
|
MSI_ASSEMBLY_MANIFEST_COMPONENT_KEYNAME));
|
|
|
|
//
|
|
//Enumerate all msi assembly in MsiAssemblyTable
|
|
//
|
|
IFFAILED_EXIT(MSI_EnumWinFuseAssembly(ENUM_ASSEMBLY_FLAG_CHECK_ASSEMBLY_ONLY, hInstall, CA_DuplicationWin32Assembly_Callback));
|
|
|
|
Exit:
|
|
if (hdb)
|
|
MsiCloseHandle(hdb);
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL WINAPI DllMain(
|
|
HINSTANCE hinstDLL,
|
|
DWORD fdwReason,
|
|
LPVOID lpvReserved
|
|
)
|
|
{
|
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
FusionpInitializeHeap(NULL);
|
|
}
|
|
else if (fdwReason == DLL_PROCESS_DETACH)
|
|
{
|
|
// NTRAID#NTBUG9 - 589779 - 2002/03/26 - xiaoyuw
|
|
// FusionpUninitializeHeap should be called when dll is detached
|
|
FusionpUninitializeHeap();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|