aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-04-16 10:29:10 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-04-19 23:12:55 -0500
commit9a061c70f8d87d4f4703bd88a0eaae98c3cfc1d5 (patch)
treed124655bcfb2aff4a026b8aac5c8b5e7d8e060c3 /src
parent66360b60b0298c88d32ce2b5e5ce5befa1c09ff8 (diff)
downloadwix-9a061c70f8d87d4f4703bd88a0eaae98c3cfc1d5.tar.gz
wix-9a061c70f8d87d4f4703bd88a0eaae98c3cfc1d5.tar.bz2
wix-9a061c70f8d87d4f4703bd88a0eaae98c3cfc1d5.zip
Always send OnCacheAcquireProgress at least once per payload.
Always send OnCacheAcquireProgress between OnCacheAcquireBegin and OnCacheAcquireComplete. Track the successful cache acquisition progress during the final progress call.
Diffstat (limited to 'src')
-rw-r--r--src/engine/apply.cpp317
-rw-r--r--src/engine/engine.mc21
-rw-r--r--src/engine/plan.cpp8
3 files changed, 185 insertions, 161 deletions
diff --git a/src/engine/apply.cpp b/src/engine/apply.cpp
index c39a7746..e62db4d2 100644
--- a/src/engine/apply.cpp
+++ b/src/engine/apply.cpp
@@ -37,7 +37,7 @@ typedef struct _BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT
37 BURN_PAYLOAD* pPayload; 37 BURN_PAYLOAD* pPayload;
38 38
39 BOOL fCancel; 39 BOOL fCancel;
40 BOOL fError; 40 HRESULT hrError;
41} BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT; 41} BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT;
42 42
43typedef struct _BURN_EXECUTE_CONTEXT 43typedef struct _BURN_EXECUTE_CONTEXT
@@ -102,12 +102,16 @@ static HRESULT LayoutBundle(
102 __in_z LPCWSTR wzExecutableName, 102 __in_z LPCWSTR wzExecutableName,
103 __in_z LPCWSTR wzUnverifiedPath 103 __in_z LPCWSTR wzUnverifiedPath
104 ); 104 );
105static HRESULT AcquireContainerOrPayload( 105static HRESULT ApplyAcquireContainerOrPayload(
106 __in BURN_CACHE_CONTEXT* pContext, 106 __in BURN_CACHE_CONTEXT* pContext,
107 __in_opt BURN_CONTAINER* pContainer, 107 __in_opt BURN_CONTAINER* pContainer,
108 __in_opt BURN_PACKAGE* pPackage, 108 __in_opt BURN_PACKAGE* pPackage,
109 __in_opt BURN_PAYLOAD* pPayload 109 __in_opt BURN_PAYLOAD* pPayload
110 ); 110 );
111static HRESULT AcquireContainerOrPayload(
112 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress,
113 __out BOOL* pfRetry
114 );
111static HRESULT LayoutOrCacheContainerOrPayload( 115static HRESULT LayoutOrCacheContainerOrPayload(
112 __in BURN_CACHE_CONTEXT* pContext, 116 __in BURN_CACHE_CONTEXT* pContext,
113 __in_opt BURN_CONTAINER* pContainer, 117 __in_opt BURN_CONTAINER* pContainer,
@@ -127,6 +131,10 @@ static HRESULT DownloadPayload(
127 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress, 131 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress,
128 __in_z LPCWSTR wzDestinationPath 132 __in_z LPCWSTR wzDestinationPath
129 ); 133 );
134static HRESULT CompleteCacheProgress(
135 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pContext,
136 __in DWORD64 qwFileSize
137 );
130static DWORD CALLBACK CacheProgressRoutine( 138static DWORD CALLBACK CacheProgressRoutine(
131 __in LARGE_INTEGER TotalFileSize, 139 __in LARGE_INTEGER TotalFileSize,
132 __in LARGE_INTEGER TotalBytesTransferred, 140 __in LARGE_INTEGER TotalBytesTransferred,
@@ -833,12 +841,10 @@ static HRESULT ApplyExtractContainer(
833 841
834 if (!pContainer->fActuallyAttached) 842 if (!pContainer->fActuallyAttached)
835 { 843 {
836 hr = AcquireContainerOrPayload(pContext, pContainer, NULL, NULL); 844 hr = ApplyAcquireContainerOrPayload(pContext, pContainer, NULL, NULL);
837 LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_CONTAINER, "Failed to acquire container: %ls to working path: %ls", pContainer->sczId, pContainer->sczUnverifiedPath); 845 LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_CONTAINER, "Failed to acquire container: %ls to working path: %ls", pContainer->sczId, pContainer->sczUnverifiedPath);
838 } 846 }
839 847
840 pContext->qwSuccessfulCacheProgress += pContainer->qwFileSize;
841
842 hr = ExtractContainer(pContext, pContainer); 848 hr = ExtractContainer(pContext, pContainer);
843 LogExitOnFailure(hr, MSG_FAILED_EXTRACT_CONTAINER, "Failed to extract payloads from container: %ls to working path: %ls", pContainer->sczId, pContainer->sczUnverifiedPath); 849 LogExitOnFailure(hr, MSG_FAILED_EXTRACT_CONTAINER, "Failed to extract payloads from container: %ls to working path: %ls", pContainer->sczId, pContainer->sczUnverifiedPath);
844 850
@@ -903,11 +909,9 @@ static HRESULT ApplyLayoutContainer(
903 { 909 {
904 fRetry = FALSE; 910 fRetry = FALSE;
905 911
906 hr = AcquireContainerOrPayload(pContext, pContainer, NULL, NULL); 912 hr = ApplyAcquireContainerOrPayload(pContext, pContainer, NULL, NULL);
907 LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_CONTAINER, "Failed to acquire container: %ls to working path: %ls", pContainer->sczId, pContainer->sczUnverifiedPath); 913 LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_CONTAINER, "Failed to acquire container: %ls to working path: %ls", pContainer->sczId, pContainer->sczUnverifiedPath);
908 914
909 pContext->qwSuccessfulCacheProgress += pContainer->qwFileSize;
910
911 hr = LayoutOrCacheContainerOrPayload(pContext, pContainer, NULL, NULL, TRUE, cTryAgainAttempts, &fRetry); 915 hr = LayoutOrCacheContainerOrPayload(pContext, pContainer, NULL, NULL, TRUE, cTryAgainAttempts, &fRetry);
912 if (SUCCEEDED(hr)) 916 if (SUCCEEDED(hr))
913 { 917 {
@@ -932,7 +936,7 @@ static HRESULT ApplyLayoutContainer(
932 ++cTryAgainAttempts; 936 ++cTryAgainAttempts;
933 pContext->qwSuccessfulCacheProgress -= pContainer->qwFileSize; 937 pContext->qwSuccessfulCacheProgress -= pContainer->qwFileSize;
934 ReleaseNullStr(pContext->sczLastUsedFolderCandidate); 938 ReleaseNullStr(pContext->sczLastUsedFolderCandidate);
935 LogErrorId(hr, MSG_APPLY_RETRYING_PAYLOAD, pContainer->sczId, NULL, NULL); 939 LogErrorId(hr, MSG_APPLY_RETRYING_CONTAINER, pContainer->sczId, NULL, NULL);
936 } 940 }
937 } 941 }
938 942
@@ -971,11 +975,9 @@ static HRESULT ApplyProcessPayload(
971 { 975 {
972 fRetry = FALSE; 976 fRetry = FALSE;
973 977
974 hr = AcquireContainerOrPayload(pContext, NULL, pPackage, pPayload); 978 hr = ApplyAcquireContainerOrPayload(pContext, NULL, pPackage, pPayload);
975 LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_PAYLOAD, "Failed to acquire payload: %ls to working path: %ls", pPayload->sczKey, pPayload->sczUnverifiedPath); 979 LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_PAYLOAD, "Failed to acquire payload: %ls to working path: %ls", pPayload->sczKey, pPayload->sczUnverifiedPath);
976 980
977 pContext->qwSuccessfulCacheProgress += pPayload->qwFileSize;
978
979 // TODO: set fMove to TRUE appropriately 981 // TODO: set fMove to TRUE appropriately
980 hr = LayoutOrCacheContainerOrPayload(pContext, NULL, pPackage, pPayload, FALSE, cTryAgainAttempts, &fRetry); 982 hr = LayoutOrCacheContainerOrPayload(pContext, NULL, pPackage, pPayload, FALSE, cTryAgainAttempts, &fRetry);
981 if (SUCCEEDED(hr)) 983 if (SUCCEEDED(hr))
@@ -1172,7 +1174,7 @@ LExit:
1172 return hr; 1174 return hr;
1173} 1175}
1174 1176
1175static HRESULT AcquireContainerOrPayload( 1177static HRESULT ApplyAcquireContainerOrPayload(
1176 __in BURN_CACHE_CONTEXT* pContext, 1178 __in BURN_CACHE_CONTEXT* pContext,
1177 __in_opt BURN_CONTAINER* pContainer, 1179 __in_opt BURN_CONTAINER* pContainer,
1178 __in_opt BURN_PACKAGE* pPackage, 1180 __in_opt BURN_PACKAGE* pPackage,
@@ -1182,164 +1184,149 @@ static HRESULT AcquireContainerOrPayload(
1182 AssertSz(pContainer || pPayload, "Must provide a container or a payload."); 1184 AssertSz(pContainer || pPayload, "Must provide a container or a payload.");
1183 1185
1184 HRESULT hr = S_OK; 1186 HRESULT hr = S_OK;
1187 BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { };
1188 BOOL fRetry = FALSE;
1189
1190 progress.pCacheContext = pContext;
1191 progress.pContainer = pContainer;
1192 progress.pPackage = pPackage;
1193 progress.pPayload = pPayload;
1194
1195 do
1196 {
1197 hr = AcquireContainerOrPayload(&progress, &fRetry);
1198
1199 if (fRetry)
1200 {
1201 hr = S_OK;
1202 LogErrorId(hr, pContainer ? MSG_APPLY_RETRYING_ACQUIRE_CONTAINER : MSG_APPLY_RETRYING_ACQUIRE_PAYLOAD, pContainer ? pContainer->sczId : pPayload->sczKey, NULL, NULL);
1203 }
1204
1205 ExitOnFailure(hr, "Failed to acquire %hs: %ls", pContainer ? "container" : "payload", pContainer ? pContainer->sczId : pPayload->sczKey);
1206 } while (fRetry);
1207
1208LExit:
1209 return hr;
1210}
1211
1212static HRESULT AcquireContainerOrPayload(
1213 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress,
1214 __out BOOL* pfRetry
1215 )
1216{
1217 BURN_CACHE_CONTEXT* pContext = pProgress->pCacheContext;
1218 BURN_CONTAINER* pContainer = pProgress->pContainer;
1219 BURN_PACKAGE* pPackage = pProgress->pPackage;
1220 BURN_PAYLOAD* pPayload = pProgress->pPayload;
1221 AssertSz(pContainer || pPayload, "Must provide a container or a payload.");
1222
1223 HRESULT hr = S_OK;
1185 int nEquivalentPaths = 0; 1224 int nEquivalentPaths = 0;
1186 LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : NULL; 1225 LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : NULL;
1187 LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : NULL; 1226 LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : NULL;
1188 LPCWSTR wzPayloadContainerId = pPayload && pPayload->pContainer ? pPayload->pContainer->sczId : NULL; 1227 LPCWSTR wzPayloadContainerId = pPayload && pPayload->pContainer ? pPayload->pContainer->sczId : NULL;
1189 LPCWSTR wzDestinationPath = pContainer ? pContainer->sczUnverifiedPath: pPayload->sczUnverifiedPath; 1228 LPCWSTR wzDestinationPath = pContainer ? pContainer->sczUnverifiedPath: pPayload->sczUnverifiedPath;
1190 LPCWSTR wzRelativePath = pContainer ? pContainer->sczFilePath : pPayload->sczFilePath; 1229 LPCWSTR wzRelativePath = pContainer ? pContainer->sczFilePath : pPayload->sczFilePath;
1191 BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { };
1192 BOOL fBeginCalled = FALSE;
1193 BOOL fRetry = FALSE;
1194 DWORD dwChosenSearchPath = 0; 1230 DWORD dwChosenSearchPath = 0;
1195 BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE; 1231 BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1196 LPWSTR* pwzDownloadUrl = pContainer ? &pContainer->downloadSource.sczUrl : &pPayload->downloadSource.sczUrl; 1232 LPWSTR* pwzDownloadUrl = pContainer ? &pContainer->downloadSource.sczUrl : &pPayload->downloadSource.sczUrl;
1197 LPWSTR* pwzSourcePath = pContainer ? &pContainer->sczSourcePath : &pPayload->sczSourcePath; 1233 LPWSTR* pwzSourcePath = pContainer ? &pContainer->sczSourcePath : &pPayload->sczSourcePath;
1234 BOOL fFoundLocal = FALSE;
1198 1235
1199 progress.pCacheContext = pContext; 1236 pContext->cSearchPaths = 0;
1200 progress.pContainer = pContainer; 1237 *pfRetry = FALSE;
1201 progress.pPackage = pPackage; 1238 pProgress->fCancel = FALSE;
1202 progress.pPayload = pPayload;
1203
1204 do
1205 {
1206 BOOL fFoundLocal = FALSE;
1207 1239
1208 pContext->cSearchPaths = 0; 1240 hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pwzSourcePath, pwzDownloadUrl, wzPayloadContainerId, &cacheOperation);
1209 dwChosenSearchPath = 0; 1241 ExitOnRootFailure(hr, "BA aborted cache acquire begin.");
1210 fRetry = FALSE;
1211 progress.fCancel = FALSE;
1212 fBeginCalled = TRUE;
1213 1242
1214 hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pwzSourcePath, pwzDownloadUrl, wzPayloadContainerId, &cacheOperation); 1243 // Skip the Resolving event and probing local paths if the BA already knew it wanted to download or extract.
1215 ExitOnRootFailure(hr, "BA aborted cache acquire begin."); 1244 if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD != cacheOperation &&
1245 BOOTSTRAPPER_CACHE_OPERATION_EXTRACT != cacheOperation)
1246 {
1247 hr = CacheGetLocalSourcePaths(wzRelativePath, *pwzSourcePath, wzDestinationPath, pContext->wzLayoutDirectory, pContext->pVariables, &pContext->rgSearchPaths, &pContext->cSearchPaths);
1248 ExitOnFailure(hr, "Failed to search local source.");
1216 1249
1217 // Skip the Resolving event and probing local paths if the BA already knew it wanted to download or extract. 1250 for (DWORD i = 0; i < pContext->cSearchPaths; ++i)
1218 if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD != cacheOperation &&
1219 BOOTSTRAPPER_CACHE_OPERATION_EXTRACT != cacheOperation)
1220 { 1251 {
1221 hr = CacheGetLocalSourcePaths(wzRelativePath, *pwzSourcePath, wzDestinationPath, pContext->wzLayoutDirectory, pContext->pVariables, &pContext->rgSearchPaths, &pContext->cSearchPaths); 1252 // If the file exists locally, choose it.
1222 ExitOnFailure(hr, "Failed to search local source."); 1253 if (FileExistsEx(pContext->rgSearchPaths[i], NULL))
1223
1224 for (DWORD i = 0; i < pContext->cSearchPaths; ++i)
1225 { 1254 {
1226 // If the file exists locally, choose it. 1255 dwChosenSearchPath = i;
1227 if (FileExistsEx(pContext->rgSearchPaths[i], NULL))
1228 {
1229 dwChosenSearchPath = i;
1230 1256
1231 fFoundLocal = TRUE; 1257 fFoundLocal = TRUE;
1232 break; 1258 break;
1233 }
1234 } 1259 }
1260 }
1235 1261
1236 if (BOOTSTRAPPER_CACHE_OPERATION_COPY == cacheOperation) 1262 if (BOOTSTRAPPER_CACHE_OPERATION_COPY == cacheOperation)
1237 { 1263 {
1238 if (!fFoundLocal) 1264 if (!fFoundLocal)
1239 {
1240 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1241 }
1242 }
1243 else
1244 { 1265 {
1245 if (fFoundLocal) // the file exists locally, so copy it. 1266 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1246 {
1247 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_COPY;
1248 }
1249 else if (wzPayloadContainerId)
1250 {
1251 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_EXTRACT;
1252 }
1253 else if (*pwzDownloadUrl && **pwzDownloadUrl)
1254 {
1255 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD;
1256 }
1257 } 1267 }
1258
1259 // Let the BA have a chance to override the action, but their chance to change the source is during begin or complete.
1260 hr = UserExperienceOnCacheAcquireResolving(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pContext->rgSearchPaths, pContext->cSearchPaths, fFoundLocal, &dwChosenSearchPath, *pwzDownloadUrl, wzPayloadContainerId, &cacheOperation);
1261 ExitOnRootFailure(hr, "BA aborted cache acquire resolving.");
1262 } 1268 }
1263 1269 else
1264 switch (cacheOperation)
1265 { 1270 {
1266 case BOOTSTRAPPER_CACHE_OPERATION_COPY: 1271 if (fFoundLocal) // the file exists locally, so copy it.
1267 // If the source path and destination path are different, do the copy (otherwise there's no point).
1268 hr = PathCompare(pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath, &nEquivalentPaths);
1269 ExitOnFailure(hr, "Failed to determine if payload paths were equivalent, source: %ls, destination: %ls.", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1270
1271 if (CSTR_EQUAL != nEquivalentPaths)
1272 { 1272 {
1273 hr = CopyPayload(&progress, INVALID_HANDLE_VALUE, pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath); 1273 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_COPY;
1274 // Error handling happens after sending complete message to BA.
1275
1276 // Store the source path so it can be used as the LastUsedFolder if it passes verification.
1277 pContext->sczLastUsedFolderCandidate = pContext->rgSearchPaths[dwChosenSearchPath];
1278 pContext->rgSearchPaths[dwChosenSearchPath] = NULL;
1279 } 1274 }
1280 1275 else if (wzPayloadContainerId)
1281 fBeginCalled = FALSE;
1282 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1283 if (fRetry)
1284 { 1276 {
1285 hr = S_OK; 1277 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_EXTRACT;
1286 } 1278 }
1287 1279 else if (*pwzDownloadUrl && **pwzDownloadUrl)
1288 ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1289
1290 break;
1291 case BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD:
1292 hr = DownloadPayload(&progress, wzDestinationPath);
1293 // Error handling happens after sending complete message to BA.
1294
1295 fBeginCalled = FALSE;
1296 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1297 if (fRetry)
1298 { 1280 {
1299 hr = S_OK; 1281 cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD;
1300 } 1282 }
1283 }
1301 1284
1302 ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", *pwzDownloadUrl, wzDestinationPath); 1285 // Let the BA have a chance to override the action, but their chance to change the source is during begin or complete.
1286 hr = UserExperienceOnCacheAcquireResolving(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pContext->rgSearchPaths, pContext->cSearchPaths, fFoundLocal, &dwChosenSearchPath, *pwzDownloadUrl, wzPayloadContainerId, &cacheOperation);
1287 ExitOnRootFailure(hr, "BA aborted cache acquire resolving.");
1288 }
1303 1289
1304 break; 1290 switch (cacheOperation)
1305 case BOOTSTRAPPER_CACHE_OPERATION_EXTRACT: 1291 {
1306 Assert(pPayload->pContainer); 1292 case BOOTSTRAPPER_CACHE_OPERATION_COPY:
1293 // If the source path and destination path are different, do the copy (otherwise there's no point).
1294 hr = PathCompare(pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath, &nEquivalentPaths);
1295 ExitOnFailure(hr, "Failed to determine if payload paths were equivalent, source: %ls, destination: %ls.", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1307 1296
1308 hr = ApplyExtractContainer(pContext, pPayload->pContainer); 1297 if (CSTR_EQUAL != nEquivalentPaths)
1309 // Error handling happens after sending complete message to BA. 1298 {
1299 hr = CopyPayload(pProgress, INVALID_HANDLE_VALUE, pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1300 ExitOnFailure(hr, "Failed to copy payload: %ls", wzPayloadId);
1310 1301
1311 fBeginCalled = FALSE; 1302 // Store the source path so it can be used as the LastUsedFolder if it passes verification.
1312 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); 1303 pContext->sczLastUsedFolderCandidate = pContext->rgSearchPaths[dwChosenSearchPath];
1313 if (fRetry) 1304 pContext->rgSearchPaths[dwChosenSearchPath] = NULL;
1314 { 1305 }
1315 hr = S_OK;
1316 }
1317 1306
1318 ExitOnFailure(hr, "Failed to extract container for payload: %ls", wzPayloadId); 1307 break;
1308 case BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD:
1309 hr = DownloadPayload(pProgress, wzDestinationPath);
1310 ExitOnFailure(hr, "Failed to download payload: %ls", wzPayloadId);
1319 1311
1320 break; 1312 break;
1321 case BOOTSTRAPPER_CACHE_OPERATION_NONE: 1313 case BOOTSTRAPPER_CACHE_OPERATION_EXTRACT:
1322 hr = E_FILENOTFOUND; 1314 Assert(pPayload->pContainer);
1323 LogErrorId(hr, MSG_RESOLVE_SOURCE_FAILED, wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL);
1324 1315
1325 fBeginCalled = FALSE; 1316 hr = ApplyExtractContainer(pContext, pPayload->pContainer);
1326 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); 1317 ExitOnFailure(hr, "Failed to extract container for payload: %ls", wzPayloadId);
1327 if (fRetry)
1328 {
1329 hr = S_OK;
1330 }
1331 1318
1332 ExitOnFailure(hr, "Failed to resolve source, payload: %ls, package: %ls, container: %ls", wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL); 1319 break;
1320 default:
1321 hr = E_FILENOTFOUND;
1322 LogExitOnFailure(hr, MSG_RESOLVE_SOURCE_FAILED, "Failed to resolve source, payload: %ls, package: %ls, container: %ls", wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL);
1323 }
1333 1324
1334 break; 1325 // Send 100% complete here. This is sometimes the only progress sent to the BA.
1335 } 1326 hr = CompleteCacheProgress(pProgress, pContainer ? pContainer->qwFileSize : pPayload->qwFileSize);
1336 } while (fRetry);
1337 1327
1338LExit: 1328LExit:
1339 if (fBeginCalled) 1329 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, pfRetry);
1340 {
1341 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1342 }
1343 1330
1344 pContext->cSearchPathsMax = max(pContext->cSearchPaths, pContext->cSearchPathsMax); 1331 pContext->cSearchPathsMax = max(pContext->cSearchPaths, pContext->cSearchPathsMax);
1345 1332
@@ -1360,9 +1347,6 @@ static HRESULT LayoutOrCacheContainerOrPayload(
1360 LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : L""; 1347 LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : L"";
1361 LPCWSTR wzUnverifiedPath = pContainer ? pContainer->sczUnverifiedPath : pPayload->sczUnverifiedPath; 1348 LPCWSTR wzUnverifiedPath = pContainer ? pContainer->sczUnverifiedPath : pPayload->sczUnverifiedPath;
1362 LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : L""; 1349 LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : L"";
1363 LARGE_INTEGER liContainerOrPayloadSize = { };
1364 LARGE_INTEGER liZero = { };
1365 BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { };
1366 BOOL fCanAffectRegistration = FALSE; 1350 BOOL fCanAffectRegistration = FALSE;
1367 1351
1368 if (!pContext->wzLayoutDirectory) 1352 if (!pContext->wzLayoutDirectory)
@@ -1373,13 +1357,6 @@ static HRESULT LayoutOrCacheContainerOrPayload(
1373 fCanAffectRegistration = pPackage->fCanAffectRegistration; 1357 fCanAffectRegistration = pPackage->fCanAffectRegistration;
1374 } 1358 }
1375 1359
1376 liContainerOrPayloadSize.QuadPart = pContainer ? pContainer->qwFileSize : pPayload->qwFileSize;
1377
1378 progress.pCacheContext = pContext;
1379 progress.pContainer = pContainer;
1380 progress.pPackage = pPackage;
1381 progress.pPayload = pPayload;
1382
1383 *pfRetry = FALSE; 1360 *pfRetry = FALSE;
1384 1361
1385 do 1362 do
@@ -1407,25 +1384,9 @@ static HRESULT LayoutOrCacheContainerOrPayload(
1407 hr = CacheCompletePayload(pPackage->fPerMachine, pPayload, pPackage->sczCacheId, wzUnverifiedPath, fMove); 1384 hr = CacheCompletePayload(pPackage->fPerMachine, pPayload, pPackage->sczCacheId, wzUnverifiedPath, fMove);
1408 } 1385 }
1409 1386
1410 // If succeeded, send 100% complete here. If the payload was already cached this is the first progress the BA 1387 if (SUCCEEDED(hr) && fCanAffectRegistration)
1411 // will get.
1412 if (SUCCEEDED(hr))
1413 { 1388 {
1414 if (fCanAffectRegistration) 1389 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
1415 {
1416 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
1417 }
1418
1419 CacheProgressRoutine(liContainerOrPayloadSize, liContainerOrPayloadSize, liZero, liZero, 0, 0, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, &progress);
1420 if (progress.fCancel)
1421 {
1422 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1423 }
1424 else if (progress.fError)
1425 {
1426 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE);
1427 }
1428 ExitOnRootFailure(hr, "BA aborted verify of %hs: %ls", pContainer ? "container" : "payload", pContainer ? wzPackageOrContainerId : wzPayloadId);
1429 } 1390 }
1430 1391
1431 BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION action = FAILED(hr) && cTryAgainAttempts < BURN_CACHE_MAX_RECOMMENDED_VERIFY_TRYAGAIN_ATTEMPTS ? BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION_RETRYACQUISITION : BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION_NONE; 1392 BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION action = FAILED(hr) && cTryAgainAttempts < BURN_CACHE_MAX_RECOMMENDED_VERIFY_TRYAGAIN_ATTEMPTS ? BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION_RETRYACQUISITION : BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION_NONE;
@@ -1624,6 +1585,39 @@ LExit:
1624 return hr; 1585 return hr;
1625} 1586}
1626 1587
1588static HRESULT CompleteCacheProgress(
1589 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pContext,
1590 __in DWORD64 qwFileSize
1591 )
1592{
1593 HRESULT hr = S_OK;
1594 LARGE_INTEGER liContainerOrPayloadSize = { };
1595 LARGE_INTEGER liZero = { };
1596 DWORD dwResult = 0;
1597
1598 liContainerOrPayloadSize.QuadPart = qwFileSize;
1599
1600 dwResult = CacheProgressRoutine(liContainerOrPayloadSize, liContainerOrPayloadSize, liZero, liZero, 0, 0, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, pContext);
1601
1602 if (PROGRESS_CONTINUE == dwResult)
1603 {
1604 pContext->pCacheContext->qwSuccessfulCacheProgress += qwFileSize;
1605 }
1606 else if (PROGRESS_CANCEL == dwResult)
1607 {
1608 if (pContext->fCancel)
1609 {
1610 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1611 }
1612 else
1613 {
1614 hr = pContext->hrError;
1615 }
1616 }
1617
1618 return hr;
1619}
1620
1627static DWORD CALLBACK CacheProgressRoutine( 1621static DWORD CALLBACK CacheProgressRoutine(
1628 __in LARGE_INTEGER TotalFileSize, 1622 __in LARGE_INTEGER TotalFileSize,
1629 __in LARGE_INTEGER TotalBytesTransferred, 1623 __in LARGE_INTEGER TotalBytesTransferred,
@@ -1650,6 +1644,9 @@ static DWORD CALLBACK CacheProgressRoutine(
1650 DWORD dwOverallPercentage = pProgress->pCacheContext->qwTotalCacheSize ? static_cast<DWORD>(qwCacheProgress * 100 / pProgress->pCacheContext->qwTotalCacheSize) : 0; 1644 DWORD dwOverallPercentage = pProgress->pCacheContext->qwTotalCacheSize ? static_cast<DWORD>(qwCacheProgress * 100 / pProgress->pCacheContext->qwTotalCacheSize) : 0;
1651 1645
1652 hr = UserExperienceOnCacheAcquireProgress(pProgress->pCacheContext->pUX, wzPackageOrContainerId, wzPayloadId, TotalBytesTransferred.QuadPart, TotalFileSize.QuadPart, dwOverallPercentage); 1646 hr = UserExperienceOnCacheAcquireProgress(pProgress->pCacheContext->pUX, wzPackageOrContainerId, wzPayloadId, TotalBytesTransferred.QuadPart, TotalFileSize.QuadPart, dwOverallPercentage);
1647 ExitOnRootFailure(hr, "BA aborted acquire of %hs: %ls", pProgress->pContainer ? "container" : "payload", pProgress->pContainer ? wzPackageOrContainerId : wzPayloadId);
1648
1649LExit:
1653 if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr) 1650 if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hr)
1654 { 1651 {
1655 dwResult = PROGRESS_CANCEL; 1652 dwResult = PROGRESS_CANCEL;
@@ -1658,7 +1655,7 @@ static DWORD CALLBACK CacheProgressRoutine(
1658 else if (FAILED(hr)) 1655 else if (FAILED(hr))
1659 { 1656 {
1660 dwResult = PROGRESS_CANCEL; 1657 dwResult = PROGRESS_CANCEL;
1661 pProgress->fError = TRUE; 1658 pProgress->hrError = hr;
1662 } 1659 }
1663 else 1660 else
1664 { 1661 {
diff --git a/src/engine/engine.mc b/src/engine/engine.mc
index f03bc1ea..0e19d3bb 100644
--- a/src/engine/engine.mc
+++ b/src/engine/engine.mc
@@ -724,6 +724,13 @@ Language=English
724Acquiring package: %1!ls!, payload: %2!ls!, %3!hs! from: %4!ls! 724Acquiring package: %1!ls!, payload: %2!ls!, %3!hs! from: %4!ls!
725. 725.
726 726
727MessageId=347
728Severity=Warning
729SymbolicName=MSG_APPLY_RETRYING_CONTAINER
730Language=English
731Application requested retry of container: %2!ls!, encountered error: %1!ls!. Retrying...
732.
733
727MessageId=348 734MessageId=348
728Severity=Warning 735Severity=Warning
729SymbolicName=MSG_APPLY_RETRYING_PACKAGE 736SymbolicName=MSG_APPLY_RETRYING_PACKAGE
@@ -780,6 +787,20 @@ Language=English
780Unable to register source directory: %1!ls!, product: %2!ls!, reason: 0x%3!x!. Continuing... 787Unable to register source directory: %1!ls!, product: %2!ls!, reason: 0x%3!x!. Continuing...
781. 788.
782 789
790MessageId=356
791Severity=Warning
792SymbolicName=MSG_APPLY_RETRYING_ACQUIRE_CONTAINER
793Language=English
794Application requested retry acquire of container: %2!ls!, encountered error: %1!ls!. Retrying...
795.
796
797MessageId=357
798Severity=Warning
799SymbolicName=MSG_APPLY_RETRYING_ACQUIRE_PAYLOAD
800Language=English
801Application requested retry acquire of payload: %2!ls!, encountered error: %1!ls!. Retrying...
802.
803
783MessageId=358 804MessageId=358
784Severity=Success 805Severity=Success
785SymbolicName=MSG_PAUSE_AU_STARTING 806SymbolicName=MSG_PAUSE_AU_STARTING
diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp
index cfe4893b..a37dcc89 100644
--- a/src/engine/plan.cpp
+++ b/src/engine/plan.cpp
@@ -1010,7 +1010,13 @@ extern "C" HRESULT PlanLayoutContainer(
1010 } 1010 }
1011 else 1011 else
1012 { 1012 {
1013 pPlan->qwCacheSizeTotal += 2 * pContainer->qwFileSize; 1013 if (!pContainer->fActuallyAttached)
1014 {
1015 pPlan->qwCacheSizeTotal += pContainer->qwFileSize;
1016 }
1017
1018 // TODO: This should be the sum of all uncompressed payloads in the container, ideally restricted to the payloads that were actually planned.
1019 pPlan->qwCacheSizeTotal += pContainer->qwFileSize;
1014 } 1020 }
1015 1021
1016 if (!pContainer->sczUnverifiedPath) 1022 if (!pContainer->sczUnverifiedPath)