aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-08-03 18:06:54 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-08-04 10:03:57 -0500
commitcdba28de1ee229369b254c62bc58cf2f001899a3 (patch)
tree4ae9a7aafd83ff311c5440df2c6d4a8693f8f23b /src
parent75d645c6aec0df0e02bd3aaf2fe2571d83316d4c (diff)
downloadwix-cdba28de1ee229369b254c62bc58cf2f001899a3.tar.gz
wix-cdba28de1ee229369b254c62bc58cf2f001899a3.tar.bz2
wix-cdba28de1ee229369b254c62bc58cf2f001899a3.zip
Add argument and policy setting to set Burn's base working directory.
Fixes #5856
Diffstat (limited to 'src')
-rw-r--r--src/burn/engine/cache.cpp65
-rw-r--r--src/burn/engine/core.cpp151
-rw-r--r--src/burn/engine/core.h7
-rw-r--r--src/burn/engine/elevation.cpp14
-rw-r--r--src/burn/engine/engine.cpp1
-rw-r--r--src/burn/engine/exeengine.cpp9
-rw-r--r--src/burn/engine/package.h1
-rw-r--r--src/burn/engine/plan.cpp2
-rw-r--r--src/burn/engine/plan.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/apputil.cpp231
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/apputil.h41
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/pathutil.h10
-rw-r--r--src/libs/dutil/WixToolset.DUtil/pathutil.cpp102
-rw-r--r--src/libs/dutil/WixToolset.DUtil/precomp.h1
14 files changed, 503 insertions, 133 deletions
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp
index 54328091..0c5266a0 100644
--- a/src/burn/engine/cache.cpp
+++ b/src/burn/engine/cache.cpp
@@ -14,6 +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 );
17static HRESULT CalculateBaseWorkingFolder(
18 __in BURN_ENGINE_COMMAND* pInternalCommand,
19 __inout_z LPWSTR* psczBaseWorkingFolder
20 );
17static HRESULT CalculateWorkingFolder( 21static HRESULT CalculateWorkingFolder(
18 __in BURN_CACHE* pCache, 22 __in BURN_CACHE* pCache,
19 __in BURN_ENGINE_COMMAND* pInternalCommand 23 __in BURN_ENGINE_COMMAND* pInternalCommand
@@ -1337,28 +1341,71 @@ extern "C" void CacheUninitialize(
1337 1341
1338// Internal functions. 1342// Internal functions.
1339 1343
1340static HRESULT CalculateWorkingFolder( 1344static HRESULT CalculateBaseWorkingFolder(
1341 __in BURN_CACHE* pCache, 1345 __in BURN_ENGINE_COMMAND* pInternalCommand,
1342 __in BURN_ENGINE_COMMAND* pInternalCommand 1346 __inout_z LPWSTR* psczBaseWorkingFolder
1343 ) 1347 )
1344{ 1348{
1345 HRESULT hr = S_OK; 1349 HRESULT hr = S_OK;
1346 RPC_STATUS rs = RPC_S_OK;
1347 LPWSTR sczTempPath = NULL;
1348 UUID guid = {};
1349 WCHAR wzGuid[39];
1350 1350
1351 ReleaseNullStr(*psczBaseWorkingFolder);
1352
1353 // The value from the command line takes precedence.
1354 if (pInternalCommand->sczWorkingDirectory)
1355 {
1356 hr = PathExpand(psczBaseWorkingFolder, pInternalCommand->sczWorkingDirectory, PATH_EXPAND_FULLPATH);
1357 ExitOnFailure(hr, "Failed to expand engine working directory from command-line: '%ls'", pInternalCommand->sczWorkingDirectory);
1358
1359 ExitFunction();
1360 }
1361
1362 // The base working folder can be specified through policy,
1363 // but only use it if elevated because it should be secured against non-admin users.
1351 if (pInternalCommand->fInitiallyElevated) 1364 if (pInternalCommand->fInitiallyElevated)
1352 { 1365 {
1353 hr = PathGetSystemTempPath(&sczTempPath); 1366 hr = PolcReadString(POLICY_BURN_REGISTRY_PATH, L"EngineWorkingDirectory", NULL, psczBaseWorkingFolder);
1367 ExitOnFailure(hr, "Failed to read EngineWorkingDirectory policy directory.");
1368
1369 if (*psczBaseWorkingFolder)
1370 {
1371 // PolcReadString is supposed to automatically expand REG_EXPAND_SZ values.
1372 ExitFunction();
1373 }
1374 }
1375
1376 // Default to the temp path specified in environment variables, but need to use system temp path for security reasons if running elevated.
1377 if (pInternalCommand->fInitiallyElevated)
1378 {
1379 hr = PathGetSystemTempPath(psczBaseWorkingFolder);
1354 ExitOnFailure(hr, "Failed to get system temp folder path for working folder."); 1380 ExitOnFailure(hr, "Failed to get system temp folder path for working folder.");
1355 } 1381 }
1356 else 1382 else
1357 { 1383 {
1358 hr = PathGetTempPath(&sczTempPath); 1384 hr = PathGetTempPath(psczBaseWorkingFolder);
1359 ExitOnFailure(hr, "Failed to get temp folder path for working folder."); 1385 ExitOnFailure(hr, "Failed to get temp folder path for working folder.");
1360 } 1386 }
1361 1387
1388LExit:
1389 return hr;
1390}
1391
1392static HRESULT CalculateWorkingFolder(
1393 __in BURN_CACHE* pCache,
1394 __in BURN_ENGINE_COMMAND* pInternalCommand
1395 )
1396{
1397 HRESULT hr = S_OK;
1398 RPC_STATUS rs = RPC_S_OK;
1399 LPWSTR sczTempPath = NULL;
1400 UUID guid = {};
1401 WCHAR wzGuid[39];
1402
1403 hr = CalculateBaseWorkingFolder(pInternalCommand, &sczTempPath);
1404 ExitOnFailure(hr, "Failed to get base engine working directory.");
1405
1406 hr = PathBackslashTerminate(&sczTempPath);
1407 ExitOnFailure(hr, "Failed to backslashify base engine working directory.");
1408
1362 rs = ::UuidCreate(&guid); 1409 rs = ::UuidCreate(&guid);
1363 hr = HRESULT_FROM_RPC(rs); 1410 hr = HRESULT_FROM_RPC(rs);
1364 ExitOnFailure(hr, "Failed to create working folder guid."); 1411 ExitOnFailure(hr, "Failed to create working folder guid.");
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index 3e45cdfc..e8c51187 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -22,6 +22,23 @@ static HRESULT CoreRecreateCommandLine(
22 __in BOOTSTRAPPER_RELATION_TYPE relationType, 22 __in BOOTSTRAPPER_RELATION_TYPE relationType,
23 __in BOOL fPassthrough 23 __in BOOL fPassthrough
24 ); 24 );
25static HRESULT AppendEscapedArgumentToCommandLine(
26 __in_z LPCWSTR wzEscapedArgument,
27 __deref_inout_z LPWSTR* psczCommandLine,
28 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
29 );
30static HRESULT EscapeAndAppendArgumentToCommandLineFormatted(
31 __deref_inout_z LPWSTR* psczCommandLine,
32 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
33 __in __format_string LPCWSTR wzFormat,
34 ...
35 );
36static HRESULT EscapeAndAppendArgumentToCommandLineFormattedArgs(
37 __deref_inout_z LPWSTR* psczCommandLine,
38 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
39 __in __format_string LPCWSTR wzFormat,
40 __in va_list args
41 );
25static HRESULT AppendLayoutToCommandLine( 42static HRESULT AppendLayoutToCommandLine(
26 __in BOOTSTRAPPER_ACTION action, 43 __in BOOTSTRAPPER_ACTION action,
27 __in_z LPCWSTR wzLayoutDirectory, 44 __in_z LPCWSTR wzLayoutDirectory,
@@ -207,11 +224,12 @@ extern "C" HRESULT CoreInitializeConstants(
207 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) 224 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
208 { 225 {
209 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; 226 BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i;
210 227
211 if (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol) // TODO: Don't assume exePackages with burn protocol are bundles. 228 if (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol) // TODO: Don't assume exePackages with burn protocol are bundles.
212 { 229 {
213 // Pass along any ancestors and ourself to prevent infinite loops. 230 // Pass along any ancestors and ourself to prevent infinite loops.
214 pPackage->Exe.wzAncestors = pRegistration->sczBundlePackageAncestors; 231 pPackage->Exe.wzAncestors = pRegistration->sczBundlePackageAncestors;
232 pPackage->Exe.wzEngineWorkingDirectory = pInternalCommand->sczWorkingDirectory;
215 } 233 }
216 } 234 }
217 235
@@ -1001,6 +1019,9 @@ static HRESULT CoreRecreateCommandLine(
1001 ExitOnFailure(hr, "Failed to append ancestors to command-line."); 1019 ExitOnFailure(hr, "Failed to append ancestors to command-line.");
1002 } 1020 }
1003 1021
1022 hr = CoreAppendEngineWorkingDirectoryToCommandLine(pInternalCommand->sczWorkingDirectory, psczCommandLine, NULL);
1023 ExitOnFailure(hr, "Failed to append the custom working directory to command-line.");
1024
1004 if (wzRelationTypeCommandLine) 1025 if (wzRelationTypeCommandLine)
1005 { 1026 {
1006 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", wzRelationTypeCommandLine); 1027 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", wzRelationTypeCommandLine);
@@ -1060,7 +1081,7 @@ extern "C" HRESULT CoreCreateCleanRoomCommandLine(
1060 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", wzLogParameter); 1081 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", wzLogParameter);
1061 ExitOnFailure(hr, "Failed to append logging switch."); 1082 ExitOnFailure(hr, "Failed to append logging switch.");
1062 1083
1063 hr = PathCommandLineAppend(psczCommandLine, pInternalCommand->sczLogFile); 1084 hr = AppAppendCommandLineArgument(psczCommandLine, pInternalCommand->sczLogFile);
1064 ExitOnFailure(hr, "Failed to append custom log path."); 1085 ExitOnFailure(hr, "Failed to append custom log path.");
1065 } 1086 }
1066 1087
@@ -1091,7 +1112,7 @@ extern "C" HRESULT CoreCreateCleanRoomCommandLine(
1091 hr = StrAllocConcat(psczCommandLine, L" /originalsource", 0); 1112 hr = StrAllocConcat(psczCommandLine, L" /originalsource", 0);
1092 ExitOnFailure(hr, "Failed to append /originalsource."); 1113 ExitOnFailure(hr, "Failed to append /originalsource.");
1093 1114
1094 hr = PathCommandLineAppend(psczCommandLine, pInternalCommand->sczOriginalSource); 1115 hr = AppAppendCommandLineArgument(psczCommandLine, pInternalCommand->sczOriginalSource);
1095 ExitOnFailure(hr, "Failed to append original source."); 1116 ExitOnFailure(hr, "Failed to append original source.");
1096 } 1117 }
1097 1118
@@ -1256,6 +1277,28 @@ LExit:
1256 return hr; 1277 return hr;
1257} 1278}
1258 1279
1280extern "C" HRESULT CoreAppendEngineWorkingDirectoryToCommandLine(
1281 __in_z_opt LPCWSTR wzEngineWorkingDirectory,
1282 __deref_inout_z LPWSTR* psczCommandLine,
1283 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
1284 )
1285{
1286 HRESULT hr = S_OK;
1287 LPWSTR sczArgument = NULL;
1288
1289 if (wzEngineWorkingDirectory)
1290 {
1291 hr = EscapeAndAppendArgumentToCommandLineFormatted(psczCommandLine, psczObfuscatedCommandLine, L"-%ls=%ls", BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY, wzEngineWorkingDirectory);
1292 ExitOnFailure(hr, "Failed to append the custom working directory to the command line.");
1293 }
1294
1295LExit:
1296 ReleaseStr(sczArgument);
1297
1298 return hr;
1299}
1300
1301
1259extern "C" void CoreCleanup( 1302extern "C" void CoreCleanup(
1260 __in BURN_ENGINE_STATE* pEngineState 1303 __in BURN_ENGINE_STATE* pEngineState
1261 ) 1304 )
@@ -1678,6 +1721,27 @@ extern "C" HRESULT CoreParseCommandLine(
1678 ExitOnFailure(hr, "Failed to allocate the list of ancestors."); 1721 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
1679 } 1722 }
1680 } 1723 }
1724 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY), BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY, lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY)))
1725 {
1726 // Get a pointer to the next character after the switch.
1727 LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY)];
1728 if (L'=' != wzParam[0])
1729 {
1730 fInvalidCommandLine = TRUE;
1731 TraceLog(E_INVALIDARG, "Invalid switch: %ls", argv[i]);
1732 }
1733 else if (L'\0' == wzParam[1])
1734 {
1735 // Need to grab the current directory here since this is passed on to other processes.
1736 hr = DirGetCurrent(&pInternalCommand->sczWorkingDirectory);
1737 ExitOnFailure(hr, "Failed to get current directory for custom working directory.");
1738 }
1739 else
1740 {
1741 hr = StrAllocString(&pInternalCommand->sczWorkingDirectory, wzParam + 1, 0);
1742 ExitOnFailure(hr, "Failed to allocate the custom working directory.");
1743 }
1744 }
1681 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED))) 1745 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED), BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)))
1682 { 1746 {
1683 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)]; 1747 LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED)];
@@ -1807,6 +1871,79 @@ LExit:
1807 1871
1808// internal helper functions 1872// internal helper functions
1809 1873
1874static HRESULT AppendEscapedArgumentToCommandLine(
1875 __in_z LPCWSTR wzEscapedArgument,
1876 __deref_inout_z LPWSTR* psczCommandLine,
1877 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
1878 )
1879{
1880 HRESULT hr = S_OK;
1881
1882 // If there is already data in the command line,
1883 // append a space before appending the argument.
1884 if (*psczCommandLine && **psczCommandLine)
1885 {
1886 hr = StrAllocConcatSecure(psczCommandLine, L" ", 0);
1887 ExitOnFailure(hr, "Failed to append space to command line with existing data.");
1888 }
1889
1890 hr = StrAllocConcatSecure(psczCommandLine, wzEscapedArgument, 0);
1891 ExitOnFailure(hr, "Failed to append escaped command line argument.");
1892
1893 if (psczObfuscatedCommandLine)
1894 {
1895 if (*psczObfuscatedCommandLine && **psczObfuscatedCommandLine)
1896 {
1897 hr = StrAllocConcat(psczObfuscatedCommandLine, L" ", 0);
1898 ExitOnFailure(hr, "Failed to append space to obfuscated command line with existing data.");
1899 }
1900
1901 hr = StrAllocConcat(psczObfuscatedCommandLine, wzEscapedArgument, 0);
1902 ExitOnFailure(hr, "Failed to append escaped argument to obfuscated command line.");
1903 }
1904
1905LExit:
1906 return hr;
1907}
1908
1909static HRESULT EscapeAndAppendArgumentToCommandLineFormatted(
1910 __deref_inout_z LPWSTR* psczCommandLine,
1911 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
1912 __in __format_string LPCWSTR wzFormat,
1913 ...
1914 )
1915{
1916 HRESULT hr = S_OK;
1917 va_list args;
1918
1919 va_start(args, wzFormat);
1920 hr = EscapeAndAppendArgumentToCommandLineFormattedArgs(psczCommandLine, psczObfuscatedCommandLine, wzFormat, args);
1921 va_end(args);
1922
1923 return hr;
1924}
1925
1926static HRESULT EscapeAndAppendArgumentToCommandLineFormattedArgs(
1927 __deref_inout_z LPWSTR* psczCommandLine,
1928 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine,
1929 __in __format_string LPCWSTR wzFormat,
1930 __in va_list args
1931 )
1932{
1933 HRESULT hr = S_OK;
1934 LPWSTR sczArgument = NULL;
1935
1936 hr = AppEscapeCommandLineArgumentFormattedArgs(&sczArgument, wzFormat, args);
1937 ExitOnFailure(hr, "Failed to escape the argument for the command line.");
1938
1939 hr = AppendEscapedArgumentToCommandLine(sczArgument, psczCommandLine, psczObfuscatedCommandLine);
1940
1941LExit:
1942 ReleaseStr(sczArgument);
1943
1944 return hr;
1945}
1946
1810static HRESULT AppendLayoutToCommandLine( 1947static HRESULT AppendLayoutToCommandLine(
1811 __in BOOTSTRAPPER_ACTION action, 1948 __in BOOTSTRAPPER_ACTION action,
1812 __in_z LPCWSTR wzLayoutDirectory, 1949 __in_z LPCWSTR wzLayoutDirectory,
@@ -1822,7 +1959,7 @@ static HRESULT AppendLayoutToCommandLine(
1822 1959
1823 if (wzLayoutDirectory) 1960 if (wzLayoutDirectory)
1824 { 1961 {
1825 hr = PathCommandLineAppend(psczCommandLine, wzLayoutDirectory); 1962 hr = AppAppendCommandLineArgument(psczCommandLine, wzLayoutDirectory);
1826 ExitOnFailure(hr, "Failed to append layout directory."); 1963 ExitOnFailure(hr, "Failed to append layout directory.");
1827 } 1964 }
1828 } 1965 }
@@ -1883,16 +2020,16 @@ static HRESULT GetSanitizedCommandLine(
1883 } 2020 }
1884 2021
1885 // Remember command-line switch to pass off to BA. 2022 // Remember command-line switch to pass off to BA.
1886 PathCommandLineAppend(&pCommand->wzCommandLine, argv[i]); 2023 AppAppendCommandLineArgument(&pCommand->wzCommandLine, argv[i]);
1887 } 2024 }
1888 2025
1889 if (fHidden) 2026 if (fHidden)
1890 { 2027 {
1891 PathCommandLineAppend(psczSanitizedCommandLine, sczSanitizedArgument); 2028 AppAppendCommandLineArgument(psczSanitizedCommandLine, sczSanitizedArgument);
1892 } 2029 }
1893 else 2030 else
1894 { 2031 {
1895 PathCommandLineAppend(psczSanitizedCommandLine, argv[i]); 2032 AppAppendCommandLineArgument(psczSanitizedCommandLine, argv[i]);
1896 } 2033 }
1897 } 2034 }
1898 2035
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h
index f3328738..5361a5c0 100644
--- a/src/burn/engine/core.h
+++ b/src/burn/engine/core.h
@@ -14,6 +14,7 @@ const LPCWSTR BURN_POLICY_REGISTRY_PATH = L"WiX\\Burn";
14const LPCWSTR BURN_COMMANDLINE_SWITCH_PARENT = L"parent"; 14const LPCWSTR BURN_COMMANDLINE_SWITCH_PARENT = L"parent";
15const LPCWSTR BURN_COMMANDLINE_SWITCH_PARENT_NONE = L"parent:none"; 15const LPCWSTR BURN_COMMANDLINE_SWITCH_PARENT_NONE = L"parent:none";
16const LPCWSTR BURN_COMMANDLINE_SWITCH_CLEAN_ROOM = L"burn.clean.room"; 16const LPCWSTR BURN_COMMANDLINE_SWITCH_CLEAN_ROOM = L"burn.clean.room";
17const LPCWSTR BURN_COMMANDLINE_SWITCH_WORKING_DIRECTORY = L"burn.working.directory";
17const LPCWSTR BURN_COMMANDLINE_SWITCH_ELEVATED = L"burn.elevated"; 18const LPCWSTR BURN_COMMANDLINE_SWITCH_ELEVATED = L"burn.elevated";
18const LPCWSTR BURN_COMMANDLINE_SWITCH_EMBEDDED = L"burn.embedded"; 19const LPCWSTR BURN_COMMANDLINE_SWITCH_EMBEDDED = L"burn.embedded";
19const LPCWSTR BURN_COMMANDLINE_SWITCH_RUNONCE = L"burn.runonce"; 20const LPCWSTR BURN_COMMANDLINE_SWITCH_RUNONCE = L"burn.runonce";
@@ -99,6 +100,7 @@ typedef struct _BURN_ENGINE_COMMAND
99 100
100 LPWSTR sczSourceProcessPath; 101 LPWSTR sczSourceProcessPath;
101 LPWSTR sczOriginalSource; 102 LPWSTR sczOriginalSource;
103 LPWSTR sczWorkingDirectory;
102 104
103 DWORD dwLoggingAttributes; 105 DWORD dwLoggingAttributes;
104 LPWSTR sczLogFile; 106 LPWSTR sczLogFile;
@@ -254,6 +256,11 @@ HRESULT CoreAppendSplashScreenWindowToCommandLine(
254 __in_opt HWND hwndSplashScreen, 256 __in_opt HWND hwndSplashScreen,
255 __deref_inout_z LPWSTR* psczCommandLine 257 __deref_inout_z LPWSTR* psczCommandLine
256 ); 258 );
259HRESULT CoreAppendEngineWorkingDirectoryToCommandLine(
260 __in_z_opt LPCWSTR wzEngineWorkingDirectory,
261 __deref_inout_z LPWSTR* psczCommandLine,
262 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
263 );
257void CoreCleanup( 264void CoreCleanup(
258 __in BURN_ENGINE_STATE* pEngineState 265 __in BURN_ENGINE_STATE* pEngineState
259 ); 266 );
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index c229fa58..0e1cf0b7 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -852,6 +852,9 @@ extern "C" HRESULT ElevationExecuteExePackage(
852 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczAncestors); 852 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczAncestors);
853 ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer."); 853 ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer.");
854 854
855 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczEngineWorkingDirectory);
856 ExitOnFailure(hr, "Failed to write the custom working directory to the message buffer.");
857
855 hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); 858 hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData);
856 ExitOnFailure(hr, "Failed to write variables."); 859 ExitOnFailure(hr, "Failed to write variables.");
857 860
@@ -2476,6 +2479,7 @@ static HRESULT OnExecuteExePackage(
2476 BURN_EXECUTE_ACTION executeAction = { }; 2479 BURN_EXECUTE_ACTION executeAction = { };
2477 LPWSTR sczIgnoreDependencies = NULL; 2480 LPWSTR sczIgnoreDependencies = NULL;
2478 LPWSTR sczAncestors = NULL; 2481 LPWSTR sczAncestors = NULL;
2482 LPWSTR sczEngineWorkingDirectory = NULL;
2479 BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; 2483 BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2480 2484
2481 executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; 2485 executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE;
@@ -2496,6 +2500,9 @@ static HRESULT OnExecuteExePackage(
2496 hr = BuffReadString(pbData, cbData, &iData, &sczAncestors); 2500 hr = BuffReadString(pbData, cbData, &iData, &sczAncestors);
2497 ExitOnFailure(hr, "Failed to read the list of ancestors."); 2501 ExitOnFailure(hr, "Failed to read the list of ancestors.");
2498 2502
2503 hr = BuffReadString(pbData, cbData, &iData, &sczEngineWorkingDirectory);
2504 ExitOnFailure(hr, "Failed to read the custom working directory.");
2505
2499 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); 2506 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
2500 ExitOnFailure(hr, "Failed to read variables."); 2507 ExitOnFailure(hr, "Failed to read variables.");
2501 2508
@@ -2520,11 +2527,18 @@ static HRESULT OnExecuteExePackage(
2520 ExitOnFailure(hr, "Failed to allocate the list of ancestors."); 2527 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
2521 } 2528 }
2522 2529
2530 if (sczEngineWorkingDirectory && *sczEngineWorkingDirectory)
2531 {
2532 hr = StrAllocString(&executeAction.exePackage.sczEngineWorkingDirectory, sczEngineWorkingDirectory, 0);
2533 ExitOnFailure(hr, "Failed to allocate the custom working directory.");
2534 }
2535
2523 // Execute EXE package. 2536 // Execute EXE package.
2524 hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart); 2537 hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart);
2525 ExitOnFailure(hr, "Failed to execute EXE package."); 2538 ExitOnFailure(hr, "Failed to execute EXE package.");
2526 2539
2527LExit: 2540LExit:
2541 ReleaseStr(sczEngineWorkingDirectory);
2528 ReleaseStr(sczAncestors); 2542 ReleaseStr(sczAncestors);
2529 ReleaseStr(sczIgnoreDependencies); 2543 ReleaseStr(sczIgnoreDependencies);
2530 ReleaseStr(sczPackage); 2544 ReleaseStr(sczPackage);
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index 0ce2de6d..d5dc0545 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -401,6 +401,7 @@ static void UninitializeEngineState(
401 ReleaseStr(pEngineState->internalCommand.sczLogFile); 401 ReleaseStr(pEngineState->internalCommand.sczLogFile);
402 ReleaseStr(pEngineState->internalCommand.sczOriginalSource); 402 ReleaseStr(pEngineState->internalCommand.sczOriginalSource);
403 ReleaseStr(pEngineState->internalCommand.sczSourceProcessPath); 403 ReleaseStr(pEngineState->internalCommand.sczSourceProcessPath);
404 ReleaseStr(pEngineState->internalCommand.sczWorkingDirectory);
404 405
405 ReleaseStr(pEngineState->log.sczExtension); 406 ReleaseStr(pEngineState->log.sczExtension);
406 ReleaseStr(pEngineState->log.sczPrefix); 407 ReleaseStr(pEngineState->log.sczPrefix);
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp
index 9eea4960..67da3bdd 100644
--- a/src/burn/engine/exeengine.cpp
+++ b/src/burn/engine/exeengine.cpp
@@ -308,6 +308,12 @@ extern "C" HRESULT ExeEnginePlanAddPackage(
308 ExitOnFailure(hr, "Failed to allocate the list of ancestors."); 308 ExitOnFailure(hr, "Failed to allocate the list of ancestors.");
309 } 309 }
310 310
311 if (pPackage->Exe.wzEngineWorkingDirectory)
312 {
313 hr = StrAllocString(&pAction->exePackage.sczEngineWorkingDirectory, pPackage->Exe.wzEngineWorkingDirectory, 0);
314 ExitOnFailure(hr, "Failed to allocate the custom working directory.");
315 }
316
311 LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors. 317 LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors.
312 } 318 }
313 319
@@ -488,6 +494,9 @@ extern "C" HRESULT ExeEngineExecutePackage(
488 494
489 if (BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol) 495 if (BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol)
490 { 496 {
497 hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczCommand, &sczCommandObfuscated);
498 ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line.");
499
491 hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, &sczCommandObfuscated); 500 hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, &sczCommandObfuscated);
492 ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); 501 ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF);
493 } 502 }
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index 94f27c23..f14064db 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -267,6 +267,7 @@ typedef struct _BURN_PACKAGE
267 LPWSTR sczUninstallArguments; 267 LPWSTR sczUninstallArguments;
268 LPWSTR sczIgnoreDependencies; 268 LPWSTR sczIgnoreDependencies;
269 LPCWSTR wzAncestors; // points directly into engine state. 269 LPCWSTR wzAncestors; // points directly into engine state.
270 LPCWSTR wzEngineWorkingDirectory; // points directly into engine state.
270 271
271 BOOL fPseudoBundle; 272 BOOL fPseudoBundle;
272 273
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index f77e8e2a..04da2a9d 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -266,6 +266,7 @@ extern "C" void PlanUninitializeExecuteAction(
266 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: 266 case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
267 ReleaseStr(pExecuteAction->exePackage.sczIgnoreDependencies); 267 ReleaseStr(pExecuteAction->exePackage.sczIgnoreDependencies);
268 ReleaseStr(pExecuteAction->exePackage.sczAncestors); 268 ReleaseStr(pExecuteAction->exePackage.sczAncestors);
269 ReleaseStr(pExecuteAction->exePackage.sczEngineWorkingDirectory);
269 break; 270 break;
270 271
271 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: 272 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
@@ -1282,6 +1283,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1282 1283
1283 // Pass along any ancestors and ourself to prevent infinite loops. 1284 // Pass along any ancestors and ourself to prevent infinite loops.
1284 pRelatedBundle->package.Exe.wzAncestors = pRegistration->sczBundlePackageAncestors; 1285 pRelatedBundle->package.Exe.wzAncestors = pRegistration->sczBundlePackageAncestors;
1286 pRelatedBundle->package.Exe.wzEngineWorkingDirectory = pPlan->pInternalCommand->sczWorkingDirectory;
1285 1287
1286 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, pPlan->action, pRegistration->pVersion, pRelatedBundle->pVersion, &pRelatedBundle->package.requested); 1288 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, pPlan->action, pRegistration->pVersion, pRelatedBundle->pVersion, &pRelatedBundle->package.requested);
1287 ExitOnFailure(hr, "Failed to get default request state for related bundle."); 1289 ExitOnFailure(hr, "Failed to get default request state for related bundle.");
diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h
index 224f3806..b148c75b 100644
--- a/src/burn/engine/plan.h
+++ b/src/burn/engine/plan.h
@@ -164,6 +164,7 @@ typedef struct _BURN_EXECUTE_ACTION
164 BOOTSTRAPPER_ACTION_STATE action; 164 BOOTSTRAPPER_ACTION_STATE action;
165 LPWSTR sczIgnoreDependencies; 165 LPWSTR sczIgnoreDependencies;
166 LPWSTR sczAncestors; 166 LPWSTR sczAncestors;
167 LPWSTR sczEngineWorkingDirectory;
167 } exePackage; 168 } exePackage;
168 struct 169 struct
169 { 170 {
diff --git a/src/libs/dutil/WixToolset.DUtil/apputil.cpp b/src/libs/dutil/WixToolset.DUtil/apputil.cpp
index 589a09dd..7e0bbc7b 100644
--- a/src/libs/dutil/WixToolset.DUtil/apputil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/apputil.cpp
@@ -20,7 +20,18 @@ const DWORD PRIVATE_LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800;
20typedef BOOL(WINAPI *LPFN_SETDEFAULTDLLDIRECTORIES)(DWORD); 20typedef BOOL(WINAPI *LPFN_SETDEFAULTDLLDIRECTORIES)(DWORD);
21typedef BOOL(WINAPI *LPFN_SETDLLDIRECTORYW)(LPCWSTR); 21typedef BOOL(WINAPI *LPFN_SETDLLDIRECTORYW)(LPCWSTR);
22 22
23extern "C" void DAPI AppFreeCommandLineArgs( 23/********************************************************************
24EscapeCommandLineArgument - encodes wzArgument such that
25 ::CommandLineToArgv() will parse it back unaltered. If no escaping
26 was required, *psczEscaped is NULL.
27
28********************************************************************/
29static HRESULT EscapeCommandLineArgument(
30 __in_z LPCWSTR wzArgument,
31 __out_z LPWSTR* psczEscaped
32 );
33
34DAPI_(void) AppFreeCommandLineArgs(
24 __in LPWSTR* argv 35 __in LPWSTR* argv
25 ) 36 )
26{ 37{
@@ -34,7 +45,7 @@ AppInitialize - initializes the standard safety precautions for an
34 installation application. 45 installation application.
35 46
36********************************************************************/ 47********************************************************************/
37extern "C" void DAPI AppInitialize( 48DAPI_(void) AppInitialize(
38 __in_ecount(cSafelyLoadSystemDlls) LPCWSTR rgsczSafelyLoadSystemDlls[], 49 __in_ecount(cSafelyLoadSystemDlls) LPCWSTR rgsczSafelyLoadSystemDlls[],
39 __in DWORD cSafelyLoadSystemDlls 50 __in DWORD cSafelyLoadSystemDlls
40 ) 51 )
@@ -85,12 +96,12 @@ extern "C" void DAPI AppInitialize(
85 } 96 }
86} 97}
87 98
88extern "C" void DAPI AppInitializeUnsafe() 99DAPI_(void) AppInitializeUnsafe()
89{ 100{
90 ::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); 101 ::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
91} 102}
92 103
93extern "C" DAPI_(HRESULT) AppParseCommandLine( 104DAPI_(HRESULT) AppParseCommandLine(
94 __in LPCWSTR wzCommandLine, 105 __in LPCWSTR wzCommandLine,
95 __in int* pArgc, 106 __in int* pArgc,
96 __in LPWSTR** pArgv 107 __in LPWSTR** pArgv
@@ -122,3 +133,215 @@ LExit:
122 133
123 return hr; 134 return hr;
124} 135}
136
137DAPI_(HRESULT) AppAppendCommandLineArgument(
138 __deref_inout_z LPWSTR* psczCommandLine,
139 __in_z LPCWSTR wzArgument
140 )
141{
142 HRESULT hr = S_OK;
143 LPWSTR sczQuotedArg = NULL;
144
145 hr = EscapeCommandLineArgument(wzArgument, &sczQuotedArg);
146 AppExitOnFailure(hr, "Failed to escape command line argument.");
147
148 // If there is already data in the command line,
149 // append a space before appending the argument.
150 if (*psczCommandLine && **psczCommandLine)
151 {
152 hr = StrAllocConcatSecure(psczCommandLine, L" ", 0);
153 AppExitOnFailure(hr, "Failed to append space to command line with existing data.");
154 }
155
156 hr = StrAllocConcatSecure(psczCommandLine, sczQuotedArg ? sczQuotedArg : wzArgument, 0);
157 AppExitOnFailure(hr, "Failed to copy command line argument.");
158
159LExit:
160 ReleaseStr(sczQuotedArg);
161
162 return hr;
163}
164
165DAPIV_(HRESULT) AppAppendCommandLineArgumentFormatted(
166 __deref_inout_z LPWSTR* psczCommandLine,
167 __in __format_string LPCWSTR wzFormat,
168 ...
169 )
170{
171 HRESULT hr = S_OK;
172 va_list args;
173
174 va_start(args, wzFormat);
175 hr = AppAppendCommandLineArgumentFormattedArgs(psczCommandLine, wzFormat, args);
176 va_end(args);
177
178 return hr;
179}
180
181DAPI_(HRESULT) AppAppendCommandLineArgumentFormattedArgs(
182 __deref_inout_z LPWSTR* psczCommandLine,
183 __in __format_string LPCWSTR wzFormat,
184 __in va_list args
185 )
186{
187 HRESULT hr = S_OK;
188 LPWSTR sczQuotedArg = NULL;
189
190 hr = AppEscapeCommandLineArgumentFormattedArgs(&sczQuotedArg, wzFormat, args);
191 AppExitOnFailure(hr, "Failed to escape command line argument.");
192
193 // If there is already data in the command line,
194 // append a space before appending the argument.
195 if (*psczCommandLine && **psczCommandLine)
196 {
197 hr = StrAllocConcatSecure(psczCommandLine, L" ", 0);
198 AppExitOnFailure(hr, "Failed to append space to command line with existing data.");
199 }
200
201 hr = StrAllocConcatSecure(psczCommandLine, sczQuotedArg, 0);
202 AppExitOnFailure(hr, "Failed to copy command line argument.");
203
204LExit:
205 ReleaseStr(sczQuotedArg);
206
207 return hr;
208}
209
210DAPIV_(HRESULT) AppEscapeCommandLineArgumentFormatted(
211 __deref_inout_z LPWSTR* psczEscapedArgument,
212 __in __format_string LPCWSTR wzFormat,
213 ...
214 )
215{
216 HRESULT hr = S_OK;
217 va_list args;
218
219 va_start(args, wzFormat);
220 hr = AppEscapeCommandLineArgumentFormattedArgs(psczEscapedArgument, wzFormat, args);
221 va_end(args);
222
223 return hr;
224}
225
226DAPI_(HRESULT) AppEscapeCommandLineArgumentFormattedArgs(
227 __deref_inout_z LPWSTR* psczEscapedArgument,
228 __in __format_string LPCWSTR wzFormat,
229 __in va_list args
230 )
231{
232 HRESULT hr = S_OK;
233 LPWSTR sczFormattedArg = NULL;
234 LPWSTR sczQuotedArg = NULL;
235
236 hr = StrAllocFormattedArgsSecure(&sczFormattedArg, wzFormat, args);
237 AppExitOnFailure(hr, "Failed to format command line argument.");
238
239 hr = EscapeCommandLineArgument(sczFormattedArg, &sczQuotedArg);
240 AppExitOnFailure(hr, "Failed to escape command line argument.");
241
242 if (sczQuotedArg)
243 {
244 *psczEscapedArgument = sczQuotedArg;
245 sczQuotedArg = NULL;
246 }
247 else
248 {
249 *psczEscapedArgument = sczFormattedArg;
250 sczFormattedArg = NULL;
251 }
252
253LExit:
254 ReleaseStr(sczFormattedArg);
255 ReleaseStr(sczQuotedArg);
256
257 return hr;
258}
259
260static HRESULT EscapeCommandLineArgument(
261 __in_z LPCWSTR wzArgument,
262 __out_z LPWSTR* psczEscaped
263 )
264{
265 HRESULT hr = S_OK;
266 BOOL fRequiresQuoting = FALSE;
267 SIZE_T cMaxEscapedSize = 0;
268
269 *psczEscaped = NULL;
270
271 // Loop through the argument determining if it needs to be quoted and what the maximum
272 // size would be if there are escape characters required.
273 for (LPCWSTR pwz = wzArgument; *pwz; ++pwz)
274 {
275 // Arguments with whitespace need quoting.
276 if (L' ' == *pwz || L'\t' == *pwz || L'\n' == *pwz || L'\v' == *pwz)
277 {
278 fRequiresQuoting = TRUE;
279 }
280 else if (L'"' == *pwz) // quotes need quoting and sometimes escaping.
281 {
282 fRequiresQuoting = TRUE;
283 ++cMaxEscapedSize;
284 }
285 else if (L'\\' == *pwz) // some backslashes need escaping, so we'll count them all to make sure there is room.
286 {
287 ++cMaxEscapedSize;
288 }
289
290 ++cMaxEscapedSize;
291 }
292
293 // If we found anything in the argument that requires our argument to be quoted
294 if (fRequiresQuoting)
295 {
296 hr = StrAlloc(psczEscaped, cMaxEscapedSize + 3); // plus three for the start and end quote plus null terminator.
297 AppExitOnFailure(hr, "Failed to allocate argument to be quoted.");
298
299 LPCWSTR pwz = wzArgument;
300 LPWSTR pwzQuoted = *psczEscaped;
301
302 *pwzQuoted = L'"';
303 ++pwzQuoted;
304 while (*pwz)
305 {
306 DWORD dwBackslashes = 0;
307 while (L'\\' == *pwz)
308 {
309 ++dwBackslashes;
310 ++pwz;
311 }
312
313 // Escape all backslashes at the end of the string.
314 if (!*pwz)
315 {
316 dwBackslashes *= 2;
317 }
318 else if (L'"' == *pwz) // escape all backslashes before the quote and escape the quote itself.
319 {
320 dwBackslashes = dwBackslashes * 2 + 1;
321 }
322 // the backslashes don't have to be escaped.
323
324 // Add the appropriate number of backslashes
325 for (DWORD i = 0; i < dwBackslashes; ++i)
326 {
327 *pwzQuoted = L'\\';
328 ++pwzQuoted;
329 }
330
331 // If there is a character, add it after all the escaped backslashes
332 if (*pwz)
333 {
334 *pwzQuoted = *pwz;
335 ++pwz;
336 ++pwzQuoted;
337 }
338 }
339
340 *pwzQuoted = L'"';
341 ++pwzQuoted;
342 *pwzQuoted = L'\0'; // ensure the arg is null terminated.
343 }
344
345LExit:
346 return hr;
347}
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/apputil.h b/src/libs/dutil/WixToolset.DUtil/inc/apputil.h
index 1a1e14f7..11280102 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/apputil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/apputil.h
@@ -34,12 +34,51 @@ AppParseCommandLine - parses the command line using CommandLineToArgvW.
34 by calling AppFreeCommandLineArgs. 34 by calling AppFreeCommandLineArgs.
35 35
36********************************************************************/ 36********************************************************************/
37DAPI_(HRESULT) AppParseCommandLine( 37HRESULT DAPI AppParseCommandLine(
38 __in LPCWSTR wzCommandLine, 38 __in LPCWSTR wzCommandLine,
39 __in int* argc, 39 __in int* argc,
40 __in LPWSTR** pArgv 40 __in LPWSTR** pArgv
41 ); 41 );
42 42
43/*******************************************************************
44 AppAppendCommandLineArgument - appends a command line argument on to a
45 string such that ::CommandLineToArgv() will shred them correctly
46 (i.e. quote arguments with spaces in them).
47********************************************************************/
48HRESULT DAPI AppAppendCommandLineArgument(
49 __deref_inout_z LPWSTR* psczCommandLine,
50 __in_z LPCWSTR wzArgument
51 );
52
53HRESULT DAPIV AppAppendCommandLineArgumentFormatted(
54 __deref_inout_z LPWSTR* psczCommandLine,
55 __in __format_string LPCWSTR wzFormat,
56 ...
57 );
58
59HRESULT DAPI AppAppendCommandLineArgumentFormattedArgs(
60 __deref_inout_z LPWSTR* psczCommandLine,
61 __in __format_string LPCWSTR wzFormat,
62 __in va_list args
63 );
64
65/********************************************************************
66AppEscapeCommandLineArgumentFormatted - formats a string and then
67 escapes it such that ::CommandLineToArgv() will parse it back unaltered.
68
69********************************************************************/
70HRESULT DAPIV AppEscapeCommandLineArgumentFormatted(
71 __deref_inout_z LPWSTR* psczEscapedArgument,
72 __in __format_string LPCWSTR wzFormat,
73 ...
74 );
75
76HRESULT DAPI AppEscapeCommandLineArgumentFormattedArgs(
77 __deref_inout_z LPWSTR* psczEscapedArgument,
78 __in __format_string LPCWSTR wzFormat,
79 __in va_list args
80 );
81
43#ifdef __cplusplus 82#ifdef __cplusplus
44} 83}
45#endif 84#endif
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
index 0ae9f437..00a468ce 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
@@ -14,16 +14,6 @@ typedef enum PATH_EXPAND
14 14
15 15
16/******************************************************************* 16/*******************************************************************
17 PathCommandLineAppend - appends a command line argument on to a
18 string such that ::CommandLineToArgv() will shred them correctly
19 (i.e. quote arguments with spaces in them).
20********************************************************************/
21DAPI_(HRESULT) PathCommandLineAppend(
22 __deref_inout_z LPWSTR* psczCommandLine,
23 __in_z LPCWSTR wzArgument
24 );
25
26/*******************************************************************
27 PathFile - returns a pointer to the file part of the path. 17 PathFile - returns a pointer to the file part of the path.
28********************************************************************/ 18********************************************************************/
29DAPI_(LPWSTR) PathFile( 19DAPI_(LPWSTR) PathFile(
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
index 5fad519b..7bac8ac3 100644
--- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
@@ -21,108 +21,6 @@
21#define PATH_GOOD_ENOUGH 64 21#define PATH_GOOD_ENOUGH 64
22 22
23 23
24DAPI_(HRESULT) PathCommandLineAppend(
25 __deref_inout_z LPWSTR* psczCommandLine,
26 __in_z LPCWSTR wzArgument
27 )
28{
29 HRESULT hr = S_OK;
30 LPWSTR sczQuotedArg = NULL;
31 BOOL fRequiresQuoting = FALSE;
32 DWORD dwMaxEscapedSize = 0;
33
34 // Loop through the argument determining if it needs to be quoted and what the maximum
35 // size would be if there are escape characters required.
36 for (LPCWSTR pwz = wzArgument; *pwz; ++pwz)
37 {
38 // Arguments with whitespace need quoting.
39 if (L' ' == *pwz || L'\t' == *pwz || L'\n' == *pwz || L'\v' == *pwz)
40 {
41 fRequiresQuoting = TRUE;
42 }
43 else if (L'"' == *pwz) // quotes need quoting and sometimes escaping.
44 {
45 fRequiresQuoting = TRUE;
46 ++dwMaxEscapedSize;
47 }
48 else if (L'\\' == *pwz) // some backslashes need escaping, so we'll count them all to make sure there is room.
49 {
50 ++dwMaxEscapedSize;
51 }
52
53 ++dwMaxEscapedSize;
54 }
55
56 // If we found anything in the argument that requires our argument to be quoted
57 if (fRequiresQuoting)
58 {
59 hr = StrAlloc(&sczQuotedArg, dwMaxEscapedSize + 3); // plus three for the start and end quote plus null terminator.
60 PathExitOnFailure(hr, "Failed to allocate argument to be quoted.");
61
62 LPCWSTR pwz = wzArgument;
63 LPWSTR pwzQuoted = sczQuotedArg;
64
65 *pwzQuoted = L'"';
66 ++pwzQuoted;
67 while (*pwz)
68 {
69 DWORD dwBackslashes = 0;
70 while (L'\\' == *pwz)
71 {
72 ++dwBackslashes;
73 ++pwz;
74 }
75
76 // Escape all backslashes at the end of the string.
77 if (!*pwz)
78 {
79 dwBackslashes *= 2;
80 }
81 else if (L'"' == *pwz) // escape all backslashes before the quote and escape the quote itself.
82 {
83 dwBackslashes = dwBackslashes * 2 + 1;
84 }
85 // the backslashes don't have to be escaped.
86
87 // Add the appropriate number of backslashes
88 for (DWORD i = 0; i < dwBackslashes; ++i)
89 {
90 *pwzQuoted = L'\\';
91 ++pwzQuoted;
92 }
93
94 // If there is a character, add it after all the escaped backslashes
95 if (*pwz)
96 {
97 *pwzQuoted = *pwz;
98 ++pwz;
99 ++pwzQuoted;
100 }
101 }
102
103 *pwzQuoted = L'"';
104 ++pwzQuoted;
105 *pwzQuoted = L'\0'; // ensure the arg is null terminated.
106 }
107
108 // If there is already data in the command line, append a space before appending the
109 // argument.
110 if (*psczCommandLine && **psczCommandLine)
111 {
112 hr = StrAllocConcat(psczCommandLine, L" ", 0);
113 PathExitOnFailure(hr, "Failed to append space to command line with existing data.");
114 }
115
116 hr = StrAllocConcat(psczCommandLine, sczQuotedArg ? sczQuotedArg : wzArgument, 0);
117 PathExitOnFailure(hr, "Failed to copy command line argument.");
118
119LExit:
120 ReleaseStr(sczQuotedArg);
121
122 return hr;
123}
124
125
126DAPI_(LPWSTR) PathFile( 24DAPI_(LPWSTR) PathFile(
127 __in_z LPCWSTR wzPath 25 __in_z LPCWSTR wzPath
128 ) 26 )
diff --git a/src/libs/dutil/WixToolset.DUtil/precomp.h b/src/libs/dutil/WixToolset.DUtil/precomp.h
index f8f3b944..46d29f21 100644
--- a/src/libs/dutil/WixToolset.DUtil/precomp.h
+++ b/src/libs/dutil/WixToolset.DUtil/precomp.h
@@ -45,6 +45,7 @@
45#include "dutil.h" 45#include "dutil.h"
46#include "verutil.h" 46#include "verutil.h"
47#include "aclutil.h" 47#include "aclutil.h"
48#include "apputil.h"
48#include "atomutil.h" 49#include "atomutil.h"
49#include "buffutil.h" 50#include "buffutil.h"
50#include "butil.h" 51#include "butil.h"