ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache()

in src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/source_update_cache/src/source_update_cache_utils.c [151:265]


ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache(
    const ADUC_WorkflowHandle workflowHandle, const char* updateCacheBasePath)
{
    ADUC_Result result = { .ResultCode = ADUC_Result_Failure };
    int res = -1;
    ADUC_FileEntity fileEntity;
    memset(&fileEntity, 0, sizeof(fileEntity));
    STRING_HANDLE sandboxUpdatePayloadFile = NULL;
    ADUC_UpdateId* updateId = NULL;
    STRING_HANDLE updateCacheFilePath = NULL;
    char dirPath[1024] = "";

    size_t countPayloads = workflow_get_update_files_count(workflowHandle);
    for (size_t index = 0; index < countPayloads; ++index)
    {
        if (!workflow_get_update_file(workflowHandle, index, &fileEntity))
        {
            Log_Error("get update file %d", index);
            goto done;
        }

        workflow_get_entity_workfolder_filepath(workflowHandle, &fileEntity, &sandboxUpdatePayloadFile);

        result = workflow_get_expected_update_id(workflowHandle, &updateId);
        if (IsAducResultCodeFailure(result.ResultCode))
        {
            Log_Error("get updateId, erc 0x%08x", result.ExtendedResultCode);
            goto done;
        }

        // When update is already installed, payloads would not be downloaded but it would still
        // attempt to move to cache with OnUpdateWorkflowCompleted contract call because overall
        // is it Apply Success result, so guard against non-existent sandbox file.
        if (!SystemUtils_IsFile(STRING_c_str(sandboxUpdatePayloadFile), NULL))
        {
            result.ExtendedResultCode = ADUC_ERC_MISSING_SOURCE_SANDBOX_FILE;
            goto done;
        }

        const char* provider = updateId->Provider;
        const char* hash = (fileEntity.Hash[0]).value;
        const char* alg = (fileEntity.Hash[0]).type;

        updateCacheFilePath =
            ADUC_SourceUpdateCacheUtils_CreateSourceUpdateCachePath(provider, hash, alg, updateCacheBasePath);
        if (updateCacheFilePath == NULL)
        {
            result.ExtendedResultCode = ADUC_ERC_MOVE_CREATE_CACHE_PATH;
            goto done;
        }

        if (strcpy_s(dirPath, ARRAY_SIZE(dirPath), STRING_c_str(updateCacheFilePath)) != 0)
        {
            result.ExtendedResultCode = ADUC_ERC_NOTRECOVERABLE;
            goto done;
        }

        const char* dirPathCache = dirname(dirPath); // free() not needed
        if (dirPathCache == NULL)
        {
            result.ExtendedResultCode = ADUC_ERC_NOTRECOVERABLE;
            goto done;
        }

        if (ADUC_SystemUtils_MkDirRecursiveDefault(dirPathCache) != 0)
        {
            result.ExtendedResultCode = ADUC_ERC_MOVE_CREATE_CACHE_PATH;
            goto done;
        }

        // First try to move the file.
        // errno EXDEV would be common if copying across different mount points.
        // For any failure, it falls back to copy.

        Log_Debug("moving '%s' -> '%s'", STRING_c_str(sandboxUpdatePayloadFile), STRING_c_str(updateCacheFilePath));

        res = ADUCPAL_rename(STRING_c_str(sandboxUpdatePayloadFile), STRING_c_str(updateCacheFilePath));
        if (res != 0)
        {
            Log_Warn("rename, errno %d", errno);

            // fallback to copy
            //
            if (ADUC_SystemUtils_CopyFileToDir(
                    STRING_c_str(sandboxUpdatePayloadFile), dirPathCache, false /* overwriteExistingFile */)
                != 0)
            {
                Log_Error("Copy Failed");
                result.ExtendedResultCode = ADUC_ERC_MOVE_COPYFALLBACK;
                goto done;
            }
        }

        ADUC_FileEntity_Uninit(&fileEntity);

        ADUC_UpdateId_UninitAndFree(updateId);
        updateId = NULL;

        STRING_delete(updateCacheFilePath);
        updateCacheFilePath = NULL;

        STRING_delete(sandboxUpdatePayloadFile);
        sandboxUpdatePayloadFile = NULL;
    }

    result.ResultCode = ADUC_Result_Success;

done:
    ADUC_FileEntity_Uninit(&fileEntity);
    ADUC_UpdateId_UninitAndFree(updateId);
    STRING_delete(sandboxUpdatePayloadFile);
    STRING_delete(updateCacheFilePath);

    return result;
}