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.
 
 
 
 
 
 

412 lines
12 KiB

/*++
Copyright (c) Microsoft Corporation
Module Name:
fusemig.cpp
Abstract:
migration support
Author:
xiaoyuw wu @ 09/2001
Revision History:
--*/
#include "stdinc.h"
#include "macros.h"
#include "common.h"
#include <msi.h>
#include <Shlwapi.h>
#include "fusionbuffer.h"
#include "fuseio.h"
#define MsiInstallDir L"%windir%\\installer\\"
BOOL WINAPI DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved
)
{
return TRUE;
}
const char g_szMSIUserDataTreeKeyName[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData";
const char g_szMSIW98KeyName[]="Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Components\\";
const char g_szComponentKeyName[] = "Components";
BOOL IsMsiFile(PCWSTR filename)
{
PWSTR p = NULL;
p = wcsrchr(filename, L'.');
if ( p == NULL)
return FALSE;
if (_wcsicmp(p, L".msi") == 0)
{
//
// check the existence of the file
//
DWORD dwAttribute = GetFileAttributesW(filename);
if ((dwAttribute == (DWORD) -1) || (dwAttribute & FILE_ATTRIBUTE_DIRECTORY)) // odd case
{
return FALSE;
}
return TRUE;
}
else
return FALSE;
}
//
// Function
// from {AA2C6017-9D29-4CE2-8EC6-23E8E8F3C088} to 7106C2AA92D92EC4E86C328E8E3F0C88, which is
// {AA2C6017-9D29-4CE2-8EC6-23E8E8F3C088} compared with
// {7106C2AA-92D9-2EC4-E86C-328E8E3F0C88}
//
HRESULT ConvertComponentGUID(PCWSTR pszComponentGUID, PWSTR pszRegKey, DWORD cchRegKey)
{
HRESULT hr = S_OK;
PWSTR pp = const_cast<PWSTR>(pszComponentGUID);
if ( cchRegKey < wcslen(pszComponentGUID) - 3)
{
SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
}
ASSERT_NTC(pp[0] == L'{');
pp++;
// switch the first 8 digit : switch every 8
for ( DWORD i = 0; i < 8; i++)
pszRegKey[i] = pp[7 - i];
// 1st 4 digits : switch every 4
pp = pp + 8 + 1; // skip "-"
for ( i = 0; i < 4; i++)
{
pszRegKey[i + 8]= pp[3 - i];
}
// 2nd 4 digits : switch every 4
pp = pp + 4 + 1; // skip "-"
for ( i = 0; i < 4; i++)
{
pszRegKey[i + 8 + 4]= pp[3 - i];
}
// 3rd 4 digits : switch every 2
pp = pp + 4 + 1; // skip "-"
for ( i = 0; i < 2; i++)
{
pszRegKey[2*i + 8 + 4 + 4]= pp[2*i + 1];
pszRegKey[2*i + 8 + 4 + 4 + 1]= pp[2*i];
}
// for the last 12 digits
pp = pp + 4 + 1; // skip "-"
for (i=0; i<6; i++)
{
pszRegKey[2*i + 8 + 4 + 4 + 4]= pp[2*i + 1];
pszRegKey[2*i + 8 + 4 + 4 + 4 + 1]= pp[2*i];
}
pszRegKey[32] = L'\0';
Exit:
return hr;
}
HRESULT W98DeleteComponentKeyFromMsiUserData(PCWSTR pszComponentRegKeyName)
{
HRESULT hr = S_OK;
CStringBuffer sbRegKey;
LONG iRet;
IFFALSE_EXIT(sbRegKey.Win32Assign(g_szMSIW98KeyName, NUMBER_OF(g_szMSIW98KeyName)-1));
IFFALSE_EXIT(sbRegKey.Win32Append(pszComponentRegKeyName, wcslen(pszComponentRegKeyName)));
//
// About RegDeleteKey :
// Windows 95/98/Me: The function also deletes all subkeys and values. To delete a key only if the key has no subkeys
// or values, use the SHDeleteEmptyKey function.
//
// Windows NT/2000 or later: The subkey to be deleted must not have subkeys. To delete a key and all its subkeys, you
// need to recursively enumerate the subkeys and delete them individually. To recursively delete keys, use the SHDeleteKey
// function.
iRet = RegDeleteKeyW(HKEY_LOCAL_MACHINE, sbRegKey);
if (iRet != ERROR_SUCCESS)
{
if (iRet == ERROR_FILE_NOT_FOUND) // this RegKey does not exist
{
goto Exit;
}
else if (iRet == ERROR_ACCESS_DENIED) // have subKeys underneath
{
if (SHDeleteKey(HKEY_LOCAL_MACHINE, sbRegKey) == ERROR_SUCCESS)
goto Exit;
}
SET_HRERR_AND_EXIT(::GetLastError());
}
Exit:
return hr;
}
HRESULT NtDeleteComponentKeyFromMsiUserData(PCWSTR pszComponentRegKeyName)
{
HRESULT hr = S_OK;
CStringBuffer sbRegKey;
LONG iRet;
HKEY hkUserData = NULL;
SIZE_T cchRegKey;
WCHAR bufSID[128]; //S-1-5-21-2127521184-1604012920-1887927527-88882
DWORD cchSID = NUMBER_OF(bufSID);
DWORD index;
IFFALSE_EXIT(sbRegKey.Win32Assign(g_szMSIUserDataTreeKeyName, NUMBER_OF(g_szMSIUserDataTreeKeyName)-1));
IF_NOTSUCCESS_SET_HRERR_EXIT(RegOpenKeyExW(HKEY_LOCAL_MACHINE, sbRegKey, 0, KEY_READ, &hkUserData));
cchRegKey = sbRegKey.Cch();
index = 0;
iRet = RegEnumKeyExW(hkUserData, index, bufSID, &cchSID, NULL, NULL, NULL, NULL);
while ((iRet == ERROR_SUCCESS) || (iRet == ERROR_MORE_DATA))
{
sbRegKey.Left(cchRegKey);
//
// construct RegKey name of a Component
// in the format of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\0020F700D33C1D112897000CF42C6133
//
IFFALSE_EXIT(sbRegKey.Win32EnsureTrailingPathSeparator());
IFFALSE_EXIT(sbRegKey.Win32Append(bufSID, cchSID));
IFFALSE_EXIT(sbRegKey.Win32EnsureTrailingPathSeparator());
IFFALSE_EXIT(sbRegKey.Win32Append(g_szComponentKeyName, NUMBER_OF(g_szComponentKeyName)-1));
IFFALSE_EXIT(sbRegKey.Win32EnsureTrailingPathSeparator());
IFFALSE_EXIT(sbRegKey.Win32Append(pszComponentRegKeyName, wcslen(pszComponentRegKeyName)));
//
// About RegDeleteKey :
// Windows 95/98/Me: The function also deletes all subkeys and values. To delete a key only if the key has no subkeys
// or values, use the SHDeleteEmptyKey function.
//
// Windows NT/2000 or later: The subkey to be deleted must not have subkeys. To delete a key and all its subkeys, you
// need to recursively enumerate the subkeys and delete them individually. To recursively delete keys, use the SHDeleteKey
// function.
iRet = RegDeleteKeyW(HKEY_LOCAL_MACHINE, sbRegKey);
if (iRet != ERROR_SUCCESS)
{
if (iRet == ERROR_FILE_NOT_FOUND) // this RegKey does not exist
{
goto cont;
}
else if (iRet == ERROR_ACCESS_DENIED) // have subKeys underneath
{
if (SHDeleteKey(HKEY_LOCAL_MACHINE, sbRegKey) == ERROR_SUCCESS)
goto cont;
}
SET_HRERR_AND_EXIT(::GetLastError());
}
cont:
index ++;
cchSID = NUMBER_OF(bufSID);
iRet = RegEnumKeyExW(hkUserData, index, bufSID, &cchSID, NULL, NULL, NULL, NULL);
if (cchSID > NUMBER_OF(bufSID))
{
SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
}
if (iRet == ERROR_NO_MORE_ITEMS)
break;
}
if (iRet != ERROR_NO_MORE_ITEMS)
{
SET_HRERR_AND_EXIT(::GetLastError());
}
Exit:
RegCloseKey(hkUserData);
return hr;
}
HRESULT DeleteComponentKeyFromMsiUserData(PCWSTR pszComponentRegKeyName)
{
HRESULT hr = S_OK;
if (GetModuleHandleA("w95upgnt.dll") == NULL) // no Freelibrary is needed, ref counter is not changed
{
// must be upgration from NT(4.0 or 5)to xp
hr = NtDeleteComponentKeyFromMsiUserData(pszComponentRegKeyName);
}
else
{
// must be upgrate from w9x to xp
hr = W98DeleteComponentKeyFromMsiUserData(pszComponentRegKeyName);
}
return hr;
}
// Function:
// (1) open database
// (2) if (this msi contain at least win32 assembly component)
// (3) get this componentID
// (4) delete the RegKey from all subtrees under
// (5) endif
//
HRESULT MigrateSingleFusionWin32AssemblyToXP(PCWSTR filename)
{
HRESULT hr = S_OK;
PMSIHANDLE hdb = NULL;
PMSIHANDLE hView = NULL;
MSIHANDLE hRecord = NULL;
WCHAR sqlbuf[CA_MAX_BUF * 2];
WCHAR szComponentID[CA_MAX_BUF];
DWORD cchComponentID;
WCHAR szComponentRegKey[CA_MAX_BUF];
DWORD cchComponentRegKey;
BOOL fExist;
ULONG iRet;
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiOpenDatabaseW(filename, LPCWSTR(MSIDBOPEN_DIRECT), &hdb));
IFFAILED_EXIT(MSI_IsTableExist(hdb, L"MsiAssembly", fExist));
if ( fExist == FALSE)
goto Exit;
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, ca_sqlQuery[CA_SQL_QUERY_MSIASSEMBLY], &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);
iRet = MsiRecordGetInteger(hRecord, 1);
if ( iRet != MSI_FUSION_WIN32_ASSEMBLY)
continue;
//
// get componentID
//
cchComponentID = NUMBER_OF(szComponentID);
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 3, szComponentID, &cchComponentID));
MsiCloseHandle(hRecord);
break;
}
//
// get Component GUID
//
swprintf(sqlbuf, ca_sqlQuery[CA_SQL_QUERY_COMPONENT_FOR_COMPONENTGUID], szComponentID);
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiDatabaseOpenViewW(hdb, sqlbuf, &hView));
IF_NOTSUCCESS_SET_HRERR_EXIT(::MsiViewExecute(hView, 0));
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiViewFetch(hView, &hRecord));
cchComponentID = NUMBER_OF(szComponentID); // reuse szComponentID
IF_NOTSUCCESS_SET_HRERR_EXIT(MsiRecordGetStringW(hRecord, 1, szComponentID, &cchComponentID));
//
// get MSI-ComponentRegKey
//
cchComponentRegKey = NUMBER_OF(szComponentRegKey);
IFFAILED_EXIT(ConvertComponentGUID(szComponentID, szComponentRegKey, cchComponentRegKey));
// delete MSI-ComponentRegKey from all subtrees of \\install\userdata\user-sid
IFFAILED_EXIT(DeleteComponentKeyFromMsiUserData(szComponentRegKey));
Exit:
MsiCloseHandle(hRecord);
return hr;
}
CDirWalk::ECallbackResult
MsiInstallerDirectoryDirWalkCallback(
CDirWalk::ECallbackReason reason,
CDirWalk* dirWalk
)
{
CDirWalk::ECallbackResult result = CDirWalk::eKeepWalking;
if (reason == CDirWalk::eFile)
{
//
CStringBuffer filename;
if (filename.Win32Assign(dirWalk->m_strParent) == FALSE)
{
goto Error;
}
if (!filename.Win32AppendPathElement(dirWalk->m_strLastObjectFound))
{
goto Error;
}
#if DBG
ASSERT_NTC(IsMsiFile(filename) == TRUE);
#endif
if (!SUCCEEDED(MigrateSingleFusionWin32AssemblyToXP(filename)))
{
goto Error;
}
}
Exit:
return result;
Error:
result = CDirWalk::eError;
goto Exit;
}
HRESULT MsiInstallerDirectoryDirWalk(PCWSTR pszParentDirectory)
{
HRESULT hr = S_OK;
CDirWalk dirWalk;
const static PCWSTR filters[]={L"*.msi"};
PWSTR pszParentDir = NULL;
WCHAR buf[64];
#if DBG
MessageBox(NULL, "In fusemig.dll", "fusemig", MB_OK);
#endif
if (pszParentDirectory == NULL)
{
UINT iret = ExpandEnvironmentStringsW(MsiInstallDir, buf, NUMBER_OF(buf));
if ((iret == 0) || (iret > NUMBER_OF(buf)))
{
SET_HRERR_AND_EXIT(::GetLastError());
}
pszParentDir = buf;
}else
{
pszParentDir = const_cast<PWSTR>(pszParentDirectory);
}
dirWalk.m_fileFiltersBegin = filters;
dirWalk.m_fileFiltersEnd = filters + NUMBER_OF(filters);
dirWalk.m_context = NULL;
dirWalk.m_callback = MsiInstallerDirectoryDirWalkCallback;
IFFALSE_EXIT(dirWalk.m_strParent.Win32Assign(pszParentDir, wcslen(pszParentDir)));
IFFALSE_EXIT(dirWalk.m_strParent.Win32RemoveTrailingPathSeparators());
IFFALSE_EXIT(dirWalk.Walk());
Exit:
return hr;
}