diff options
Diffstat (limited to '')
| -rw-r--r-- | src/burn/engine/cache.cpp | 127 | ||||
| -rw-r--r-- | src/burn/engine/cache.h | 7 | ||||
| -rw-r--r-- | src/burn/engine/engine.cpp | 7 | ||||
| -rw-r--r-- | src/burn/engine/engine.mc | 16 | ||||
| -rw-r--r-- | src/burn/test/BurnUnitTest/CacheTest.cpp | 95 | ||||
| -rw-r--r-- | src/burn/test/BurnUnitTest/precomp.h | 2 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/guidutil.cpp | 4 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | 9 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/pathutil.cpp | 38 | ||||
| -rw-r--r-- | src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | 28 | ||||
| -rw-r--r-- | src/test/burn/WixTestTools/BundleVerifier.cs | 12 | ||||
| -rw-r--r-- | src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs | 68 |
12 files changed, 338 insertions, 75 deletions
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index b311a195..7fca8cc7 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp | |||
| @@ -14,10 +14,10 @@ static HRESULT CacheVerifyPayloadSignature( | |||
| 14 | __in_z LPCWSTR wzUnverifiedPayloadPath, | 14 | __in_z LPCWSTR wzUnverifiedPayloadPath, |
| 15 | __in HANDLE hFile | 15 | __in HANDLE hFile |
| 16 | ); | 16 | ); |
| 17 | static HRESULT CalculateBaseWorkingFolder( | 17 | static HRESULT CalculatePotentialBaseWorkingFolders( |
| 18 | __in BURN_CACHE* pCache, | ||
| 18 | __in BURN_ENGINE_COMMAND* pInternalCommand, | 19 | __in BURN_ENGINE_COMMAND* pInternalCommand, |
| 19 | __in LPCWSTR wzAcquisitionFolder, | 20 | __in LPCWSTR wzAcquisitionFolder |
| 20 | __inout_z LPWSTR* psczBaseWorkingFolder | ||
| 21 | ); | 21 | ); |
| 22 | static HRESULT CalculateWorkingFolders( | 22 | static HRESULT CalculateWorkingFolders( |
| 23 | __in BURN_CACHE* pCache, | 23 | __in BURN_CACHE* pCache, |
| @@ -321,8 +321,8 @@ extern "C" HRESULT CacheEnsureAcquisitionFolder( | |||
| 321 | hr = DirEnsureExists(pCache->sczAcquisitionFolder, NULL); | 321 | hr = DirEnsureExists(pCache->sczAcquisitionFolder, NULL); |
| 322 | ExitOnFailure(hr, "Failed create acquisition folder."); | 322 | ExitOnFailure(hr, "Failed create acquisition folder."); |
| 323 | 323 | ||
| 324 | // Best effort to ensure our working folder is not encrypted. | 324 | // Best effort to ensure our acquisition folder is not encrypted. |
| 325 | ::DecryptFileW(pCache->sczBaseWorkingFolder, 0); | 325 | ::DecryptFileW(pCache->sczAcquisitionFolder, 0); |
| 326 | 326 | ||
| 327 | LExit: | 327 | LExit: |
| 328 | return hr; | 328 | return hr; |
| @@ -336,9 +336,30 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder( | |||
| 336 | Assert(pCache->fInitializedCache); | 336 | Assert(pCache->fInitializedCache); |
| 337 | 337 | ||
| 338 | HRESULT hr = S_OK; | 338 | HRESULT hr = S_OK; |
| 339 | LPWSTR sczPotential = NULL; | ||
| 340 | |||
| 341 | if (!pCache->fInitializedBaseWorkingFolder) | ||
| 342 | { | ||
| 343 | for (DWORD i = 0; i < pCache->cPotentialBaseWorkingFolders; ++i) | ||
| 344 | { | ||
| 345 | hr = PathConcatRelativeToBase(pCache->rgsczPotentialBaseWorkingFolders[i], pCache->wzGuid, &sczPotential); | ||
| 346 | ExitOnFailure(hr, "Failed to append random guid on to potential path for working folder."); | ||
| 347 | |||
| 348 | hr = DirEnsureExists(sczPotential, NULL); | ||
| 349 | if (SUCCEEDED(hr)) | ||
| 350 | { | ||
| 351 | pCache->sczBaseWorkingFolder = sczPotential; | ||
| 352 | sczPotential = NULL; | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | |||
| 356 | LogErrorId(hr, MSG_INVALID_BASE_WORKING_FOLDER, sczPotential, NULL, NULL); | ||
| 357 | } | ||
| 339 | 358 | ||
| 340 | hr = DirEnsureExists(pCache->sczBaseWorkingFolder, NULL); | 359 | ExitOnNull(pCache->sczBaseWorkingFolder, hr, E_INVALIDSTATE, "No usable base working folder found."); |
| 341 | ExitOnFailure(hr, "Failed create working folder."); | 360 | |
| 361 | pCache->fInitializedBaseWorkingFolder = TRUE; | ||
| 362 | } | ||
| 342 | 363 | ||
| 343 | // Best effort to ensure our working folder is not encrypted. | 364 | // Best effort to ensure our working folder is not encrypted. |
| 344 | ::DecryptFileW(pCache->sczBaseWorkingFolder, 0); | 365 | ::DecryptFileW(pCache->sczBaseWorkingFolder, 0); |
| @@ -350,6 +371,8 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder( | |||
| 350 | } | 371 | } |
| 351 | 372 | ||
| 352 | LExit: | 373 | LExit: |
| 374 | ReleaseStr(sczPotential); | ||
| 375 | |||
| 353 | return hr; | 376 | return hr; |
| 354 | } | 377 | } |
| 355 | 378 | ||
| @@ -360,6 +383,7 @@ extern "C" HRESULT CacheCalculateBundleWorkingPath( | |||
| 360 | ) | 383 | ) |
| 361 | { | 384 | { |
| 362 | Assert(pCache->fInitializedCache); | 385 | Assert(pCache->fInitializedCache); |
| 386 | Assert(pCache->fInitializedBaseWorkingFolder); | ||
| 363 | 387 | ||
| 364 | HRESULT hr = S_OK; | 388 | HRESULT hr = S_OK; |
| 365 | 389 | ||
| @@ -1180,7 +1204,7 @@ extern "C" HRESULT CacheRemoveBaseWorkingFolder( | |||
| 1180 | { | 1204 | { |
| 1181 | HRESULT hr = S_OK; | 1205 | HRESULT hr = S_OK; |
| 1182 | 1206 | ||
| 1183 | if (pCache->fInitializedCacheSources) | 1207 | if (pCache->fInitializedBaseWorkingFolder) |
| 1184 | { | 1208 | { |
| 1185 | // Try to clean out everything in the working folder. | 1209 | // Try to clean out everything in the working folder. |
| 1186 | hr = DirEnsureDeleteEx(pCache->sczBaseWorkingFolder, DIR_DELETE_FILES | DIR_DELETE_RECURSE | DIR_DELETE_SCHEDULE); | 1210 | hr = DirEnsureDeleteEx(pCache->sczBaseWorkingFolder, DIR_DELETE_FILES | DIR_DELETE_RECURSE | DIR_DELETE_SCHEDULE); |
| @@ -1343,70 +1367,78 @@ extern "C" void CacheUninitialize( | |||
| 1343 | __in BURN_CACHE* pCache | 1367 | __in BURN_CACHE* pCache |
| 1344 | ) | 1368 | ) |
| 1345 | { | 1369 | { |
| 1346 | ReleaseNullStr(pCache->sczCurrentMachinePackageCache); | 1370 | ReleaseStrArray(pCache->rgsczPotentialBaseWorkingFolders, pCache->cPotentialBaseWorkingFolders); |
| 1347 | ReleaseNullStr(pCache->sczDefaultMachinePackageCache); | 1371 | ReleaseStr(pCache->sczCurrentMachinePackageCache); |
| 1348 | ReleaseNullStr(pCache->sczDefaultUserPackageCache); | 1372 | ReleaseStr(pCache->sczDefaultMachinePackageCache); |
| 1349 | ReleaseNullStr(pCache->sczBaseWorkingFolder); | 1373 | ReleaseStr(pCache->sczDefaultUserPackageCache); |
| 1350 | ReleaseNullStr(pCache->sczAcquisitionFolder); | 1374 | ReleaseStr(pCache->sczBaseWorkingFolder); |
| 1351 | ReleaseNullStr(pCache->sczSourceProcessFolder); | 1375 | ReleaseStr(pCache->sczAcquisitionFolder); |
| 1352 | 1376 | ReleaseStr(pCache->sczSourceProcessFolder); | |
| 1353 | pCache->fRunningFromCache = FALSE; | 1377 | |
| 1354 | pCache->fInitializedCache = FALSE; | 1378 | memset(pCache, 0, sizeof(BURN_CACHE)); |
| 1355 | pCache->fInitializedCacheSources = FALSE; | ||
| 1356 | pCache->fPerMachineCacheRootVerified = FALSE; | ||
| 1357 | pCache->fOriginalPerMachineCacheRootVerified = FALSE; | ||
| 1358 | pCache->fUnverifiedCacheFolderCreated = FALSE; | ||
| 1359 | pCache->fCustomMachinePackageCache = FALSE; | ||
| 1360 | } | 1379 | } |
| 1361 | 1380 | ||
| 1362 | // Internal functions. | 1381 | // Internal functions. |
| 1363 | 1382 | ||
| 1364 | static HRESULT CalculateBaseWorkingFolder( | 1383 | static HRESULT CalculatePotentialBaseWorkingFolders( |
| 1384 | __in BURN_CACHE* pCache, | ||
| 1365 | __in BURN_ENGINE_COMMAND* pInternalCommand, | 1385 | __in BURN_ENGINE_COMMAND* pInternalCommand, |
| 1366 | __in LPCWSTR wzAcquisitionFolder, | 1386 | __in LPCWSTR wzAcquisitionFolder |
| 1367 | __inout_z LPWSTR* psczBaseWorkingFolder | ||
| 1368 | ) | 1387 | ) |
| 1369 | { | 1388 | { |
| 1389 | Assert(!pCache->rgsczPotentialBaseWorkingFolders && !pCache->cPotentialBaseWorkingFolders); | ||
| 1370 | HRESULT hr = S_OK; | 1390 | HRESULT hr = S_OK; |
| 1391 | LPWSTR sczTemp = NULL; | ||
| 1371 | 1392 | ||
| 1372 | ReleaseNullStr(*psczBaseWorkingFolder); | 1393 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pCache->rgsczPotentialBaseWorkingFolders), 6, sizeof(LPWSTR), 6); |
| 1394 | ExitOnFailure(hr, "Failed to initialize array."); | ||
| 1373 | 1395 | ||
| 1374 | // The value from the command line takes precedence. | 1396 | // The value from the command line takes precedence. |
| 1375 | if (pInternalCommand->sczEngineWorkingDirectory) | 1397 | if (pInternalCommand->sczEngineWorkingDirectory) |
| 1376 | { | 1398 | { |
| 1377 | hr = PathExpand(psczBaseWorkingFolder, pInternalCommand->sczEngineWorkingDirectory, PATH_EXPAND_FULLPATH); | 1399 | hr = PathExpand(&sczTemp, pInternalCommand->sczEngineWorkingDirectory, PATH_EXPAND_FULLPATH); |
| 1378 | ExitOnFailure(hr, "Failed to expand engine working directory from command-line: '%ls'", pInternalCommand->sczEngineWorkingDirectory); | 1400 | ExitOnFailure(hr, "Failed to expand engine working directory from command-line: '%ls'", pInternalCommand->sczEngineWorkingDirectory); |
| 1379 | 1401 | ||
| 1380 | ExitFunction(); | 1402 | pCache->rgsczPotentialBaseWorkingFolders[pCache->cPotentialBaseWorkingFolders] = sczTemp; |
| 1403 | sczTemp = NULL; | ||
| 1404 | ++pCache->cPotentialBaseWorkingFolders; | ||
| 1381 | } | 1405 | } |
| 1382 | 1406 | ||
| 1383 | // The base working folder can be specified through policy, | 1407 | // The base working folder can be specified through policy, |
| 1384 | // but only use it if elevated because it should be secured against non-admin users. | 1408 | // but only use it if elevated because it should be secured against non-admin users. |
| 1385 | if (pInternalCommand->fInitiallyElevated) | 1409 | if (pInternalCommand->fInitiallyElevated) |
| 1386 | { | 1410 | { |
| 1387 | hr = PolcReadString(POLICY_BURN_REGISTRY_PATH, L"EngineWorkingDirectory", NULL, psczBaseWorkingFolder); | 1411 | hr = PolcReadString(POLICY_BURN_REGISTRY_PATH, L"EngineWorkingDirectory", NULL, &sczTemp); |
| 1388 | ExitOnFailure(hr, "Failed to read EngineWorkingDirectory policy directory."); | 1412 | ExitOnFailure(hr, "Failed to read EngineWorkingDirectory policy directory."); |
| 1389 | 1413 | ||
| 1390 | if (*psczBaseWorkingFolder) | 1414 | if (sczTemp) |
| 1391 | { | 1415 | { |
| 1392 | // PolcReadString is supposed to automatically expand REG_EXPAND_SZ values. | 1416 | // PolcReadString is supposed to automatically expand REG_EXPAND_SZ values. |
| 1393 | ExitFunction(); | 1417 | pCache->rgsczPotentialBaseWorkingFolders[pCache->cPotentialBaseWorkingFolders] = sczTemp; |
| 1418 | sczTemp = NULL; | ||
| 1419 | ++pCache->cPotentialBaseWorkingFolders; | ||
| 1394 | } | 1420 | } |
| 1395 | } | 1421 | } |
| 1396 | 1422 | ||
| 1397 | // Default to the acquisition folder, but need to use system temp path for security reasons if running elevated. | 1423 | // Default to the acquisition folder, but need to use system temp path for security reasons if running elevated. |
| 1398 | if (pInternalCommand->fInitiallyElevated) | 1424 | if (pInternalCommand->fInitiallyElevated) |
| 1399 | { | 1425 | { |
| 1400 | hr = PathGetSystemTempPath(psczBaseWorkingFolder); | 1426 | hr = PathGetSystemTempPaths(&pCache->rgsczPotentialBaseWorkingFolders, &pCache->cPotentialBaseWorkingFolders); |
| 1401 | ExitOnFailure(hr, "Failed to get system temp folder path for base working folder."); | 1427 | ExitOnFailure(hr, "Failed to get system temp folder paths for base working folder."); |
| 1402 | } | 1428 | } |
| 1403 | else | 1429 | else |
| 1404 | { | 1430 | { |
| 1405 | hr = StrAllocString(psczBaseWorkingFolder, wzAcquisitionFolder, 0); | 1431 | hr = StrAllocString(&sczTemp, wzAcquisitionFolder, 0); |
| 1406 | ExitOnFailure(hr, "Failed to copy acquisition folder path for base working folder."); | 1432 | ExitOnFailure(hr, "Failed to copy acquisition folder path for base working folder."); |
| 1433 | |||
| 1434 | pCache->rgsczPotentialBaseWorkingFolders[pCache->cPotentialBaseWorkingFolders] = sczTemp; | ||
| 1435 | sczTemp = NULL; | ||
| 1436 | ++pCache->cPotentialBaseWorkingFolders; | ||
| 1407 | } | 1437 | } |
| 1408 | 1438 | ||
| 1409 | LExit: | 1439 | LExit: |
| 1440 | ReleaseStr(sczTemp); | ||
| 1441 | |||
| 1410 | return hr; | 1442 | return hr; |
| 1411 | } | 1443 | } |
| 1412 | 1444 | ||
| @@ -1416,11 +1448,7 @@ static HRESULT CalculateWorkingFolders( | |||
| 1416 | ) | 1448 | ) |
| 1417 | { | 1449 | { |
| 1418 | HRESULT hr = S_OK; | 1450 | HRESULT hr = S_OK; |
| 1419 | RPC_STATUS rs = RPC_S_OK; | ||
| 1420 | LPWSTR sczBaseAcquisitionPath = NULL; | 1451 | LPWSTR sczBaseAcquisitionPath = NULL; |
| 1421 | LPWSTR sczTempPath = NULL; | ||
| 1422 | UUID guid = {}; | ||
| 1423 | WCHAR wzGuid[39]; | ||
| 1424 | 1452 | ||
| 1425 | hr = PathGetTempPath(&sczBaseAcquisitionPath); | 1453 | hr = PathGetTempPath(&sczBaseAcquisitionPath); |
| 1426 | ExitOnFailure(hr, "Failed to get temp folder path for acquisition folder base."); | 1454 | ExitOnFailure(hr, "Failed to get temp folder path for acquisition folder base."); |
| @@ -1428,31 +1456,20 @@ static HRESULT CalculateWorkingFolders( | |||
| 1428 | hr = PathBackslashTerminate(&sczBaseAcquisitionPath); | 1456 | hr = PathBackslashTerminate(&sczBaseAcquisitionPath); |
| 1429 | ExitOnFailure(hr, "Failed to backslashify base engine working directory."); | 1457 | ExitOnFailure(hr, "Failed to backslashify base engine working directory."); |
| 1430 | 1458 | ||
| 1431 | hr = CalculateBaseWorkingFolder(pInternalCommand, sczBaseAcquisitionPath, &sczTempPath); | 1459 | hr = CalculatePotentialBaseWorkingFolders(pCache, pInternalCommand, sczBaseAcquisitionPath); |
| 1432 | ExitOnFailure(hr, "Failed to get base engine working directory."); | 1460 | ExitOnFailure(hr, "Failed to get potential base engine working directories."); |
| 1433 | |||
| 1434 | hr = PathBackslashTerminate(&sczTempPath); | ||
| 1435 | ExitOnFailure(hr, "Failed to backslashify base engine working directory."); | ||
| 1436 | 1461 | ||
| 1437 | rs = ::UuidCreate(&guid); | 1462 | hr = GuidFixedCreate(pCache->wzGuid); |
| 1438 | hr = HRESULT_FROM_RPC(rs); | ||
| 1439 | ExitOnFailure(hr, "Failed to create working folder guid."); | 1463 | ExitOnFailure(hr, "Failed to create working folder guid."); |
| 1440 | 1464 | ||
| 1441 | if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) | 1465 | pCache->wzGuid[GUID_STRING_LENGTH - 1] = L'\\'; |
| 1442 | { | 1466 | pCache->wzGuid[GUID_STRING_LENGTH] = L'\0'; |
| 1443 | hr = E_OUTOFMEMORY; | ||
| 1444 | ExitOnRootFailure(hr, "Failed to convert working folder guid into string."); | ||
| 1445 | } | ||
| 1446 | 1467 | ||
| 1447 | hr = StrAllocFormatted(&pCache->sczAcquisitionFolder, L"%ls%ls\\", sczBaseAcquisitionPath, wzGuid); | 1468 | hr = PathConcatRelativeToBase(sczBaseAcquisitionPath, pCache->wzGuid, &pCache->sczAcquisitionFolder); |
| 1448 | ExitOnFailure(hr, "Failed to append random guid on to temp path for acquisition folder."); | 1469 | ExitOnFailure(hr, "Failed to append random guid on to temp path for acquisition folder."); |
| 1449 | 1470 | ||
| 1450 | hr = StrAllocFormatted(&pCache->sczBaseWorkingFolder, L"%ls%ls\\", sczTempPath, wzGuid); | ||
| 1451 | ExitOnFailure(hr, "Failed to append random guid on to temp path for working folder."); | ||
| 1452 | |||
| 1453 | LExit: | 1471 | LExit: |
| 1454 | ReleaseStr(sczBaseAcquisitionPath); | 1472 | ReleaseStr(sczBaseAcquisitionPath); |
| 1455 | ReleaseStr(sczTempPath); | ||
| 1456 | 1473 | ||
| 1457 | return hr; | 1474 | return hr; |
| 1458 | } | 1475 | } |
diff --git a/src/burn/engine/cache.h b/src/burn/engine/cache.h index 8b038b99..9c698b4b 100644 --- a/src/burn/engine/cache.h +++ b/src/burn/engine/cache.h | |||
| @@ -35,11 +35,18 @@ typedef struct _BURN_CACHE | |||
| 35 | LPWSTR sczDefaultMachinePackageCache; | 35 | LPWSTR sczDefaultMachinePackageCache; |
| 36 | LPWSTR sczCurrentMachinePackageCache; | 36 | LPWSTR sczCurrentMachinePackageCache; |
| 37 | 37 | ||
| 38 | WCHAR wzGuid[GUID_STRING_LENGTH + 1]; | ||
| 39 | LPWSTR* rgsczPotentialBaseWorkingFolders; | ||
| 40 | DWORD cPotentialBaseWorkingFolders; | ||
| 41 | |||
| 38 | // Only valid after CacheInitializeSources | 42 | // Only valid after CacheInitializeSources |
| 39 | BOOL fInitializedCacheSources; | 43 | BOOL fInitializedCacheSources; |
| 40 | BOOL fRunningFromCache; | 44 | BOOL fRunningFromCache; |
| 41 | LPWSTR sczSourceProcessFolder; | 45 | LPWSTR sczSourceProcessFolder; |
| 42 | LPWSTR sczAcquisitionFolder; | 46 | LPWSTR sczAcquisitionFolder; |
| 47 | |||
| 48 | // Only valid after CacheEnsureBaseWorkingFolder | ||
| 49 | BOOL fInitializedBaseWorkingFolder; | ||
| 43 | LPWSTR sczBaseWorkingFolder; | 50 | LPWSTR sczBaseWorkingFolder; |
| 44 | } BURN_CACHE; | 51 | } BURN_CACHE; |
| 45 | 52 | ||
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index a408ed4a..aca43438 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp | |||
| @@ -97,6 +97,7 @@ extern "C" HRESULT EngineRun( | |||
| 97 | LPWSTR sczExePath = NULL; | 97 | LPWSTR sczExePath = NULL; |
| 98 | BOOL fRunUntrusted = FALSE; | 98 | BOOL fRunUntrusted = FALSE; |
| 99 | BOOL fRunNormal = FALSE; | 99 | BOOL fRunNormal = FALSE; |
| 100 | BOOL fRunRunOnce = FALSE; | ||
| 100 | BOOL fRestart = FALSE; | 101 | BOOL fRestart = FALSE; |
| 101 | 102 | ||
| 102 | BURN_ENGINE_STATE engineState = { }; | 103 | BURN_ENGINE_STATE engineState = { }; |
| @@ -221,6 +222,8 @@ extern "C" HRESULT EngineRun( | |||
| 221 | break; | 222 | break; |
| 222 | 223 | ||
| 223 | case BURN_MODE_RUNONCE: | 224 | case BURN_MODE_RUNONCE: |
| 225 | fRunRunOnce = TRUE; | ||
| 226 | |||
| 224 | hr = RunRunOnce(&engineState, nCmdShow); | 227 | hr = RunRunOnce(&engineState, nCmdShow); |
| 225 | ExitOnFailure(hr, "Failed to run RunOnce mode."); | 228 | ExitOnFailure(hr, "Failed to run RunOnce mode."); |
| 226 | break; | 229 | break; |
| @@ -303,6 +306,10 @@ LExit: | |||
| 303 | { | 306 | { |
| 304 | LogId(REPORT_STANDARD, MSG_EXITING_CLEAN_ROOM, FAILED(hr) ? (int)hr : *pdwExitCode); | 307 | LogId(REPORT_STANDARD, MSG_EXITING_CLEAN_ROOM, FAILED(hr) ? (int)hr : *pdwExitCode); |
| 305 | } | 308 | } |
| 309 | else if (fRunRunOnce) | ||
| 310 | { | ||
| 311 | LogId(REPORT_STANDARD, MSG_EXITING_RUN_ONCE, FAILED(hr) ? (int)hr : *pdwExitCode); | ||
| 312 | } | ||
| 306 | 313 | ||
| 307 | if (fLogInitialized) | 314 | if (fLogInitialized) |
| 308 | { | 315 | { |
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 32473252..9a08fa3f 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc | |||
| @@ -149,6 +149,20 @@ Language=English | |||
| 149 | Exit code: 0x%1!x! | 149 | Exit code: 0x%1!x! |
| 150 | . | 150 | . |
| 151 | 151 | ||
| 152 | MessageId=18 | ||
| 153 | Severity=Success | ||
| 154 | SymbolicName=MSG_EXITING_RUN_ONCE | ||
| 155 | Language=English | ||
| 156 | Exit code: 0x%1!x! | ||
| 157 | . | ||
| 158 | |||
| 159 | MessageId=19 | ||
| 160 | Severity=Warning | ||
| 161 | SymbolicName=MSG_INVALID_BASE_WORKING_FOLDER | ||
| 162 | Language=English | ||
| 163 | Failed to use folder as base working folder: %2!ls!, encountered error: %1!ls!. | ||
| 164 | . | ||
| 165 | |||
| 152 | MessageId=51 | 166 | MessageId=51 |
| 153 | Severity=Error | 167 | Severity=Error |
| 154 | SymbolicName=MSG_FAILED_PARSE_CONDITION | 168 | SymbolicName=MSG_FAILED_PARSE_CONDITION |
| @@ -811,7 +825,7 @@ MessageId=346 | |||
| 811 | Severity=Warning | 825 | Severity=Warning |
| 812 | SymbolicName=MSG_CACHE_RETRYING_PACKAGE | 826 | SymbolicName=MSG_CACHE_RETRYING_PACKAGE |
| 813 | Language=English | 827 | Language=English |
| 814 | Application requested retry of caching package: %1!ls!, encountered error: 0x%2!x!. Retrying... | 828 | Application requested retry of caching package: %2!ls!, encountered error: %1!ls!. Retrying... |
| 815 | . | 829 | . |
| 816 | 830 | ||
| 817 | MessageId=347 | 831 | MessageId=347 |
diff --git a/src/burn/test/BurnUnitTest/CacheTest.cpp b/src/burn/test/BurnUnitTest/CacheTest.cpp index 6979ec1a..eb0b31ab 100644 --- a/src/burn/test/BurnUnitTest/CacheTest.cpp +++ b/src/burn/test/BurnUnitTest/CacheTest.cpp | |||
| @@ -37,11 +37,100 @@ namespace Bootstrapper | |||
| 37 | using namespace System::IO; | 37 | using namespace System::IO; |
| 38 | using namespace Xunit; | 38 | using namespace Xunit; |
| 39 | 39 | ||
| 40 | public ref class CacheTest : BurnUnitTest | 40 | public ref class CacheTest : BurnUnitTest, IClassFixture<TestRegistryFixture^> |
| 41 | { | 41 | { |
| 42 | private: | ||
| 43 | TestRegistryFixture^ testRegistry; | ||
| 42 | public: | 44 | public: |
| 43 | CacheTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture) | 45 | CacheTest(BurnTestFixture^ fixture, TestRegistryFixture^ registryFixture) : BurnUnitTest(fixture) |
| 44 | { | 46 | { |
| 47 | this->testRegistry = registryFixture; | ||
| 48 | } | ||
| 49 | |||
| 50 | [Fact] | ||
| 51 | void CacheElevatedTempFallbacksTest() | ||
| 52 | { | ||
| 53 | HRESULT hr = S_OK; | ||
| 54 | BURN_CACHE cache = { }; | ||
| 55 | BURN_ENGINE_COMMAND internalCommand = { }; | ||
| 56 | HKEY hkSystemEnvironment = NULL; | ||
| 57 | HKEY hkBurnPolicy = NULL; | ||
| 58 | |||
| 59 | internalCommand.fInitiallyElevated = TRUE; | ||
| 60 | |||
| 61 | try | ||
| 62 | { | ||
| 63 | this->testRegistry->SetUp(); | ||
| 64 | |||
| 65 | // No registry keys, so should fallback to %windir%\TEMP. | ||
| 66 | hr = CacheInitialize(&cache, &internalCommand); | ||
| 67 | NativeAssert::Succeeded(hr, "Failed to initialize cache."); | ||
| 68 | Assert::NotEqual<DWORD>(0, cache.cPotentialBaseWorkingFolders); | ||
| 69 | VerifyBaseWorkingFolder(L"%windir%\\TEMP\\", cache.rgsczPotentialBaseWorkingFolders[0]); | ||
| 70 | CacheUninitialize(&cache); | ||
| 71 | |||
| 72 | hr = RegCreate(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", GENERIC_WRITE, &hkSystemEnvironment); | ||
| 73 | NativeAssert::Succeeded(hr, "Failed to create system environment key."); | ||
| 74 | |||
| 75 | // Third fallback is system-level %TEMP%. | ||
| 76 | hr = RegWriteExpandString(hkSystemEnvironment, L"TEMP", L"A:\\TEST\\TEMP"); | ||
| 77 | NativeAssert::Succeeded(hr, "Failed to write TEMP system environment value."); | ||
| 78 | |||
| 79 | hr = CacheInitialize(&cache, &internalCommand); | ||
| 80 | NativeAssert::Succeeded(hr, "Failed to initialize cache."); | ||
| 81 | Assert::NotEqual<DWORD>(0, cache.cPotentialBaseWorkingFolders); | ||
| 82 | VerifyBaseWorkingFolder(L"A:\\TEST\\TEMP\\", cache.rgsczPotentialBaseWorkingFolders[0]); | ||
| 83 | CacheUninitialize(&cache); | ||
| 84 | |||
| 85 | // Second fallback is system-level %TMP%. | ||
| 86 | hr = RegWriteExpandString(hkSystemEnvironment, L"TMP", L"B:\\TEST\\TMP\\"); | ||
| 87 | NativeAssert::Succeeded(hr, "Failed to write TEMP system environment value."); | ||
| 88 | |||
| 89 | hr = CacheInitialize(&cache, &internalCommand); | ||
| 90 | NativeAssert::Succeeded(hr, "Failed to initialize cache."); | ||
| 91 | Assert::NotEqual<DWORD>(0, cache.cPotentialBaseWorkingFolders); | ||
| 92 | VerifyBaseWorkingFolder(L"B:\\TEST\\TMP\\", cache.rgsczPotentialBaseWorkingFolders[0]); | ||
| 93 | CacheUninitialize(&cache); | ||
| 94 | |||
| 95 | hr = RegCreate(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\WiX\\Burn", GENERIC_WRITE, &hkBurnPolicy); | ||
| 96 | NativeAssert::Succeeded(hr, "Failed to create Burn policy key."); | ||
| 97 | |||
| 98 | // Default source is Burn policy. | ||
| 99 | hr = RegWriteExpandString(hkBurnPolicy, L"EngineWorkingDirectory", L"D:\\TEST\\POLICY\\"); | ||
| 100 | NativeAssert::Succeeded(hr, "Failed to write EngineWorkingDirectory Burn policy value."); | ||
| 101 | |||
| 102 | hr = CacheInitialize(&cache, &internalCommand); | ||
| 103 | NativeAssert::Succeeded(hr, "Failed to initialize cache."); | ||
| 104 | Assert::NotEqual<DWORD>(0, cache.cPotentialBaseWorkingFolders); | ||
| 105 | VerifyBaseWorkingFolder(L"D:\\TEST\\POLICY\\", cache.rgsczPotentialBaseWorkingFolders[0]); | ||
| 106 | CacheUninitialize(&cache); | ||
| 107 | |||
| 108 | // Command line parameter overrides everything else. | ||
| 109 | hr = StrAllocString(&internalCommand.sczEngineWorkingDirectory, L"E:\\TEST\\COMMANDLINE\\", 0); | ||
| 110 | NativeAssert::Succeeded(hr, "Failed to copy command line working directory."); | ||
| 111 | |||
| 112 | hr = CacheInitialize(&cache, &internalCommand); | ||
| 113 | NativeAssert::Succeeded(hr, "Failed to initialize cache."); | ||
| 114 | Assert::NotEqual<DWORD>(0, cache.cPotentialBaseWorkingFolders); | ||
| 115 | VerifyBaseWorkingFolder(L"E:\\TEST\\COMMANDLINE\\", cache.rgsczPotentialBaseWorkingFolders[0]); | ||
| 116 | CacheUninitialize(&cache); | ||
| 117 | } | ||
| 118 | finally | ||
| 119 | { | ||
| 120 | ReleaseRegKey(hkBurnPolicy); | ||
| 121 | ReleaseRegKey(hkSystemEnvironment); | ||
| 122 | ReleaseStr(internalCommand.sczEngineWorkingDirectory); | ||
| 123 | |||
| 124 | CacheUninitialize(&cache); | ||
| 125 | |||
| 126 | this->testRegistry->TearDown(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | void VerifyBaseWorkingFolder(LPCWSTR wzExpectedUnexpanded, LPCWSTR wzActual) | ||
| 131 | { | ||
| 132 | String^ expected = Environment::ExpandEnvironmentVariables(gcnew String(wzExpectedUnexpanded)); | ||
| 133 | WixAssert::StringEqual(expected, gcnew String(wzActual), true); | ||
| 45 | } | 134 | } |
| 46 | 135 | ||
| 47 | [Fact] | 136 | [Fact] |
| @@ -93,6 +182,8 @@ namespace Bootstrapper | |||
| 93 | File::SetAttributes(filePath, FileAttributes::Normal); | 182 | File::SetAttributes(filePath, FileAttributes::Normal); |
| 94 | File::Delete(filePath); | 183 | File::Delete(filePath); |
| 95 | } | 184 | } |
| 185 | |||
| 186 | CacheUninitialize(&cache); | ||
| 96 | } | 187 | } |
| 97 | } | 188 | } |
| 98 | }; | 189 | }; |
diff --git a/src/burn/test/BurnUnitTest/precomp.h b/src/burn/test/BurnUnitTest/precomp.h index 11e54284..92c8c4c0 100644 --- a/src/burn/test/BurnUnitTest/precomp.h +++ b/src/burn/test/BurnUnitTest/precomp.h | |||
| @@ -19,9 +19,11 @@ | |||
| 19 | #include <buffutil.h> | 19 | #include <buffutil.h> |
| 20 | #include <dirutil.h> | 20 | #include <dirutil.h> |
| 21 | #include <fileutil.h> | 21 | #include <fileutil.h> |
| 22 | #include <guidutil.h> | ||
| 22 | #include <logutil.h> | 23 | #include <logutil.h> |
| 23 | #include <memutil.h> | 24 | #include <memutil.h> |
| 24 | #include <pathutil.h> | 25 | #include <pathutil.h> |
| 26 | #include <polcutil.h> | ||
| 25 | #include <regutil.h> | 27 | #include <regutil.h> |
| 26 | #include <resrutil.h> | 28 | #include <resrutil.h> |
| 27 | #include <shelutil.h> | 29 | #include <shelutil.h> |
diff --git a/src/libs/dutil/WixToolset.DUtil/guidutil.cpp b/src/libs/dutil/WixToolset.DUtil/guidutil.cpp index 204c9af2..946c256f 100644 --- a/src/libs/dutil/WixToolset.DUtil/guidutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/guidutil.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #define GuidExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) | 9 | #define GuidExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) |
| 10 | #define GuidExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) | 10 | #define GuidExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) |
| 11 | #define GuidExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) | 11 | #define GuidExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) |
| 12 | #define GuidExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_GUIDUTIL, x, e, s, __VA_ARGS__) | ||
| 12 | #define GuidExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) | 13 | #define GuidExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__) |
| 13 | #define GuidExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_GUIDUTIL, p, x, e, s, __VA_ARGS__) | 14 | #define GuidExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_GUIDUTIL, p, x, e, s, __VA_ARGS__) |
| 14 | #define GuidExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_GUIDUTIL, p, x, s, __VA_ARGS__) | 15 | #define GuidExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_GUIDUTIL, p, x, s, __VA_ARGS__) |
| @@ -29,8 +30,7 @@ extern "C" HRESULT DAPI GuidFixedCreate( | |||
| 29 | 30 | ||
| 30 | if (!::StringFromGUID2(guid, wzGuid, GUID_STRING_LENGTH)) | 31 | if (!::StringFromGUID2(guid, wzGuid, GUID_STRING_LENGTH)) |
| 31 | { | 32 | { |
| 32 | hr = E_OUTOFMEMORY; | 33 | GuidExitWithRootFailure(hr, E_OUTOFMEMORY, "Failed to convert guid into string."); |
| 33 | GuidExitOnRootFailure(hr, "Failed to convert guid into string."); | ||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | LExit: | 36 | LExit: |
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index 727318f2..875cfafb 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | |||
| @@ -205,11 +205,12 @@ DAPI_(HRESULT) PathGetTempPath( | |||
| 205 | ); | 205 | ); |
| 206 | 206 | ||
| 207 | /******************************************************************* | 207 | /******************************************************************* |
| 208 | PathGetSystemTempPath - returns the path to the system temp folder | 208 | PathGetSystemTempPaths - returns the paths to system temp folders |
| 209 | that is backslash terminated. | 209 | that are backslash terminated with higher preference first. |
| 210 | *******************************************************************/ | 210 | *******************************************************************/ |
| 211 | DAPI_(HRESULT) PathGetSystemTempPath( | 211 | DAPI_(HRESULT) PathGetSystemTempPaths( |
| 212 | __out_z LPWSTR* psczSystemTempPath | 212 | __inout_z LPWSTR** prgsczSystemTempPaths, |
| 213 | __inout DWORD* pcSystemTempPaths | ||
| 213 | ); | 214 | ); |
| 214 | 215 | ||
| 215 | /******************************************************************* | 216 | /******************************************************************* |
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp index 1ac76626..dc33e656 100644 --- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp | |||
| @@ -923,12 +923,14 @@ LExit: | |||
| 923 | } | 923 | } |
| 924 | 924 | ||
| 925 | 925 | ||
| 926 | DAPI_(HRESULT) PathGetSystemTempPath( | 926 | DAPI_(HRESULT) PathGetSystemTempPaths( |
| 927 | __out_z LPWSTR* psczSystemTempPath | 927 | __inout_z LPWSTR** prgsczSystemTempPaths, |
| 928 | __inout DWORD* pcSystemTempPaths | ||
| 928 | ) | 929 | ) |
| 929 | { | 930 | { |
| 930 | HRESULT hr = S_OK; | 931 | HRESULT hr = S_OK; |
| 931 | HKEY hKey = NULL; | 932 | HKEY hKey = NULL; |
| 933 | LPWSTR sczTemp = NULL; | ||
| 932 | WCHAR wzTempPath[MAX_PATH + 1] = { }; | 934 | WCHAR wzTempPath[MAX_PATH + 1] = { }; |
| 933 | DWORD cch = 0; | 935 | DWORD cch = 0; |
| 934 | 936 | ||
| @@ -940,26 +942,36 @@ DAPI_(HRESULT) PathGetSystemTempPath( | |||
| 940 | 942 | ||
| 941 | // Follow documented precedence rules for TMP/TEMP from ::GetTempPath. | 943 | // Follow documented precedence rules for TMP/TEMP from ::GetTempPath. |
| 942 | // TODO: values will be expanded with the current environment variables instead of the system environment variables. | 944 | // TODO: values will be expanded with the current environment variables instead of the system environment variables. |
| 943 | hr = RegReadString(hKey, L"TMP", psczSystemTempPath); | 945 | hr = RegReadString(hKey, L"TMP", &sczTemp); |
| 944 | if (E_FILENOTFOUND != hr) | 946 | if (E_FILENOTFOUND != hr) |
| 945 | { | 947 | { |
| 946 | PathExitOnFailure(hr, "Failed to get system TMP value."); | 948 | PathExitOnFailure(hr, "Failed to get system TMP value."); |
| 947 | 949 | ||
| 948 | hr = PathBackslashTerminate(psczSystemTempPath); | 950 | hr = PathBackslashTerminate(&sczTemp); |
| 949 | PathExitOnFailure(hr, "Failed to backslash terminate system TMP value."); | 951 | PathExitOnFailure(hr, "Failed to backslash terminate system TMP value."); |
| 950 | 952 | ||
| 951 | ExitFunction(); | 953 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3); |
| 954 | PathExitOnFailure(hr, "Failed to ensure array size for system TMP value."); | ||
| 955 | |||
| 956 | (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; | ||
| 957 | sczTemp = NULL; | ||
| 958 | *pcSystemTempPaths += 1; | ||
| 952 | } | 959 | } |
| 953 | 960 | ||
| 954 | hr = RegReadString(hKey, L"TEMP", psczSystemTempPath); | 961 | hr = RegReadString(hKey, L"TEMP", &sczTemp); |
| 955 | if (E_FILENOTFOUND != hr) | 962 | if (E_FILENOTFOUND != hr) |
| 956 | { | 963 | { |
| 957 | PathExitOnFailure(hr, "Failed to get system TEMP value."); | 964 | PathExitOnFailure(hr, "Failed to get system TEMP value."); |
| 958 | 965 | ||
| 959 | hr = PathBackslashTerminate(psczSystemTempPath); | 966 | hr = PathBackslashTerminate(&sczTemp); |
| 960 | PathExitOnFailure(hr, "Failed to backslash terminate system TEMP value."); | 967 | PathExitOnFailure(hr, "Failed to backslash terminate system TEMP value."); |
| 961 | 968 | ||
| 962 | ExitFunction(); | 969 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2); |
| 970 | PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value."); | ||
| 971 | |||
| 972 | (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; | ||
| 973 | sczTemp = NULL; | ||
| 974 | *pcSystemTempPaths += 1; | ||
| 963 | } | 975 | } |
| 964 | } | 976 | } |
| 965 | 977 | ||
| @@ -973,11 +985,19 @@ DAPI_(HRESULT) PathGetSystemTempPath( | |||
| 973 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long."); | 985 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long."); |
| 974 | } | 986 | } |
| 975 | 987 | ||
| 976 | hr = PathConcat(wzTempPath, L"TEMP\\", psczSystemTempPath); | 988 | hr = PathConcat(wzTempPath, L"TEMP\\", &sczTemp); |
| 977 | PathExitOnFailure(hr, "Failed to concat Temp directory on Windows directory path."); | 989 | PathExitOnFailure(hr, "Failed to concat Temp directory on Windows directory path."); |
| 978 | 990 | ||
| 991 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1); | ||
| 992 | PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value."); | ||
| 993 | |||
| 994 | (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp; | ||
| 995 | sczTemp = NULL; | ||
| 996 | *pcSystemTempPaths += 1; | ||
| 997 | |||
| 979 | LExit: | 998 | LExit: |
| 980 | ReleaseRegKey(hKey); | 999 | ReleaseRegKey(hKey); |
| 1000 | ReleaseStr(sczTemp); | ||
| 981 | 1001 | ||
| 982 | return hr; | 1002 | return hr; |
| 983 | } | 1003 | } |
diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index d1d304d3..e9ef1047 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | |||
| @@ -800,6 +800,34 @@ namespace DutilTests | |||
| 800 | } | 800 | } |
| 801 | 801 | ||
| 802 | [Fact] | 802 | [Fact] |
| 803 | void PathGetSystemTempPathsTest() | ||
| 804 | { | ||
| 805 | HRESULT hr = S_OK; | ||
| 806 | LPWSTR* rgsczPaths = NULL; | ||
| 807 | DWORD cPaths = 0; | ||
| 808 | DWORD cPathsOriginal = 0; | ||
| 809 | |||
| 810 | try | ||
| 811 | { | ||
| 812 | hr = PathGetSystemTempPaths(&rgsczPaths, &cPaths); | ||
| 813 | NativeAssert::Succeeded(hr, "PathGetSystemTempPaths failed."); | ||
| 814 | |||
| 815 | Assert::InRange<DWORD>(cPaths, 1, 3); | ||
| 816 | WixAssert::StringEqual(Environment::ExpandEnvironmentVariables("%windir%\\temp\\"), gcnew String(rgsczPaths[cPaths - 1]), true); | ||
| 817 | |||
| 818 | cPathsOriginal = cPaths; | ||
| 819 | |||
| 820 | hr = PathGetSystemTempPaths(&rgsczPaths, &cPaths); | ||
| 821 | NativeAssert::Succeeded(hr, "PathGetSystemTempPaths failed."); | ||
| 822 | Assert::Equal(cPathsOriginal * 2, cPaths); | ||
| 823 | } | ||
| 824 | finally | ||
| 825 | { | ||
| 826 | ReleaseStrArray(rgsczPaths, cPaths); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | [Fact] | ||
| 803 | void PathNormalizeSlashesFixedTest() | 831 | void PathNormalizeSlashesFixedTest() |
| 804 | { | 832 | { |
| 805 | HRESULT hr = S_OK; | 833 | HRESULT hr = S_OK; |
diff --git a/src/test/burn/WixTestTools/BundleVerifier.cs b/src/test/burn/WixTestTools/BundleVerifier.cs index 594b19aa..103171cd 100644 --- a/src/test/burn/WixTestTools/BundleVerifier.cs +++ b/src/test/burn/WixTestTools/BundleVerifier.cs | |||
| @@ -15,7 +15,8 @@ namespace WixTestTools | |||
| 15 | public partial class BundleInstaller | 15 | public partial class BundleInstaller |
| 16 | { | 16 | { |
| 17 | public const string DependencyRegistryRoot = "Software\\Classes\\Installer\\Dependencies"; | 17 | public const string DependencyRegistryRoot = "Software\\Classes\\Installer\\Dependencies"; |
| 18 | public const string FULL_BURN_POLICY_REGISTRY_PATH = "SOFTWARE\\WOW6432Node\\Policies\\WiX\\Burn"; | 18 | public const string FULL_BURN_POLICY_REGISTRY_PATH = "SOFTWARE\\Policies\\WiX\\Burn"; |
| 19 | public const string FULL_BURN_POLICY_REGISTRY_PATH_WOW6432NODE = "SOFTWARE\\WOW6432Node\\Policies\\WiX\\Burn"; | ||
| 19 | public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache"; | 20 | public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache"; |
| 20 | 21 | ||
| 21 | public string BundlePdb { get; } | 22 | public string BundlePdb { get; } |
| @@ -35,12 +36,19 @@ namespace WixTestTools | |||
| 35 | return this.BundleSymbol; | 36 | return this.BundleSymbol; |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 39 | public string GetFullBurnPolicyRegistryPath() | ||
| 40 | { | ||
| 41 | var bundleSymbol = this.GetBundleSymbol(); | ||
| 42 | var x64 = bundleSymbol.Platform != Platform.X86; | ||
| 43 | return x64 ? FULL_BURN_POLICY_REGISTRY_PATH : FULL_BURN_POLICY_REGISTRY_PATH_WOW6432NODE; | ||
| 44 | } | ||
| 45 | |||
| 38 | public string GetPackageCachePathForCacheId(string cacheId, bool perMachine) | 46 | public string GetPackageCachePathForCacheId(string cacheId, bool perMachine) |
| 39 | { | 47 | { |
| 40 | string cachePath; | 48 | string cachePath; |
| 41 | if (perMachine) | 49 | if (perMachine) |
| 42 | { | 50 | { |
| 43 | using var policyKey = Registry.LocalMachine.OpenSubKey(FULL_BURN_POLICY_REGISTRY_PATH); | 51 | using var policyKey = Registry.LocalMachine.OpenSubKey(this.GetFullBurnPolicyRegistryPath()); |
| 44 | var redirectedCachePath = policyKey?.GetValue("PackageCache") as string; | 52 | var redirectedCachePath = policyKey?.GetValue("PackageCache") as string; |
| 45 | cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME); | 53 | cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME); |
| 46 | } | 54 | } |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs index 6c8250d9..f5a1cda8 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs | |||
| @@ -5,6 +5,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using System.IO; | 7 | using System.IO; |
| 8 | using Microsoft.Win32; | ||
| 8 | using WixBuildTools.TestSupport; | 9 | using WixBuildTools.TestSupport; |
| 9 | using WixTestTools; | 10 | using WixTestTools; |
| 10 | using WixToolset.Mba.Core; | 11 | using WixToolset.Mba.Core; |
| @@ -201,5 +202,72 @@ namespace WixToolsetTest.BurnE2E | |||
| 201 | packageB.VerifyInstalled(true); | 202 | packageB.VerifyInstalled(true); |
| 202 | } | 203 | } |
| 203 | } | 204 | } |
| 205 | |||
| 206 | [RuntimeFact] | ||
| 207 | public void CanGetEngineWorkingDirectoryFromCommandLine() | ||
| 208 | { | ||
| 209 | var bundleA = this.CreateBundleInstaller("BundleA"); | ||
| 210 | var testBAController = this.CreateTestBAController(); | ||
| 211 | |||
| 212 | testBAController.SetImmediatelyQuit(); | ||
| 213 | |||
| 214 | using (var dfs = new DisposableFileSystem()) | ||
| 215 | { | ||
| 216 | var baseTempPath = dfs.GetFolder(true); | ||
| 217 | var logPath = bundleA.Install(0, $"-burn.engine.working.directory=\"{baseTempPath}\""); | ||
| 218 | LogVerifier.MessageInLogFileRegex(logPath, $"Burn x86 v4.*, Windows v.* \\(Build .*: Service Pack .*\\), path: {baseTempPath.Replace("\\", "\\\\")}\\\\.*\\\\.cr\\\\BundleA.exe"); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | [RuntimeFact] | ||
| 223 | public void CanGetEngineWorkingDirectoryFromPolicy() | ||
| 224 | { | ||
| 225 | var deletePolicyKey = false; | ||
| 226 | string originalPolicyValue = null; | ||
| 227 | |||
| 228 | var bundleA = this.CreateBundleInstaller("BundleA"); | ||
| 229 | var testBAController = this.CreateTestBAController(); | ||
| 230 | var policyPath = bundleA.GetFullBurnPolicyRegistryPath(); | ||
| 231 | |||
| 232 | testBAController.SetImmediatelyQuit(); | ||
| 233 | |||
| 234 | try | ||
| 235 | { | ||
| 236 | using (var dfs = new DisposableFileSystem()) | ||
| 237 | { | ||
| 238 | var baseTempPath = dfs.GetFolder(true); | ||
| 239 | |||
| 240 | var policyKey = Registry.LocalMachine.OpenSubKey(policyPath, writable: true); | ||
| 241 | if (policyKey == null) | ||
| 242 | { | ||
| 243 | policyKey = Registry.LocalMachine.CreateSubKey(policyPath, writable: true); | ||
| 244 | deletePolicyKey = true; | ||
| 245 | } | ||
| 246 | |||
| 247 | using (policyKey) | ||
| 248 | { | ||
| 249 | originalPolicyValue = policyKey.GetValue("EngineWorkingDirectory") as string; | ||
| 250 | policyKey.SetValue("EngineWorkingDirectory", baseTempPath); | ||
| 251 | } | ||
| 252 | |||
| 253 | var logPath = bundleA.Install(); | ||
| 254 | LogVerifier.MessageInLogFileRegex(logPath, $"Burn x86 v4.*, Windows v.* \\(Build .*: Service Pack .*\\), path: {baseTempPath.Replace("\\", "\\\\")}\\\\.*\\\\.cr\\\\BundleA.exe"); | ||
| 255 | } | ||
| 256 | } | ||
| 257 | finally | ||
| 258 | { | ||
| 259 | if (deletePolicyKey) | ||
| 260 | { | ||
| 261 | Registry.LocalMachine.DeleteSubKeyTree(policyPath); | ||
| 262 | } | ||
| 263 | else if (originalPolicyValue != null) | ||
| 264 | { | ||
| 265 | using (var policyKey = Registry.LocalMachine.CreateSubKey(policyPath, writable: true)) | ||
| 266 | { | ||
| 267 | policyKey.SetValue("EngineWorkingDirectory", originalPolicyValue); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | } | ||
| 204 | } | 272 | } |
| 205 | } | 273 | } |
