Leaked source code of windows server 2003
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

#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;
}