|
|
/*
Copyright (c) Microsoft Corporation */ #include "stdinc.h"
#include "xmlparser.hxx"
#include "fusioneventlog.h"
#include "hashfile.h"
#include "cassemblyrecoveryinfo.h"
#include "recover.h"
#include "sxsprotect.h"
#include "fusionheap.h"
#include "fusionparser.h"
#include "protectionui.h"
#include "msi.h"
#include "sxsp.h"
#include "sxscabinet.h"
class CSetErrorMode { public: CSetErrorMode(UINT uMode) { m_uiPreviousMode = ::SetErrorMode(uMode); } ~CSetErrorMode() { ::SetErrorMode(m_uiPreviousMode); }
private: UINT m_uiPreviousMode;
CSetErrorMode(); CSetErrorMode(const CSetErrorMode &r); void operator =(const CSetErrorMode &r); };
BOOL SxspOpenAssemblyInstallationKey( DWORD dwFlags, DWORD dwAccess, CRegKey &rhkAssemblyInstallation ) { FN_PROLOG_WIN32
rhkAssemblyInstallation = CRegKey::GetInvalidValue();
PARAMETER_CHECK(dwFlags == 0);
IFREGFAILED_ORIGINATE_AND_EXIT( ::RegCreateKeyExW( HKEY_LOCAL_MACHINE, WINSXS_INSTALLATION_INFO_REGKEY, 0, NULL, 0, dwAccess | FUSIONP_KEY_WOW64_64KEY, NULL, &rhkAssemblyInstallation , NULL));
FN_EPILOG }
//
// BUGBUG: The BBT folk need the 'codebase' key to be at the top level.
// Why we're shipping metadata that's only required for an internal
// build tool is beyond my meager understanding.
// - jonwis 07/11/2002
//
#define SXS_BBT_REG_HACK (TRUE)
BOOL SxspAddAssemblyInstallationInfo( DWORD dwFlags, IN CAssemblyRecoveryInfo& AssemblyInfo, IN const CCodebaseInformation& rcCodebase ) /*++
Called by SxsInstallAssemblyW to add the codebase and prompt information to the registry for future use with SxspGetAssemblyInstallationInfoW.
--*/ { FN_PROLOG_WIN32
CFusionRegKey hkAllInstallationInfo; CFusionRegKey hkSingleAssemblyInfo; CStringBuffer buffRegKeyName; const CSecurityMetaData &rcsmdAssemblySecurityData = AssemblyInfo.GetSecurityInformation(); const CBaseStringBuffer &rcbuffAssemblyIdentity = rcsmdAssemblySecurityData.GetTextualIdentity(); ULONG WriteRegFlags = 0; DWORD dwDisposition = 0;
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_INSTALLATION, "SXS: %s - starting\n", __FUNCTION__);
PARAMETER_CHECK((dwFlags & ~(SXSP_ADD_ASSEMBLY_INSTALLATION_INFO_FLAG_REFRESH)) == 0);
if (SXS_AVOID_WRITING_REGISTRY) FN_SUCCESSFUL_EXIT();
//
// Create or open the top-level key - take our name and append the
// key to it.
//
IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(0, KEY_CREATE_SUB_KEY, hkAllInstallationInfo));
//
// Convert back to an identity so we can figure out where to install this data to
//
IFW32FALSE_EXIT(::SxspGenerateAssemblyNameInRegistry(rcbuffAssemblyIdentity, buffRegKeyName));
IFW32FALSE_EXIT( hkAllInstallationInfo.OpenOrCreateSubKey( hkSingleAssemblyInfo, buffRegKeyName, KEY_WRITE | KEY_READ | FUSIONP_KEY_WOW64_64KEY, 0, &dwDisposition));
if (dwFlags & SXSP_ADD_ASSEMBLY_INSTALLATION_INFO_FLAG_REFRESH) { WriteRegFlags |= SXSP_WRITE_PRIMARY_ASSEMBLY_INFO_TO_REGISTRY_KEY_FLAG_REFRESH; #if DBG
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_INSTALLATION, "SXS.DLL: %s - propping recovery flag to WritePrimaryAssemblyInfoToRegistryKey\n", __FUNCTION__); #endif
}
IFW32FALSE_EXIT(AssemblyInfo.PrepareForWriting()); // NTRAID#NTBUG9 - 589798 - 2002/03/26 - xiaoyuw:
// there is no reason to make two functions(Primary Secondary)
IFW32FALSE_EXIT(AssemblyInfo.WritePrimaryAssemblyInfoToRegistryKey(WriteRegFlags, hkSingleAssemblyInfo)); IFW32FALSE_EXIT(AssemblyInfo.WriteSecondaryAssemblyInfoIntoRegistryKey( hkSingleAssemblyInfo ) );
//
// If we got this far, then we've got all the right moves.
//
//
// Are we still being broken for BBT? If so, then write the codebase generated for this
// installation back into the "Codebase" value of the single-assembly-info key. This
// ensures last-installer-wins semantic.
//
#if SXS_BBT_REG_HACK
if ((dwFlags & SXSP_ADD_ASSEMBLY_INSTALLATION_INFO_FLAG_REFRESH) == 0) { IFW32FALSE_EXIT(hkSingleAssemblyInfo.SetValue( CSMD_TOPLEVEL_CODEBASE, rcCodebase.GetCodebase())); } else { #if DBG
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP | FUSION_DBG_LEVEL_INSTALLATION, "SXS.DLL: %s - refresh/wfp/sfc not writing top level codebase\n", __FUNCTION__); #endif
} #endif
FN_EPILOG }
BOOL SxspLookForCDROMLocalPathForURL( IN const CBaseStringBuffer &rbuffURL, OUT CBaseStringBuffer &rbuffLocalPath ) { FN_PROLOG_WIN32
BOOL fFoundMedia = FALSE; CSmallStringBuffer sbIdentData1; CSmallStringBuffer sbIdentData2; CSmallStringBuffer buffDriveStrings; CSmallStringBuffer buffTemp; CStringBufferAccessor acc; SIZE_T HeadLength = 0; PCWSTR wcsCursor = NULL; ULONG ulSerialNumber = 0; WCHAR rgchVolumeName[MAX_PATH]; rgchVolumeName[0] = 0; SIZE_T i = 0; PCWSTR pszSource = rbuffURL; SIZE_T cchTemp = 0;
enum CDRomSearchType { CDRST_Tagfile, CDRST_SerialNumber, CDRST_VolumeName } SearchType;
rbuffLocalPath.Clear();
#define ENTRY(_x, _st) { _x, NUMBER_OF(_x) - 1, _st },
const static struct { PCWSTR pszPrefix; SIZE_T cchPrefix; CDRomSearchType SearchType; } s_rgMap[] = { ENTRY(L"tagfile", CDRST_Tagfile) ENTRY(L"serialnumber", CDRST_SerialNumber) ENTRY(L"volumename", CDRST_VolumeName) };
#undef ENTRY
SearchType = CDRST_Tagfile; // arbitrary initialization to make compiler happy about init only
// occurring in the for loop
for (i=0; i<NUMBER_OF(s_rgMap); i++) { if (::_wcsnicmp(s_rgMap[i].pszPrefix, rbuffURL, s_rgMap[i].cchPrefix) == 0) { HeadLength = s_rgMap[i].cchPrefix; SearchType = s_rgMap[i].SearchType; break; } }
// If it wasn't in the map, it's a bogus cdrom: url so we just skip it.
if (i == NUMBER_OF(s_rgMap)) { #if DBG
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS.DLL: %s() - no prefix found, skipping CDROM Drive %ls\n", __FUNCTION__, static_cast<PCWSTR>(rbuffURL)); #endif
FN_SUCCESSFUL_EXIT(); }
//
// Get the type of identifier here, and then move the cursor past them and
// the slashes in the url.
//
pszSource += HeadLength; pszSource += wcsspn(pszSource, CUnicodeCharTraits::PathSeparators());
//
// Spin past slashes, assign chunklets
//
IFW32FALSE_EXIT(sbIdentData1.Win32Assign(pszSource, wcscspn(pszSource, CUnicodeCharTraits::PathSeparators()))); pszSource += sbIdentData1.Cch(); pszSource += wcsspn(pszSource, CUnicodeCharTraits::PathSeparators());
//
// If this is a tagfile, also get another blobbet of data off the string
//
if (SearchType == CDRST_Tagfile) { IFW32FALSE_EXIT(sbIdentData2.Win32Assign(pszSource, wcscspn(pszSource, CUnicodeCharTraits::PathSeparators()))); pszSource += sbIdentData2.Cch(); pszSource += wcsspn(pszSource, CUnicodeCharTraits::PathSeparators()); } else if (SearchType == CDRST_SerialNumber) { IFW32FALSE_EXIT(CFusionParser::ParseULONG( ulSerialNumber, sbIdentData1, sbIdentData1.Cch(), 16)); }
// Find the CDROM drives...
IFW32ZERO_ORIGINATE_AND_EXIT(cchTemp = ::GetLogicalDriveStringsW(0, NULL)); IFW32FALSE_EXIT(buffDriveStrings.Win32ResizeBuffer(cchTemp + 1, eDoNotPreserveBufferContents));
acc.Attach(&buffDriveStrings);
IFW32ZERO_ORIGINATE_AND_EXIT( ::GetLogicalDriveStringsW( acc.GetBufferCchAsDWORD(), acc));
acc.Detach();
wcsCursor = buffDriveStrings;
//
// Look at all the found drive letters
//
while ((wcsCursor != NULL) && (wcsCursor[0] != L'\0') && !fFoundMedia) { DWORD dwSerialNumber = 0; const UINT uiDriveType = ::GetDriveTypeW(wcsCursor);
if (uiDriveType != DRIVE_CDROM) { wcsCursor += (::wcslen(wcsCursor) + 1); continue; }
CSetErrorMode sem(SEM_FAILCRITICALERRORS); bool fNotReady = false;
IFW32FALSE_ORIGINATE_AND_EXIT_UNLESS2( ::GetVolumeInformationW( wcsCursor, rgchVolumeName, NUMBER_OF(rgchVolumeName), &dwSerialNumber, NULL, NULL, NULL, 0), LIST_2(ERROR_NOT_READY, ERROR_CRC), fNotReady);
if (fNotReady) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS.DLL: %s() - CDROM Drive %ls has no media present or had read errors; skipping\n", __FUNCTION__, wcsCursor);
// skip past this drive
wcsCursor += (::wcslen(wcsCursor) + 1); continue; }
switch (SearchType) { case CDRST_Tagfile: { CFusionFile FileHandle; CStringBufferAccessor acc; DWORD dwTextLength = 0; bool fNoFile = false; CHAR rgchBuffer[32]; rgchBuffer[0] = 0;
IFW32FALSE_EXIT_UNLESS2( FileHandle.Win32CreateFile( sbIdentData1, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING), LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_NOT_READY), fNoFile);
if (fNoFile) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS.DLL: %s() - CDROM Drive %ls could not open tag file \"%ls\"; skipping\n", __FUNCTION__, wcsCursor, static_cast<PCWSTR>(sbIdentData1));
// skip past this drive
wcsCursor += (::wcslen(wcsCursor) + 1); continue; }
buffTemp.Clear();
for (;;) { IFW32FALSE_ORIGINATE_AND_EXIT( ::ReadFile( FileHandle, rgchBuffer, sizeof(rgchBuffer), &dwTextLength, NULL));
IFW32FALSE_EXIT(buffTemp.Win32Append(rgchBuffer, dwTextLength));
if ((dwTextLength != sizeof(rgchBuffer)) || (buffTemp.Cch() > sbIdentData2.Cch())) break; }
fFoundMedia = (::FusionpCompareStrings(buffTemp, sbIdentData2, true) == 0);
break; } case CDRST_SerialNumber: fFoundMedia = (dwSerialNumber == ulSerialNumber); break;
case CDRST_VolumeName: fFoundMedia = (::FusionpCompareStrings(rgchVolumeName, ::wcslen(rgchVolumeName), sbIdentData1, true) == 0); break;
default: INTERNAL_ERROR_CHECK(false); break; }
if (!fFoundMedia) wcsCursor += ::wcslen(wcsCursor) + 1; }
if (fFoundMedia) { IFW32FALSE_EXIT(buffTemp.Win32Assign(wcsCursor, ::wcslen(wcsCursor))); IFW32FALSE_EXIT(buffTemp.Win32AppendPathElement(pszSource, ::wcslen(pszSource))); IFW32FALSE_EXIT(rbuffLocalPath.Win32Assign(buffTemp)); }
FN_EPILOG }
BOOL SxspResolveWinSourceMediaURL( const CBaseStringBuffer &rbuffCodebaseInfo, CBaseStringBuffer &rbuffLocalPath ) { FN_PROLOG_WIN32
CSmallStringBuffer buffWindowsInstallSource; CSmallStringBuffer buffLocalPathTemp; #if DBG
CSmallStringBuffer buffLocalPathCodebasePrefix; #endif
DWORD dwWin32Error = 0; DWORD dwFileAttributes = 0;
const static PCWSTR AssemblySourceStrings[] = { WINSXS_INSTALL_SVCPACK_REGKEY, WINSXS_INSTALL_SOURCEPATH_REGKEY };
SIZE_T iWhichSource = 0; bool fFoundCodebase = false; CFusionRegKey hkSetupInfo; DWORD dwWasFromCDRom = 0;
rbuffLocalPath.Clear();
IFREGFAILED_ORIGINATE_AND_EXIT( ::RegOpenKeyExW( HKEY_LOCAL_MACHINE, WINSXS_INSTALL_SOURCE_BASEDIR, 0, KEY_READ | FUSIONP_KEY_WOW64_64KEY, &hkSetupInfo));
if (!::FusionpRegQueryDwordValueEx( 0, hkSetupInfo, WINSXS_INSTALL_SOURCE_IS_CDROM, &dwWasFromCDRom)) { dwWasFromCDRom = 0; }
for (iWhichSource = 0; (!fFoundCodebase) && iWhichSource < NUMBER_OF(AssemblySourceStrings); iWhichSource++) { IFW32FALSE_EXIT( ::FusionpRegQuerySzValueEx( FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING, hkSetupInfo, AssemblySourceStrings[iWhichSource], buffWindowsInstallSource));
//
// This really _really_ should not be empty. If it is, then someone
// went and fiddled with the registry on us.
//
if (buffWindowsInstallSource.Cch() == 0) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - skipping use of source string \"%ls\" in registry because either missing or null value\n", __FUNCTION__, AssemblySourceStrings[iWhichSource]);
continue; }
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - WFP probing windows source location \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(buffWindowsInstallSource));
//
// If this was from a CD, then spin through the list of CD's in the system
// and see if we can match the codebase against the root dir of the CD
//
if (dwWasFromCDRom) { CSmallStringBuffer buffDriveStrings; CStringBufferAccessor acc; PCWSTR pszCursor = NULL; SIZE_T cchTemp = 0;
IFW32ZERO_EXIT(cchTemp = ::GetLogicalDriveStringsW(0, NULL)); IFW32FALSE_EXIT(buffDriveStrings.Win32ResizeBuffer(cchTemp + 1, eDoNotPreserveBufferContents));
acc.Attach(&buffDriveStrings);
IFW32ZERO_EXIT( ::GetLogicalDriveStringsW( acc.GetBufferCchAsDWORD(), acc.GetBufferPtr()));
acc.Detach();
pszCursor = buffDriveStrings;
while (pszCursor[0] != L'\0') { if (::GetDriveTypeW(pszCursor) == DRIVE_CDROM) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - Scanning CDROM drive \"%ls\" for windows source media\n", __FUNCTION__, pszCursor);
IFW32FALSE_EXIT(buffLocalPathTemp.Win32Assign(pszCursor, ::wcslen(pszCursor))); IFW32FALSE_EXIT(buffLocalPathTemp.Win32AppendPathElement(rbuffCodebaseInfo));
IFW32FALSE_EXIT( ::SxspGetFileAttributesW( buffLocalPathTemp, dwFileAttributes, dwWin32Error, 4, ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_NOT_READY, ERROR_ACCESS_DENIED));
if (dwWin32Error == ERROR_SUCCESS) { #if DBG
buffLocalPathCodebasePrefix.Win32Assign(pszCursor, ::wcslen(pszCursor)); #endif
fFoundCodebase = true; break; }
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - Could not find key file \"%ls\"; moving on to next drive\n", __FUNCTION__, static_cast<PCWSTR>(buffLocalPathTemp)); }
pszCursor += ::wcslen(pszCursor) + 1; }
if (fFoundCodebase) break;
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - Could not find any CDROMs with key file \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(rbuffCodebaseInfo));
buffLocalPathTemp.Clear(); } else { //
// This wasn't a CD-rom installation, so prepend the install source path to
// the string that was passed in.
//
IFW32FALSE_EXIT(buffLocalPathTemp.Win32Assign(buffWindowsInstallSource)); IFW32FALSE_EXIT(buffLocalPathTemp.Win32AppendPathElement(rbuffCodebaseInfo));
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - trying to access windows source file \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(buffLocalPathTemp));
IFW32FALSE_EXIT( ::SxspGetFileAttributesW( buffLocalPathTemp, dwFileAttributes, dwWin32Error, 4, ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_NOT_READY, ERROR_ACCESS_DENIED));
if (dwWin32Error == ERROR_SUCCESS) { #if DBG
buffLocalPathCodebasePrefix.Win32Assign(buffWindowsInstallSource); #endif
fFoundCodebase = true; break; }
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - Unable to find key file \"%ls\"; win32 status = %lu\n", __FUNCTION__, static_cast<PCWSTR>(buffLocalPathTemp), dwWin32Error);
buffLocalPathTemp.Clear(); } if (fFoundCodebase) break; }
IFW32FALSE_EXIT(rbuffLocalPath.Win32Assign(buffLocalPathTemp));
#if DBG
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - buffLocalPathCodebasePrefix \"%ls\" and returning rbuffLocalPath \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(buffLocalPathCodebasePrefix), static_cast<PCWSTR>(rbuffLocalPath) ); #endif
FN_EPILOG }
#define SXSP_REPEAT_UNTIL_LOCAL_PATH_AVAILABLE_FLAG_UI (0x00000001)
BOOL SxspRepeatUntilLocalPathAvailable( IN ULONG Flags, IN const CAssemblyRecoveryInfo &rRecoveryInfo, IN const CCodebaseInformation *pCodeBaseIn, IN SxsWFPResolveCodebase CodebaseType, IN const CBaseStringBuffer &rbuffCodebaseInfo, OUT CBaseStringBuffer &rbuffLocalPath, OUT BOOL &fRetryPressed ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
BOOL fCodebaseOk = FALSE; CSmallStringBuffer buffFinalLocalPath; DWORD dwAttributes = 0;
PARAMETER_CHECK(pCodeBaseIn != NULL);
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - got codebase \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(pCodeBaseIn->GetCodebase()));
rbuffLocalPath.Clear(); fRetryPressed = FALSE;
PARAMETER_CHECK( (CodebaseType == CODEBASE_RESOLVED_URLHEAD_FILE) || (CodebaseType == CODEBASE_RESOLVED_URLHEAD_WINSOURCE) || (CodebaseType == CODEBASE_RESOLVED_URLHEAD_CDROM));
PARAMETER_CHECK((Flags & ~(SXSP_REPEAT_UNTIL_LOCAL_PATH_AVAILABLE_FLAG_UI)) == 0);
#if DBG
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s() CodebaseType : %s (0x%lx)\n", __FUNCTION__, (CodebaseType == CODEBASE_RESOLVED_URLHEAD_FILE) ? "file" : (CodebaseType == CODEBASE_RESOLVED_URLHEAD_WINSOURCE) ? "winsource" : (CodebaseType == CODEBASE_RESOLVED_URLHEAD_CDROM) ? "cdrom" : "", static_cast<ULONG>(CodebaseType) ); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s() rbuffCodebaseInfo : %ls\n", __FUNCTION__, static_cast<PCWSTR>(rbuffCodebaseInfo) ); #endif
for (;;) { bool fNotFound = true;
// First, let's see if we have to do any trickery.
switch (CodebaseType) { case CODEBASE_RESOLVED_URLHEAD_CDROM: IFW32FALSE_EXIT( ::SxspLookForCDROMLocalPathForURL( rbuffCodebaseInfo, buffFinalLocalPath));
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - cdrom: URL resolved to \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(buffFinalLocalPath));
break;
case CODEBASE_RESOLVED_URLHEAD_WINSOURCE: IFW32FALSE_EXIT( ::SxspResolveWinSourceMediaURL( rbuffCodebaseInfo, buffFinalLocalPath));
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - windows source URL resolved to \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(buffFinalLocalPath));
break;
case CODEBASE_RESOLVED_URLHEAD_FILE: IFW32FALSE_EXIT(buffFinalLocalPath.Win32Assign(rbuffCodebaseInfo));
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - file: URL resolved to \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(buffFinalLocalPath));
break; }
if (buffFinalLocalPath.Cch() != 0) { DWORD dwWin32Error = NO_ERROR;
IFW32FALSE_EXIT( ::SxspGetFileAttributesW( buffFinalLocalPath, dwAttributes, dwWin32Error, 5, ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND, ERROR_BAD_NET_NAME, ERROR_BAD_NETPATH, ERROR_ACCESS_DENIED));
if (dwWin32Error == ERROR_SUCCESS) break; }
if ((Flags & SXSP_REPEAT_UNTIL_LOCAL_PATH_AVAILABLE_FLAG_UI) == 0) { buffFinalLocalPath.Clear(); break; }
//
// Nope, didn't find it (or the codebase specified is gone. Ask the user
// to insert media or whatnot so we can find it again.
//
if (fNotFound) { CSXSMediaPromptDialog PromptBox; CSXSMediaPromptDialog::DialogResults result;
IFW32FALSE_EXIT(PromptBox.Initialize(pCodeBaseIn));
IFW32FALSE_EXIT(PromptBox.ShowSelf(result));
if (result == CSXSMediaPromptDialog::DialogCancelled) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - user cancelled media prompt dialog\n", __FUNCTION__);
buffFinalLocalPath.Clear(); break; }
// Otherwise, try again!
fRetryPressed = TRUE; break; } }
IFW32FALSE_EXIT(rbuffLocalPath.Win32Assign(buffFinalLocalPath));
#if DBG
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - returning rbuffLocalPath \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(rbuffLocalPath) ); #endif
FN_EPILOG }
BOOL SxspAskDarwinDoReinstall( IN PCWSTR buffLocalPath) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
UINT (WINAPI * pfnMsiProvideAssemblyW)( LPCWSTR wzAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwUnused, LPWSTR lpPathBuf, DWORD *pcchPathBuf) = NULL;
INSTALLUILEVEL (WINAPI * pfnMsiSetInternalUI)( INSTALLUILEVEL dwUILevel, // UI level
HWND *phWnd) // handle of owner window
= NULL;
INSTALLUILEVEL OldInstallUILevel; CDynamicLinkLibrary hMSIDll;
//
// We should hoist the load/unload out of the loop.
//
IFW32FALSE_ORIGINATE_AND_EXIT(hMSIDll.Win32LoadLibrary(L"msi.dll")); IFW32NULL_ORIGINATE_AND_EXIT(hMSIDll.Win32GetProcAddress("MsiProvideAssemblyW", &pfnMsiProvideAssemblyW)); IFW32NULL_ORIGINATE_AND_EXIT(hMSIDll.Win32GetProcAddress("MsiSetInternalUI", &pfnMsiSetInternalUI));
// No real failure from this API...
OldInstallUILevel = (*pfnMsiSetInternalUI)(INSTALLUILEVEL_NONE, NULL); IFREGFAILED_ORIGINATE_AND_EXIT((*pfnMsiProvideAssemblyW)(buffLocalPath, NULL, REINSTALLMODE_FILEREPLACE, MSIASSEMBLYINFO_WIN32ASSEMBLY, NULL, NULL)); // and restore it
(*pfnMsiSetInternalUI)(OldInstallUILevel, NULL);
fSuccess = TRUE; Exit: return fSuccess; }
BOOL SxspRecoverAssembly( IN const CAssemblyRecoveryInfo &AsmRecoveryInfo, OUT SxsRecoveryResult &rStatus ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); CSmallStringBuffer sbPerTypeCodebaseString; SxsWFPResolveCodebase CodebaseType; SXS_INSTALLW Install = { sizeof(SXS_INSTALLW) }; Install.dwFlags |= SXS_INSTALL_FLAG_REPLACE_EXISTING; bool fNotFound = false; CCodebaseInformationList::ConstIterator CodebaseIterator; const CCodebaseInformationList& CodebaseList = AsmRecoveryInfo.GetCodeBaseList(); ULONG RetryNumber = 0; BOOL fRetryPressed = FALSE; ULONG RetryPressedCount = 0;
rStatus = Recover_Unknown;
//
// As long as they hit retry, keep putting up the ui, cycling through the paths.
//
for (RetryNumber = 0 ; (rStatus != Recover_OK) && RetryNumber != 3 ; RetryNumber += (fRetryPressed ? 0 : 1)) { for (CodebaseIterator = CodebaseList.Begin() ; (rStatus != Recover_OK) && CodebaseIterator != CodebaseList.End() ; ++CodebaseIterator) { fRetryPressed = FALSE;
//
// eg:
// xcopy /fiver \\winbuilds\release\main\usa\latest.idw\x86fre\pro\i386 x:\blah\blah\i386
//
// buffLocalPath x:\blah\blah\i386\asms\1000\msft\windows\gdiplus\gdiplus.man
// buffLocalPathCodebasePrefix x:\blah\blah
// buffCodebaseMetaPrefix x-ms-windows://
// buffCodebaseTail \i386\asms\1000\msft\windows\gdiplus\gdiplus.man.
//
// Install.lpCodeBaseUrl x:\blah\blah
// Install.lpManifestPath x:\blah\blah\i386\asms\1000\msft\windows\gdiplus\gdiplus.man
//
CSmallStringBuffer buffLocalPath; CSmallStringBuffer buffCodebaseTail; CTinyStringBuffer buffExtension; const static UNICODE_STRING UnicodeString_dot_cab = RTL_CONSTANT_STRING(L".cab"); const static UNICODE_STRING UnicodeString_cab = RTL_CONSTANT_STRING(L"cab");
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - beginning recovery of assembly directory \"%ls\"\n", __FUNCTION__, static_cast<PCWSTR>(AsmRecoveryInfo.GetAssemblyDirectoryName()));
//
// Go try and get the codebase resolved
//
rStatus = Recover_Unknown;
IFW32FALSE_EXIT( ::SxspDetermineCodebaseType( // this should be cached in m_CodebaseInfo.
CodebaseIterator->GetCodebase(), CodebaseType, &buffCodebaseTail)); if (CodebaseType == CODEBASE_RESOLVED_URLHEAD_UNKNOWN) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - Couldn't figure out what to do with codebase \"%ls\"; skipping\n", __FUNCTION__, static_cast<PCWSTR>(CodebaseIterator->GetCodebase()));
rStatus = Recover_SourceMissing; continue; }
if (!::SxspRepeatUntilLocalPathAvailable( (RetryNumber == 2 && (CodebaseIterator == (CodebaseList.Begin() + (RetryPressedCount % CodebaseList.GetSize())))) ? SXSP_REPEAT_UNTIL_LOCAL_PATH_AVAILABLE_FLAG_UI : 0, AsmRecoveryInfo, &*CodebaseIterator, CodebaseType, buffCodebaseTail, buffLocalPath, fRetryPressed)) { continue; } if (fRetryPressed) RetryPressedCount += 1;
if (buffLocalPath.Cch() == 0 ) { ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - unable to resolve codebase \"%ls\" to a local path\n", __FUNCTION__, static_cast<PCWSTR>(CodebaseIterator->GetCodebase()));
rStatus = Recover_ManifestMissing; continue; }
Install.dwFlags |= SXS_INSTALL_FLAG_REFRESH;
IFW32FALSE_EXIT(buffLocalPath.Win32GetPathExtension(buffExtension)); if (::FusionpEqualStringsI(buffExtension, &UnicodeString_cab) || ::FusionpEqualStringsI(buffExtension, &UnicodeString_dot_cab) ) {
IFW32FALSE_EXIT_UNLESS2(::SxspRecoverAssemblyFromCabinet( buffLocalPath, AsmRecoveryInfo.GetSecurityInformation().GetTextualIdentity(), &Install), LIST_2(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND), fNotFound); } else { Install.lpManifestPath = buffLocalPath;
IFW32FALSE_EXIT_UNLESS2( ::SxsInstallW(&Install), LIST_2(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND), fNotFound); }
if (fNotFound) { rStatus = Recover_ManifestMissing; // may also be a file in the assembly missing
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS: %s - installation from %ls failed with win32 last error = %ld\n", __FUNCTION__, static_cast<PCWSTR>(buffLocalPath), ::FusionpGetLastWin32Error()); continue; } else { rStatus = Recover_OK; break; } }
//
// Last chance - try MSI reinstallation
//
if ( rStatus != Recover_OK ) { BOOL fMsiKnowsAssembly = FALSE; const CBaseStringBuffer &rcbuffIdentity = AsmRecoveryInfo.GetSecurityInformation().GetTextualIdentity(); IFW32FALSE_EXIT(::SxspDoesMSIStillNeedAssembly( rcbuffIdentity, fMsiKnowsAssembly));
if ( fMsiKnowsAssembly && ::SxspAskDarwinDoReinstall(rcbuffIdentity)) { rStatus = Recover_OK; break; } } } fSuccess = TRUE; Exit: CSxsPreserveLastError ple;
//
// Here we have to check something. If the assembly wasn't able to be reinstalled,
// then we do the following:
//
// 1. Rename away old assembly directory to .old or similar
// 2. Log a message to the event log
//
DWORD dwMessageToPrint = 0;
if (rStatus != Recover_OK) { dwMessageToPrint = MSG_SXS_SFC_ASSEMBLY_RESTORE_FAILED; } else { dwMessageToPrint = MSG_SXS_SFC_ASSEMBLY_RESTORE_SUCCESS; }
::FusionpDbgPrintEx( FUSION_DBG_LEVEL_WFP, "SXS.DLL: %s: Recovery of assembly \"%ls\" resulted in fSuccess=%d rStatus=%d\n", __FUNCTION__, static_cast<PCWSTR>(AsmRecoveryInfo.GetAssemblyDirectoryName()), fSuccess, rStatus);
::FusionpLogError( dwMessageToPrint, CUnicodeString(AsmRecoveryInfo.GetAssemblyDirectoryName()));
ple.Restore();
return fSuccess; }
|