diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/burn/engine/apply.cpp | 4 | ||||
| -rw-r--r-- | src/burn/engine/cache.cpp | 95 | ||||
| -rw-r--r-- | src/burn/engine/container.cpp | 50 | ||||
| -rw-r--r-- | src/burn/engine/container.h | 8 | ||||
| -rw-r--r-- | src/burn/engine/payload.cpp | 127 | ||||
| -rw-r--r-- | src/burn/engine/payload.h | 8 | ||||
| -rw-r--r-- | src/burn/engine/pseudobundle.cpp | 5 | ||||
| -rw-r--r-- | src/burn/test/BurnUnitTest/CacheTest.cpp | 2 | ||||
| -rw-r--r-- | src/burn/test/BurnUnitTest/PlanTest.cpp | 2 |
9 files changed, 209 insertions, 92 deletions
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index b4fa9dac..4d527409 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp | |||
| @@ -1410,12 +1410,12 @@ static HRESULT AcquireContainerOrPayload( | |||
| 1410 | fMinimumFileSize = TRUE; | 1410 | fMinimumFileSize = TRUE; |
| 1411 | qwFileSize = pContainer->qwAttachedOffset + pContainer->qwFileSize; | 1411 | qwFileSize = pContainer->qwAttachedOffset + pContainer->qwFileSize; |
| 1412 | } | 1412 | } |
| 1413 | else if (pContainer->pbHash && pContext->wzLayoutDirectory) | 1413 | else |
| 1414 | { | 1414 | { |
| 1415 | qwFileSize = pContainer->qwFileSize; | 1415 | qwFileSize = pContainer->qwFileSize; |
| 1416 | } | 1416 | } |
| 1417 | } | 1417 | } |
| 1418 | else if (pPayload->pbHash) | 1418 | else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification || BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE == pPayload->verification) |
| 1419 | { | 1419 | { |
| 1420 | qwFileSize = pPayload->qwFileSize; | 1420 | qwFileSize = pPayload->qwFileSize; |
| 1421 | } | 1421 | } |
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index 02cad4a5..44267cbc 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp | |||
| @@ -114,10 +114,16 @@ static HRESULT RemoveBundleOrPackage( | |||
| 114 | __in_z LPCWSTR wzBundleOrPackageId, | 114 | __in_z LPCWSTR wzBundleOrPackageId, |
| 115 | __in_z LPCWSTR wzCacheId | 115 | __in_z LPCWSTR wzCacheId |
| 116 | ); | 116 | ); |
| 117 | static HRESULT VerifyFileSize( | ||
| 118 | __in HANDLE hFile, | ||
| 119 | __in DWORD64 qwFileSize, | ||
| 120 | __in_z LPCWSTR wzUnverifiedPayloadPath | ||
| 121 | ); | ||
| 117 | static HRESULT VerifyHash( | 122 | static HRESULT VerifyHash( |
| 118 | __in BYTE* pbHash, | 123 | __in BYTE* pbHash, |
| 119 | __in DWORD cbHash, | 124 | __in DWORD cbHash, |
| 120 | __in DWORD64 qwFileSize, | 125 | __in DWORD64 qwFileSize, |
| 126 | __in BOOL fVerifyFileSize, | ||
| 121 | __in_z LPCWSTR wzUnverifiedPayloadPath, | 127 | __in_z LPCWSTR wzUnverifiedPayloadPath, |
| 122 | __in HANDLE hFile, | 128 | __in HANDLE hFile, |
| 123 | __in BURN_CACHE_STEP cacheStep, | 129 | __in BURN_CACHE_STEP cacheStep, |
| @@ -1513,11 +1519,16 @@ static HRESULT VerifyThenTransferContainer( | |||
| 1513 | ExitWithLastError(hr, "Failed to open container in working path: %ls", wzUnverifiedContainerPath); | 1519 | ExitWithLastError(hr, "Failed to open container in working path: %ls", wzUnverifiedContainerPath); |
| 1514 | } | 1520 | } |
| 1515 | 1521 | ||
| 1516 | // Container should have a hash we can use to verify with. | 1522 | |
| 1517 | if (pContainer->pbHash) | 1523 | switch (pContainer->verification) |
| 1518 | { | 1524 | { |
| 1519 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, wzUnverifiedContainerPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | 1525 | case BURN_CONTAINER_VERIFICATION_HASH: |
| 1526 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, TRUE, wzUnverifiedContainerPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | ||
| 1520 | ExitOnFailure(hr, "Failed to verify container hash: %ls", wzCachedPath); | 1527 | ExitOnFailure(hr, "Failed to verify container hash: %ls", wzCachedPath); |
| 1528 | break; | ||
| 1529 | default: | ||
| 1530 | ExitOnRootFailure(hr = E_INVALIDARG, "Container has no verification information: %ls", pContainer->sczId); | ||
| 1531 | break; | ||
| 1521 | } | 1532 | } |
| 1522 | 1533 | ||
| 1523 | LogStringLine(REPORT_STANDARD, "%ls container from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedContainerPath, wzCachedPath); | 1534 | LogStringLine(REPORT_STANDARD, "%ls container from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedContainerPath, wzCachedPath); |
| @@ -1550,10 +1561,16 @@ static HRESULT VerifyThenTransferPayload( | |||
| 1550 | ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath); | 1561 | ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath); |
| 1551 | } | 1562 | } |
| 1552 | 1563 | ||
| 1553 | if (pPayload->pbHash) // the payload should have a hash we can use to verify it. | 1564 | switch (pPayload->verification) |
| 1554 | { | 1565 | { |
| 1555 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | 1566 | case BURN_PAYLOAD_VERIFICATION_HASH: |
| 1567 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, TRUE, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | ||
| 1556 | ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); | 1568 | ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); |
| 1569 | break; | ||
| 1570 | case BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE: __fallthrough; | ||
| 1571 | default: | ||
| 1572 | ExitOnRootFailure(hr = E_INVALIDARG, "Payload has no verification information: %ls", pPayload->sczKey); | ||
| 1573 | break; | ||
| 1557 | } | 1574 | } |
| 1558 | 1575 | ||
| 1559 | LogStringLine(REPORT_STANDARD, "%ls payload from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedPayloadPath, wzCachedPath); | 1576 | LogStringLine(REPORT_STANDARD, "%ls payload from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedPayloadPath, wzCachedPath); |
| @@ -1627,10 +1644,15 @@ static HRESULT VerifyFileAgainstContainer( | |||
| 1627 | ExitOnRootFailure(hr, "Failed to open container at path: %ls", wzVerifyPath); | 1644 | ExitOnRootFailure(hr, "Failed to open container at path: %ls", wzVerifyPath); |
| 1628 | } | 1645 | } |
| 1629 | 1646 | ||
| 1630 | if (pContainer->pbHash) // the container should have a hash we can use to verify it. | 1647 | switch (pContainer->verification) |
| 1631 | { | 1648 | { |
| 1632 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | 1649 | case BURN_CONTAINER_VERIFICATION_HASH: |
| 1650 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, TRUE, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | ||
| 1633 | ExitOnFailure(hr, "Failed to verify hash of container: %ls", pContainer->sczId); | 1651 | ExitOnFailure(hr, "Failed to verify hash of container: %ls", pContainer->sczId); |
| 1652 | break; | ||
| 1653 | default: | ||
| 1654 | ExitOnRootFailure(hr = E_INVALIDARG, "Container has no verification information: %ls", pContainer->sczId); | ||
| 1655 | break; | ||
| 1634 | } | 1656 | } |
| 1635 | 1657 | ||
| 1636 | if (fAlreadyCached) | 1658 | if (fAlreadyCached) |
| @@ -1667,6 +1689,7 @@ static HRESULT VerifyFileAgainstPayload( | |||
| 1667 | { | 1689 | { |
| 1668 | HRESULT hr = S_OK; | 1690 | HRESULT hr = S_OK; |
| 1669 | HANDLE hFile = INVALID_HANDLE_VALUE; | 1691 | HANDLE hFile = INVALID_HANDLE_VALUE; |
| 1692 | BOOL fVerifyFileSize = FALSE; | ||
| 1670 | 1693 | ||
| 1671 | // Get the payload on disk actual hash. | 1694 | // Get the payload on disk actual hash. |
| 1672 | hFile = ::CreateFileW(wzVerifyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | 1695 | hFile = ::CreateFileW(wzVerifyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); |
| @@ -1680,10 +1703,33 @@ static HRESULT VerifyFileAgainstPayload( | |||
| 1680 | ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath); | 1703 | ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath); |
| 1681 | } | 1704 | } |
| 1682 | 1705 | ||
| 1683 | if (pPayload->pbHash) // the payload should have a hash we can use to verify it. | 1706 | switch (pPayload->verification) |
| 1684 | { | 1707 | { |
| 1685 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | 1708 | case BURN_PAYLOAD_VERIFICATION_HASH: |
| 1709 | fVerifyFileSize = TRUE; | ||
| 1710 | |||
| 1711 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, fVerifyFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | ||
| 1686 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); | 1712 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); |
| 1713 | |||
| 1714 | break; | ||
| 1715 | case BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE: | ||
| 1716 | fVerifyFileSize = 0 != pPayload->qwFileSize; | ||
| 1717 | |||
| 1718 | if (pPayload->pbHash) | ||
| 1719 | { | ||
| 1720 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, fVerifyFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | ||
| 1721 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); | ||
| 1722 | } | ||
| 1723 | else if (fVerifyFileSize) | ||
| 1724 | { | ||
| 1725 | hr = VerifyFileSize(hFile, pPayload->qwFileSize, wzVerifyPath); | ||
| 1726 | ExitOnFailure(hr, "Failed to verify file size for path: %ls", wzVerifyPath); | ||
| 1727 | } | ||
| 1728 | |||
| 1729 | break; | ||
| 1730 | default: | ||
| 1731 | ExitOnRootFailure(hr = E_INVALIDARG, "Payload has no verification information: %ls", pPayload->sczKey); | ||
| 1732 | break; | ||
| 1687 | } | 1733 | } |
| 1688 | 1734 | ||
| 1689 | if (fAlreadyCached) | 1735 | if (fAlreadyCached) |
| @@ -2015,10 +2061,32 @@ LExit: | |||
| 2015 | return hr; | 2061 | return hr; |
| 2016 | } | 2062 | } |
| 2017 | 2063 | ||
| 2064 | static HRESULT VerifyFileSize( | ||
| 2065 | __in HANDLE hFile, | ||
| 2066 | __in DWORD64 qwFileSize, | ||
| 2067 | __in_z LPCWSTR wzUnverifiedPayloadPath | ||
| 2068 | ) | ||
| 2069 | { | ||
| 2070 | HRESULT hr = S_OK; | ||
| 2071 | LONGLONG llSize = 0; | ||
| 2072 | |||
| 2073 | hr = FileSizeByHandle(hFile, &llSize); | ||
| 2074 | ExitOnFailure(hr, "Failed to get file size for path: %ls", wzUnverifiedPayloadPath); | ||
| 2075 | |||
| 2076 | if (static_cast<DWORD64>(llSize) != qwFileSize) | ||
| 2077 | { | ||
| 2078 | ExitOnRootFailure(hr = ERROR_FILE_CORRUPT, "File size mismatch for path: %ls, expected: %llu, actual: %lld", wzUnverifiedPayloadPath, qwFileSize, llSize); | ||
| 2079 | } | ||
| 2080 | |||
| 2081 | LExit: | ||
| 2082 | return hr; | ||
| 2083 | } | ||
| 2084 | |||
| 2018 | static HRESULT VerifyHash( | 2085 | static HRESULT VerifyHash( |
| 2019 | __in BYTE* pbHash, | 2086 | __in BYTE* pbHash, |
| 2020 | __in DWORD cbHash, | 2087 | __in DWORD cbHash, |
| 2021 | __in DWORD64 qwFileSize, | 2088 | __in DWORD64 qwFileSize, |
| 2089 | __in BOOL fVerifyFileSize, | ||
| 2022 | __in_z LPCWSTR wzUnverifiedPayloadPath, | 2090 | __in_z LPCWSTR wzUnverifiedPayloadPath, |
| 2023 | __in HANDLE hFile, | 2091 | __in HANDLE hFile, |
| 2024 | __in BURN_CACHE_STEP cacheStep, | 2092 | __in BURN_CACHE_STEP cacheStep, |
| @@ -2032,19 +2100,16 @@ static HRESULT VerifyHash( | |||
| 2032 | HRESULT hr = S_OK; | 2100 | HRESULT hr = S_OK; |
| 2033 | BYTE rgbActualHash[SHA512_HASH_LEN] = { }; | 2101 | BYTE rgbActualHash[SHA512_HASH_LEN] = { }; |
| 2034 | DWORD64 qwHashedBytes = 0; | 2102 | DWORD64 qwHashedBytes = 0; |
| 2035 | LONGLONG llSize = 0; | ||
| 2036 | LPWSTR pszExpected = NULL; | 2103 | LPWSTR pszExpected = NULL; |
| 2037 | LPWSTR pszActual = NULL; | 2104 | LPWSTR pszActual = NULL; |
| 2038 | 2105 | ||
| 2039 | hr = SendCacheBeginMessage(pfnCacheMessageHandler, pContext, cacheStep); | 2106 | hr = SendCacheBeginMessage(pfnCacheMessageHandler, pContext, cacheStep); |
| 2040 | ExitOnFailure(hr, "Aborted cache verify hash begin."); | 2107 | ExitOnFailure(hr, "Aborted cache verify hash begin."); |
| 2041 | 2108 | ||
| 2042 | hr = FileSizeByHandle(hFile, &llSize); | 2109 | if (fVerifyFileSize) |
| 2043 | ExitOnFailure(hr, "Failed to get file size for path: %ls", wzUnverifiedPayloadPath); | ||
| 2044 | |||
| 2045 | if (static_cast<DWORD64>(llSize) != qwFileSize) | ||
| 2046 | { | 2110 | { |
| 2047 | ExitOnFailure(hr = ERROR_FILE_CORRUPT, "File size mismatch for path: %ls, expected: %llu, actual: %lld", wzUnverifiedPayloadPath, qwFileSize, llSize); | 2111 | hr = VerifyFileSize(hFile, qwFileSize, wzUnverifiedPayloadPath); |
| 2112 | ExitOnFailure(hr, "Failed to verify file size for path: %ls", wzUnverifiedPayloadPath); | ||
| 2048 | } | 2113 | } |
| 2049 | 2114 | ||
| 2050 | // TODO: create a cryp hash file that sends progress. | 2115 | // TODO: create a cryp hash file that sends progress. |
diff --git a/src/burn/engine/container.cpp b/src/burn/engine/container.cpp index 0cce3131..c6f2ada8 100644 --- a/src/burn/engine/container.cpp +++ b/src/burn/engine/container.cpp | |||
| @@ -50,16 +50,9 @@ extern "C" HRESULT ContainersParseFromXml( | |||
| 50 | hr = XmlGetAttributeEx(pixnNode, L"Id", &pContainer->sczId); | 50 | hr = XmlGetAttributeEx(pixnNode, L"Id", &pContainer->sczId); |
| 51 | ExitOnFailure(hr, "Failed to get @Id."); | 51 | ExitOnFailure(hr, "Failed to get @Id."); |
| 52 | 52 | ||
| 53 | // @Primary | ||
| 54 | hr = XmlGetYesNoAttribute(pixnNode, L"Primary", &pContainer->fPrimary); | ||
| 55 | if (E_NOTFOUND != hr) | ||
| 56 | { | ||
| 57 | ExitOnFailure(hr, "Failed to get @Primary."); | ||
| 58 | } | ||
| 59 | |||
| 60 | // @Attached | 53 | // @Attached |
| 61 | hr = XmlGetYesNoAttribute(pixnNode, L"Attached", &pContainer->fAttached); | 54 | hr = XmlGetYesNoAttribute(pixnNode, L"Attached", &pContainer->fAttached); |
| 62 | if (E_NOTFOUND != hr || pContainer->fPrimary) // if it is a primary container, it has to be attached | 55 | if (E_NOTFOUND != hr) |
| 63 | { | 56 | { |
| 64 | ExitOnFailure(hr, "Failed to get @Attached."); | 57 | ExitOnFailure(hr, "Failed to get @Attached."); |
| 65 | } | 58 | } |
| @@ -87,10 +80,7 @@ extern "C" HRESULT ContainersParseFromXml( | |||
| 87 | { | 80 | { |
| 88 | // @FilePath | 81 | // @FilePath |
| 89 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pContainer->sczFilePath); | 82 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pContainer->sczFilePath); |
| 90 | if (E_NOTFOUND != hr) | 83 | ExitOnFailure(hr, "Failed to get @FilePath."); |
| 91 | { | ||
| 92 | ExitOnFailure(hr, "Failed to get @FilePath."); | ||
| 93 | } | ||
| 94 | } | 84 | } |
| 95 | 85 | ||
| 96 | // The source path starts as the file path. | 86 | // The source path starts as the file path. |
| @@ -99,23 +89,32 @@ extern "C" HRESULT ContainersParseFromXml( | |||
| 99 | 89 | ||
| 100 | // @DownloadUrl | 90 | // @DownloadUrl |
| 101 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pContainer->downloadSource.sczUrl); | 91 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pContainer->downloadSource.sczUrl); |
| 102 | if (E_NOTFOUND != hr || (!pContainer->fPrimary && !pContainer->sczSourcePath)) // if the package is not a primary package, it must have a source path or a download url | 92 | if (E_NOTFOUND != hr) |
| 103 | { | 93 | { |
| 104 | ExitOnFailure(hr, "Failed to get @DownloadUrl. Either @SourcePath or @DownloadUrl needs to be provided."); | 94 | ExitOnFailure(hr, "Failed to get @DownloadUrl."); |
| 105 | } | 95 | } |
| 106 | 96 | ||
| 107 | // @Hash | 97 | // @Hash |
| 108 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &pContainer->sczHash); | 98 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &pContainer->sczHash); |
| 109 | if (SUCCEEDED(hr)) | 99 | ExitOnFailure(hr, "Failed to get @Hash."); |
| 110 | { | 100 | |
| 111 | hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash); | 101 | hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash); |
| 112 | ExitOnFailure(hr, "Failed to hex decode the Container/@Hash."); | 102 | ExitOnFailure(hr, "Failed to hex decode the Container/@Hash."); |
| 113 | } | 103 | |
| 114 | else if (E_NOTFOUND != hr) | 104 | // @FileSize |
| 105 | hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); | ||
| 106 | ExitOnFailure(hr, "Failed to get @FileSize."); | ||
| 107 | |||
| 108 | hr = StrStringToUInt64(scz, 0, &pContainer->qwFileSize); | ||
| 109 | ExitOnFailure(hr, "Failed to parse @FileSize."); | ||
| 110 | |||
| 111 | if (!pContainer->qwFileSize) | ||
| 115 | { | 112 | { |
| 116 | ExitOnFailure(hr, "Failed to get @Hash."); | 113 | ExitOnRootFailure(hr = E_INVALIDDATA, "File size is required when verifying by hash for container: %ls", pContainer->sczId); |
| 117 | } | 114 | } |
| 118 | 115 | ||
| 116 | pContainer->verification = BURN_CONTAINER_VERIFICATION_HASH; | ||
| 117 | |||
| 119 | // prepare next iteration | 118 | // prepare next iteration |
| 120 | ReleaseNullObject(pixnNode); | 119 | ReleaseNullObject(pixnNode); |
| 121 | } | 120 | } |
| @@ -136,6 +135,7 @@ extern "C" HRESULT ContainersInitialize( | |||
| 136 | ) | 135 | ) |
| 137 | { | 136 | { |
| 138 | HRESULT hr = S_OK; | 137 | HRESULT hr = S_OK; |
| 138 | DWORD64 qwSize = 0; | ||
| 139 | 139 | ||
| 140 | if (pContainers->rgContainers) | 140 | if (pContainers->rgContainers) |
| 141 | { | 141 | { |
| @@ -147,8 +147,13 @@ extern "C" HRESULT ContainersInitialize( | |||
| 147 | // manifest contained and get the offset to the container. | 147 | // manifest contained and get the offset to the container. |
| 148 | if (pContainer->fAttached) | 148 | if (pContainer->fAttached) |
| 149 | { | 149 | { |
| 150 | hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &pContainer->qwFileSize, &pContainer->fActuallyAttached); | 150 | hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &qwSize, &pContainer->fActuallyAttached); |
| 151 | ExitOnFailure(hr, "Failed to get attached container information."); | 151 | ExitOnFailure(hr, "Failed to get attached container information."); |
| 152 | |||
| 153 | if (qwSize != pContainer->qwFileSize) | ||
| 154 | { | ||
| 155 | ExitOnFailure(hr, "Attached container '%ls' size '%llu' didn't match size from manifest: '%llu'", pContainer->sczId, qwSize, pContainer->qwFileSize); | ||
| 156 | } | ||
| 152 | } | 157 | } |
| 153 | } | 158 | } |
| 154 | } | 159 | } |
| @@ -195,7 +200,6 @@ extern "C" HRESULT ContainerOpenUX( | |||
| 195 | 200 | ||
| 196 | // open attached container | 201 | // open attached container |
| 197 | container.type = BURN_CONTAINER_TYPE_CABINET; | 202 | container.type = BURN_CONTAINER_TYPE_CABINET; |
| 198 | container.fPrimary = TRUE; | ||
| 199 | container.fAttached = TRUE; | 203 | container.fAttached = TRUE; |
| 200 | container.dwAttachedIndex = 0; | 204 | container.dwAttachedIndex = 0; |
| 201 | 205 | ||
diff --git a/src/burn/engine/container.h b/src/burn/engine/container.h index c2c1c9a8..d454a248 100644 --- a/src/burn/engine/container.h +++ b/src/burn/engine/container.h | |||
| @@ -52,6 +52,12 @@ enum BURN_CAB_OPERATION | |||
| 52 | BURN_CAB_OPERATION_CLOSE, | 52 | BURN_CAB_OPERATION_CLOSE, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | enum BURN_CONTAINER_VERIFICATION | ||
| 56 | { | ||
| 57 | BURN_CONTAINER_VERIFICATION_NONE, | ||
| 58 | BURN_CONTAINER_VERIFICATION_HASH, | ||
| 59 | }; | ||
| 60 | |||
| 55 | 61 | ||
| 56 | // structs | 62 | // structs |
| 57 | 63 | ||
| @@ -59,7 +65,6 @@ typedef struct _BURN_CONTAINER | |||
| 59 | { | 65 | { |
| 60 | LPWSTR sczId; | 66 | LPWSTR sczId; |
| 61 | BURN_CONTAINER_TYPE type; | 67 | BURN_CONTAINER_TYPE type; |
| 62 | BOOL fPrimary; | ||
| 63 | BOOL fAttached; | 68 | BOOL fAttached; |
| 64 | DWORD dwAttachedIndex; | 69 | DWORD dwAttachedIndex; |
| 65 | DWORD64 qwFileSize; | 70 | DWORD64 qwFileSize; |
| @@ -69,6 +74,7 @@ typedef struct _BURN_CONTAINER | |||
| 69 | 74 | ||
| 70 | BYTE* pbHash; | 75 | BYTE* pbHash; |
| 71 | DWORD cbHash; | 76 | DWORD cbHash; |
| 77 | BURN_CONTAINER_VERIFICATION verification; | ||
| 72 | DWORD64 qwAttachedOffset; | 78 | DWORD64 qwAttachedOffset; |
| 73 | BOOL fActuallyAttached; // indicates whether an attached container is attached or missing. | 79 | BOOL fActuallyAttached; // indicates whether an attached container is attached or missing. |
| 74 | 80 | ||
diff --git a/src/burn/engine/payload.cpp b/src/burn/engine/payload.cpp index 72eb3476..392a3dd4 100644 --- a/src/burn/engine/payload.cpp +++ b/src/burn/engine/payload.cpp | |||
| @@ -27,6 +27,8 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
| 27 | IXMLDOMNode* pixnNode = NULL; | 27 | IXMLDOMNode* pixnNode = NULL; |
| 28 | DWORD cNodes = 0; | 28 | DWORD cNodes = 0; |
| 29 | LPWSTR scz = NULL; | 29 | LPWSTR scz = NULL; |
| 30 | BOOL fChainPayload = pContainers && pLayoutPayloads; // These are required when parsing chain payloads. | ||
| 31 | BOOL fValidFileSize = FALSE; | ||
| 30 | 32 | ||
| 31 | // select payload nodes | 33 | // select payload nodes |
| 32 | hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes); | 34 | hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes); |
| @@ -51,6 +53,7 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
| 51 | for (DWORD i = 0; i < cNodes; ++i) | 53 | for (DWORD i = 0; i < cNodes; ++i) |
| 52 | { | 54 | { |
| 53 | BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i]; | 55 | BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i]; |
| 56 | fValidFileSize = FALSE; | ||
| 54 | 57 | ||
| 55 | hr = XmlNextElement(pixnNodes, &pixnNode, NULL); | 58 | hr = XmlNextElement(pixnNodes, &pixnNode, NULL); |
| 56 | ExitOnFailure(hr, "Failed to get next node."); | 59 | ExitOnFailure(hr, "Failed to get next node."); |
| @@ -63,27 +66,36 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
| 63 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath); | 66 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath); |
| 64 | ExitOnFailure(hr, "Failed to get @FilePath."); | 67 | ExitOnFailure(hr, "Failed to get @FilePath."); |
| 65 | 68 | ||
| 66 | // @Packaging | 69 | // @SourcePath |
| 67 | hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz); | 70 | hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath); |
| 68 | ExitOnFailure(hr, "Failed to get @Packaging."); | 71 | ExitOnFailure(hr, "Failed to get @SourcePath."); |
| 69 | 72 | ||
| 70 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1)) | 73 | if (!fChainPayload) |
| 71 | { | 74 | { |
| 75 | // All non-chain payloads are embedded in the UX container. | ||
| 72 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; | 76 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; |
| 73 | } | 77 | } |
| 74 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1)) | ||
| 75 | { | ||
| 76 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL; | ||
| 77 | } | ||
| 78 | else | 78 | else |
| 79 | { | 79 | { |
| 80 | hr = E_INVALIDARG; | 80 | // @Packaging |
| 81 | ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz); | 81 | hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz); |
| 82 | } | 82 | ExitOnFailure(hr, "Failed to get @Packaging."); |
| 83 | 83 | ||
| 84 | // @Container | 84 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1)) |
| 85 | if (pContainers) | 85 | { |
| 86 | { | 86 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; |
| 87 | } | ||
| 88 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1)) | ||
| 89 | { | ||
| 90 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL; | ||
| 91 | } | ||
| 92 | else | ||
| 93 | { | ||
| 94 | hr = E_INVALIDARG; | ||
| 95 | ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz); | ||
| 96 | } | ||
| 97 | |||
| 98 | // @Container | ||
| 87 | hr = XmlGetAttributeEx(pixnNode, L"Container", &scz); | 99 | hr = XmlGetAttributeEx(pixnNode, L"Container", &scz); |
| 88 | if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging) | 100 | if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging) |
| 89 | { | 101 | { |
| @@ -93,52 +105,67 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
| 93 | hr = ContainerFindById(pContainers, scz, &pPayload->pContainer); | 105 | hr = ContainerFindById(pContainers, scz, &pPayload->pContainer); |
| 94 | ExitOnFailure(hr, "Failed to to find container: %ls", scz); | 106 | ExitOnFailure(hr, "Failed to to find container: %ls", scz); |
| 95 | } | 107 | } |
| 96 | } | ||
| 97 | 108 | ||
| 98 | // @LayoutOnly | 109 | // @LayoutOnly |
| 99 | hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly); | 110 | hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly); |
| 100 | if (E_NOTFOUND != hr) | 111 | if (E_NOTFOUND != hr) |
| 101 | { | 112 | { |
| 102 | ExitOnFailure(hr, "Failed to get @LayoutOnly."); | 113 | ExitOnFailure(hr, "Failed to get @LayoutOnly."); |
| 103 | } | 114 | } |
| 104 | 115 | ||
| 105 | // @SourcePath | 116 | // @DownloadUrl |
| 106 | hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath); | 117 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl); |
| 107 | ExitOnFailure(hr, "Failed to get @SourcePath."); | 118 | if (E_NOTFOUND != hr) |
| 119 | { | ||
| 120 | ExitOnFailure(hr, "Failed to get @DownloadUrl."); | ||
| 121 | } | ||
| 108 | 122 | ||
| 109 | // @DownloadUrl | 123 | // @FileSize |
| 110 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl); | 124 | hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); |
| 111 | if (E_NOTFOUND != hr) | 125 | if (E_NOTFOUND != hr) |
| 112 | { | 126 | { |
| 113 | ExitOnFailure(hr, "Failed to get @DownloadUrl."); | 127 | ExitOnFailure(hr, "Failed to get @FileSize."); |
| 114 | } | ||
| 115 | 128 | ||
| 116 | // @FileSize | 129 | hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize); |
| 117 | hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); | 130 | ExitOnFailure(hr, "Failed to parse @FileSize."); |
| 118 | if (E_NOTFOUND != hr) | ||
| 119 | { | ||
| 120 | ExitOnFailure(hr, "Failed to get @FileSize."); | ||
| 121 | 131 | ||
| 122 | hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize); | 132 | fValidFileSize = TRUE; |
| 123 | ExitOnFailure(hr, "Failed to parse @FileSize."); | 133 | } |
| 124 | } | 134 | |
| 135 | // @Hash | ||
| 136 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz); | ||
| 137 | if (E_NOTFOUND != hr) | ||
| 138 | { | ||
| 139 | ExitOnFailure(hr, "Failed to get @Hash."); | ||
| 125 | 140 | ||
| 126 | // @Hash | 141 | hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash); |
| 127 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz); | 142 | ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash."); |
| 128 | ExitOnFailure(hr, "Failed to get @Hash."); | ||
| 129 | 143 | ||
| 130 | hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash); | 144 | if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification) |
| 131 | ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash."); | 145 | { |
| 146 | pPayload->verification = BURN_PAYLOAD_VERIFICATION_HASH; | ||
| 147 | } | ||
| 148 | } | ||
| 132 | 149 | ||
| 133 | if (pPayload->fLayoutOnly && pLayoutPayloads) | 150 | if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification) |
| 134 | { | 151 | { |
| 135 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5); | 152 | ExitOnRootFailure(hr = E_INVALIDDATA, "There was no verification information for payload: %ls", pPayload->sczKey); |
| 136 | ExitOnFailure(hr, "Failed to allocate memory for layout payloads."); | 153 | } |
| 154 | else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification && !fValidFileSize) | ||
| 155 | { | ||
| 156 | ExitOnRootFailure(hr = E_INVALIDDATA, "File size is required when verifying by hash for payload: %ls", pPayload->sczKey); | ||
| 157 | } | ||
| 137 | 158 | ||
| 138 | pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload; | 159 | if (pPayload->fLayoutOnly) |
| 139 | ++pLayoutPayloads->cItems; | 160 | { |
| 161 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5); | ||
| 162 | ExitOnFailure(hr, "Failed to allocate memory for layout payloads."); | ||
| 140 | 163 | ||
| 141 | pLayoutPayloads->qwTotalSize += pPayload->qwFileSize; | 164 | pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload; |
| 165 | ++pLayoutPayloads->cItems; | ||
| 166 | |||
| 167 | pLayoutPayloads->qwTotalSize += pPayload->qwFileSize; | ||
| 168 | } | ||
| 142 | } | 169 | } |
| 143 | 170 | ||
| 144 | // prepare next iteration | 171 | // prepare next iteration |
diff --git a/src/burn/engine/payload.h b/src/burn/engine/payload.h index f28b437f..6fc6de5e 100644 --- a/src/burn/engine/payload.h +++ b/src/burn/engine/payload.h | |||
| @@ -23,6 +23,13 @@ enum BURN_PAYLOAD_STATE | |||
| 23 | BURN_PAYLOAD_STATE_CACHED, | 23 | BURN_PAYLOAD_STATE_CACHED, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | enum BURN_PAYLOAD_VERIFICATION | ||
| 27 | { | ||
| 28 | BURN_PAYLOAD_VERIFICATION_NONE, | ||
| 29 | BURN_PAYLOAD_VERIFICATION_HASH, | ||
| 30 | BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE, | ||
| 31 | }; | ||
| 32 | |||
| 26 | 33 | ||
| 27 | // structs | 34 | // structs |
| 28 | 35 | ||
| @@ -36,6 +43,7 @@ typedef struct _BURN_PAYLOAD | |||
| 36 | 43 | ||
| 37 | BYTE* pbHash; | 44 | BYTE* pbHash; |
| 38 | DWORD cbHash; | 45 | DWORD cbHash; |
| 46 | BURN_PAYLOAD_VERIFICATION verification; | ||
| 39 | 47 | ||
| 40 | LPWSTR sczSourcePath; | 48 | LPWSTR sczSourcePath; |
| 41 | BURN_CONTAINER* pContainer; | 49 | BURN_CONTAINER* pContainer; |
diff --git a/src/burn/engine/pseudobundle.cpp b/src/burn/engine/pseudobundle.cpp index 180cc621..1b2eae75 100644 --- a/src/burn/engine/pseudobundle.cpp +++ b/src/burn/engine/pseudobundle.cpp | |||
| @@ -69,6 +69,11 @@ extern "C" HRESULT PseudoBundleInitialize( | |||
| 69 | memcpy_s(pPayload->pbHash, pPayload->cbHash, pbHash, cbHash); | 69 | memcpy_s(pPayload->pbHash, pPayload->cbHash, pbHash, cbHash); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | if (BOOTSTRAPPER_RELATION_UPDATE == relationType) | ||
| 73 | { | ||
| 74 | pPayload->verification = BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE; | ||
| 75 | } | ||
| 76 | |||
| 72 | pPackage->Exe.fPseudoBundle = TRUE; | 77 | pPackage->Exe.fPseudoBundle = TRUE; |
| 73 | 78 | ||
| 74 | pPackage->type = BURN_PACKAGE_TYPE_EXE; | 79 | pPackage->type = BURN_PACKAGE_TYPE_EXE; |
diff --git a/src/burn/test/BurnUnitTest/CacheTest.cpp b/src/burn/test/BurnUnitTest/CacheTest.cpp index d0cc237f..e9ad555b 100644 --- a/src/burn/test/BurnUnitTest/CacheTest.cpp +++ b/src/burn/test/BurnUnitTest/CacheTest.cpp | |||
| @@ -71,6 +71,8 @@ namespace Bootstrapper | |||
| 71 | payload.sczFilePath = L"CacheSignatureTest.File"; | 71 | payload.sczFilePath = L"CacheSignatureTest.File"; |
| 72 | payload.pbHash = pb; | 72 | payload.pbHash = pb; |
| 73 | payload.cbHash = cb; | 73 | payload.cbHash = cb; |
| 74 | payload.qwFileSize = 27; | ||
| 75 | payload.verification = BURN_PAYLOAD_VERIFICATION_HASH; | ||
| 74 | 76 | ||
| 75 | hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE, CacheTestEventRoutine, CacheTestProgressRoutine, &context); | 77 | hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE, CacheTestEventRoutine, CacheTestProgressRoutine, &context); |
| 76 | Assert::Equal(S_OK, hr); | 78 | Assert::Equal(S_OK, hr); |
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 001acaee..045c510e 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp | |||
| @@ -71,7 +71,7 @@ namespace Bootstrapper | |||
| 71 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | 71 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); |
| 72 | 72 | ||
| 73 | Assert::Equal(107082ull, pPlan->qwEstimatedSize); | 73 | Assert::Equal(107082ull, pPlan->qwEstimatedSize); |
| 74 | Assert::Equal(506145ull, pPlan->qwCacheSizeTotal); | 74 | Assert::Equal(522548ull, pPlan->qwCacheSizeTotal); |
| 75 | 75 | ||
| 76 | fRollback = FALSE; | 76 | fRollback = FALSE; |
| 77 | dwIndex = 0; | 77 | dwIndex = 0; |
