Make PathGetSystemPath return an array of paths ordered by preference.
Sean Hall committed
Jun 3, 2022 at 17:48 UTC
648f370f7966b2738c1446601057d888bbd2c70f
12 files changed
+338
-75
src/burn/engine/cache.cpp
+72
-55
@@ -14,10 +14,10 @@ static HRESULT CacheVerifyPayloadSignature(
14
__in_z LPCWSTR wzUnverifiedPayloadPath,
15
__in HANDLE hFile
16
);
17
-static HRESULT CalculateBaseWorkingFolder(
17
+static HRESULT CalculatePotentialBaseWorkingFolders(
18
+ __in BURN_CACHE* pCache,
19
__in BURN_ENGINE_COMMAND* pInternalCommand,
19
- __in LPCWSTR wzAcquisitionFolder,
20
- __inout_z LPWSTR* psczBaseWorkingFolder
20
+ __in LPCWSTR wzAcquisitionFolder
21
);
22
static HRESULT CalculateWorkingFolders(
23
__in BURN_CACHE* pCache,
@@ -321,8 +321,8 @@ extern "C" HRESULT CacheEnsureAcquisitionFolder(
321
hr = DirEnsureExists(pCache->sczAcquisitionFolder, NULL);
322
ExitOnFailure(hr, "Failed create acquisition folder.");
323
324
- // Best effort to ensure our working folder is not encrypted.
325
- ::DecryptFileW(pCache->sczBaseWorkingFolder, 0);
324
+ // Best effort to ensure our acquisition folder is not encrypted.
325
+ ::DecryptFileW(pCache->sczAcquisitionFolder, 0);
326
327
LExit:
328
return hr;
@@ -336,9 +336,30 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
336
Assert(pCache->fInitializedCache);
337
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
+ }
358
340
- hr = DirEnsureExists(pCache->sczBaseWorkingFolder, NULL);
341
- ExitOnFailure(hr, "Failed create working folder.");
359
+ ExitOnNull(pCache->sczBaseWorkingFolder, hr, E_INVALIDSTATE, "No usable base working folder found.");
360
+
361
+ pCache->fInitializedBaseWorkingFolder = TRUE;
362
+ }
363
364
// Best effort to ensure our working folder is not encrypted.
365
::DecryptFileW(pCache->sczBaseWorkingFolder, 0);
@@ -350,6 +371,8 @@ extern "C" HRESULT CacheEnsureBaseWorkingFolder(
371
}
372
373
LExit:
374
+ ReleaseStr(sczPotential);
375
+
376
return hr;
377
}
378
@@ -360,6 +383,7 @@ extern "C" HRESULT CacheCalculateBundleWorkingPath(
383
)
384
{
385
Assert(pCache->fInitializedCache);
386
+ Assert(pCache->fInitializedBaseWorkingFolder);
387
388
HRESULT hr = S_OK;
389
@@ -1180,7 +1204,7 @@ extern "C" HRESULT CacheRemoveBaseWorkingFolder(
1204
{
1205
HRESULT hr = S_OK;
1206
1183
- if (pCache->fInitializedCacheSources)
1207
+ if (pCache->fInitializedBaseWorkingFolder)
1208
{
1209
// Try to clean out everything in the working folder.
1210
hr = DirEnsureDeleteEx(pCache->sczBaseWorkingFolder, DIR_DELETE_FILES | DIR_DELETE_RECURSE | DIR_DELETE_SCHEDULE);
@@ -1343,70 +1367,78 @@ extern "C" void CacheUninitialize(
1367
__in BURN_CACHE* pCache
1368
)
1369
{
1346
- ReleaseNullStr(pCache->sczCurrentMachinePackageCache);
1347
- ReleaseNullStr(pCache->sczDefaultMachinePackageCache);
1348
- ReleaseNullStr(pCache->sczDefaultUserPackageCache);
1349
- ReleaseNullStr(pCache->sczBaseWorkingFolder);
1350
- ReleaseNullStr(pCache->sczAcquisitionFolder);
1351
- ReleaseNullStr(pCache->sczSourceProcessFolder);
1352
-
1353
- pCache->fRunningFromCache = FALSE;
1354
- pCache->fInitializedCache = FALSE;
1355
- pCache->fInitializedCacheSources = FALSE;
1356
- pCache->fPerMachineCacheRootVerified = FALSE;
1357
- pCache->fOriginalPerMachineCacheRootVerified = FALSE;
1358
- pCache->fUnverifiedCacheFolderCreated = FALSE;
1359
- pCache->fCustomMachinePackageCache = FALSE;
1370
+ ReleaseStrArray(pCache->rgsczPotentialBaseWorkingFolders, pCache->cPotentialBaseWorkingFolders);
1371
+ ReleaseStr(pCache->sczCurrentMachinePackageCache);
1372
+ ReleaseStr(pCache->sczDefaultMachinePackageCache);
1373
+ ReleaseStr(pCache->sczDefaultUserPackageCache);
1374
+ ReleaseStr(pCache->sczBaseWorkingFolder);
1375
+ ReleaseStr(pCache->sczAcquisitionFolder);
1376
+ ReleaseStr(pCache->sczSourceProcessFolder);
1377
+
1378
+ memset(pCache, 0, sizeof(BURN_CACHE));
1379
}
1380
1381
// Internal functions.
1382
1364
-static HRESULT CalculateBaseWorkingFolder(
1383
+static HRESULT CalculatePotentialBaseWorkingFolders(
1384
+ __in BURN_CACHE* pCache,
1385
__in BURN_ENGINE_COMMAND* pInternalCommand,
1366
- __in LPCWSTR wzAcquisitionFolder,
1367
- __inout_z LPWSTR* psczBaseWorkingFolder
1386
+ __in LPCWSTR wzAcquisitionFolder
1387
)
1388
{
1389
+ Assert(!pCache->rgsczPotentialBaseWorkingFolders && !pCache->cPotentialBaseWorkingFolders);
1390
HRESULT hr = S_OK;
1391
+ LPWSTR sczTemp = NULL;
1392
1372
- ReleaseNullStr(*psczBaseWorkingFolder);
1393
+ hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pCache->rgsczPotentialBaseWorkingFolders), 6, sizeof(LPWSTR), 6);
1394
+ ExitOnFailure(hr, "Failed to initialize array.");
1395
1396
// The value from the command line takes precedence.
1397
if (pInternalCommand->sczEngineWorkingDirectory)
1398
{
1377
- hr = PathExpand(psczBaseWorkingFolder, pInternalCommand->sczEngineWorkingDirectory, PATH_EXPAND_FULLPATH);
1399
+ hr = PathExpand(&sczTemp, pInternalCommand->sczEngineWorkingDirectory, PATH_EXPAND_FULLPATH);
1400
ExitOnFailure(hr, "Failed to expand engine working directory from command-line: '%ls'", pInternalCommand->sczEngineWorkingDirectory);
1401
1380
- ExitFunction();
1402
+ pCache->rgsczPotentialBaseWorkingFolders[pCache->cPotentialBaseWorkingFolders] = sczTemp;
1403
+ sczTemp = NULL;
1404
+ ++pCache->cPotentialBaseWorkingFolders;
1405
}
1406
1407
// The base working folder can be specified through policy,
1408
// but only use it if elevated because it should be secured against non-admin users.
1409
if (pInternalCommand->fInitiallyElevated)
1410
{
1387
- hr = PolcReadString(POLICY_BURN_REGISTRY_PATH, L"EngineWorkingDirectory", NULL, psczBaseWorkingFolder);
1411
+ hr = PolcReadString(POLICY_BURN_REGISTRY_PATH, L"EngineWorkingDirectory", NULL, &sczTemp);
1412
ExitOnFailure(hr, "Failed to read EngineWorkingDirectory policy directory.");
1413
1390
- if (*psczBaseWorkingFolder)
1414
+ if (sczTemp)
1415
{
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;
1420
}
1421
}
1422
1423
// Default to the acquisition folder, but need to use system temp path for security reasons if running elevated.
1424
if (pInternalCommand->fInitiallyElevated)
1425
{
1400
- hr = PathGetSystemTempPath(psczBaseWorkingFolder);
1401
- ExitOnFailure(hr, "Failed to get system temp folder path for base working folder.");
1426
+ hr = PathGetSystemTempPaths(&pCache->rgsczPotentialBaseWorkingFolders, &pCache->cPotentialBaseWorkingFolders);
1427
+ ExitOnFailure(hr, "Failed to get system temp folder paths for base working folder.");
1428
}
1429
else
1430
{
1405
- hr = StrAllocString(psczBaseWorkingFolder, wzAcquisitionFolder, 0);
1431
+ hr = StrAllocString(&sczTemp, wzAcquisitionFolder, 0);
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;
1437
}
1438
1439
LExit:
1440
+ ReleaseStr(sczTemp);
1441
+
1442
return hr;
1443
}
1444
@@ -1416,11 +1448,7 @@ static HRESULT CalculateWorkingFolders(
1448
)
1449
{
1450
HRESULT hr = S_OK;
1419
- RPC_STATUS rs = RPC_S_OK;
1451
LPWSTR sczBaseAcquisitionPath = NULL;
1421
- LPWSTR sczTempPath = NULL;
1422
- UUID guid = {};
1423
- WCHAR wzGuid[39];
1452
1453
hr = PathGetTempPath(&sczBaseAcquisitionPath);
1454
ExitOnFailure(hr, "Failed to get temp folder path for acquisition folder base.");
@@ -1428,31 +1456,20 @@ static HRESULT CalculateWorkingFolders(
1456
hr = PathBackslashTerminate(&sczBaseAcquisitionPath);
1457
ExitOnFailure(hr, "Failed to backslashify base engine working directory.");
1458
1431
- hr = CalculateBaseWorkingFolder(pInternalCommand, sczBaseAcquisitionPath, &sczTempPath);
1432
- ExitOnFailure(hr, "Failed to get base engine working directory.");
1433
-
1434
- hr = PathBackslashTerminate(&sczTempPath);
1435
- ExitOnFailure(hr, "Failed to backslashify base engine working directory.");
1459
+ hr = CalculatePotentialBaseWorkingFolders(pCache, pInternalCommand, sczBaseAcquisitionPath);
1460
+ ExitOnFailure(hr, "Failed to get potential base engine working directories.");
1461
1437
- rs = ::UuidCreate(&guid);
1438
- hr = HRESULT_FROM_RPC(rs);
1462
+ hr = GuidFixedCreate(pCache->wzGuid);
1463
ExitOnFailure(hr, "Failed to create working folder guid.");
1464
1441
- if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid)))
1442
- {
1443
- hr = E_OUTOFMEMORY;
1444
- ExitOnRootFailure(hr, "Failed to convert working folder guid into string.");
1445
- }
1465
+ pCache->wzGuid[GUID_STRING_LENGTH - 1] = L'\\';
1466
+ pCache->wzGuid[GUID_STRING_LENGTH] = L'\0';
1467
1447
- hr = StrAllocFormatted(&pCache->sczAcquisitionFolder, L"%ls%ls\\", sczBaseAcquisitionPath, wzGuid);
1468
+ hr = PathConcatRelativeToBase(sczBaseAcquisitionPath, pCache->wzGuid, &pCache->sczAcquisitionFolder);
1469
ExitOnFailure(hr, "Failed to append random guid on to temp path for acquisition folder.");
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
-
1471
LExit:
1472
ReleaseStr(sczBaseAcquisitionPath);
1455
- ReleaseStr(sczTempPath);
1473
1474
return hr;
1475
}
src/burn/engine/cache.h
+7
@@ -35,11 +35,18 @@ typedef struct _BURN_CACHE
35
LPWSTR sczDefaultMachinePackageCache;
36
LPWSTR sczCurrentMachinePackageCache;
37
38
+ WCHAR wzGuid[GUID_STRING_LENGTH + 1];
39
+ LPWSTR* rgsczPotentialBaseWorkingFolders;
40
+ DWORD cPotentialBaseWorkingFolders;
41
+
42
// Only valid after CacheInitializeSources
43
BOOL fInitializedCacheSources;
44
BOOL fRunningFromCache;
45
LPWSTR sczSourceProcessFolder;
46
LPWSTR sczAcquisitionFolder;
47
+
48
+ // Only valid after CacheEnsureBaseWorkingFolder
49
+ BOOL fInitializedBaseWorkingFolder;
50
LPWSTR sczBaseWorkingFolder;
51
} BURN_CACHE;
52
src/burn/engine/engine.cpp
+7
@@ -97,6 +97,7 @@ extern "C" HRESULT EngineRun(
97
LPWSTR sczExePath = NULL;
98
BOOL fRunUntrusted = FALSE;
99
BOOL fRunNormal = FALSE;
100
+ BOOL fRunRunOnce = FALSE;
101
BOOL fRestart = FALSE;
102
103
BURN_ENGINE_STATE engineState = { };
@@ -221,6 +222,8 @@ extern "C" HRESULT EngineRun(
222
break;
223
224
case BURN_MODE_RUNONCE:
225
+ fRunRunOnce = TRUE;
226
+
227
hr = RunRunOnce(&engineState, nCmdShow);
228
ExitOnFailure(hr, "Failed to run RunOnce mode.");
229
break;
@@ -303,6 +306,10 @@ LExit:
306
{
307
LogId(REPORT_STANDARD, MSG_EXITING_CLEAN_ROOM, FAILED(hr) ? (int)hr : *pdwExitCode);
308
}
309
+ else if (fRunRunOnce)
310
+ {
311
+ LogId(REPORT_STANDARD, MSG_EXITING_RUN_ONCE, FAILED(hr) ? (int)hr : *pdwExitCode);
312
+ }
313
314
if (fLogInitialized)
315
{
src/burn/engine/engine.mc
+15
-1
@@ -149,6 +149,20 @@ Language=English
149
Exit code: 0x%1!x!
150
.
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
+
166
MessageId=51
167
Severity=Error
168
SymbolicName=MSG_FAILED_PARSE_CONDITION
@@ -811,7 +825,7 @@ MessageId=346
825
Severity=Warning
826
SymbolicName=MSG_CACHE_RETRYING_PACKAGE
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...
829
.
830
831
MessageId=347
src/burn/test/BurnUnitTest/CacheTest.cpp
+93
-2
@@ -37,11 +37,100 @@ namespace Bootstrapper
37
using namespace System::IO;
38
using namespace Xunit;
39
40
- public ref class CacheTest : BurnUnitTest
40
+ public ref class CacheTest : BurnUnitTest, IClassFixture<TestRegistryFixture^>
41
{
42
+ private:
43
+ TestRegistryFixture^ testRegistry;
44
public:
43
- CacheTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
45
+ CacheTest(BurnTestFixture^ fixture, TestRegistryFixture^ registryFixture) : BurnUnitTest(fixture)
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);
134
}
135
136
[Fact]
@@ -93,6 +182,8 @@ namespace Bootstrapper
182
File::SetAttributes(filePath, FileAttributes::Normal);
183
File::Delete(filePath);
184
}
185
+
186
+ CacheUninitialize(&cache);
187
}
188
}
189
};
src/burn/test/BurnUnitTest/precomp.h
+2
@@ -19,9 +19,11 @@
19
#include <buffutil.h>
20
#include <dirutil.h>
21
#include <fileutil.h>
22
+#include <guidutil.h>
23
#include <logutil.h>
24
#include <memutil.h>
25
#include <pathutil.h>
26
+#include <polcutil.h>
27
#include <regutil.h>
28
#include <resrutil.h>
29
#include <shelutil.h>
src/libs/dutil/WixToolset.DUtil/guidutil.cpp
+2
-2
@@ -9,6 +9,7 @@
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__)
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__)
13
#define GuidExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__)
14
#define GuidExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_GUIDUTIL, p, x, e, 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(
30
31
if (!::StringFromGUID2(guid, wzGuid, GUID_STRING_LENGTH))
32
{
32
- hr = E_OUTOFMEMORY;
33
- GuidExitOnRootFailure(hr, "Failed to convert guid into string.");
33
+ GuidExitWithRootFailure(hr, E_OUTOFMEMORY, "Failed to convert guid into string.");
34
}
35
36
LExit:
src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
+5
-4
@@ -205,11 +205,12 @@ DAPI_(HRESULT) PathGetTempPath(
205
);
206
207
/*******************************************************************
208
- PathGetSystemTempPath - returns the path to the system temp folder
209
- that is backslash terminated.
208
+ PathGetSystemTempPaths - returns the paths to system temp folders
209
+ that are backslash terminated with higher preference first.
210
*******************************************************************/
211
-DAPI_(HRESULT) PathGetSystemTempPath(
212
- __out_z LPWSTR* psczSystemTempPath
211
+DAPI_(HRESULT) PathGetSystemTempPaths(
212
+ __inout_z LPWSTR** prgsczSystemTempPaths,
213
+ __inout DWORD* pcSystemTempPaths
214
);
215
216
/*******************************************************************
src/libs/dutil/WixToolset.DUtil/pathutil.cpp
+29
-9
@@ -923,12 +923,14 @@ LExit:
923
}
924
925
926
-DAPI_(HRESULT) PathGetSystemTempPath(
927
- __out_z LPWSTR* psczSystemTempPath
926
+DAPI_(HRESULT) PathGetSystemTempPaths(
927
+ __inout_z LPWSTR** prgsczSystemTempPaths,
928
+ __inout DWORD* pcSystemTempPaths
929
)
930
{
931
HRESULT hr = S_OK;
932
HKEY hKey = NULL;
933
+ LPWSTR sczTemp = NULL;
934
WCHAR wzTempPath[MAX_PATH + 1] = { };
935
DWORD cch = 0;
936
@@ -940,26 +942,36 @@ DAPI_(HRESULT) PathGetSystemTempPath(
942
943
// Follow documented precedence rules for TMP/TEMP from ::GetTempPath.
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);
946
if (E_FILENOTFOUND != hr)
947
{
948
PathExitOnFailure(hr, "Failed to get system TMP value.");
949
948
- hr = PathBackslashTerminate(psczSystemTempPath);
950
+ hr = PathBackslashTerminate(&sczTemp);
951
PathExitOnFailure(hr, "Failed to backslash terminate system TMP value.");
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;
959
}
960
954
- hr = RegReadString(hKey, L"TEMP", psczSystemTempPath);
961
+ hr = RegReadString(hKey, L"TEMP", &sczTemp);
962
if (E_FILENOTFOUND != hr)
963
{
964
PathExitOnFailure(hr, "Failed to get system TEMP value.");
965
959
- hr = PathBackslashTerminate(psczSystemTempPath);
966
+ hr = PathBackslashTerminate(&sczTemp);
967
PathExitOnFailure(hr, "Failed to backslash terminate system TEMP value.");
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;
975
}
976
}
977
@@ -973,11 +985,19 @@ DAPI_(HRESULT) PathGetSystemTempPath(
985
PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long.");
986
}
987
976
- hr = PathConcat(wzTempPath, L"TEMP\\", psczSystemTempPath);
988
+ hr = PathConcat(wzTempPath, L"TEMP\\", &sczTemp);
989
PathExitOnFailure(hr, "Failed to concat Temp directory on Windows directory path.");
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
+
998
LExit:
999
ReleaseRegKey(hKey);
1000
+ ReleaseStr(sczTemp);
1001
1002
return hr;
1003
}
src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp
+28
@@ -799,6 +799,34 @@ namespace DutilTests
799
}
800
}
801
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]
831
void PathNormalizeSlashesFixedTest()
832
{
src/test/burn/WixTestTools/BundleVerifier.cs
+10
-2
@@ -15,7 +15,8 @@ namespace WixTestTools
15
public partial class BundleInstaller
16
{
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";
20
public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache";
21
22
public string BundlePdb { get; }
@@ -35,12 +36,19 @@ namespace WixTestTools
36
return this.BundleSymbol;
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
+
46
public string GetPackageCachePathForCacheId(string cacheId, bool perMachine)
47
{
48
string cachePath;
49
if (perMachine)
50
{
43
- using var policyKey = Registry.LocalMachine.OpenSubKey(FULL_BURN_POLICY_REGISTRY_PATH);
51
+ using var policyKey = Registry.LocalMachine.OpenSubKey(this.GetFullBurnPolicyRegistryPath());
52
var redirectedCachePath = policyKey?.GetValue("PackageCache") as string;
53
cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME);
54
}
src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs
+68
@@ -5,6 +5,7 @@ namespace WixToolsetTest.BurnE2E
5
using System;
6
using System.Collections.Generic;
7
using System.IO;
8
+ using Microsoft.Win32;
9
using WixBuildTools.TestSupport;
10
using WixTestTools;
11
using WixToolset.Mba.Core;
@@ -201,5 +202,72 @@ namespace WixToolsetTest.BurnE2E
202
packageB.VerifyInstalled(true);
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
+ }
272
}
273
}