Ejemplo n.º 1
0
static HRESULT AddDetectedTargetProduct(
    __in BURN_PACKAGES* pPackages,
    __in BURN_PACKAGE* pPackage,
    __in MSIINSTALLCONTEXT context,
    __in DWORD dwOrder,
    __in_z LPCWSTR wzProductCode
    )
{
    HRESULT hr = S_OK;

    hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackage->Msp.rgTargetProducts), pPackage->Msp.cTargetProductCodes + 1, sizeof(BURN_MSPTARGETPRODUCT), 5);
    ExitOnFailure(hr, "Failed to ensure enough target product codes were allocated.");

    hr = ::StringCchCopyW(pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].wzTargetProductCode, countof(pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].wzTargetProductCode), wzProductCode);
    ExitOnFailure(hr, "Failed to copy target product code.");

    DeterminePatchChainedTarget(pPackages, pPackage, wzProductCode, 
                                &pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].pChainedTargetPackage,
                                &pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].fSlipstream);

    pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].context = context;
    pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].dwOrder = dwOrder;
    ++pPackage->Msp.cTargetProductCodes;

LExit:
    return hr;
}
Ejemplo n.º 2
0
DAPI_(HRESULT) BalInfoAddRelatedBundleAsPackage(
    __in BAL_INFO_PACKAGES* pPackages,
    __in LPCWSTR wzId,
    __in BOOTSTRAPPER_RELATION_TYPE relationType,
    __in BOOL /*fPerMachine*/
    )
{
    HRESULT hr = S_OK;
    BAL_INFO_PACKAGE_TYPE type = BAL_INFO_PACKAGE_TYPE_UNKNOWN;
    BAL_INFO_PACKAGE* pPackage = NULL;

    // Ensure we have a supported relation type.
    switch (relationType)
    {
    case BOOTSTRAPPER_RELATION_ADDON:
        type = BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON;
        break;

    case BOOTSTRAPPER_RELATION_PATCH:
        type = BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH;
        break;

    case BOOTSTRAPPER_RELATION_UPGRADE:
        type = BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE;
        break;

    default:
        ExitOnFailure1(hr = E_INVALIDARG, "Unknown related bundle type: %u", relationType);
    }

    // Check to see if the bundle is already in the list of packages.
    for (DWORD i = 0; i < pPackages->cPackages; ++i)
    {
        if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1))
        {
            ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS));
        }
    }

    // Add the related bundle as a package.
    hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackages->rgPackages), pPackages->cPackages + 1, sizeof(BAL_INFO_PACKAGE), 2);
    ExitOnFailure(hr, "Failed to allocate memory for related bundle package information.");

    pPackage = pPackages->rgPackages + pPackages->cPackages;
    ++pPackages->cPackages;

    hr = StrAllocString(&pPackage->sczId, wzId, 0);
    ExitOnFailure(hr, "Failed to copy related bundle package id.");

    pPackage->type = type;

    // TODO: try to look up the DisplayName and Description in Add/Remove Programs with the wzId.

LExit:
    return hr;
}
Ejemplo n.º 3
0
static HRESULT EnsureTokenStack(
    __in JSON_WRITER* pWriter
    )
{
    HRESULT hr = S_OK;
    DWORD cNumAlloc = pWriter->cTokens != 0 ? pWriter->cTokens : 0;

    hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pWriter->rgTokenStack), cNumAlloc, sizeof(JSON_TOKEN), JSON_STACK_INCREMENT);
    ExitOnFailure(hr, "Failed to allocate JSON token stack.");

    if (0 == pWriter->cTokens)
    {
        pWriter->rgTokenStack[0] = JSON_TOKEN_NONE;
        ++pWriter->cTokens;
    }

LExit:
    return hr;
}
Ejemplo n.º 4
0
HRESULT UtilGrowDatabaseList(
    __inout BROWSE_DATABASE_LIST *pbdlDatabaseList,
    __out DWORD *pdwNewIndex
    )
{
    HRESULT hr = S_OK;

    ::EnterCriticalSection(&pbdlDatabaseList->cs);

    // TODO: make UI thread appropriately enter database list critical section. For now, grow this array by 10 at a time
    hr = MemEnsureArraySize(reinterpret_cast<void **>(&(pbdlDatabaseList->rgDatabases)), pbdlDatabaseList->cDatabases + 1, sizeof(BROWSE_DATABASE), 10);
    ExitOnFailure(hr, "Failed to allocate space for one more database struct");

    *pdwNewIndex = pbdlDatabaseList->cDatabases;
    ++(pbdlDatabaseList->cDatabases);

    ::InitializeCriticalSection(&pbdlDatabaseList->rgDatabases[pbdlDatabaseList->cDatabases-1].cs);

    ::LeaveCriticalSection(&pbdlDatabaseList->cs);

LExit:
    return hr;
}
Ejemplo n.º 5
0
        ::FreeLibrary(vhModule);
        vhModule = NULL;
    }
}

static HRESULT RmuApplicationArrayAlloc(
    __deref_inout_ecount(*pcApplications) RM_UNIQUE_PROCESS **prgApplications,
    __inout LPUINT pcApplications,
    __in DWORD dwProcessId,
    __in FILETIME ProcessStartTime
    )
{
    HRESULT hr = S_OK;
    RM_UNIQUE_PROCESS *pApplication = NULL;

    hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgApplications), *pcApplications + 1, sizeof(RM_UNIQUE_PROCESS), ARRAY_GROWTH_SIZE);
    ExitOnFailure(hr, "Failed to allocate memory for the application array.");

    pApplication = static_cast<RM_UNIQUE_PROCESS*>(&(*prgApplications)[*pcApplications]);
    pApplication->dwProcessId = dwProcessId;
    pApplication->ProcessStartTime = ProcessStartTime;

    ++(*pcApplications);

LExit:
    return hr;
}

static HRESULT RmuApplicationArrayFree(
    __in RM_UNIQUE_PROCESS *rgApplications
    )
Ejemplo n.º 6
0
HRESULT ProductSyncValues(
    __in CFGDB_STRUCT *pcdb1,
    __in CFGDB_STRUCT *pcdb2,
    __in BOOL fAllowLocalToReceiveData,
    __in STRINGDICT_HANDLE shDictValuesSeen,
    __out CONFLICT_PRODUCT **ppcpProduct
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczName = NULL;
    DWORD dwInserting = 0;
    SCE_QUERY_HANDLE sqhHandle = NULL;
    SCE_QUERY_RESULTS_HANDLE sqrhResults = NULL;
    SCE_ROW_HANDLE sceRow = NULL;
    DWORD dwFoundIndex = 0;
    DWORD dwSubsumeIndex = 0;
    BOOL fSame = FALSE;
    BOOL fFirstIsLocal = (NULL == pcdb1->pcdbLocal);

    CFG_ENUMERATION * valueHistory1 = NULL;
    DWORD dwCfgCount1 = 0;
    CFG_ENUMERATION * valueHistory2 = NULL;
    DWORD dwCfgCount2 = 0;

    hr = SceBeginQuery(pcdb1->psceDb, VALUE_INDEX_TABLE, 0, &sqhHandle);
    ExitOnFailure(hr, "Failed to begin query into value table");

    hr = SceSetQueryColumnDword(sqhHandle, pcdb1->dwAppID);
    ExitOnFailure(hr, "Failed to set query column dword to: %u", pcdb1->dwAppID);

    hr = SceRunQueryRange(&sqhHandle, &sqrhResults);
    if (E_NOTFOUND == hr)
    {
        ExitFunction1(hr = S_OK);
    }
    ExitOnFailure(hr, "Failed to enumerate values for product %u", pcdb1->dwAppID);

    hr = SceGetNextResultRow(sqrhResults, &sceRow);
    while (E_NOTFOUND != hr)
    {
        ExitOnFailure(hr, "Failed to get next row from query into value table");

        CfgReleaseEnumeration(valueHistory1);
        valueHistory1 = NULL;
        CfgReleaseEnumeration(valueHistory2);
        valueHistory2 = NULL;

        hr = SceGetColumnString(sceRow, VALUE_COMMON_NAME, &sczName);
        ExitOnFailure(hr, "Failed to get value name");

        if (NULL != shDictValuesSeen)
        {
            hr = DictKeyExists(shDictValuesSeen, sczName);
            if (E_NOTFOUND == hr)
            {
                hr = DictAddKey(shDictValuesSeen, sczName);
                ExitOnFailure(hr, "Failed to add to dictionary value: %ls", sczName);
            }
            else
            {
                ExitOnFailure(hr, "Failed to check if key exists: %ls", sczName);

                // This value was already synced; skip it!
                goto Skip;
            }
        }

        // Exclude legacy detect cache values, they should never be synced off the machine
        // TODO: when we support per-machine settings, migrate this to use that feature
        if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczName, lstrlenW(wzLegacyDetectCacheValuePrefix), wzLegacyDetectCacheValuePrefix, lstrlenW(wzLegacyDetectCacheValuePrefix)))
        {
            goto Skip;
        }

        // First check if the values are identical. Even if they were set by different folks at different times,
        // same value means nothing to sync.
        hr = ValueMatch(sczName, pcdb1, pcdb2, sceRow, &fSame);
        ExitOnFailure(hr, "Failed to check if values are identical");

        if (fSame)
        {
            goto Skip;
        }

        // Get history of the value in db2
        hr = EnumPastValues(pcdb2, sczName, &valueHistory2, &dwCfgCount2);
        if (E_NOTFOUND == hr)
        {
            hr = S_OK;
        }
        ExitOnFailure(hr, "Failed to enumerate previous values in db2");

        // Get history of the value in db1
        hr = EnumPastValues(pcdb1, sczName, &valueHistory1, &dwCfgCount1);
        ExitOnFailure(hr, "Found value in db1, but failed to enumerate previous values in db1 while searching for conflicts");

        if (0 == dwCfgCount2)
        {
            if (fFirstIsLocal || fAllowLocalToReceiveData)
            {
                hr = ValueTransferFromHistory(pcdb2, valueHistory1, 0, pcdb1);
                ExitOnFailure(hr, "Failed to transfer history (due to value not present) from db 2 to db 1 for value %ls", sczName);
            }

            goto Skip;
        }

        // Don't write anything to db2 if it's local and we're told not to
        if (fFirstIsLocal || fAllowLocalToReceiveData)
        {
            // We first check the latest value. However, if the previous value is identical (same type & value, just different source), check for subsumation of that too.
            // This reduces unnecessary conflicts in rare corner case scenarios.
            dwSubsumeIndex = dwCfgCount2;
            do
            {
                --dwSubsumeIndex;

                // Check if the last history entry for database 2 exists in the database 1 - if it does, database 2's changes are subsumed
                hr = EnumFindValueInHistory(valueHistory1, dwCfgCount1, valueHistory2->valueHistory.rgcValues + dwSubsumeIndex, &dwFoundIndex);
                if (S_OK == hr)
                {
                    // Database 2 is subsumed - pipe over all the newest history entries
                    hr = ValueTransferFromHistory(pcdb2, valueHistory1, dwFoundIndex + 1, pcdb1);
                    ExitOnFailure(hr, "Failed to transfer history (due to history subsumed) from db 1 to db 2 for value %ls", sczName);

                    goto Skip;
                }
                else if (E_NOTFOUND == hr)
                {
                    hr = S_OK;
                }
                else
                {
                    ExitOnFailure(hr, "Failed to check if db2's value history is subsumed by db1's value history");
                }

                if (0 < dwSubsumeIndex)
                {
                    hr = ValueCompare(valueHistory2->valueHistory.rgcValues + dwSubsumeIndex, valueHistory2->valueHistory.rgcValues + dwSubsumeIndex - 1, FALSE, &fSame);
                    ExitOnFailure(hr, "Failed to check if value and previous value in database 2 are equivalent");
                }
            }
            while (0 < dwSubsumeIndex && fSame);
        }

        // Don't write anything to db1 if it's local and we're told not to
        if (!fFirstIsLocal || fAllowLocalToReceiveData)
        {
            // We first check the latest value. However, if the previous value is identical (same type & value, just different source), check for subsumation of that too.
            // This reduces unnecessary conflicts in rare corner case scenarios.
            dwSubsumeIndex = dwCfgCount1;
            do
            {
                --dwSubsumeIndex;

                hr = EnumFindValueInHistory(valueHistory2, dwCfgCount2, valueHistory1->valueHistory.rgcValues + dwSubsumeIndex, &dwFoundIndex);
                if (S_OK == hr)
                {
                    // Database 1 is subsumed - pipe over all the newest history entries
                    hr = ValueTransferFromHistory(pcdb1, valueHistory2, dwFoundIndex + 1, pcdb2);
                    ExitOnFailure(hr, "Failed to transfer history (due to history subsumed) from db 2 to db 1 for value %ls", sczName);

                    goto Skip;
                }
                else if (E_NOTFOUND == hr)
                {
                    hr = S_OK;
                }
                else
                {
                    ExitOnFailure(hr, "Failed to check if db1's value history is subsumed by db2's value history");
                }

                if (0 < dwSubsumeIndex)
                {
                    hr = ValueCompare(valueHistory1->valueHistory.rgcValues + dwSubsumeIndex, valueHistory1->valueHistory.rgcValues + dwSubsumeIndex - 1, FALSE, &fSame);
                    ExitOnFailure(hr, "Failed to check if value and previous value in database 1 are equivalent");
                }
            }
            while (0 < dwSubsumeIndex && fSame);
        }

        // OK, we have a conflict. Report it.
        if (NULL == *ppcpProduct)
        {
            *ppcpProduct = static_cast<CONFLICT_PRODUCT *>(MemAlloc(sizeof(CONFLICT_PRODUCT), TRUE));
            ExitOnNull(*ppcpProduct, hr, E_OUTOFMEMORY, "Failed to allocate product conflict struct");

            (*ppcpProduct)->cValues = 1;
        }
        else
        {
            ++(*ppcpProduct)->cValues;
        }

        hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgcesValueEnumLocal), (*ppcpProduct)->cValues, sizeof(CFG_ENUMERATION *), 10);
        ExitOnFailure(hr, "Failed to ensure product local value conflict array size");
        hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgdwValueCountLocal), (*ppcpProduct)->cValues, sizeof(DWORD), 10);
        ExitOnFailure(hr, "Failed to ensure product local value conflict count array size");
        hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgcesValueEnumRemote), (*ppcpProduct)->cValues, sizeof(CFG_ENUMERATION *), 10);
        ExitOnFailure(hr, "Failed to ensure product remote value conflict array size");
        hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgdwValueCountRemote), (*ppcpProduct)->cValues, sizeof(DWORD), 10);
        ExitOnFailure(hr, "Failed to ensure product remote value conflict count array size");
        hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgrcValueChoices), (*ppcpProduct)->cValues, sizeof(RESOLUTION_CHOICE), 10);
        ExitOnFailure(hr, "Failed to ensure product value resolution choice array size");

        dwInserting = (*ppcpProduct)->cValues - 1;

        // Neither is subsumed by the other, so we have conflicts - report them
        if (fFirstIsLocal)
        {
            hr = ConflictGetList(reinterpret_cast<const CFG_ENUMERATION *>(valueHistory1), dwCfgCount1,
                reinterpret_cast<const CFG_ENUMERATION *>(valueHistory2), dwCfgCount2,
                &((*ppcpProduct)->rgcesValueEnumLocal[dwInserting]), &(*ppcpProduct)->rgdwValueCountLocal[dwInserting],
                &((*ppcpProduct)->rgcesValueEnumRemote[dwInserting]), &(*ppcpProduct)->rgdwValueCountRemote[dwInserting]);
        }
        else
        {
            hr = ConflictGetList(reinterpret_cast<const CFG_ENUMERATION *>(valueHistory2), dwCfgCount2,
                reinterpret_cast<const CFG_ENUMERATION *>(valueHistory1), dwCfgCount1,
                &((*ppcpProduct)->rgcesValueEnumLocal[dwInserting]), &(*ppcpProduct)->rgdwValueCountLocal[dwInserting],
                &((*ppcpProduct)->rgcesValueEnumRemote[dwInserting]), &(*ppcpProduct)->rgdwValueCountRemote[dwInserting]);
        }
        ExitOnFailure(hr, "Failed to get conflict list");

    Skip:
        ReleaseNullSceRow(sceRow);
        hr = SceGetNextResultRow(sqrhResults, &sceRow);
    }

    hr = S_OK;

LExit:
    ReleaseSceQuery(sqhHandle);
    ReleaseSceQueryResults(sqrhResults);
    ReleaseSceRow(sceRow);
    CfgReleaseEnumeration(valueHistory1);
    CfgReleaseEnumeration(valueHistory2);
    ReleaseStr(sczName);

    return hr;
}
Ejemplo n.º 7
0
HRESULT LegacySyncSetProduct(
    __in CFGDB_STRUCT *pcdb,
    __inout LEGACY_SYNC_SESSION *pSyncSession,
    __in LPCWSTR wzName
    )
{
    HRESULT hr = S_OK;
    LEGACY_SYNC_PRODUCT_SESSION *pSyncProductSession = &pSyncSession->syncProductSession;
    LEGACY_FILE *pFile = NULL;
    LEGACY_FILE_SPECIAL *pFileSpecial = NULL;
    LEGACY_INI_FILE *pIniFile = NULL;
    CONFIG_VALUE cvManifestContents = { };
    CONFIG_VALUE cvManifestConvertedToBlob = { };
    SCE_ROW_HANDLE sceManifestValueRow = NULL;
    LPWSTR sczManifestValueName = NULL;
    BOOL fWasRegistered = FALSE;
    BYTE *pbManifestBuffer = NULL;
    SIZE_T iManifestBuffer = 0;
    LPWSTR sczBlobManifestAsString = NULL;

    if (pSyncSession->fInSceTransaction)
    {
        SceRollbackTransaction(pcdb->psceDb);
        pSyncSession->fInSceTransaction = FALSE;
    }

    hr = ProductGetLegacyManifestValueName(wzName, &sczManifestValueName);
    ExitOnFailure(hr, "Failed to get legacy manifest value name");

    ManifestFreeProductStruct(&pSyncProductSession->product);
    ZeroMemory(&pSyncProductSession->product, sizeof(pSyncProductSession->product));

    for (DWORD i = 0; i < pSyncProductSession->cIniFiles; ++i)
    {
        IniFree(pSyncProductSession->rgIniFiles + i);
    }
    ReleaseNullMem(pSyncProductSession->rgIniFiles);
    pSyncProductSession->cIniFiles = 0;

    ReleaseNullDict(pSyncProductSession->shDictValuesSeen);
    ReleaseNullDict(pSyncProductSession->shIniFilesByNamespace);

    hr = DictCreateStringList(&pSyncProductSession->shDictValuesSeen, 0, DICT_FLAG_CASEINSENSITIVE);
    ExitOnFailure(hr, "Failed to create dictionary of values seen");

    hr = DictCreateWithEmbeddedKey(&pSyncProductSession->shIniFilesByNamespace, 0, reinterpret_cast<void **>(&pSyncProductSession->rgIniFiles), offsetof(LEGACY_INI_FILE, sczNamespace), DICT_FLAG_CASEINSENSITIVE);
    ExitOnFailure(hr, "Failed to create ini file dictionary");

    hr = DictCreateWithEmbeddedKey(&pSyncProductSession->product.detect.shCachedDetectionPropertyValues, offsetof(LEGACY_CACHED_DETECTION_RESULT, sczPropertyName), reinterpret_cast<void **>(&pSyncProductSession->product.detect.rgCachedDetectionProperties), 0, DICT_FLAG_CASEINSENSITIVE);
    ExitOnFailure(hr, "Failed to create cached detection property values dictionary");

    hr = ValueFindRow(pcdb, pcdb->dwCfgAppID, sczManifestValueName, &sceManifestValueRow);
    ExitOnFailure(hr, "Failed to find config value for legacy manifest (AppID: %u, Config Value named: %ls)", pcdb->dwCfgAppID, sczManifestValueName);

    hr = ValueRead(pcdb, sceManifestValueRow, &cvManifestContents);
    ExitOnFailure(hr, "Failed to read manifest contents");

    // TODO: someday remove this temporary conversion code when we feel confident nobody has old databases with old manifests laying around
    if (VALUE_STRING == cvManifestContents.cvType)
    {
        LogStringLine(REPORT_STANDARD, "Converting manifest value named %ls from string to blob value", sczManifestValueName);

        hr = ValueSetBlob(reinterpret_cast<BYTE *>(cvManifestContents.string.sczValue), lstrlenW(cvManifestContents.string.sczValue) * sizeof(WCHAR), FALSE, NULL, pcdb->sczGuid, &cvManifestConvertedToBlob);
        ExitOnFailure(hr, "Failed to set converted manifest value in memory");

        hr = ValueWrite(pcdb, pcdb->dwCfgAppID, sczManifestValueName, &cvManifestConvertedToBlob, TRUE, NULL);
        ExitOnFailure(hr, "Failed to set converted manifest blob: %ls", sczManifestValueName);

        ReleaseNullSceRow(sceManifestValueRow);
        ReleaseNullCfgValue(cvManifestContents);
        hr = ValueFindRow(pcdb, pcdb->dwCfgAppID, sczManifestValueName, &sceManifestValueRow);
        ExitOnFailure(hr, "Failed to find config value for legacy manifest after conversion (AppID: %u, Config Value named: %ls)", pcdb->dwCfgAppID, sczManifestValueName);

        hr = ValueRead(pcdb, sceManifestValueRow, &cvManifestContents);
        ExitOnFailure(hr, "Failed to read converted manifest contents");
    }

    if (VALUE_BLOB != cvManifestContents.cvType)
    {
        hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
        ExitOnFailure(hr, "Stored manifest value was not of type blob");
    }

    if (CFG_BLOB_DB_STREAM != cvManifestContents.blob.cbType)
    {
        hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
        ExitOnFailure(hr, "Stored manifest blob was not a database stream");
    }

    hr = StreamRead(pcdb, cvManifestContents.blob.dbstream.dwContentID, NULL, &pbManifestBuffer, &iManifestBuffer);
    ExitOnFailure(hr, "Failed to get binary content of blob named: %ls, with content ID: %u", sczManifestValueName, pcdb->dwCfgAppID);

    hr = StrAllocString(&sczBlobManifestAsString, reinterpret_cast<LPWSTR>(pbManifestBuffer), iManifestBuffer / sizeof(WCHAR));
    ExitOnFailure(hr, "Failed to add null terminator to manifest blob");

    hr = ParseManifest(sczBlobManifestAsString, &pSyncProductSession->product);
    ExitOnFailure(hr, "Failed to parse manifest");

    hr = ProductSet(pcdb, wzName, wzLegacyVersion, wzLegacyPublicKey, FALSE, NULL);
    ExitOnFailure(hr, "Failed to set product");

    hr = ProductIsRegistered(pcdb, pcdb->sczProductName, wzLegacyVersion, wzLegacyPublicKey, &fWasRegistered);
    ExitOnFailure(hr, "Failed to check if product is registered");

    hr = DetectProduct(pcdb, !pSyncSession->fDetect, &pSyncSession->arpProducts, &pSyncSession->exeProducts, pSyncProductSession);
    ExitOnFailure(hr, "Failed to detect product with AppID: %u", pcdb->dwAppID);

    // Don't bother writing new registration state data to the database if detect is disabled
    if (pSyncSession->fDetect)
    {
        hr = UpdateProductRegistrationState(pcdb, pSyncProductSession, pcdb->sczProductName, wzLegacyVersion, wzLegacyPublicKey);
        ExitOnFailure(hr, "Failed to update product registration state");
    }

    hr = ProductIsRegistered(pcdb, pcdb->sczProductName, wzLegacyVersion, wzLegacyPublicKey, &pSyncProductSession->fRegistered);
    ExitOnFailure(hr, "Failed to check if product is registered");

    pSyncProductSession->fNewlyRegistered = (!fWasRegistered && pSyncProductSession->fRegistered);

    for (DWORD i = 0; i < pSyncProductSession->product.cFiles; ++i)
    {
        pFile = pSyncProductSession->product.rgFiles + i;

        hr = UtilExpandLegacyPath(pFile->sczLocation, &pSyncProductSession->product.detect, &pFile->sczExpandedPath);
        if (E_NOTFOUND == hr)
        {
            hr = S_OK;
        }

        if (NULL != pFile->sczExpandedPath)
        {
            for (DWORD j = 0; j < pFile->cFileSpecials; ++j)
            {
                pFileSpecial = pFile->rgFileSpecials + j;

                if (0 < pFileSpecial->cIniInfo)
                {
                    hr = MemEnsureArraySize(reinterpret_cast<void **>(&pSyncProductSession->rgIniFiles), pSyncProductSession->cIniFiles + 1, sizeof(LEGACY_INI_FILE), 5);
                    ExitOnFailure(hr, "Failed to grow active IniFiles array");

                    pIniFile = pSyncProductSession->rgIniFiles + pSyncProductSession->cIniFiles;

                    hr = IniFileOpen(pFile, pFileSpecial, pFileSpecial->rgIniInfo, pIniFile);
                    ExitOnFailure(hr, "Failed to parse INI file");

                    hr = DictAddValue(pSyncProductSession->shIniFilesByNamespace, pIniFile);
                    ExitOnFailure(hr, "Failed to add INI file to dict for namespace: %ls", pIniFile->sczNamespace);

                    ++pSyncProductSession->cIniFiles;
                }
            }
        }
    }

    // IMPORTANT: Put all legacy database actions into a separate transaction
    // for each product. In the case of any kind of failure, it's OK to leave
    // changes written to local machine registry / file system, but not the
    // legacy database - they'll just appear as local machine changes on next
    // sync, and everything will be happy. The other way around is NOT happy,
    // because every sync would create another history entry, ad infinitum!
    hr = SceBeginTransaction(pcdb->psceDb);
    ExitOnFailure(hr, "Failed to begin transaction");
    pSyncSession->fInSceTransaction = TRUE;

LExit:
    ReleaseSceRow(sceManifestValueRow);
    ReleaseCfgValue(cvManifestContents);
    ReleaseCfgValue(cvManifestConvertedToBlob);
    ReleaseStr(sczManifestValueName);
    ReleaseMem(pbManifestBuffer);
    ReleaseStr(sczBlobManifestAsString);

    return hr;
}
Ejemplo n.º 8
0
static HRESULT PlanTargetProduct(
    __in BOOTSTRAPPER_DISPLAY display,
    __in BOOL fRollback,
    __in BURN_PLAN* pPlan,
    __in BURN_LOGGING* pLog,
    __in BURN_VARIABLES* pVariables,
    __in BOOTSTRAPPER_ACTION_STATE actionState,
    __in BURN_PACKAGE* pPackage,
    __in BURN_MSPTARGETPRODUCT* pTargetProduct
    )
{
    HRESULT hr = S_OK;
    BURN_EXECUTE_ACTION* rgActions = fRollback ? pPlan->rgRollbackActions : pPlan->rgExecuteActions;
    DWORD cActions = fRollback ? pPlan->cRollbackActions : pPlan->cExecuteActions;
    BURN_EXECUTE_ACTION* pAction = NULL;

    // Try to find another MSP action with the exact same action (install or uninstall) targeting
    // the same product in the same machine context (per-user or per-machine).
    for (DWORD i = 0; i < cActions; ++i)
    {
        pAction = rgActions + i;

        if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type &&
            pAction->mspTarget.action == actionState &&
            pAction->mspTarget.fPerMachineTarget == (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context) &&
            CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pAction->mspTarget.sczTargetProductCode, -1, pTargetProduct->wzTargetProductCode, -1))
        {
            break;
        }

        pAction = NULL;
    }

    // If we didn't find an MSP target action already updating the product, create a new action.
    if (!pAction)
    {
        if (fRollback)
        {
            hr = PlanAppendRollbackAction(pPlan, &pAction);
        }
        else
        {
            hr = PlanAppendExecuteAction(pPlan, &pAction);
        }
        ExitOnFailure(hr, "Failed to plan action for target product.");

        pAction->type = BURN_EXECUTE_ACTION_TYPE_MSP_TARGET;
        pAction->mspTarget.action = actionState;
        pAction->mspTarget.pPackage = pPackage;
        pAction->mspTarget.fPerMachineTarget = (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context);
        pAction->mspTarget.uiLevel = MsiEngineCalculateInstallLevel(pPackage->Msp.fDisplayInternalUI, display);
        pAction->mspTarget.pChainedTargetPackage = pTargetProduct->pChainedTargetPackage;
        pAction->mspTarget.fSlipstream = pTargetProduct->fSlipstream;
        hr = StrAllocString(&pAction->mspTarget.sczTargetProductCode, pTargetProduct->wzTargetProductCode, 0);
        ExitOnFailure(hr, "Failed to copy target product code.");

        // If this is a per-machine target product, then the plan needs to be per-machine as well.
        if (pAction->mspTarget.fPerMachineTarget)
        {
            pPlan->fPerMachine = TRUE;
        }

        LoggingSetPackageVariable(pPackage, pAction->mspTarget.sczTargetProductCode, fRollback, pLog, pVariables, &pAction->mspTarget.sczLogPath); // ignore errors.
    }

    // Add our target product to the array and sort based on their order determined during detection.
    hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pAction->mspTarget.rgOrderedPatches), pAction->mspTarget.cOrderedPatches + 1, sizeof(BURN_ORDERED_PATCHES), 2);
    ExitOnFailure(hr, "Failed grow array of ordered patches.");

    pAction->mspTarget.rgOrderedPatches[pAction->mspTarget.cOrderedPatches].dwOrder = pTargetProduct->dwOrder;
    pAction->mspTarget.rgOrderedPatches[pAction->mspTarget.cOrderedPatches].pPackage = pPackage;
    ++pAction->mspTarget.cOrderedPatches;

    // Insertion sort to keep the patches ordered.
    for (DWORD i = pAction->mspTarget.cOrderedPatches - 1; i > 0; --i)
    {
        if (pAction->mspTarget.rgOrderedPatches[i].dwOrder < pAction->mspTarget.rgOrderedPatches[i - 1].dwOrder)
        {
            BURN_ORDERED_PATCHES temp = pAction->mspTarget.rgOrderedPatches[i - 1];
            pAction->mspTarget.rgOrderedPatches[i - 1] = pAction->mspTarget.rgOrderedPatches[i];
            pAction->mspTarget.rgOrderedPatches[i] = temp;
        }
        else // no swap necessary, we're done.
        {
            break;
        }
    }

LExit:
    return hr;
}