From 648f370f7966b2738c1446601057d888bbd2c70f Mon Sep 17 00:00:00 2001
From: Sean Hall <r.sean.hall@gmail.com>
Date: Fri, 3 Jun 2022 17:48:57 -0500
Subject: Make PathGetSystemPath return an array of paths ordered by
 preference.

---
 src/libs/dutil/WixToolset.DUtil/guidutil.cpp       |  4 +--
 src/libs/dutil/WixToolset.DUtil/inc/pathutil.h     |  9 ++---
 src/libs/dutil/WixToolset.DUtil/pathutil.cpp       | 38 +++++++++++++++++-----
 src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | 28 ++++++++++++++++
 4 files changed, 64 insertions(+), 15 deletions(-)

(limited to 'src/libs/dutil')

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 @@
 #define GuidExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__)
 #define GuidExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__)
 #define GuidExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__)
+#define GuidExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_GUIDUTIL, x, e, s, __VA_ARGS__)
 #define GuidExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_GUIDUTIL, x, s, __VA_ARGS__)
 #define GuidExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_GUIDUTIL, p, x, e, s, __VA_ARGS__)
 #define GuidExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_GUIDUTIL, p, x, s, __VA_ARGS__)
@@ -29,8 +30,7 @@ extern "C" HRESULT DAPI GuidFixedCreate(
 
     if (!::StringFromGUID2(guid, wzGuid, GUID_STRING_LENGTH))
     {
-        hr = E_OUTOFMEMORY;
-        GuidExitOnRootFailure(hr, "Failed to convert guid into string.");
+        GuidExitWithRootFailure(hr, E_OUTOFMEMORY, "Failed to convert guid into string.");
     }
 
 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(
     );
 
 /*******************************************************************
- PathGetSystemTempPath - returns the path to the system temp folder
-    that is backslash terminated.
+ PathGetSystemTempPaths - returns the paths to system temp folders
+    that are backslash terminated with higher preference first.
 *******************************************************************/
-DAPI_(HRESULT) PathGetSystemTempPath(
-    __out_z LPWSTR* psczSystemTempPath
+DAPI_(HRESULT) PathGetSystemTempPaths(
+    __inout_z LPWSTR** prgsczSystemTempPaths,
+    __inout DWORD* pcSystemTempPaths
     );
 
 /*******************************************************************
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:
 }
 
 
-DAPI_(HRESULT) PathGetSystemTempPath(
-    __out_z LPWSTR* psczSystemTempPath
+DAPI_(HRESULT) PathGetSystemTempPaths(
+    __inout_z LPWSTR** prgsczSystemTempPaths,
+    __inout DWORD* pcSystemTempPaths
     )
 {
     HRESULT hr = S_OK;
     HKEY hKey = NULL;
+    LPWSTR sczTemp = NULL;
     WCHAR wzTempPath[MAX_PATH + 1] = { };
     DWORD cch = 0;
 
@@ -940,26 +942,36 @@ DAPI_(HRESULT) PathGetSystemTempPath(
 
         // Follow documented precedence rules for TMP/TEMP from ::GetTempPath.
         // TODO: values will be expanded with the current environment variables instead of the system environment variables.
-        hr = RegReadString(hKey, L"TMP", psczSystemTempPath);
+        hr = RegReadString(hKey, L"TMP", &sczTemp);
         if (E_FILENOTFOUND != hr)
         {
             PathExitOnFailure(hr, "Failed to get system TMP value.");
 
-            hr = PathBackslashTerminate(psczSystemTempPath);
+            hr = PathBackslashTerminate(&sczTemp);
             PathExitOnFailure(hr, "Failed to backslash terminate system TMP value.");
 
-            ExitFunction();
+            hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3);
+            PathExitOnFailure(hr, "Failed to ensure array size for system TMP value.");
+
+            (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
+            sczTemp = NULL;
+            *pcSystemTempPaths += 1;
         }
 
-        hr = RegReadString(hKey, L"TEMP", psczSystemTempPath);
+        hr = RegReadString(hKey, L"TEMP", &sczTemp);
         if (E_FILENOTFOUND != hr)
         {
             PathExitOnFailure(hr, "Failed to get system TEMP value.");
 
-            hr = PathBackslashTerminate(psczSystemTempPath);
+            hr = PathBackslashTerminate(&sczTemp);
             PathExitOnFailure(hr, "Failed to backslash terminate system TEMP value.");
 
-            ExitFunction();
+            hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2);
+            PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value.");
+
+            (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
+            sczTemp = NULL;
+            *pcSystemTempPaths += 1;
         }
     }
 
@@ -973,11 +985,19 @@ DAPI_(HRESULT) PathGetSystemTempPath(
         PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long.");
     }
 
-    hr = PathConcat(wzTempPath, L"TEMP\\", psczSystemTempPath);
+    hr = PathConcat(wzTempPath, L"TEMP\\", &sczTemp);
     PathExitOnFailure(hr, "Failed to concat Temp directory on Windows directory path.");
 
+    hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1);
+    PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value.");
+
+    (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
+    sczTemp = NULL;
+    *pcSystemTempPaths += 1;
+
 LExit:
     ReleaseRegKey(hKey);
+    ReleaseStr(sczTemp);
 
     return hr;
 }
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
@@ -799,6 +799,34 @@ namespace DutilTests
             }
         }
 
+        [Fact]
+        void PathGetSystemTempPathsTest()
+        {
+            HRESULT hr = S_OK;
+            LPWSTR* rgsczPaths = NULL;
+            DWORD cPaths = 0;
+            DWORD cPathsOriginal = 0;
+
+            try
+            {
+                hr = PathGetSystemTempPaths(&rgsczPaths, &cPaths);
+                NativeAssert::Succeeded(hr, "PathGetSystemTempPaths failed.");
+
+                Assert::InRange<DWORD>(cPaths, 1, 3);
+                WixAssert::StringEqual(Environment::ExpandEnvironmentVariables("%windir%\\temp\\"), gcnew String(rgsczPaths[cPaths - 1]), true);
+
+                cPathsOriginal = cPaths;
+
+                hr = PathGetSystemTempPaths(&rgsczPaths, &cPaths);
+                NativeAssert::Succeeded(hr, "PathGetSystemTempPaths failed.");
+                Assert::Equal(cPathsOriginal * 2, cPaths);
+            }
+            finally
+            {
+                ReleaseStrArray(rgsczPaths, cPaths);
+            }
+        }
+
         [Fact]
         void PathNormalizeSlashesFixedTest()
         {
-- 
cgit v1.2.3-55-g6feb