Пример #1
0
static HRESULT GetPossibleTargetProductCodes(
    __in BURN_PACKAGES* pPackages,
    __deref_inout_ecount_opt(*pcPossibleTargetProducts) POSSIBLE_TARGETPRODUCT** prgPossibleTargetProducts,
    __inout DWORD* pcPossibleTargetProducts
    )
{
    HRESULT hr = S_OK;
    STRINGDICT_HANDLE sdUniquePossibleTargetProductCodes = NULL;
    BOOL fCheckAll = FALSE;
    WCHAR wzPossibleTargetProductCode[MAX_GUID_CHARS + 1];

    // Use a dictionary to ensure we capture unique product codes. Otherwise, we could end up
    // doing patch applicability for the same product code multiple times and that would confuse
    // everything down stream.
    hr = DictCreateStringList(&sdUniquePossibleTargetProductCodes, 5, DICT_FLAG_NONE);
    ExitOnFailure(hr, "Failed to create unique target product codes.");

    // If the patches target a specific set of product/upgrade codes, search only those. This
    // should be much faster than searching all packages on the machine.
    if (pPackages->rgPatchTargetCodes)
    {
        for (DWORD i = 0; i < pPackages->cPatchTargetCodes; ++i)
        {
            BURN_PATCH_TARGETCODE* pTargetCode = pPackages->rgPatchTargetCodes + i;

            // If targeting a product, add the unique product code to the list.
            if (BURN_PATCH_TARGETCODE_TYPE_PRODUCT == pTargetCode->type)
            {
                hr = AddPossibleTargetProduct(sdUniquePossibleTargetProductCodes, pTargetCode->sczTargetCode, MSIINSTALLCONTEXT_NONE, prgPossibleTargetProducts, pcPossibleTargetProducts);
                ExitOnFailure(hr, "Failed to add product code to possible target product codes.");
Пример #2
0
 SplitIgnoreDependencies - Splits a semicolon-delimited
  string into a list of unique dependencies to ignore.

*********************************************************************/
static HRESULT SplitIgnoreDependencies(
    __in_z LPCWSTR wzIgnoreDependencies,
    __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies,
    __inout LPUINT pcDependencies
    )
{
    HRESULT hr = S_OK;
    LPWSTR wzContext = NULL;
    STRINGDICT_HANDLE sdIgnoreDependencies = NULL;

    // Create a dictionary to hold unique dependencies.
    hr = DictCreateStringList(&sdIgnoreDependencies, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
    ExitOnFailure(hr, "Failed to create the string dictionary.");

    // Parse through the semicolon-delimited tokens and add to the array.
    for (LPCWSTR wzToken = ::wcstok_s(const_cast<LPWSTR>(wzIgnoreDependencies), vcszIgnoreDependenciesDelim, &wzContext); wzToken; wzToken = ::wcstok_s(NULL, vcszIgnoreDependenciesDelim, &wzContext))
    {
        hr = DictKeyExists(sdIgnoreDependencies, wzToken);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to check the dictionary of unique dependencies.");
        }
        else
        {
            hr = DepDependencyArrayAlloc(prgDependencies, pcDependencies, wzToken, NULL);
            ExitOnFailure1(hr, "Failed to add \"%ls\" to the list of dependencies to ignore.", wzToken);
Пример #3
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;
}