aboutsummaryrefslogtreecommitdiff
path: root/src/libs
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-06-24 12:28:27 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-06-27 11:14:21 -0500
commiteb53852d7ae6838e54525eb57df1d8ce8a722f9b (patch)
tree7fa05bd6df1bce2e20d87c5fbacc1c658dc000aa /src/libs
parent6ee12a64cb75097a238e60d4fd0ea542e8312214 (diff)
downloadwix-eb53852d7ae6838e54525eb57df1d8ce8a722f9b.tar.gz
wix-eb53852d7ae6838e54525eb57df1d8ce8a722f9b.tar.bz2
wix-eb53852d7ae6838e54525eb57df1d8ce8a722f9b.zip
Add longPathAware to Burn manifest to support long paths.
Fixes 3455
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/apputil.cpp28
-rw-r--r--src/libs/dutil/WixToolset.DUtil/cabcutil.cpp86
-rw-r--r--src/libs/dutil/WixToolset.DUtil/cabutil.cpp68
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dirutil.cpp64
-rw-r--r--src/libs/dutil/WixToolset.DUtil/fileutil.cpp12
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/dirutil.h3
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/pathutil.h67
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/shelutil.h15
-rw-r--r--src/libs/dutil/WixToolset.DUtil/logutil.cpp19
-rw-r--r--src/libs/dutil/WixToolset.DUtil/path2utl.cpp145
-rw-r--r--src/libs/dutil/WixToolset.DUtil/pathutil.cpp404
-rw-r--r--src/libs/dutil/WixToolset.DUtil/rexutil.cpp77
-rw-r--r--src/libs/dutil/WixToolset.DUtil/sceutil.cpp11
-rw-r--r--src/libs/dutil/WixToolset.DUtil/shelutil.cpp210
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp182
15 files changed, 1083 insertions, 308 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/apputil.cpp b/src/libs/dutil/WixToolset.DUtil/apputil.cpp
index b70c8cfb..9e75082a 100644
--- a/src/libs/dutil/WixToolset.DUtil/apputil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/apputil.cpp
@@ -87,31 +87,27 @@ DAPI_(HRESULT) LoadSystemLibraryWithPath(
87 ) 87 )
88{ 88{
89 HRESULT hr = S_OK; 89 HRESULT hr = S_OK;
90 DWORD cch = 0; 90 LPWSTR sczDirectory = NULL;
91 WCHAR wzPath[MAX_PATH] = { }; 91 LPWSTR sczPath = NULL;
92 92
93 cch = ::GetSystemDirectoryW(wzPath, MAX_PATH); 93 hr = PathGetSystemDirectory(&sczDirectory);
94 AppExitOnNullWithLastError(cch, hr, "Failed to get the Windows system directory."); 94 AppExitOnFailure(hr, "Failed to get the Windows system directory.");
95 95
96 if (L'\\' != wzPath[cch - 1]) 96 hr = StrAllocFormatted(&sczPath, L"%ls%ls", sczDirectory, wzModuleName);
97 { 97 AppExitOnFailure(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName);
98 hr = ::StringCchCatNW(wzPath, MAX_PATH, L"\\", 1);
99 AppExitOnRootFailure(hr, "Failed to terminate the string with a backslash.");
100 }
101 98
102 hr = ::StringCchCatW(wzPath, MAX_PATH, wzModuleName); 99 *phModule = ::LoadLibraryExW(sczPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
103 AppExitOnRootFailure(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName); 100 AppExitOnNullWithLastError(*phModule, hr, "Failed to load the library %ls.", sczPath);
104
105 *phModule = ::LoadLibraryExW(wzPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
106 AppExitOnNullWithLastError(*phModule, hr, "Failed to load the library %ls.", wzModuleName);
107 101
108 if (psczPath) 102 if (psczPath)
109 { 103 {
110 hr = StrAllocString(psczPath, wzPath, MAX_PATH); 104 *psczPath = sczPath;
111 AppExitOnFailure(hr, "Failed to copy the path to library."); 105 sczPath = NULL;
112 } 106 }
113 107
114LExit: 108LExit:
109 ReleaseStr(sczDirectory);
110
115 return hr; 111 return hr;
116} 112}
117 113
diff --git a/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp b/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp
index d1edc54d..294669af 100644
--- a/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp
@@ -89,8 +89,8 @@ struct CABC_DATA
89 89
90 STRINGDICT_HANDLE shDictHandle; 90 STRINGDICT_HANDLE shDictHandle;
91 91
92 WCHAR wzCabinetPath[MAX_PATH]; 92 LPWSTR sczCabinetPath;
93 WCHAR wzEmptyFile[MAX_PATH]; 93 LPWSTR sczEmptyFile;
94 HANDLE hEmptyFile; 94 HANDLE hEmptyFile;
95 DWORD dwLastFileIndex; 95 DWORD dwLastFileIndex;
96 96
@@ -197,33 +197,17 @@ extern "C" HRESULT DAPI CabCBegin(
197 197
198 HRESULT hr = S_OK; 198 HRESULT hr = S_OK;
199 CABC_DATA *pcd = NULL; 199 CABC_DATA *pcd = NULL;
200 WCHAR wzTempPath[MAX_PATH] = { };
201 200
202 C_ASSERT(sizeof(MSIFILEHASHINFO) == 20); 201 C_ASSERT(sizeof(MSIFILEHASHINFO) == 20);
203 202
204 WCHAR wzPathBuffer [MAX_PATH] = L""; 203 LPWSTR pwzPathBuffer = NULL;
205 size_t cchPathBuffer;
206 if (wzCabDir) 204 if (wzCabDir)
207 { 205 {
208 hr = ::StringCchLengthW(wzCabDir, MAX_PATH, &cchPathBuffer); 206 hr = StrAllocString(&pwzPathBuffer, wzCabDir, 0);
209 CabcExitOnFailure(hr, "Failed to get length of cab directory");
210
211 // Need room to terminate with L'\\' and L'\0'
212 if((MAX_PATH - 1) <= cchPathBuffer || 0 == cchPathBuffer)
213 {
214 hr = E_INVALIDARG;
215 CabcExitOnFailure(hr, "Cab directory had invalid length: %u", cchPathBuffer);
216 }
217
218 hr = ::StringCchCopyW(wzPathBuffer, countof(wzPathBuffer), wzCabDir);
219 CabcExitOnFailure(hr, "Failed to copy cab directory to buffer"); 207 CabcExitOnFailure(hr, "Failed to copy cab directory to buffer");
220 208
221 if (L'\\' != wzPathBuffer[cchPathBuffer - 1]) 209 hr = PathBackslashTerminate(&pwzPathBuffer);
222 { 210 CabcExitOnFailure(hr, "Failed to cat \\ to end of buffer");
223 hr = ::StringCchCatW(wzPathBuffer, countof(wzPathBuffer), L"\\");
224 CabcExitOnFailure(hr, "Failed to cat \\ to end of buffer");
225 ++cchPathBuffer;
226 }
227 } 211 }
228 212
229 pcd = static_cast<CABC_DATA*>(MemAlloc(sizeof(CABC_DATA), TRUE)); 213 pcd = static_cast<CABC_DATA*>(MemAlloc(sizeof(CABC_DATA), TRUE));
@@ -290,33 +274,23 @@ extern "C" HRESULT DAPI CabCBegin(
290 CabcExitWithLastError(hr, "failed to convert cab name to multi-byte"); 274 CabcExitWithLastError(hr, "failed to convert cab name to multi-byte");
291 } 275 }
292 276
293 if (0 == ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wzPathBuffer, -1, pcd->ccab.szCabPath, sizeof(pcd->ccab.szCab), NULL, NULL)) 277 if (0 == ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pwzPathBuffer, -1, pcd->ccab.szCabPath, sizeof(pcd->ccab.szCab), NULL, NULL))
294 { 278 {
295 CabcExitWithLastError(hr, "failed to convert cab dir to multi-byte"); 279 CabcExitWithLastError(hr, "failed to convert cab dir to multi-byte");
296 } 280 }
297 281
298 // Remember the path to the cabinet. 282 // Remember the path to the cabinet.
299 hr= ::StringCchCopyW(pcd->wzCabinetPath, countof(pcd->wzCabinetPath), wzPathBuffer); 283 hr = PathConcat(pwzPathBuffer, wzCab, &pcd->sczCabinetPath);
300 CabcExitOnFailure(hr, "Failed to copy cabinet path from path: %ls", wzPathBuffer);
301
302 hr = ::StringCchCatW(pcd->wzCabinetPath, countof(pcd->wzCabinetPath), wzCab);
303 CabcExitOnFailure(hr, "Failed to concat to cabinet path cabinet name: %ls", wzCab); 284 CabcExitOnFailure(hr, "Failed to concat to cabinet path cabinet name: %ls", wzCab);
304 285
305 // Get the empty file to use as the blank marker for duplicates. 286 // Get the empty file to use as the blank marker for duplicates.
306 if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) 287 hr = DirCreateTempPath(L"WSC", &pcd->sczEmptyFile);
307 { 288 CabcExitOnFailure(hr, "Failed to create a temp file name.");
308 CabcExitWithLastError(hr, "Failed to get temp path.");
309 }
310
311 if (!::GetTempFileNameW(wzTempPath, L"WSC", 0, pcd->wzEmptyFile))
312 {
313 CabcExitWithLastError(hr, "Failed to create a temp file name.");
314 }
315 289
316 // Try to open the newly created empty file (remember, GetTempFileName() is kind enough to create a file for us) 290 // Try to open the newly created empty file (remember, GetTempFileName() is kind enough to create a file for us)
317 // with a handle to automatically delete the file on close. Ignore any failure that might happen, since the worst 291 // with a handle to automatically delete the file on close. Ignore any failure that might happen, since the worst
318 // case is we'll leave a zero byte file behind in the temp folder. 292 // case is we'll leave a zero byte file behind in the temp folder.
319 pcd->hEmptyFile = ::CreateFileW(pcd->wzEmptyFile, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); 293 pcd->hEmptyFile = ::CreateFileW(pcd->sczEmptyFile, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
320 294
321 hr = DictCreateWithEmbeddedKey(&pcd->shDictHandle, dwMaxFiles, reinterpret_cast<void **>(&pcd->prgFiles), offsetof(CABC_FILE, pwzSourcePath), DICT_FLAG_CASEINSENSITIVE); 295 hr = DictCreateWithEmbeddedKey(&pcd->shDictHandle, dwMaxFiles, reinterpret_cast<void **>(&pcd->prgFiles), offsetof(CABC_FILE, pwzSourcePath), DICT_FLAG_CASEINSENSITIVE);
322 CabcExitOnFailure(hr, "Failed to create dictionary to keep track of duplicate files"); 296 CabcExitOnFailure(hr, "Failed to create dictionary to keep track of duplicate files");
@@ -358,6 +332,8 @@ extern "C" HRESULT DAPI CabCBegin(
358 *phContext = pcd; 332 *phContext = pcd;
359 333
360LExit: 334LExit:
335 ReleaseStr(pwzPathBuffer);
336
361 if (FAILED(hr) && pcd && pcd->hfci) 337 if (FAILED(hr) && pcd && pcd->hfci)
362 { 338 {
363 ::FCIDestroy(pcd->hfci); 339 ::FCIDestroy(pcd->hfci);
@@ -527,7 +503,7 @@ extern "C" HRESULT DAPI CabCFinish(
527 // files point at the same path (the empty file) so there is no point in tracking them with 503 // files point at the same path (the empty file) so there is no point in tracking them with
528 // their path. 504 // their path.
529 fileInfo.wzSourcePath = pcd->prgDuplicates[dwDupeArrayFileIndex].pwzSourcePath; 505 fileInfo.wzSourcePath = pcd->prgDuplicates[dwDupeArrayFileIndex].pwzSourcePath;
530 fileInfo.wzEmptyPath = pcd->wzEmptyFile; 506 fileInfo.wzEmptyPath = pcd->sczEmptyFile;
531 507
532 // Use the provided token, otherwise default to the source file name. 508 // Use the provided token, otherwise default to the source file name.
533 if (pcd->prgDuplicates[dwDupeArrayFileIndex].pwzToken) 509 if (pcd->prgDuplicates[dwDupeArrayFileIndex].pwzToken)
@@ -643,7 +619,7 @@ extern "C" HRESULT DAPI CabCFinish(
643 if (pcd->fGoodCab && pcd->cDuplicates) 619 if (pcd->fGoodCab && pcd->cDuplicates)
644 { 620 {
645 hr = UpdateDuplicateFiles(pcd); 621 hr = UpdateDuplicateFiles(pcd);
646 CabcExitOnFailure(hr, "Failed to update duplicates in cabinet: %ls", pcd->wzCabinetPath); 622 CabcExitOnFailure(hr, "Failed to update duplicates in cabinet: %ls", pcd->sczCabinetPath);
647 } 623 }
648 624
649LExit: 625LExit:
@@ -692,6 +668,9 @@ static void FreeCabCData(
692 ReleaseMem(pcd->prgFiles); 668 ReleaseMem(pcd->prgFiles);
693 ReleaseMem(pcd->prgDuplicates); 669 ReleaseMem(pcd->prgDuplicates);
694 670
671 ReleaseStr(pcd->sczCabinetPath);
672 ReleaseStr(pcd->sczEmptyFile);
673
695 ReleaseMem(pcd); 674 ReleaseMem(pcd);
696 } 675 }
697} 676}
@@ -709,7 +688,7 @@ static HRESULT CheckForDuplicateFile(
709 __in LONGLONG llFileSize 688 __in LONGLONG llFileSize
710 ) 689 )
711{ 690{
712 DWORD i; 691 DWORD i = 0;
713 HRESULT hr = S_OK; 692 HRESULT hr = S_OK;
714 UINT er = ERROR_SUCCESS; 693 UINT er = ERROR_SUCCESS;
715 694
@@ -916,17 +895,17 @@ static HRESULT UpdateDuplicateFiles(
916 LPVOID pv = NULL; 895 LPVOID pv = NULL;
917 MS_CABINET_HEADER *pCabinetHeader = NULL; 896 MS_CABINET_HEADER *pCabinetHeader = NULL;
918 897
919 hCabinet = ::CreateFileW(pcd->wzCabinetPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 898 hCabinet = ::CreateFileW(pcd->sczCabinetPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
920 if (INVALID_HANDLE_VALUE == hCabinet) 899 if (INVALID_HANDLE_VALUE == hCabinet)
921 { 900 {
922 CabcExitWithLastError(hr, "Failed to open cabinet: %ls", pcd->wzCabinetPath); 901 CabcExitWithLastError(hr, "Failed to open cabinet: %ls", pcd->sczCabinetPath);
923 } 902 }
924 903
925 // Shouldn't need more than 16 MB to get the whole cabinet header into memory so use that as 904 // Shouldn't need more than 16 MB to get the whole cabinet header into memory so use that as
926 // the upper bound for the memory map. 905 // the upper bound for the memory map.
927 if (!::GetFileSizeEx(hCabinet, &liCabinetSize)) 906 if (!::GetFileSizeEx(hCabinet, &liCabinetSize))
928 { 907 {
929 CabcExitWithLastError(hr, "Failed to get size of cabinet: %ls", pcd->wzCabinetPath); 908 CabcExitWithLastError(hr, "Failed to get size of cabinet: %ls", pcd->sczCabinetPath);
930 } 909 }
931 910
932 if (0 == liCabinetSize.HighPart && liCabinetSize.LowPart < MAX_CABINET_HEADER_SIZE) 911 if (0 == liCabinetSize.HighPart && liCabinetSize.LowPart < MAX_CABINET_HEADER_SIZE)
@@ -942,11 +921,11 @@ static HRESULT UpdateDuplicateFiles(
942 hCabinetMapping = ::CreateFileMappingW(hCabinet, NULL, PAGE_READWRITE | SEC_COMMIT, 0, cbCabinet, NULL); 921 hCabinetMapping = ::CreateFileMappingW(hCabinet, NULL, PAGE_READWRITE | SEC_COMMIT, 0, cbCabinet, NULL);
943 if (NULL == hCabinetMapping || INVALID_HANDLE_VALUE == hCabinetMapping) 922 if (NULL == hCabinetMapping || INVALID_HANDLE_VALUE == hCabinetMapping)
944 { 923 {
945 CabcExitWithLastError(hr, "Failed to memory map cabinet file: %ls", pcd->wzCabinetPath); 924 CabcExitWithLastError(hr, "Failed to memory map cabinet file: %ls", pcd->sczCabinetPath);
946 } 925 }
947 926
948 pv = ::MapViewOfFile(hCabinetMapping, FILE_MAP_WRITE, 0, 0, 0); 927 pv = ::MapViewOfFile(hCabinetMapping, FILE_MAP_WRITE, 0, 0, 0);
949 CabcExitOnNullWithLastError(pv, hr, "Failed to map view of cabinet file: %ls", pcd->wzCabinetPath); 928 CabcExitOnNullWithLastError(pv, hr, "Failed to map view of cabinet file: %ls", pcd->sczCabinetPath);
950 929
951 pCabinetHeader = static_cast<MS_CABINET_HEADER*>(pv); 930 pCabinetHeader = static_cast<MS_CABINET_HEADER*>(pv);
952 931
@@ -1155,7 +1134,7 @@ static __callback INT_PTR DIAMONDAPI CabCOpen(
1155 1134
1156 if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile)) 1135 if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile))
1157 { 1136 {
1158 CabcExitOnLastError(hr, "failed to open file: %s", pszFile); 1137 CabcExitOnLastError(hr, "failed to open file: %hs", pszFile);
1159 } 1138 }
1160 1139
1161LExit: 1140LExit:
@@ -1326,11 +1305,12 @@ static __callback BOOL DIAMONDAPI CabCGetTempFile(
1326 1305
1327 HRESULT hr = S_OK; 1306 HRESULT hr = S_OK;
1328 char szTempPath[MAX_PATH] = { }; 1307 char szTempPath[MAX_PATH] = { };
1329 DWORD cchTempPath = MAX_PATH;
1330 DWORD dwProcessId = ::GetCurrentProcessId(); 1308 DWORD dwProcessId = ::GetCurrentProcessId();
1331 HANDLE hTempFile = INVALID_HANDLE_VALUE; 1309 HANDLE hTempFile = INVALID_HANDLE_VALUE;
1332 1310
1333 if (MAX_PATH < ::GetTempPathA(cchTempPath, szTempPath)) 1311 // TODO: Allow user to pass in different temp path in case the default is too long,
1312 // and/or see if magic similar to CABC_MAGIC_UNICODE_STRING_MARKER can be used to pass ourselves a path longer than MAX_PATH.
1313 if (MAX_PATH < ::GetTempPathA(countof(szTempPath), szTempPath))
1334 { 1314 {
1335 CabcExitWithLastError(hr, "Failed to get temp path during cabinet creation."); 1315 CabcExitWithLastError(hr, "Failed to get temp path during cabinet creation.");
1336 } 1316 }
@@ -1339,7 +1319,7 @@ static __callback BOOL DIAMONDAPI CabCGetTempFile(
1339 { 1319 {
1340 LONG dwTempIndex = ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(&dwIndex)); 1320 LONG dwTempIndex = ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(&dwIndex));
1341 1321
1342 hr = ::StringCbPrintfA(szFile, cbFile, "%s\\%08x.%03x", szTempPath, dwTempIndex, dwProcessId); 1322 hr = ::StringCbPrintfA(szFile, cbFile, "%hs\\%08x.%03x", szTempPath, dwTempIndex, dwProcessId);
1343 CabcExitOnFailure(hr, "failed to format log file path."); 1323 CabcExitOnFailure(hr, "failed to format log file path.");
1344 1324
1345 hTempFile = ::CreateFileA(szFile, 0, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); 1325 hTempFile = ::CreateFileA(szFile, 0, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
@@ -1351,7 +1331,11 @@ static __callback BOOL DIAMONDAPI CabCGetTempFile(
1351 } 1331 }
1352 else 1332 else
1353 { 1333 {
1354 hr = E_FAIL; // this file was taken so be pessimistic and assume we're not going to find one. 1334 hr = HRESULT_FROM_WIN32(::GetLastError()); // this file was taken so be pessimistic and assume we're not going to find one.
1335 if (SUCCEEDED(hr))
1336 {
1337 hr = E_FAIL;
1338 }
1355 } 1339 }
1356 } 1340 }
1357 CabcExitOnFailure(hr, "failed to find temporary file."); 1341 CabcExitOnFailure(hr, "failed to find temporary file.");
@@ -1386,7 +1370,7 @@ static __callback BOOL DIAMONDAPI CabCGetNextCabinet(
1386 if (pccab->iCab == 1) 1370 if (pccab->iCab == 1)
1387 { 1371 {
1388 pcd->wzFirstCabinetName[0] = '\0'; 1372 pcd->wzFirstCabinetName[0] = '\0';
1389 LPCWSTR pwzCabinetName = PathFile(pcd->wzCabinetPath); 1373 LPCWSTR pwzCabinetName = PathFile(pcd->sczCabinetPath);
1390 size_t len = wcsnlen(pwzCabinetName, sizeof(pwzCabinetName)); 1374 size_t len = wcsnlen(pwzCabinetName, sizeof(pwzCabinetName));
1391 if (len > 4) 1375 if (len > 4)
1392 { 1376 {
diff --git a/src/libs/dutil/WixToolset.DUtil/cabutil.cpp b/src/libs/dutil/WixToolset.DUtil/cabutil.cpp
index f3629d57..57463e1a 100644
--- a/src/libs/dutil/WixToolset.DUtil/cabutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/cabutil.cpp
@@ -261,15 +261,15 @@ static HRESULT DAPI CabOperation(
261 ) 261 )
262{ 262{
263 HRESULT hr = S_OK; 263 HRESULT hr = S_OK;
264 BOOL fResult; 264 BOOL fResult = FALSE;
265 265
266 LPWSTR sczCabinet = NULL; 266 LPWSTR sczCabinet = NULL;
267 LPWSTR pwz = NULL; 267 LPWSTR pwz = NULL;
268 CHAR szCabDirectory[MAX_PATH * 4]; // Make sure these are big enough for UTF-8 strings 268 LPSTR pszCabDirectory = NULL;
269 CHAR szCabFile[MAX_PATH * 4]; 269 CHAR szCabFile[MAX_PATH * 4] = { }; // Make sure this is big enough for UTF-8 strings
270 270
271 CAB_CALLBACK_STRUCT ccs; 271 CAB_CALLBACK_STRUCT ccs = { };
272 PFNFDINOTIFY pfnFdiNotify; 272 PFNFDINOTIFY pfnFdiNotify = NULL;
273 273
274 // 274 //
275 // ensure the cabinet.dll is loaded 275 // ensure the cabinet.dll is loaded
@@ -299,15 +299,13 @@ static HRESULT DAPI CabOperation(
299 // If a full path was not provided, use the relative current directory. 299 // If a full path was not provided, use the relative current directory.
300 if (wzCabinet == pwz) 300 if (wzCabinet == pwz)
301 { 301 {
302 hr = ::StringCchCopyA(szCabDirectory, countof(szCabDirectory), ".\\"); 302 hr = StrAnsiAllocStringAnsi(&pszCabDirectory, ".\\", 0);
303 CabExitOnFailure(hr, "Failed to copy relative current directory as cabinet directory."); 303 CabExitOnFailure(hr, "Failed to copy relative current directory as cabinet directory.");
304 } 304 }
305 else 305 else
306 { 306 {
307 if (!::WideCharToMultiByte(CP_UTF8, 0, sczCabinet, -1, szCabDirectory, countof(szCabDirectory), NULL, NULL)) 307 hr = StrAnsiAllocString(&pszCabDirectory, sczCabinet, 0, CP_UTF8);
308 { 308 CabExitOnFailure(hr, "failed to convert cabinet directory to ASCII: %ls", sczCabinet);
309 CabExitWithLastError(hr, "failed to convert cabinet directory to ASCII: %ls", sczCabinet);
310 }
311 } 309 }
312 310
313 // 311 //
@@ -331,7 +329,7 @@ static HRESULT DAPI CabOperation(
331 v_pfnNetFx11Notify = pfnNotify; 329 v_pfnNetFx11Notify = pfnNotify;
332 pfnFdiNotify = FDINotify; 330 pfnFdiNotify = FDINotify;
333 } 331 }
334 fResult = vpfnFDICopy(vhfdi, szCabFile, szCabDirectory, 0, pfnFdiNotify, NULL, static_cast<void*>(&ccs)); 332 fResult = vpfnFDICopy(vhfdi, szCabFile, pszCabDirectory, 0, pfnFdiNotify, NULL, static_cast<void*>(&ccs));
335 if (!fResult && !ccs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure 333 if (!fResult && !ccs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure
336 { 334 {
337 CabExitWithLastError(hr, "failed to extract cabinet file: %ls", sczCabinet); 335 CabExitWithLastError(hr, "failed to extract cabinet file: %ls", sczCabinet);
@@ -339,6 +337,7 @@ static HRESULT DAPI CabOperation(
339 337
340LExit: 338LExit:
341 ReleaseStr(sczCabinet); 339 ReleaseStr(sczCabinet);
340 ReleaseStr(pszCabDirectory);
342 v_pfnNetFx11Notify = NULL; 341 v_pfnNetFx11Notify = NULL;
343 342
344 return hr; 343 return hr;
@@ -493,14 +492,15 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
493 INT_PTR ipResult = 0; // result to return on success 492 INT_PTR ipResult = 0; // result to return on success
494 493
495 CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv); 494 CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv);
496 LPCSTR sz; 495 LPCSTR sz = NULL;
497 WCHAR wz[MAX_PATH]; 496 LPWSTR pwz = NULL;
498 FILETIME ft; 497 LPWSTR pwzPath = NULL;
498 FILETIME ft = { };
499 499
500 switch (iNotification) 500 switch (iNotification)
501 { 501 {
502 case fdintCOPY_FILE: // begin extracting a resource from cabinet 502 case fdintCOPY_FILE: // begin extracting a resource from cabinet
503 CabExitOnNull(pFDINotify->psz1, hr, E_INVALIDARG, "No cabinet file ID given to convert"); 503 Assert(pccs && pFDINotify->psz1);
504 CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided"); 504 CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided");
505 505
506 if (pccs->fStopExtracting) 506 if (pccs->fStopExtracting)
@@ -510,40 +510,37 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
510 510
511 // convert params to useful variables 511 // convert params to useful variables
512 sz = static_cast<LPCSTR>(pFDINotify->psz1); 512 sz = static_cast<LPCSTR>(pFDINotify->psz1);
513 if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) 513 CabExitOnNull(sz, hr, E_INVALIDARG, "No cabinet file ID given to convert");
514 { 514
515 CabExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); 515 hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP);
516 } 516 CabExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz);
517 517
518 if (pccs->pfnProgress) 518 if (pccs->pfnProgress)
519 { 519 {
520 hr = pccs->pfnProgress(TRUE, wz, pccs->pvContext); 520 hr = pccs->pfnProgress(TRUE, pwz, pccs->pvContext);
521 if (S_OK != hr) 521 if (S_OK != hr)
522 { 522 {
523 ExitFunction(); 523 ExitFunction();
524 } 524 }
525 } 525 }
526 526
527 if (L'*' == *pccs->pwzExtract || 0 == lstrcmpW(pccs->pwzExtract, wz)) 527 if (L'*' == *pccs->pwzExtract || 0 == lstrcmpW(pccs->pwzExtract, pwz))
528 { 528 {
529 // get the created date for the resource in the cabinet 529 // get the created date for the resource in the cabinet
530 FILETIME ftLocal; 530 FILETIME ftLocal;
531 if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal)) 531 if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal))
532 { 532 {
533 CabExitWithLastError(hr, "failed to get time for resource: %ls", wz); 533 CabExitWithLastError(hr, "failed to get time for resource: %ls", pwz);
534 } 534 }
535 ::LocalFileTimeToFileTime(&ftLocal, &ft); 535 ::LocalFileTimeToFileTime(&ftLocal, &ft);
536 536
537 WCHAR wzPath[MAX_PATH]; 537 hr = PathConcat(pccs->pwzExtractDir, pwz, &pwzPath);
538 hr = ::StringCchCopyW(wzPath, countof(wzPath), pccs->pwzExtractDir); 538 CabExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", pccs->pwzExtractDir, pwz);
539 CabExitOnFailure(hr, "failed to copy in extract directory: %ls for file: %ls", pccs->pwzExtractDir, wz);
540 hr = ::StringCchCatW(wzPath, countof(wzPath), wz);
541 CabExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz);
542 539
543 hFile = OpenFileWithRetry(wzPath, GENERIC_WRITE, CREATE_ALWAYS); 540 hFile = OpenFileWithRetry(pwzPath, GENERIC_WRITE, CREATE_ALWAYS);
544 if (INVALID_HANDLE_VALUE == hFile) 541 if (INVALID_HANDLE_VALUE == hFile)
545 { 542 {
546 CabExitWithLastError(hr, "failed to create file: %ls", wzPath); 543 CabExitWithLastError(hr, "failed to create file: %ls", pwzPath);
547 } 544 }
548 545
549 ::SetFileTime(hFile, &ft, &ft, &ft); // try to set the file time (who cares if it fails) 546 ::SetFileTime(hFile, &ft, &ft, &ft); // try to set the file time (who cares if it fails)
@@ -567,17 +564,15 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
567 564
568 break; 565 break;
569 case fdintCLOSE_FILE_INFO: // resource extraction complete 566 case fdintCLOSE_FILE_INFO: // resource extraction complete
570 Assert(pFDINotify->hf && pFDINotify->psz1); 567 Assert(pFDINotify->hf && pccs && pFDINotify->psz1);
571 CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided"); 568 CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided");
572 569
573 // convert params to useful variables 570 // convert params to useful variables
574 sz = static_cast<LPCSTR>(pFDINotify->psz1); 571 sz = static_cast<LPCSTR>(pFDINotify->psz1);
575 CabExitOnNull(sz, hr, E_INVALIDARG, "Failed to convert cabinet file id, because no cabinet file id was provided"); 572 CabExitOnNull(sz, hr, E_INVALIDARG, "Failed to convert cabinet file id, because no cabinet file id was provided");
576 573
577 if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) 574 hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP);
578 { 575 CabExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz);
579 CabExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz);
580 }
581 576
582 if (NULL != pFDINotify->hf) // just close the file 577 if (NULL != pFDINotify->hf) // just close the file
583 { 578 {
@@ -586,7 +581,7 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
586 581
587 if (pccs->pfnProgress) 582 if (pccs->pfnProgress)
588 { 583 {
589 hr = pccs->pfnProgress(FALSE, wz, pccs->pvContext); 584 hr = pccs->pfnProgress(FALSE, pwz, pccs->pvContext);
590 } 585 }
591 586
592 if (S_OK == hr && L'*' == *pccs->pwzExtract) // if everything is okay and we're extracting all files, keep going 587 if (S_OK == hr && L'*' == *pccs->pwzExtract) // if everything is okay and we're extracting all files, keep going
@@ -613,5 +608,8 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
613LExit: 608LExit:
614 ReleaseFileHandle(hFile); 609 ReleaseFileHandle(hFile);
615 610
611 ReleaseStr(pwz);
612 ReleaseStr(pwzPath);
613
616 return (S_OK == hr) ? ipResult : -1; 614 return (S_OK == hr) ? ipResult : -1;
617} 615}
diff --git a/src/libs/dutil/WixToolset.DUtil/dirutil.cpp b/src/libs/dutil/WixToolset.DUtil/dirutil.cpp
index 94eab9e7..2c02225d 100644
--- a/src/libs/dutil/WixToolset.DUtil/dirutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/dirutil.cpp
@@ -59,34 +59,10 @@ LExit:
59 *******************************************************************/ 59 *******************************************************************/
60extern "C" HRESULT DAPI DirCreateTempPath( 60extern "C" HRESULT DAPI DirCreateTempPath(
61 __in_z LPCWSTR wzPrefix, 61 __in_z LPCWSTR wzPrefix,
62 __out_ecount_z(cchPath) LPWSTR wzPath, 62 __out_opt LPWSTR* psczTempFile
63 __in DWORD cchPath
64 ) 63 )
65{ 64{
66 Assert(wzPrefix); 65 return PathCreateTempFile(NULL, NULL, 0, wzPrefix, 0, psczTempFile, NULL);
67 Assert(wzPath);
68
69 HRESULT hr = S_OK;
70
71 WCHAR wzDir[MAX_PATH];
72 WCHAR wzFile[MAX_PATH];
73 DWORD cch = 0;
74
75 cch = ::GetTempPathW(countof(wzDir), wzDir);
76 if (!cch || cch >= countof(wzDir))
77 {
78 DirExitWithLastError(hr, "Failed to GetTempPath.");
79 }
80
81 if (!::GetTempFileNameW(wzDir, wzPrefix, 0, wzFile))
82 {
83 DirExitWithLastError(hr, "Failed to GetTempFileName.");
84 }
85
86 hr = ::StringCchCopyW(wzPath, cchPath, wzFile);
87
88LExit:
89 return hr;
90} 66}
91 67
92 68
@@ -192,18 +168,19 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx(
192 Assert(wzPath && *wzPath); 168 Assert(wzPath && *wzPath);
193 169
194 HRESULT hr = S_OK; 170 HRESULT hr = S_OK;
195 DWORD er; 171 DWORD er = ERROR_SUCCESS;
196 172
197 DWORD dwAttrib; 173 DWORD dwAttrib = 0;
198 HANDLE hFind = INVALID_HANDLE_VALUE; 174 HANDLE hFind = INVALID_HANDLE_VALUE;
199 LPWSTR sczDelete = NULL; 175 LPWSTR sczDelete = NULL;
200 WIN32_FIND_DATAW wfd; 176 WIN32_FIND_DATAW wfd = { };
201 177
202 BOOL fDeleteFiles = (DIR_DELETE_FILES == (dwFlags & DIR_DELETE_FILES)); 178 BOOL fDeleteFiles = (DIR_DELETE_FILES == (dwFlags & DIR_DELETE_FILES));
203 BOOL fRecurse = (DIR_DELETE_RECURSE == (dwFlags & DIR_DELETE_RECURSE)); 179 BOOL fRecurse = (DIR_DELETE_RECURSE == (dwFlags & DIR_DELETE_RECURSE));
204 BOOL fScheduleDelete = (DIR_DELETE_SCHEDULE == (dwFlags & DIR_DELETE_SCHEDULE)); 180 BOOL fScheduleDelete = (DIR_DELETE_SCHEDULE == (dwFlags & DIR_DELETE_SCHEDULE));
205 WCHAR wzTempDirectory[MAX_PATH] = { }; 181 WCHAR wzSafeFileName[MAX_PATH + 1] = { };
206 WCHAR wzTempPath[MAX_PATH] = { }; 182 LPWSTR sczTempDirectory = NULL;
183 LPWSTR sczTempPath = NULL;
207 184
208 if (-1 == (dwAttrib = ::GetFileAttributesW(wzPath))) 185 if (-1 == (dwAttrib = ::GetFileAttributesW(wzPath)))
209 { 186 {
@@ -231,10 +208,8 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx(
231 { 208 {
232 if (fScheduleDelete) 209 if (fScheduleDelete)
233 { 210 {
234 if (!::GetTempPathW(countof(wzTempDirectory), wzTempDirectory)) 211 hr = PathGetTempPath(&sczTempDirectory, NULL);
235 { 212 DirExitOnFailure(hr, "Failed to get temp directory.");
236 DirExitWithLastError(hr, "Failed to get temp directory.");
237 }
238 } 213 }
239 214
240 // Delete everything in this directory. 215 // Delete everything in this directory.
@@ -256,10 +231,11 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx(
256 } 231 }
257 232
258 // For extra safety and to silence OACR. 233 // For extra safety and to silence OACR.
259 wfd.cFileName[MAX_PATH - 1] = L'\0'; 234 hr = ::StringCchCopyNExW(wzSafeFileName, countof(wzSafeFileName), wfd.cFileName, countof(wfd.cFileName), NULL, NULL, STRSAFE_FILL_BEHIND_NULL | STRSAFE_NULL_ON_FAILURE);
235 DirExitOnFailure(hr, "Failed to ensure file name was null terminated.");
260 236
261 hr = PathConcat(wzPath, wfd.cFileName, &sczDelete); 237 hr = PathConcat(wzPath, wzSafeFileName, &sczDelete);
262 DirExitOnFailure(hr, "Failed to concat filename '%ls' to directory: %ls", wfd.cFileName, wzPath); 238 DirExitOnFailure(hr, "Failed to concat filename '%ls' to directory: %ls", wzSafeFileName, wzPath);
263 239
264 if (fRecurse && wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 240 if (fRecurse && wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
265 { 241 {
@@ -288,16 +264,14 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx(
288 { 264 {
289 if (fScheduleDelete) 265 if (fScheduleDelete)
290 { 266 {
291 if (!::GetTempFileNameW(wzTempDirectory, L"DEL", 0, wzTempPath)) 267 hr = PathGetTempFileName(sczTempDirectory, L"DEL", 0, &sczTempPath);
292 { 268 DirExitOnFailure(hr, "Failed to get temp file to move to.");
293 DirExitWithLastError(hr, "Failed to get temp file to move to.");
294 }
295 269
296 // Try to move the file to the temp directory then schedule for delete, 270 // Try to move the file to the temp directory then schedule for delete,
297 // otherwise just schedule for delete. 271 // otherwise just schedule for delete.
298 if (::MoveFileExW(sczDelete, wzTempPath, MOVEFILE_REPLACE_EXISTING)) 272 if (::MoveFileExW(sczDelete, sczTempPath, MOVEFILE_REPLACE_EXISTING))
299 { 273 {
300 ::MoveFileExW(wzTempPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); 274 ::MoveFileExW(sczTempPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
301 } 275 }
302 else 276 else
303 { 277 {
@@ -348,6 +322,8 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx(
348LExit: 322LExit:
349 ReleaseFileFindHandle(hFind); 323 ReleaseFileFindHandle(hFind);
350 ReleaseStr(sczDelete); 324 ReleaseStr(sczDelete);
325 ReleaseStr(sczTempDirectory);
326 ReleaseStr(sczTempPath);
351 327
352 return hr; 328 return hr;
353} 329}
diff --git a/src/libs/dutil/WixToolset.DUtil/fileutil.cpp b/src/libs/dutil/WixToolset.DUtil/fileutil.cpp
index 9f68ee52..ac407916 100644
--- a/src/libs/dutil/WixToolset.DUtil/fileutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/fileutil.cpp
@@ -1284,21 +1284,18 @@ extern "C" HRESULT DAPI FileCreateTempW(
1284 Assert(wzPrefix && *wzPrefix); 1284 Assert(wzPrefix && *wzPrefix);
1285 HRESULT hr = E_FAIL; 1285 HRESULT hr = E_FAIL;
1286 1286
1287 WCHAR wzTempPath[MAX_PATH]; 1287 LPWSTR pwzTempPath = NULL;
1288 DWORD cchTempPath = countof(wzTempPath);
1289 LPWSTR pwzTempFile = NULL; 1288 LPWSTR pwzTempFile = NULL;
1290 1289
1291 HANDLE hTempFile = INVALID_HANDLE_VALUE; 1290 HANDLE hTempFile = INVALID_HANDLE_VALUE;
1292 int i = 0; 1291 int i = 0;
1293 1292
1294 if (!::GetTempPathW(cchTempPath, wzTempPath)) 1293 hr = PathGetTempPath(&pwzTempPath, NULL);
1295 { 1294 FileExitOnFailure(hr, "failed to get temp path");
1296 FileExitOnLastError(hr, "failed to get temp path");
1297 }
1298 1295
1299 for (i = 0; i < 1000 && INVALID_HANDLE_VALUE == hTempFile; ++i) 1296 for (i = 0; i < 1000 && INVALID_HANDLE_VALUE == hTempFile; ++i)
1300 { 1297 {
1301 hr = StrAllocFormatted(&pwzTempFile, L"%s%s%05d.%s", wzTempPath, wzPrefix, i, wzExtension); 1298 hr = StrAllocFormatted(&pwzTempFile, L"%s%s%05d.%s", pwzTempPath, wzPrefix, i, wzExtension);
1302 FileExitOnFailure(hr, "failed to allocate memory for temp filename"); 1299 FileExitOnFailure(hr, "failed to allocate memory for temp filename");
1303 1300
1304 hTempFile = ::CreateFileW(pwzTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 1301 hTempFile = ::CreateFileW(pwzTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
@@ -1330,6 +1327,7 @@ extern "C" HRESULT DAPI FileCreateTempW(
1330LExit: 1327LExit:
1331 ReleaseFile(hTempFile); 1328 ReleaseFile(hTempFile);
1332 ReleaseStr(pwzTempFile); 1329 ReleaseStr(pwzTempFile);
1330 ReleaseStr(pwzTempPath);
1333 1331
1334 return hr; 1332 return hr;
1335} 1333}
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h b/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h
index 42268a16..b8fc0431 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h
@@ -20,8 +20,7 @@ BOOL DAPI DirExists(
20 20
21HRESULT DAPI DirCreateTempPath( 21HRESULT DAPI DirCreateTempPath(
22 __in_z LPCWSTR wzPrefix, 22 __in_z LPCWSTR wzPrefix,
23 __out_ecount_z(cchPath) LPWSTR wzPath, 23 __out_opt LPWSTR* psczTempFile
24 __in DWORD cchPath
25 ); 24 );
26 25
27HRESULT DAPI DirEnsureExists( 26HRESULT DAPI DirEnsureExists(
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
index 971ef887..de46b95d 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
@@ -159,19 +159,31 @@ DAPI_(HRESULT) PathRelativeToModule(
159/******************************************************************* 159/*******************************************************************
160 PathCreateTempFile 160 PathCreateTempFile
161 161
162 Note: if wzDirectory is null, ::GetTempPath() will be used instead. 162 Note: if wzDirectory is null, ::GetTempPath2() will be used instead.
163 if wzFileNameTemplate is null, GetTempFileName() will be used instead. 163 if wzFileNameTemplate is null, GetTempFileName() will be used instead.
164*******************************************************************/ 164*******************************************************************/
165DAPI_(HRESULT) PathCreateTempFile( 165DAPI_(HRESULT) PathCreateTempFile(
166 __in_opt LPCWSTR wzDirectory, 166 __in_opt LPCWSTR wzDirectory,
167 __in_opt __format_string LPCWSTR wzFileNameTemplate, 167 __in_opt __format_string LPCWSTR wzFileNameTemplate,
168 __in DWORD dwUniqueCount, 168 __in DWORD dwUniqueCount,
169 __in_z LPCWSTR wzPrefix,
169 __in DWORD dwFileAttributes, 170 __in DWORD dwFileAttributes,
170 __out_opt LPWSTR* psczTempFile, 171 __out_opt LPWSTR* psczTempFile,
171 __out_opt HANDLE* phTempFile 172 __out_opt HANDLE* phTempFile
172 ); 173 );
173 174
174/******************************************************************* 175/*******************************************************************
176 PathGetTempFileName - wrapper around ::GetTempFileName.
177 If the wzPathName is too long, it will use its own algorithm.
178*******************************************************************/
179DAPI_(HRESULT) PathGetTempFileName(
180 __in LPCWSTR wzPathName,
181 __in LPCWSTR wzPrefixString,
182 __in UINT uUnique,
183 __out LPWSTR* psczTempFileName
184 );
185
186/*******************************************************************
175 PathCreateTimeBasedTempFile - creates an empty temp file based on current 187 PathCreateTimeBasedTempFile - creates an empty temp file based on current
176 system time 188 system time
177********************************************************************/ 189********************************************************************/
@@ -187,7 +199,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile(
187/******************************************************************* 199/*******************************************************************
188 PathCreateTempDirectory 200 PathCreateTempDirectory
189 201
190 Note: if wzDirectory is null, ::GetTempPath() will be used instead. 202 Note: if wzDirectory is null, ::GetTempPath2() will be used instead.
191*******************************************************************/ 203*******************************************************************/
192DAPI_(HRESULT) PathCreateTempDirectory( 204DAPI_(HRESULT) PathCreateTempDirectory(
193 __in_opt LPCWSTR wzDirectory, 205 __in_opt LPCWSTR wzDirectory,
@@ -201,7 +213,24 @@ DAPI_(HRESULT) PathCreateTempDirectory(
201 that is backslash terminated. 213 that is backslash terminated.
202*******************************************************************/ 214*******************************************************************/
203DAPI_(HRESULT) PathGetTempPath( 215DAPI_(HRESULT) PathGetTempPath(
204 __out_z LPWSTR* psczTempPath 216 __out_z LPWSTR* psczTempPath,
217 __out_opt SIZE_T* pcch
218 );
219
220/*******************************************************************
221 PathGetSystemDirectory - returns the path to the system folder
222 that is backslash terminated.
223*******************************************************************/
224DAPI_(HRESULT) PathGetSystemDirectory(
225 __out_z LPWSTR* psczSystemPath
226 );
227
228/*******************************************************************
229 PathGetSystemWow64Directory - returns the path to the system WoW 64 folder
230 that is backslash terminated.
231*******************************************************************/
232DAPI_(HRESULT) PathGetSystemWow64Directory(
233 __out_z LPWSTR* psczSystemPath
205 ); 234 );
206 235
207/******************************************************************* 236/*******************************************************************
@@ -223,12 +252,11 @@ DAPI_(HRESULT) PathGetSystemTempPaths(
223 ); 252 );
224 253
225/******************************************************************* 254/*******************************************************************
226 PathGetKnownFolder - returns the path to a well-known shell folder 255 PathGetVolumePathName - wrapper for ::GetVolumePathNameW.
227
228*******************************************************************/ 256*******************************************************************/
229DAPI_(HRESULT) PathGetKnownFolder( 257DAPI_(HRESULT) PathGetVolumePathName(
230 __in int csidl, 258 __in_z LPCWSTR wzFileName,
231 __out LPWSTR* psczKnownFolder 259 __out_z LPWSTR* psczVolumePathName
232 ); 260 );
233 261
234/******************************************************************* 262/*******************************************************************
@@ -340,6 +368,20 @@ DAPI_(HRESULT) PathGetHierarchyArray(
340 __inout LPUINT pcPathArray 368 __inout LPUINT pcPathArray
341 ); 369 );
342 370
371/********************************************************************
372 Path2FunctionAllowFallback - allow functions only available in newer versions of Windows.
373 Typically used for unit testing.
374
375*********************************************************************/
376void DAPI Path2FunctionAllowFallback();
377
378/********************************************************************
379 Path2FunctionForceFallback - ignore functions only available in newer versions of Windows.
380 Typically used for unit testing.
381
382*********************************************************************/
383void DAPI Path2FunctionForceFallback();
384
343/******************************************************************* 385/*******************************************************************
344 PathCanonicalizePath - wrapper around PathCanonicalizeW. 386 PathCanonicalizePath - wrapper around PathCanonicalizeW.
345*******************************************************************/ 387*******************************************************************/
@@ -349,6 +391,15 @@ DAPI_(HRESULT) PathCanonicalizePath(
349 ); 391 );
350 392
351/******************************************************************* 393/*******************************************************************
394 PathAllocCanonicalizePath - wrapper around PathAllocCanonicalize.
395*******************************************************************/
396DAPI_(HRESULT) PathAllocCanonicalizePath(
397 __in_z LPCWSTR wzPath,
398 __in DWORD dwFlags,
399 __deref_out_z LPWSTR* psczCanonicalized
400 );
401
402/*******************************************************************
352 PathCanonicalizeForComparison - canonicalizes the path based on the given flags. 403 PathCanonicalizeForComparison - canonicalizes the path based on the given flags.
353 . and .. directories are collapsed. 404 . and .. directories are collapsed.
354 All / are replaced with \. 405 All / are replaced with \.
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h b/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h
index 0b9f539d..2ee7ce87 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h
@@ -33,10 +33,25 @@ HRESULT DAPI ShelExecUnelevated(
33 __in_z_opt LPCWSTR wzWorkingDirectory, 33 __in_z_opt LPCWSTR wzWorkingDirectory,
34 __in int nShowCmd 34 __in int nShowCmd
35 ); 35 );
36
37/********************************************************************
38 ShelGetFolder() - translates the CSIDL into KNOWNFOLDERID and calls ShelGetKnownFolder.
39 If that returns E_NOTIMPL then falls back to ::SHGetFolderPathW.
40 The CSIDL_FLAG values are not supported, CSIDL_FLAG_CREATE is always used.
41 The path is backslash terminated.
42
43*******************************************************************/
36HRESULT DAPI ShelGetFolder( 44HRESULT DAPI ShelGetFolder(
37 __out_z LPWSTR* psczFolderPath, 45 __out_z LPWSTR* psczFolderPath,
38 __in int csidlFolder 46 __in int csidlFolder
39 ); 47 );
48
49/********************************************************************
50 ShelGetKnownFolder() - gets a folder by KNOWNFOLDERID with ::SHGetKnownFolderPath.
51 The path is backslash terminated.
52
53 Note: return E_NOTIMPL if called on pre-Vista operating systems.
54*******************************************************************/
40HRESULT DAPI ShelGetKnownFolder( 55HRESULT DAPI ShelGetKnownFolder(
41 __out_z LPWSTR* psczFolderPath, 56 __out_z LPWSTR* psczFolderPath,
42 __in REFKNOWNFOLDERID rfidFolder 57 __in REFKNOWNFOLDERID rfidFolder
diff --git a/src/libs/dutil/WixToolset.DUtil/logutil.cpp b/src/libs/dutil/WixToolset.DUtil/logutil.cpp
index 88a90d8c..3a130b4e 100644
--- a/src/libs/dutil/WixToolset.DUtil/logutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/logutil.cpp
@@ -684,9 +684,10 @@ LExit:
684extern "C" HRESULT DAPI LogHeader() 684extern "C" HRESULT DAPI LogHeader()
685{ 685{
686 HRESULT hr = S_OK; 686 HRESULT hr = S_OK;
687 WCHAR wzComputerName[MAX_PATH]; 687 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1] = { };
688 DWORD cchComputerName = countof(wzComputerName); 688 DWORD cchComputerName = countof(wzComputerName);
689 WCHAR wzPath[MAX_PATH]; 689 LPWSTR sczPath = NULL;
690 LPCWSTR wzPath = NULL;
690 DWORD dwMajorVersion = 0; 691 DWORD dwMajorVersion = 0;
691 DWORD dwMinorVersion = 0; 692 DWORD dwMinorVersion = 0;
692 LPCSTR szLevel = LOGUTIL_UNKNOWN; 693 LPCSTR szLevel = LOGUTIL_UNKNOWN;
@@ -695,12 +696,19 @@ extern "C" HRESULT DAPI LogHeader()
695 // 696 //
696 // get the interesting data 697 // get the interesting data
697 // 698 //
698 if (!::GetModuleFileNameW(NULL, wzPath, countof(wzPath))) 699
700 hr = PathForCurrentProcess(&sczPath, NULL);
701 if (FAILED(hr))
702 {
703 wzPath = L"";
704 }
705 else
699 { 706 {
700 memset(wzPath, 0, sizeof(wzPath)); 707 wzPath = sczPath;
708
709 hr = FileVersion(wzPath, &dwMajorVersion, &dwMinorVersion);
701 } 710 }
702 711
703 hr = FileVersion(wzPath, &dwMajorVersion, &dwMinorVersion);
704 if (FAILED(hr)) 712 if (FAILED(hr))
705 { 713 {
706 dwMajorVersion = 0; 714 dwMajorVersion = 0;
@@ -743,6 +751,7 @@ extern "C" HRESULT DAPI LogHeader()
743 hr = S_OK; 751 hr = S_OK;
744 752
745 ReleaseStr(sczCurrentDateTime); 753 ReleaseStr(sczCurrentDateTime);
754 ReleaseStr(sczPath);
746 755
747 return hr; 756 return hr;
748} 757}
diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp
index 3c4b2f88..862a743d 100644
--- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp
@@ -19,6 +19,65 @@
19#define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__) 19#define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__)
20 20
21 21
22typedef HRESULT(WINAPI* PFN_PATH_ALLOC_CANONICALIZE)(
23 __in LPCWSTR wzSource,
24 __in DWORD dwFlags,
25 __out_z LPWSTR* psczPathOut
26 );
27
28static BOOL vfInitialized = FALSE;
29static HMODULE vhPathApiSet_1_1_0 = NULL;
30static PFN_PATH_ALLOC_CANONICALIZE vpfnPathAllocCanonicalize = NULL;
31static BOOL vfForceFallback = FALSE;
32
33// from PathCch.h
34#ifndef PATHCCH_ALLOW_LONG_PATHS
35#define PATHCCH_ALLOW_LONG_PATHS 0x01
36#endif
37
38static HRESULT Initialize()
39{
40 HRESULT hr = S_OK;
41 DWORD er = ERROR_SUCCESS;
42
43 if (vfInitialized)
44 {
45 ExitFunction();
46 }
47
48 hr = LoadSystemApiSet(L"api-ms-win-core-path-l1-1-0.dll", &vhPathApiSet_1_1_0);
49 if (E_MODNOTFOUND == hr)
50 {
51 hr = E_NOTIMPL;
52 }
53 PathExitOnFailure(hr, "Failed to load api-ms-win-core-path-l1-1-0.dll");
54
55 vpfnPathAllocCanonicalize = reinterpret_cast<PFN_PATH_ALLOC_CANONICALIZE>(::GetProcAddress(vhPathApiSet_1_1_0, "PathAllocCanonicalize"));
56 if (!vpfnPathAllocCanonicalize)
57 {
58 er = ::GetLastError();
59 PathExitWithRootFailure(hr, ERROR_PROC_NOT_FOUND == er ? E_NOTIMPL : HRESULT_FROM_WIN32(er), "Failed to get address of PathAllocCanonicalize.");
60 }
61
62 vfInitialized = TRUE;
63
64LExit:
65 return hr;
66}
67
68
69DAPI_(void) Path2FunctionAllowFallback()
70{
71 vfForceFallback = FALSE;
72}
73
74
75DAPI_(void) Path2FunctionForceFallback()
76{
77 vfForceFallback = TRUE;
78}
79
80
22DAPI_(HRESULT) PathCanonicalizePath( 81DAPI_(HRESULT) PathCanonicalizePath(
23 __in_z LPCWSTR wzPath, 82 __in_z LPCWSTR wzPath,
24 __deref_out_z LPWSTR* psczCanonicalized 83 __deref_out_z LPWSTR* psczCanonicalized
@@ -43,6 +102,37 @@ LExit:
43 return hr; 102 return hr;
44} 103}
45 104
105DAPI_(HRESULT) PathAllocCanonicalizePath(
106 __in_z LPCWSTR wzPath,
107 __in DWORD dwFlags,
108 __deref_out_z LPWSTR* psczCanonicalized
109 )
110{
111 HRESULT hr = S_OK;
112 LPWSTR sczCanonicalizedPath = NULL;
113
114 hr = Initialize();
115 if (E_NOTIMPL == hr || SUCCEEDED(hr) && !vpfnPathAllocCanonicalize)
116 {
117 ExitFunction1(hr = E_NOTIMPL);
118 }
119 PathExitOnFailure(hr, "Failed to initialize path2utl.");
120
121 hr = vpfnPathAllocCanonicalize(wzPath, dwFlags, &sczCanonicalizedPath);
122 PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzPath);
123
124 hr = StrAllocString(psczCanonicalized, sczCanonicalizedPath, 0);
125 PathExitOnFailure(hr, "Failed to copy the canonicalized path.");
126
127LExit:
128 if (sczCanonicalizedPath)
129 {
130 ::LocalFree(sczCanonicalizedPath);
131 }
132
133 return hr;
134}
135
46DAPI_(HRESULT) PathCanonicalizeForComparison( 136DAPI_(HRESULT) PathCanonicalizeForComparison(
47 __in_z LPCWSTR wzPath, 137 __in_z LPCWSTR wzPath,
48 __in DWORD dwCanonicalizeFlags, 138 __in DWORD dwCanonicalizeFlags,
@@ -75,7 +165,19 @@ DAPI_(HRESULT) PathCanonicalizeForComparison(
75 165
76 if (*wzNormalizedPath) 166 if (*wzNormalizedPath)
77 { 167 {
78 hr = PathCanonicalizePath(wzNormalizedPath, psczCanonicalized); 168 if (!vfForceFallback)
169 {
170 hr = PathAllocCanonicalizePath(wzNormalizedPath, PATHCCH_ALLOW_LONG_PATHS, psczCanonicalized);
171 }
172 else
173 {
174 hr = E_NOTIMPL;
175 }
176
177 if (E_NOTIMPL == hr)
178 {
179 hr = PathCanonicalizePath(wzNormalizedPath, psczCanonicalized);
180 }
79 PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzNormalizedPath); 181 PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzNormalizedPath);
80 } 182 }
81 else 183 else
@@ -273,33 +375,52 @@ DAPI_(HRESULT) PathSystemWindowsSubdirectory(
273 ) 375 )
274{ 376{
275 HRESULT hr = S_OK; 377 HRESULT hr = S_OK;
276 WCHAR wzTempPath[MAX_PATH + 1] = { }; 378 LPWSTR sczWindowsPath = NULL;
379 DWORD cchBuffer = MAX_PATH + 1;
277 DWORD cch = 0; 380 DWORD cch = 0;
278 381
279 cch = ::GetSystemWindowsDirectoryW(wzTempPath, countof(wzTempPath)); 382 hr = StrAlloc(&sczWindowsPath, cchBuffer);
280 if (!cch) 383 PathExitOnFailure(hr, "Failed to alloc Windows directory path.");
281 { 384
282 PathExitWithLastError(hr, "Failed to get Windows directory path."); 385 cch = ::GetSystemWindowsDirectoryW(sczWindowsPath, cchBuffer);
283 } 386 PathExitOnNullWithLastError(cch, hr, "Failed to get Windows directory path with default size.");
284 else if (cch >= countof(wzTempPath)) 387
388 cch += 1; // add 1 for null terminator.
389
390 if (cch > cchBuffer)
285 { 391 {
286 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long."); 392 hr = StrAlloc(&sczWindowsPath, cch);
393 PathExitOnFailure(hr, "Failed to realloc Windows directory path.");
394
395 cchBuffer = cch;
396
397 cch = ::GetSystemWindowsDirectoryW(sczWindowsPath, cchBuffer);
398 PathExitOnNullWithLastError(cch, hr, "Failed to get Windows directory path with returned size.");
399
400 cch += 1; // add 1 for null terminator.
401
402 if (cch > cchBuffer)
403 {
404 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get Windows directory path with returned size.");
405 }
287 } 406 }
288 407
289 if (wzSubdirectory) 408 if (wzSubdirectory)
290 { 409 {
291 hr = PathConcatRelativeToBase(wzTempPath, wzSubdirectory, psczFullPath); 410 hr = PathConcatRelativeToBase(sczWindowsPath, wzSubdirectory, psczFullPath);
292 PathExitOnFailure(hr, "Failed to concat subdirectory on Windows directory path."); 411 PathExitOnFailure(hr, "Failed to concat subdirectory on Windows directory path.");
293 } 412 }
294 else 413 else
295 { 414 {
296 hr = StrAllocString(psczFullPath, wzTempPath, 0); 415 *psczFullPath = sczWindowsPath;
297 PathExitOnFailure(hr, "Failed to copy Windows directory path."); 416 sczWindowsPath = NULL;
298 } 417 }
299 418
300 hr = PathBackslashTerminate(psczFullPath); 419 hr = PathBackslashTerminate(psczFullPath);
301 PathExitOnFailure(hr, "Failed to terminate Windows directory path with backslash."); 420 PathExitOnFailure(hr, "Failed to terminate Windows directory path with backslash.");
302 421
303LExit: 422LExit:
423 ReleaseStr(sczWindowsPath);
424
304 return hr; 425 return hr;
305} 426}
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
index 0e2a5dec..dd5385fc 100644
--- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
@@ -20,6 +20,11 @@
20 20
21#define PATH_GOOD_ENOUGH 64 21#define PATH_GOOD_ENOUGH 64
22 22
23typedef DWORD(APIENTRY* PFN_GETTEMPPATH2W)(
24 __in DWORD BufferLength,
25 __out LPWSTR Buffer
26 );
27
23static BOOL IsPathSeparatorChar( 28static BOOL IsPathSeparatorChar(
24 __in WCHAR wc 29 __in WCHAR wc
25 ); 30 );
@@ -527,28 +532,55 @@ DAPI_(HRESULT) PathForCurrentProcess(
527 ) 532 )
528{ 533{
529 HRESULT hr = S_OK; 534 HRESULT hr = S_OK;
530 DWORD cch = MAX_PATH; 535 WCHAR smallBuffer[1] = { };
536 SIZE_T cchMax = 0;
537 DWORD cchBuffer = 0;
538 DWORD cch = 0;
539 DWORD dwMaxAttempts = 20;
531 540
532 do 541 // GetModuleFileNameW didn't originally set the last error when the buffer was too small.
542 ::SetLastError(ERROR_SUCCESS);
543
544 cch = ::GetModuleFileNameW(hModule, smallBuffer, countof(smallBuffer));
545 PathExitOnNullWithLastError(cch, hr, "Failed to get size of path for executing process.");
546
547 if (*psczFullPath && ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
533 { 548 {
534 hr = StrAlloc(psczFullPath, cch); 549 hr = StrMaxLength(*psczFullPath, &cchMax);
535 PathExitOnFailure(hr, "Failed to allocate string for module path."); 550 PathExitOnFailure(hr, "Failed to get max length of input buffer.");
551
552 cchBuffer = (DWORD)min(DWORD_MAX, cchMax);
553 }
554 else
555 {
556 cchBuffer = MAX_PATH + 1;
557
558 hr = StrAlloc(psczFullPath, cchBuffer);
559 PathExitOnFailure(hr, "Failed to allocate space for module path.");
560 }
561
562 ::SetLastError(ERROR_SUCCESS);
536 563
537 DWORD cchRequired = ::GetModuleFileNameW(hModule, *psczFullPath, cch); 564 for (DWORD i = 0; i < dwMaxAttempts; ++i)
538 if (0 == cchRequired) 565 {
566 cch = ::GetModuleFileNameW(hModule, *psczFullPath, cchBuffer);
567 PathExitOnNullWithLastError(cch, hr, "Failed to get path for executing process.");
568
569 if (ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
539 { 570 {
540 PathExitWithLastError(hr, "Failed to get path for executing process."); 571 break;
541 } 572 }
542 else if (cchRequired == cch) 573
574 if ((dwMaxAttempts - 1) == i)
543 { 575 {
544 cch = cchRequired + 1; 576 PathExitWithRootFailure(hr, E_FAIL, "Unexpected failure getting path for executing process.");
545 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
546 } 577 }
547 else 578
548 { 579 cchBuffer *= 2;
549 hr = S_OK; 580
550 } 581 hr = StrAlloc(psczFullPath, cchBuffer);
551 } while (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr); 582 PathExitOnFailure(hr, "Failed to re-allocate more space for module path.");
583 }
552 584
553LExit: 585LExit:
554 return hr; 586 return hr;
@@ -582,17 +614,18 @@ DAPI_(HRESULT) PathCreateTempFile(
582 __in_opt LPCWSTR wzDirectory, 614 __in_opt LPCWSTR wzDirectory,
583 __in_opt __format_string LPCWSTR wzFileNameTemplate, 615 __in_opt __format_string LPCWSTR wzFileNameTemplate,
584 __in DWORD dwUniqueCount, 616 __in DWORD dwUniqueCount,
617 __in_z LPCWSTR wzPrefix,
585 __in DWORD dwFileAttributes, 618 __in DWORD dwFileAttributes,
586 __out_opt LPWSTR* psczTempFile, 619 __out_opt LPWSTR* psczTempFile,
587 __out_opt HANDLE* phTempFile 620 __out_opt HANDLE* phTempFile
588 ) 621 )
589{ 622{
590 AssertSz(0 < dwUniqueCount, "Must specify a non-zero unique count."); 623 Assert(wzPrefix);
624 AssertSz(!wzFileNameTemplate || !*wzFileNameTemplate || 0 < dwUniqueCount, "Must specify a non-zero unique count.");
591 625
592 HRESULT hr = S_OK; 626 HRESULT hr = S_OK;
593 627
594 LPWSTR sczTempPath = NULL; 628 LPWSTR sczTempPath = NULL;
595 DWORD cchTempPath = MAX_PATH;
596 629
597 HANDLE hTempFile = INVALID_HANDLE_VALUE; 630 HANDLE hTempFile = INVALID_HANDLE_VALUE;
598 LPWSTR scz = NULL; 631 LPWSTR scz = NULL;
@@ -605,13 +638,8 @@ DAPI_(HRESULT) PathCreateTempFile(
605 } 638 }
606 else 639 else
607 { 640 {
608 hr = StrAlloc(&sczTempPath, cchTempPath); 641 hr = PathGetTempPath(&sczTempPath, NULL);
609 PathExitOnFailure(hr, "Failed to allocate memory for the temp path."); 642 PathExitOnFailure(hr, "Failed to get temp path.");
610
611 if (!::GetTempPathW(cchTempPath, sczTempPath))
612 {
613 PathExitWithLastError(hr, "Failed to get temp path.");
614 }
615 } 643 }
616 644
617 if (wzFileNameTemplate && *wzFileNameTemplate) 645 if (wzFileNameTemplate && *wzFileNameTemplate)
@@ -621,7 +649,7 @@ DAPI_(HRESULT) PathCreateTempFile(
621 hr = StrAllocFormatted(&scz, wzFileNameTemplate, i); 649 hr = StrAllocFormatted(&scz, wzFileNameTemplate, i);
622 PathExitOnFailure(hr, "Failed to allocate memory for file template."); 650 PathExitOnFailure(hr, "Failed to allocate memory for file template.");
623 651
624 hr = StrAllocFormatted(&sczTempFile, L"%s%s", sczTempPath, scz); 652 hr = StrAllocFormatted(&sczTempFile, L"%ls%ls", sczTempPath, scz);
625 PathExitOnFailure(hr, "Failed to allocate temp file name."); 653 PathExitOnFailure(hr, "Failed to allocate temp file name.");
626 654
627 hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, dwFileAttributes, NULL); 655 hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, dwFileAttributes, NULL);
@@ -642,13 +670,8 @@ DAPI_(HRESULT) PathCreateTempFile(
642 // the system to provide us a temp file using its built-in mechanism. 670 // the system to provide us a temp file using its built-in mechanism.
643 if (INVALID_HANDLE_VALUE == hTempFile) 671 if (INVALID_HANDLE_VALUE == hTempFile)
644 { 672 {
645 hr = StrAlloc(&sczTempFile, MAX_PATH); 673 hr = PathGetTempFileName(sczTempPath, wzPrefix, 0, &sczTempFile);
646 PathExitOnFailure(hr, "Failed to allocate memory for the temp path"); 674 PathExitOnFailure(hr, "Failed to create new temp file name.");
647
648 if (!::GetTempFileNameW(sczTempPath, L"TMP", 0, sczTempFile))
649 {
650 PathExitWithLastError(hr, "Failed to create new temp file name.");
651 }
652 675
653 hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, dwFileAttributes, NULL); 676 hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, dwFileAttributes, NULL);
654 if (INVALID_HANDLE_VALUE == hTempFile) 677 if (INVALID_HANDLE_VALUE == hTempFile)
@@ -684,6 +707,82 @@ LExit:
684} 707}
685 708
686 709
710DAPI_(HRESULT) PathGetTempFileName(
711 __in LPCWSTR wzPathName,
712 __in LPCWSTR wzPrefixString,
713 __in UINT uUnique,
714 __out LPWSTR* psczTempFileName
715 )
716{
717 HRESULT hr = S_OK;
718 size_t cchFullPath = 0;
719 WORD wValue = (WORD)(0xffff & uUnique);
720 LPWSTR scz = NULL;
721 LPWSTR sczTempFile = NULL;
722 HANDLE hTempFile = INVALID_HANDLE_VALUE;
723
724 hr = ::StringCchLengthW(wzPathName, STRSAFE_MAX_CCH, &cchFullPath);
725 PathExitOnFailure(hr, "Failed to get length of path to prefix.");
726
727 if (MAX_PATH - 14 >= cchFullPath)
728 {
729 hr = StrAlloc(psczTempFileName, MAX_PATH);
730 PathExitOnFailure(hr, "Failed to allocate buffer for GetTempFileNameW.");
731
732 if (!::GetTempFileNameW(wzPathName, wzPrefixString, uUnique, *psczTempFileName))
733 {
734 PathExitWithLastError(hr, "Failed to create new temp file name.");
735 }
736
737 ExitFunction();
738 }
739
740 // TODO: when uUnique is 0, consider not always starting at 0 to avoid collisions if this is called repeatedly.
741 // Purposely let it wrap around.
742 for (WORD w = 0; w < WORD_MAX && INVALID_HANDLE_VALUE == hTempFile; ++wValue)
743 {
744 hr = StrAllocFormatted(&scz, L"%ls%x.TMP", wzPrefixString, w);
745 PathExitOnFailure(hr, "Failed to allocate memory for file template.");
746
747 hr = PathConcat(wzPathName, scz, &sczTempFile);
748 PathExitOnFailure(hr, "Failed to allocate temp file name.");
749
750 hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, 0, NULL);
751 if (INVALID_HANDLE_VALUE == hTempFile)
752 {
753 // if the file already exists, try next one.
754 hr = HRESULT_FROM_WIN32(::GetLastError());
755 if (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr)
756 {
757 hr = S_OK;
758 }
759 PathExitOnFailure(hr, "Failed to create file: %ls", sczTempFile);
760 }
761
762 ++w;
763 }
764
765 if (INVALID_HANDLE_VALUE == hTempFile)
766 {
767 PathExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "Failed to create temp file.");
768 }
769
770 hr = StrAllocString(psczTempFileName, sczTempFile, 0);
771 PathExitOnFailure(hr, "Failed to copy temp file string.");
772
773LExit:
774 if (INVALID_HANDLE_VALUE != hTempFile)
775 {
776 ::CloseHandle(hTempFile);
777 }
778
779 ReleaseStr(scz);
780 ReleaseStr(sczTempFile);
781
782 return hr;
783}
784
785
687DAPI_(HRESULT) PathCreateTimeBasedTempFile( 786DAPI_(HRESULT) PathCreateTimeBasedTempFile(
688 __in_z_opt LPCWSTR wzDirectory, 787 __in_z_opt LPCWSTR wzDirectory,
689 __in_z LPCWSTR wzPrefix, 788 __in_z LPCWSTR wzPrefix,
@@ -695,7 +794,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile(
695{ 794{
696 HRESULT hr = S_OK; 795 HRESULT hr = S_OK;
697 BOOL fRetry = FALSE; 796 BOOL fRetry = FALSE;
698 WCHAR wzTempPath[MAX_PATH] = { }; 797 LPWSTR sczTempParentPath = NULL;
699 LPWSTR sczPrefix = NULL; 798 LPWSTR sczPrefix = NULL;
700 LPWSTR sczPrefixFolder = NULL; 799 LPWSTR sczPrefixFolder = NULL;
701 SYSTEMTIME time = { }; 800 SYSTEMTIME time = { };
@@ -711,12 +810,10 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile(
711 } 810 }
712 else 811 else
713 { 812 {
714 if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) 813 hr = PathGetTempPath(&sczTempParentPath, NULL);
715 { 814 PathExitOnFailure(hr, "Failed to get temp folder.");
716 PathExitWithLastError(hr, "Failed to get temp folder.");
717 }
718 815
719 hr = PathConcat(wzTempPath, wzPrefix, &sczPrefix); 816 hr = PathConcat(sczTempParentPath, wzPrefix, &sczPrefix);
720 PathExitOnFailure(hr, "Failed to concatenate the temp folder and log prefix."); 817 PathExitOnFailure(hr, "Failed to concatenate the temp folder and log prefix.");
721 } 818 }
722 819
@@ -778,6 +875,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile(
778 875
779LExit: 876LExit:
780 ReleaseFile(hTempFile); 877 ReleaseFile(hTempFile);
878 ReleaseStr(sczTempParentPath);
781 ReleaseStr(sczTempPath); 879 ReleaseStr(sczTempPath);
782 ReleaseStr(sczPrefixFolder); 880 ReleaseStr(sczPrefixFolder);
783 ReleaseStr(sczPrefix); 881 ReleaseStr(sczPrefix);
@@ -799,7 +897,6 @@ DAPI_(HRESULT) PathCreateTempDirectory(
799 HRESULT hr = S_OK; 897 HRESULT hr = S_OK;
800 898
801 LPWSTR sczTempPath = NULL; 899 LPWSTR sczTempPath = NULL;
802 DWORD cchTempPath = MAX_PATH;
803 900
804 LPWSTR scz = NULL; 901 LPWSTR scz = NULL;
805 902
@@ -813,13 +910,8 @@ DAPI_(HRESULT) PathCreateTempDirectory(
813 } 910 }
814 else 911 else
815 { 912 {
816 hr = StrAlloc(&sczTempPath, cchTempPath); 913 hr = PathGetTempPath(&sczTempPath, NULL);
817 PathExitOnFailure(hr, "Failed to allocate memory for the temp path."); 914 PathExitOnFailure(hr, "Failed to get temp path.");
818
819 if (!::GetTempPathW(cchTempPath, sczTempPath))
820 {
821 PathExitWithLastError(hr, "Failed to get temp path.");
822 }
823 } 915 }
824 916
825 for (DWORD i = 1; i <= dwUniqueCount; ++i) 917 for (DWORD i = 1; i <= dwUniqueCount; ++i)
@@ -869,46 +961,230 @@ LExit:
869 961
870 962
871DAPI_(HRESULT) PathGetTempPath( 963DAPI_(HRESULT) PathGetTempPath(
872 __out_z LPWSTR* psczTempPath 964 __out_z LPWSTR* psczTempPath,
965 __out_opt SIZE_T* pcch
966 )
967{
968
969 HRESULT hr = S_OK;
970 SIZE_T cchMax = 0;
971 DWORD cchBuffer = 0;
972 DWORD cch = 0;
973 DWORD dwAttempts = 0;
974 HMODULE hModule = NULL;
975 PFN_GETTEMPPATH2W pfnGetTempPath = NULL;
976 const DWORD dwMaxAttempts = 10;
977
978 if (*psczTempPath)
979 {
980 hr = StrMaxLength(*psczTempPath, &cchMax);
981 PathExitOnFailure(hr, "Failed to get max length of input buffer.");
982
983 cchBuffer = (DWORD)min(DWORD_MAX, cchMax);
984 }
985 else
986 {
987 cchBuffer = MAX_PATH + 1;
988
989 hr = StrAlloc(psczTempPath, cchBuffer);
990 PathExitOnFailure(hr, "Failed to allocate space for temp path.");
991 }
992
993 hr = LoadSystemLibrary(L"kernel32.dll", &hModule);
994 PathExitOnFailure(hr, "Failed to load kernel32.dll");
995
996 pfnGetTempPath = reinterpret_cast<PFN_GETTEMPPATH2W>(::GetProcAddress(hModule, "GetTempPath2W"));
997 if (!pfnGetTempPath)
998 {
999 pfnGetTempPath = ::GetTempPathW;
1000 }
1001
1002 for (; dwAttempts < dwMaxAttempts; ++dwAttempts)
1003 {
1004 cch = pfnGetTempPath(cchBuffer, *psczTempPath);
1005 PathExitOnNullWithLastError(cch, hr, "Failed to get temp path.");
1006
1007 cch += 1; // add one for null terminator.
1008
1009 if (cch <= cchBuffer)
1010 {
1011 break;
1012 }
1013
1014 hr = StrAlloc(psczTempPath, cch);
1015 PathExitOnFailure(hr, "Failed to reallocate space for temp path.");
1016
1017 cchBuffer = cch;
1018 }
1019
1020 if (dwMaxAttempts == dwAttempts)
1021 {
1022 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "GetTempPathW results never converged.");
1023 }
1024
1025 if (pcch)
1026 {
1027 *pcch = cch - 1; // remove one for null terminator.
1028 }
1029
1030LExit:
1031 return hr;
1032}
1033
1034
1035DAPI_(HRESULT) PathGetSystemDirectory(
1036 __out_z LPWSTR* psczSystemPath
1037 )
1038{
1039 HRESULT hr = S_OK;
1040 SIZE_T cchMax = 0;
1041 DWORD cchBuffer = 0;
1042 DWORD cch = 0;
1043
1044 if (*psczSystemPath)
1045 {
1046 hr = StrMaxLength(*psczSystemPath, &cchMax);
1047 PathExitOnFailure(hr, "Failed to get max length of input buffer.");
1048
1049 cchBuffer = (DWORD)min(DWORD_MAX, cchMax);
1050 }
1051 else
1052 {
1053 cchBuffer = MAX_PATH + 1;
1054
1055 hr = StrAlloc(psczSystemPath, cchBuffer);
1056 PathExitOnFailure(hr, "Failed to allocate space for system directory.");
1057 }
1058
1059 cch = ::GetSystemDirectoryW(*psczSystemPath, cchBuffer);
1060 PathExitOnNullWithLastError(cch, hr, "Failed to get system directory path with default size.");
1061
1062 if (cch > cchBuffer)
1063 {
1064 hr = StrAlloc(psczSystemPath, cch);
1065 PathExitOnFailure(hr, "Failed to realloc system directory path.");
1066
1067 cchBuffer = cch;
1068
1069 cch = ::GetSystemDirectoryW(*psczSystemPath, cchBuffer);
1070 PathExitOnNullWithLastError(cch, hr, "Failed to get system directory path with returned size.");
1071
1072 if (cch > cchBuffer)
1073 {
1074 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get system directory path with returned size.");
1075 }
1076 }
1077
1078 hr = PathBackslashTerminate(psczSystemPath);
1079 PathExitOnFailure(hr, "Failed to terminate system directory path with backslash.");
1080
1081LExit:
1082 return hr;
1083}
1084
1085
1086DAPI_(HRESULT) PathGetSystemWow64Directory(
1087 __out_z LPWSTR* psczSystemPath
873 ) 1088 )
874{ 1089{
875 HRESULT hr = S_OK; 1090 HRESULT hr = S_OK;
876 WCHAR wzTempPath[MAX_PATH + 1] = { }; 1091 SIZE_T cchMax = 0;
1092 DWORD cchBuffer = 0;
877 DWORD cch = 0; 1093 DWORD cch = 0;
878 1094
879 cch = ::GetTempPathW(countof(wzTempPath), wzTempPath); 1095 if (*psczSystemPath)
880 if (!cch)
881 { 1096 {
882 PathExitWithLastError(hr, "Failed to GetTempPath."); 1097 hr = StrMaxLength(*psczSystemPath, &cchMax);
1098 PathExitOnFailure(hr, "Failed to get max length of input buffer.");
1099
1100 cchBuffer = (DWORD)min(DWORD_MAX, cchMax);
883 } 1101 }
884 else if (cch >= countof(wzTempPath)) 1102 else
885 { 1103 {
886 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "TEMP directory path too long."); 1104 cchBuffer = MAX_PATH + 1;
1105
1106 hr = StrAlloc(psczSystemPath, cchBuffer);
1107 PathExitOnFailure(hr, "Failed to allocate space for system wow64 directory.");
887 } 1108 }
888 1109
889 hr = StrAllocString(psczTempPath, wzTempPath, cch); 1110 cch = ::GetSystemWow64DirectoryW(*psczSystemPath, cchBuffer);
890 PathExitOnFailure(hr, "Failed to copy TEMP directory path."); 1111 PathExitOnNullWithLastError(cch, hr, "Failed to get system wow64 directory path with default size.");
1112
1113 cch += 1; // add one for the null terminator.
1114
1115 if (cch > cchBuffer)
1116 {
1117 hr = StrAlloc(psczSystemPath, cch);
1118 PathExitOnFailure(hr, "Failed to realloc system wow64 directory path.");
1119
1120 cchBuffer = cch;
1121
1122 cch = ::GetSystemWow64DirectoryW(*psczSystemPath, cchBuffer);
1123 PathExitOnNullWithLastError(cch, hr, "Failed to get system wow64 directory path with returned size.");
1124
1125 cch += 1; // add one for the null terminator.
1126
1127 if (cch > cchBuffer)
1128 {
1129 PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get system wow64 directory path with returned size.");
1130 }
1131 }
1132
1133 hr = PathBackslashTerminate(psczSystemPath);
1134 PathExitOnFailure(hr, "Failed to terminate system wow64 directory path with backslash.");
891 1135
892LExit: 1136LExit:
893 return hr; 1137 return hr;
894} 1138}
895 1139
896 1140
897DAPI_(HRESULT) PathGetKnownFolder( 1141DAPI_(HRESULT) PathGetVolumePathName(
898 __in int csidl, 1142 __in_z LPCWSTR wzFileName,
899 __out LPWSTR* psczKnownFolder 1143 __out_z LPWSTR* psczVolumePathName
900 ) 1144 )
901{ 1145{
902 HRESULT hr = S_OK; 1146 HRESULT hr = S_OK;
1147 DWORD cchBuffer = 0;
1148 SIZE_T cchMax = 0;
1149 const DWORD dwMaxAttempts = 20;
903 1150
904 hr = StrAlloc(psczKnownFolder, MAX_PATH); 1151 if (*psczVolumePathName)
905 PathExitOnFailure(hr, "Failed to allocate memory for known folder."); 1152 {
1153 hr = StrMaxLength(*psczVolumePathName, &cchMax);
1154 PathExitOnFailure(hr, "Failed to get max length of input buffer.");
906 1155
907 hr = ::SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, *psczKnownFolder); 1156 cchBuffer = (DWORD)min(DWORD_MAX, cchMax);
908 PathExitOnFailure(hr, "Failed to get known folder path."); 1157 }
1158 else
1159 {
1160 cchBuffer = MAX_PATH + 1;
1161
1162 hr = StrAlloc(psczVolumePathName, cchBuffer);
1163 PathExitOnFailure(hr, "Failed to allocate space for volume path name.");
1164 }
1165
1166 for (DWORD i = 0; i < dwMaxAttempts; ++i)
1167 {
1168 if (::GetVolumePathNameW(wzFileName, *psczVolumePathName, cchBuffer))
1169 {
1170 break;
1171 }
1172
1173 hr = HRESULT_FROM_WIN32(::GetLastError());
1174 if (HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) != hr && E_INSUFFICIENT_BUFFER != hr ||
1175 (dwMaxAttempts - 1) == i)
1176 {
1177 PathExitWithRootFailure(hr, hr, "Failed to get volume path name of: %ls", wzFileName);
1178 }
1179
1180 cchBuffer *= 2;
1181
1182 hr = StrAlloc(psczVolumePathName, cchBuffer);
1183 PathExitOnFailure(hr, "Failed to re-allocate more space for volume path name.");
1184 }
909 1185
910 hr = PathBackslashTerminate(psczKnownFolder); 1186 hr = PathBackslashTerminate(psczVolumePathName);
911 PathExitOnFailure(hr, "Failed to ensure known folder path is backslash terminated."); 1187 PathExitOnFailure(hr, "Failed to terminate volume path name with backslash.");
912 1188
913LExit: 1189LExit:
914 return hr; 1190 return hr;
diff --git a/src/libs/dutil/WixToolset.DUtil/rexutil.cpp b/src/libs/dutil/WixToolset.DUtil/rexutil.cpp
index 155ca714..ce28beb3 100644
--- a/src/libs/dutil/WixToolset.DUtil/rexutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/rexutil.cpp
@@ -28,7 +28,7 @@ static ERF verf;
28static FAKE_FILE vrgffFileTable[FILETABLESIZE]; 28static FAKE_FILE vrgffFileTable[FILETABLESIZE];
29static DWORD vcbRes; 29static DWORD vcbRes;
30static LPCBYTE vpbRes; 30static LPCBYTE vpbRes;
31static CHAR vszResource[MAX_PATH]; 31static LPSTR vpszResource = NULL;
32static REX_CALLBACK_WRITE vpfnWrite = NULL; 32static REX_CALLBACK_WRITE vpfnWrite = NULL;
33 33
34static HRESULT vhrLastError = S_OK; 34static HRESULT vhrLastError = S_OK;
@@ -85,6 +85,8 @@ LExit:
85 { 85 {
86 ::FDIDestroy(vhfdi); 86 ::FDIDestroy(vhfdi);
87 vhfdi = NULL; 87 vhfdi = NULL;
88
89 ReleaseNullStr(vpszResource);
88 } 90 }
89 91
90 return hr; 92 return hr;
@@ -101,6 +103,8 @@ extern "C" void RexUninitialize()
101 { 103 {
102 ::FDIDestroy(vhfdi); 104 ::FDIDestroy(vhfdi);
103 vhfdi = NULL; 105 vhfdi = NULL;
106
107 ReleaseNullStr(vpszResource);
104 } 108 }
105} 109}
106 110
@@ -124,12 +128,12 @@ extern "C" HRESULT RexExtract(
124{ 128{
125 Assert(vhfdi); 129 Assert(vhfdi);
126 HRESULT hr = S_OK; 130 HRESULT hr = S_OK;
127 BOOL fResult; 131 BOOL fResult = FALSE;
128 132
129 HRSRC hResInfo = NULL; 133 HRSRC hResInfo = NULL;
130 HANDLE hRes = NULL; 134 HANDLE hRes = NULL;
131 135
132 REX_CALLBACK_STRUCT rcs; 136 REX_CALLBACK_STRUCT rcs = { };
133 137
134 // remember the write callback 138 // remember the write callback
135 vpfnWrite = pfnWrite; 139 vpfnWrite = pfnWrite;
@@ -158,7 +162,7 @@ extern "C" HRESULT RexExtract(
158 // RexExitOnLastError(hr, "failed to convert cabinet resource name to ASCII: %ls", wzResource); 162 // RexExitOnLastError(hr, "failed to convert cabinet resource name to ASCII: %ls", wzResource);
159 //} 163 //}
160 164
161 hr = ::StringCchCopyA(vszResource, countof(vszResource), szResource); 165 hr = StrAnsiAllocStringAnsi(&vpszResource, szResource, 0);
162 RexExitOnFailure(hr, "Failed to copy resource name to global."); 166 RexExitOnFailure(hr, "Failed to copy resource name to global.");
163 167
164 // 168 //
@@ -171,7 +175,7 @@ extern "C" HRESULT RexExtract(
171 rcs.pfnProgress = pfnProgress; 175 rcs.pfnProgress = pfnProgress;
172 rcs.pvContext = pvContext; 176 rcs.pvContext = pvContext;
173 177
174 fResult = ::FDICopy(vhfdi, vszResource, "", 0, RexCallback, NULL, static_cast<void*>(&rcs)); 178 fResult = ::FDICopy(vhfdi, vpszResource, "", 0, RexCallback, NULL, static_cast<void*>(&rcs));
175 if (!fResult && !rcs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure 179 if (!fResult && !rcs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure
176 { 180 {
177 hr = vhrLastError; // TODO: put verf info in trace message here 181 hr = vhrLastError; // TODO: put verf info in trace message here
@@ -227,7 +231,7 @@ static __callback INT_PTR FAR DIAMONDAPI RexOpen(__in_z char FAR *pszFile, int o
227 RexExitOnFailure(hr, "File table exceeded"); 231 RexExitOnFailure(hr, "File table exceeded");
228 } 232 }
229 233
230 if (0 == lstrcmpA(vszResource, pszFile)) 234 if (0 == lstrcmpA(vpszResource, pszFile))
231 { 235 {
232 vrgffFileTable[i].fUsed = TRUE; 236 vrgffFileTable[i].fUsed = TRUE;
233 vrgffFileTable[i].fftType = MEMORY_FILE; 237 vrgffFileTable[i].fftType = MEMORY_FILE;
@@ -436,15 +440,16 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati
436 HANDLE hFile = INVALID_HANDLE_VALUE; 440 HANDLE hFile = INVALID_HANDLE_VALUE;
437 441
438 REX_CALLBACK_STRUCT* prcs = static_cast<REX_CALLBACK_STRUCT*>(pFDINotify->pv); 442 REX_CALLBACK_STRUCT* prcs = static_cast<REX_CALLBACK_STRUCT*>(pFDINotify->pv);
439 LPCSTR sz; 443 LPCSTR sz = NULL;
440 WCHAR wz[MAX_PATH]; 444 LPWSTR pwz = NULL;
441 FILETIME ft; 445 LPWSTR pwzPath = NULL;
446 FILETIME ft = { };
442 int i = 0; 447 int i = 0;
443 448
444 switch (iNotification) 449 switch (iNotification)
445 { 450 {
446 case fdintCOPY_FILE: // beGIN extracting a resource from cabinet 451 case fdintCOPY_FILE: // beGIN extracting a resource from cabinet
447 Assert(pFDINotify->psz1); 452 Assert(pFDINotify->psz1 && prcs);
448 453
449 if (prcs->fStopExtracting) 454 if (prcs->fStopExtracting)
450 { 455 {
@@ -453,55 +458,50 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati
453 458
454 // convert params to useful variables 459 // convert params to useful variables
455 sz = static_cast<LPCSTR>(pFDINotify->psz1); 460 sz = static_cast<LPCSTR>(pFDINotify->psz1);
456 if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) 461 RexExitOnNull(sz, hr, E_INVALIDARG, "No cabinet file ID given to convert");
457 { 462
458 RexExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); 463 hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP);
459 } 464 RexExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz);
460 465
461 if (prcs->pfnProgress) 466 if (prcs->pfnProgress)
462 { 467 {
463 hr = prcs->pfnProgress(TRUE, wz, prcs->pvContext); 468 hr = prcs->pfnProgress(TRUE, pwz, prcs->pvContext);
464 if (S_OK != hr) 469 if (S_OK != hr)
465 { 470 {
466 ExitFunction(); 471 ExitFunction();
467 } 472 }
468 } 473 }
469 474
470 if (L'*' == *prcs->pwzExtract || 0 == lstrcmpW(prcs->pwzExtract, wz)) 475 if (L'*' == *prcs->pwzExtract || 0 == lstrcmpW(prcs->pwzExtract, pwz))
471 { 476 {
472 // get the created date for the resource in the cabinet 477 // get the created date for the resource in the cabinet
473 if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ft)) 478 if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ft))
474 { 479 {
475 RexExitWithLastError(hr, "failed to get time for resource: %ls", wz); 480 RexExitWithLastError(hr, "failed to get time for resource: %ls", pwz);
476 } 481 }
477 482
478 WCHAR wzPath[MAX_PATH];
479
480 hr = ::StringCchCopyW(wzPath, countof(wzPath), prcs->pwzExtractDir);
481 RexExitOnFailure(hr, "failed to copy extract directory: %ls for file: %ls", prcs->pwzExtractDir, wz);
482
483 if (L'*' == *prcs->pwzExtract) 483 if (L'*' == *prcs->pwzExtract)
484 { 484 {
485 hr = ::StringCchCatW(wzPath, countof(wzPath), wz); 485 hr = PathConcat(prcs->pwzExtractDir, pwz, &pwzPath);
486 RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz); 486 RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", prcs->pwzExtractDir, pwz);
487 } 487 }
488 else 488 else
489 { 489 {
490 Assert(*prcs->pwzExtractName); 490 Assert(*prcs->pwzExtractName);
491 491
492 hr = ::StringCchCatW(wzPath, countof(wzPath), prcs->pwzExtractName); 492 hr = PathConcat(prcs->pwzExtractDir, prcs->pwzExtractName, &pwzPath);
493 RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, prcs->pwzExtractName); 493 RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", prcs->pwzExtractDir, prcs->pwzExtractName);
494 } 494 }
495 495
496 // Quickly chop off the file name part of the path to ensure the path exists 496 // Quickly chop off the file name part of the path to ensure the path exists
497 // then put the file name back on the path (by putting the first character 497 // then put the file name back on the path (by putting the first character
498 // back over the null terminator). 498 // back over the null terminator).
499 LPWSTR wzFile = PathFile(wzPath); 499 LPWSTR wzFile = PathFile(pwzPath);
500 WCHAR wzFileFirstChar = *wzFile; 500 WCHAR wzFileFirstChar = *wzFile;
501 *wzFile = L'\0'; 501 *wzFile = L'\0';
502 502
503 hr = DirEnsureExists(wzPath, NULL); 503 hr = DirEnsureExists(pwzPath, NULL);
504 RexExitOnFailure(hr, "failed to ensure directory: %ls", wzPath); 504 RexExitOnFailure(hr, "failed to ensure directory: %ls", pwzPath);
505 505
506 hr = S_OK; 506 hr = S_OK;
507 507
@@ -524,10 +524,10 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati
524 } 524 }
525 525
526 // open the file 526 // open the file
527 hFile = ::CreateFileW(wzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 527 hFile = ::CreateFileW(pwzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
528 if (INVALID_HANDLE_VALUE == hFile) 528 if (INVALID_HANDLE_VALUE == hFile)
529 { 529 {
530 RexExitWithLastError(hr, "failed to open file: %ls", wzPath); 530 RexExitWithLastError(hr, "failed to open file: %ls", pwzPath);
531 } 531 }
532 532
533 vrgffFileTable[i].fUsed = TRUE; 533 vrgffFileTable[i].fUsed = TRUE;
@@ -554,20 +554,20 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati
554 554
555 break; 555 break;
556 case fdintCLOSE_FILE_INFO: // resource extraction complete 556 case fdintCLOSE_FILE_INFO: // resource extraction complete
557 Assert(pFDINotify->hf && pFDINotify->psz1); 557 Assert(pFDINotify->hf && prcs && pFDINotify->psz1);
558 558
559 // convert params to useful variables 559 // convert params to useful variables
560 sz = static_cast<LPCSTR>(pFDINotify->psz1); 560 sz = static_cast<LPCSTR>(pFDINotify->psz1);
561 if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) 561 RexExitOnNull(sz, hr, E_INVALIDARG, "No cabinet file ID given to convert");
562 { 562
563 RexExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); 563 hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP);
564 } 564 RexExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz);
565 565
566 RexClose(pFDINotify->hf); 566 RexClose(pFDINotify->hf);
567 567
568 if (prcs->pfnProgress) 568 if (prcs->pfnProgress)
569 { 569 {
570 hr = prcs->pfnProgress(FALSE, wz, prcs->pvContext); 570 hr = prcs->pfnProgress(FALSE, pwz, prcs->pvContext);
571 } 571 }
572 572
573 if (S_OK == hr && L'*' == *prcs->pwzExtract) // if everything is okay and we're extracting all files, keep going 573 if (S_OK == hr && L'*' == *prcs->pwzExtract) // if everything is okay and we're extracting all files, keep going
@@ -597,5 +597,8 @@ LExit:
597 vhrLastError = hr; 597 vhrLastError = hr;
598 } 598 }
599 599
600 ReleaseStr(pwz);
601 ReleaseStr(pwzPath);
602
600 return (S_OK == hr) ? ipResult : -1; 603 return (S_OK == hr) ? ipResult : -1;
601} 604}
diff --git a/src/libs/dutil/WixToolset.DUtil/sceutil.cpp b/src/libs/dutil/WixToolset.DUtil/sceutil.cpp
index 4eede74f..590c937a 100644
--- a/src/libs/dutil/WixToolset.DUtil/sceutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/sceutil.cpp
@@ -317,7 +317,7 @@ extern "C" HRESULT DAPI SceOpenDatabase(
317{ 317{
318 HRESULT hr = S_OK; 318 HRESULT hr = S_OK;
319 DWORD dwVersionFound = 0; 319 DWORD dwVersionFound = 0;
320 WCHAR wzTempDbFile[MAX_PATH]; 320 LPWSTR sczTempDbFile = NULL;
321 LPCWSTR wzPathToOpen = NULL; 321 LPCWSTR wzPathToOpen = NULL;
322 LPWSTR sczSchemaType = NULL; 322 LPWSTR sczSchemaType = NULL;
323 SCE_DATABASE *pNewSceDatabase = NULL; 323 SCE_DATABASE *pNewSceDatabase = NULL;
@@ -343,16 +343,16 @@ extern "C" HRESULT DAPI SceOpenDatabase(
343 // TODO: had trouble getting SQL CE to read a file read-only, so we're copying it to a temp path for now. 343 // TODO: had trouble getting SQL CE to read a file read-only, so we're copying it to a temp path for now.
344 if (fReadOnly) 344 if (fReadOnly)
345 { 345 {
346 hr = DirCreateTempPath(PathFile(sczFile), (LPWSTR)wzTempDbFile, _countof(wzTempDbFile)); 346 hr = DirCreateTempPath(PathFile(sczFile), &sczTempDbFile);
347 ExitOnFailure(hr, "Failed to get temp path"); 347 ExitOnFailure(hr, "Failed to get temp path");
348 348
349 hr = FileEnsureCopy(sczFile, (LPCWSTR)wzTempDbFile, TRUE); 349 hr = FileEnsureCopy(sczFile, sczTempDbFile, TRUE);
350 ExitOnFailure(hr, "Failed to copy file to temp path"); 350 ExitOnFailure(hr, "Failed to copy file to temp path");
351 351
352 hr = StrAllocString(&pNewSceDatabaseInternal->sczTempDbFile, (LPCWSTR)wzTempDbFile, 0); 352 hr = StrAllocString(&pNewSceDatabaseInternal->sczTempDbFile, sczTempDbFile, 0);
353 ExitOnFailure(hr, "Failed to copy temp db file path"); 353 ExitOnFailure(hr, "Failed to copy temp db file path");
354 354
355 wzPathToOpen = (LPCWSTR)wzTempDbFile; 355 wzPathToOpen = sczTempDbFile;
356 } 356 }
357 else 357 else
358 { 358 {
@@ -424,6 +424,7 @@ extern "C" HRESULT DAPI SceOpenDatabase(
424LExit: 424LExit:
425 ReleaseBSTR(rgdbpDataSourceProp[0].vValue.bstrVal); 425 ReleaseBSTR(rgdbpDataSourceProp[0].vValue.bstrVal);
426 ReleaseStr(sczSchemaType); 426 ReleaseStr(sczSchemaType);
427 ReleaseStr(sczTempDbFile);
427 ReleaseDatabase(pNewSceDatabase); 428 ReleaseDatabase(pNewSceDatabase);
428 429
429 return hr; 430 return hr;
diff --git a/src/libs/dutil/WixToolset.DUtil/shelutil.cpp b/src/libs/dutil/WixToolset.DUtil/shelutil.cpp
index 2eb9a52a..72a0e5ce 100644
--- a/src/libs/dutil/WixToolset.DUtil/shelutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/shelutil.cpp
@@ -9,6 +9,7 @@
9#define ShelExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) 9#define ShelExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__)
10#define ShelExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) 10#define ShelExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__)
11#define ShelExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) 11#define ShelExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__)
12#define ShelExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_SHELUTIL, x, e, s, __VA_ARGS__)
12#define ShelExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) 13#define ShelExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__)
13#define ShelExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SHELUTIL, p, x, e, s, __VA_ARGS__) 14#define ShelExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SHELUTIL, p, x, e, s, __VA_ARGS__)
14#define ShelExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, p, x, s, __VA_ARGS__) 15#define ShelExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, p, x, s, __VA_ARGS__)
@@ -19,6 +20,10 @@
19 20
20static PFN_SHELLEXECUTEEXW vpfnShellExecuteExW = ::ShellExecuteExW; 21static PFN_SHELLEXECUTEEXW vpfnShellExecuteExW = ::ShellExecuteExW;
21 22
23static HRESULT DAPI GetFolderFromCsidl(
24 __out_z LPWSTR* psczFolderPath,
25 __in int csidlFolder
26 );
22static HRESULT GetDesktopShellView( 27static HRESULT GetDesktopShellView(
23 __in REFIID riid, 28 __in REFIID riid,
24 __out void **ppv 29 __out void **ppv
@@ -57,7 +62,14 @@ extern "C" HRESULT DAPI ShelExec(
57 ) 62 )
58{ 63{
59 HRESULT hr = S_OK; 64 HRESULT hr = S_OK;
60 SHELLEXECUTEINFOW shExecInfo = {}; 65 SHELLEXECUTEINFOW shExecInfo = { };
66 size_t cchWorkingDirectory = 0;
67
68 // CreateProcessW has undocumented MAX_PATH restriction for lpCurrentDirectory even when long path support is enabled.
69 if (wzWorkingDirectory && FAILED(::StringCchLengthW(wzWorkingDirectory, MAX_PATH - 1, &cchWorkingDirectory)))
70 {
71 wzWorkingDirectory = NULL;
72 }
61 73
62 shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); 74 shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
63 shExecInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; 75 shExecInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
@@ -159,11 +171,7 @@ LExit:
159} 171}
160 172
161 173
162/******************************************************************** 174static HRESULT DAPI GetFolderFromCsidl(
163 ShelGetFolder() - gets a folder by CSIDL.
164
165*******************************************************************/
166extern "C" HRESULT DAPI ShelGetFolder(
167 __out_z LPWSTR* psczFolderPath, 175 __out_z LPWSTR* psczFolderPath,
168 __in int csidlFolder 176 __in int csidlFolder
169 ) 177 )
@@ -185,19 +193,6 @@ LExit:
185} 193}
186 194
187 195
188/********************************************************************
189 ShelGetKnownFolder() - gets a folder by KNOWNFOLDERID.
190
191 Note: return E_NOTIMPL if called on pre-Vista operating systems.
192*******************************************************************/
193#ifndef REFKNOWNFOLDERID
194#define REFKNOWNFOLDERID REFGUID
195#endif
196
197#ifndef KF_FLAG_CREATE
198#define KF_FLAG_CREATE 0x00008000 // Make sure that the folder already exists or create it and apply security specified in folder definition
199#endif
200
201EXTERN_C typedef HRESULT (STDAPICALLTYPE *PFN_SHGetKnownFolderPath)( 196EXTERN_C typedef HRESULT (STDAPICALLTYPE *PFN_SHGetKnownFolderPath)(
202 REFKNOWNFOLDERID rfid, 197 REFKNOWNFOLDERID rfid,
203 DWORD dwFlags, 198 DWORD dwFlags,
@@ -249,6 +244,181 @@ LExit:
249 return hr; 244 return hr;
250} 245}
251 246
247extern "C" HRESULT DAPI ShelGetFolder(
248 __out_z LPWSTR* psczFolderPath,
249 __in int csidlFolder
250 )
251{
252 HRESULT hr = S_OK;
253 LPWSTR sczPath = NULL;
254 KNOWNFOLDERID rfid = { };
255
256 csidlFolder &= ~CSIDL_FLAG_MASK;
257
258 switch (csidlFolder)
259 {
260 case CSIDL_ADMINTOOLS:
261 rfid = FOLDERID_AdminTools;
262 break;
263 case CSIDL_APPDATA:
264 rfid = FOLDERID_RoamingAppData;
265 break;
266 case CSIDL_CDBURN_AREA:
267 rfid = FOLDERID_CDBurning;
268 break;
269 case CSIDL_COMMON_ADMINTOOLS:
270 rfid = FOLDERID_CommonAdminTools;
271 break;
272 case CSIDL_COMMON_APPDATA:
273 rfid = FOLDERID_ProgramData;
274 break;
275 case CSIDL_COMMON_DESKTOPDIRECTORY:
276 rfid = FOLDERID_PublicDesktop;
277 break;
278 case CSIDL_COMMON_DOCUMENTS:
279 rfid = FOLDERID_PublicDocuments;
280 break;
281 case CSIDL_COMMON_MUSIC:
282 rfid = FOLDERID_PublicMusic;
283 break;
284 case CSIDL_COMMON_OEM_LINKS:
285 rfid = FOLDERID_CommonOEMLinks;
286 break;
287 case CSIDL_COMMON_PICTURES:
288 rfid = FOLDERID_PublicPictures;
289 break;
290 case CSIDL_COMMON_PROGRAMS:
291 rfid = FOLDERID_CommonPrograms;
292 break;
293 case CSIDL_COMMON_STARTMENU:
294 rfid = FOLDERID_CommonStartMenu;
295 break;
296 case CSIDL_COMMON_STARTUP: __fallthrough;
297 case CSIDL_COMMON_ALTSTARTUP:
298 rfid = FOLDERID_CommonStartup;
299 break;
300 case CSIDL_COMMON_TEMPLATES:
301 rfid = FOLDERID_CommonTemplates;
302 break;
303 case CSIDL_COMMON_VIDEO:
304 rfid = FOLDERID_PublicVideos;
305 break;
306 case CSIDL_COOKIES:
307 rfid = FOLDERID_Cookies;
308 break;
309 case CSIDL_DESKTOP:
310 case CSIDL_DESKTOPDIRECTORY:
311 rfid = FOLDERID_Desktop;
312 break;
313 case CSIDL_FAVORITES: __fallthrough;
314 case CSIDL_COMMON_FAVORITES:
315 rfid = FOLDERID_Favorites;
316 break;
317 case CSIDL_FONTS:
318 rfid = FOLDERID_Fonts;
319 break;
320 case CSIDL_HISTORY:
321 rfid = FOLDERID_History;
322 break;
323 case CSIDL_INTERNET_CACHE:
324 rfid = FOLDERID_InternetCache;
325 break;
326 case CSIDL_LOCAL_APPDATA:
327 rfid = FOLDERID_LocalAppData;
328 break;
329 case CSIDL_MYMUSIC:
330 rfid = FOLDERID_Music;
331 break;
332 case CSIDL_MYPICTURES:
333 rfid = FOLDERID_Pictures;
334 break;
335 case CSIDL_MYVIDEO:
336 rfid = FOLDERID_Videos;
337 break;
338 case CSIDL_NETHOOD:
339 rfid = FOLDERID_NetHood;
340 break;
341 case CSIDL_PERSONAL:
342 rfid = FOLDERID_Documents;
343 break;
344 case CSIDL_PRINTHOOD:
345 rfid = FOLDERID_PrintHood;
346 break;
347 case CSIDL_PROFILE:
348 rfid = FOLDERID_Profile;
349 break;
350 case CSIDL_PROGRAM_FILES:
351 rfid = FOLDERID_ProgramFiles;
352 break;
353 case CSIDL_PROGRAM_FILESX86:
354 rfid = FOLDERID_ProgramFilesX86;
355 break;
356 case CSIDL_PROGRAM_FILES_COMMON:
357 rfid = FOLDERID_ProgramFilesCommon;
358 break;
359 case CSIDL_PROGRAM_FILES_COMMONX86:
360 rfid = FOLDERID_ProgramFilesCommonX86;
361 break;
362 case CSIDL_PROGRAMS:
363 rfid = FOLDERID_Programs;
364 break;
365 case CSIDL_RECENT:
366 rfid = FOLDERID_Recent;
367 break;
368 case CSIDL_RESOURCES:
369 rfid = FOLDERID_ResourceDir;
370 break;
371 case CSIDL_RESOURCES_LOCALIZED:
372 rfid = FOLDERID_LocalizedResourcesDir;
373 break;
374 case CSIDL_SENDTO:
375 rfid = FOLDERID_SendTo;
376 break;
377 case CSIDL_STARTMENU:
378 rfid = FOLDERID_StartMenu;
379 break;
380 case CSIDL_STARTUP:
381 case CSIDL_ALTSTARTUP:
382 rfid = FOLDERID_Startup;
383 break;
384 case CSIDL_SYSTEM:
385 rfid = FOLDERID_System;
386 break;
387 case CSIDL_SYSTEMX86:
388 rfid = FOLDERID_SystemX86;
389 break;
390 case CSIDL_TEMPLATES:
391 rfid = FOLDERID_Templates;
392 break;
393 case CSIDL_WINDOWS:
394 rfid = FOLDERID_Windows;
395 break;
396 default:
397 ShelExitWithRootFailure(hr, E_INVALIDARG, "Unknown csidl: %d", csidlFolder);
398 }
399
400 hr = ShelGetKnownFolder(&sczPath, rfid);
401 if (E_NOTIMPL == hr)
402 {
403 hr = S_FALSE;
404 }
405 ShelExitOnFailure(hr, "Failed to get known folder.");
406
407 if (S_FALSE == hr)
408 {
409 hr = GetFolderFromCsidl(&sczPath, csidlFolder);
410 ShelExitOnFailure(hr, "Failed to get csidl folder.");
411 }
412
413 *psczFolderPath = sczPath;
414 sczPath = NULL;
415
416LExit:
417 ReleaseStr(sczPath);
418
419 return hr;
420}
421
252 422
253// Internal functions. 423// Internal functions.
254 424
@@ -287,7 +457,7 @@ static HRESULT GetDesktopShellView(
287 else if (S_FALSE == hr) 457 else if (S_FALSE == hr)
288 { 458 {
289 //Windows XP 459 //Windows XP
290 hr = SHGetDesktopFolder(&psf); 460 hr = ::SHGetDesktopFolder(&psf);
291 ShelExitOnFailure(hr, "Failed to get desktop folder."); 461 ShelExitOnFailure(hr, "Failed to get desktop folder.");
292 462
293 hr = psf->CreateViewObject(NULL, IID_IShellView, ppv); 463 hr = psf->CreateViewObject(NULL, IID_IShellView, ppv);
diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp
index e9ef1047..109c558c 100644
--- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp
+++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp
@@ -7,6 +7,11 @@ using namespace System::IO;
7using namespace Xunit; 7using namespace Xunit;
8using namespace WixBuildTools::TestSupport; 8using namespace WixBuildTools::TestSupport;
9 9
10// from PathCch.h
11#ifndef PATHCCH_ALLOW_LONG_PATHS
12#define PATHCCH_ALLOW_LONG_PATHS 0x01
13#endif
14
10namespace DutilTests 15namespace DutilTests
11{ 16{
12 public ref class PathUtil 17 public ref class PathUtil
@@ -102,18 +107,54 @@ namespace DutilTests
102 } 107 }
103 108
104 [Fact] 109 [Fact]
110 void PathCanonicalizeForComparisonFallbackTest()
111 {
112 Path2FunctionForceFallback();
113
114 try
115 {
116 PathCanonicalizeForComparisonTestCore(FALSE);
117 }
118 finally
119 {
120 Path2FunctionAllowFallback();
121 }
122 }
123
124 [Fact]
105 void PathCanonicalizeForComparisonTest() 125 void PathCanonicalizeForComparisonTest()
106 { 126 {
127 PathCanonicalizeForComparisonTestCore(TRUE);
128 }
129
130 void PathCanonicalizeForComparisonTestCore(BOOL fLongPathSupported)
131 {
107 HRESULT hr = S_OK; 132 HRESULT hr = S_OK;
108 LPWSTR sczCanonicalized = NULL; 133 LPWSTR sczCanonicalized = NULL;
109 134
110 try 135 try
111 { 136 {
112 hr = PathCanonicalizeForComparison(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); 137 hr = PathCanonicalizeForComparison(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized);
113 Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr); 138 if (!fLongPathSupported)
139 {
140 Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
141 }
142 else
143 {
144 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
145 NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized);
146 }
114 147
115 hr = PathCanonicalizeForComparison(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); 148 hr = PathCanonicalizeForComparison(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized);
116 Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr); 149 if (!fLongPathSupported)
150 {
151 Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
152 }
153 else
154 {
155 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
156 NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized);
157 }
117 158
118 hr = PathCanonicalizeForComparison(L"\\\\server", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); 159 hr = PathCanonicalizeForComparison(L"\\\\server", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized);
119 NativeAssert::Succeeded(hr, "Failed to canonicalize path"); 160 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
@@ -238,6 +279,52 @@ namespace DutilTests
238 } 279 }
239 280
240 [Fact] 281 [Fact]
282 void PathAllocCanonicalizePathTest()
283 {
284 HRESULT hr = S_OK;
285 LPWSTR sczCanonicalized = NULL;
286
287 try
288 {
289 hr = PathAllocCanonicalizePath(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
290 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
291 NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized);
292
293 hr = PathAllocCanonicalizePath(L"abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
294 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
295 NativeAssert::StringEqual(L"abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized);
296
297 hr = PathAllocCanonicalizePath(L"\\\\server\\share\\..\\..\\otherdir\\unc.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
298 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
299 NativeAssert::StringEqual(L"\\\\otherdir\\unc.exe", sczCanonicalized); // This is surprising.
300
301 hr = PathAllocCanonicalizePath(L"C:\\dir\\subdir\\..\\..\\otherdir\\backslashes.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
302 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
303 NativeAssert::StringEqual(L"C:\\otherdir\\backslashes.exe", sczCanonicalized);
304
305 hr = PathAllocCanonicalizePath(L"C:/dir/subdir/../../otherdir/forwardslashes.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
306 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
307 NativeAssert::StringEqual(L"C:/dir/subdir/../../otherdir/forwardslashes.exe", sczCanonicalized);
308
309 hr = PathAllocCanonicalizePath(L"\\\\?\\C:\\test\\..\\validlongpath.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
310 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
311 NativeAssert::StringEqual(L"C:\\validlongpath.exe", sczCanonicalized);
312
313 hr = PathAllocCanonicalizePath(L"\\\\?\\test\\..\\invalidlongpath.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
314 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
315 NativeAssert::StringEqual(L"\\\\?\\invalidlongpath.exe", sczCanonicalized);
316
317 hr = PathAllocCanonicalizePath(L"C:\\.\\invalid:pathchars?.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized);
318 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
319 NativeAssert::StringEqual(L"C:\\invalid:pathchars?.exe", sczCanonicalized);
320 }
321 finally
322 {
323 ReleaseStr(sczCanonicalized);
324 }
325 }
326
327 [Fact]
241 void PathConcatTest() 328 void PathConcatTest()
242 { 329 {
243 HRESULT hr = S_OK; 330 HRESULT hr = S_OK;
@@ -545,6 +632,25 @@ namespace DutilTests
545 } 632 }
546 633
547 [Fact] 634 [Fact]
635 void PathForCurrentProcessTest()
636 {
637 HRESULT hr = S_OK;
638 LPWSTR sczPath = NULL;
639
640 try
641 {
642 hr = PathForCurrentProcess(&sczPath, NULL);
643 NativeAssert::Succeeded(hr, "Failed to get current process path.");
644
645 WixAssert::StringEqual(System::Diagnostics::Process::GetCurrentProcess()->MainModule->FileName, gcnew String(sczPath), false);
646 }
647 finally
648 {
649 ReleaseStr(sczPath);
650 }
651 }
652
653 [Fact]
548 void PathGetDirectoryTest() 654 void PathGetDirectoryTest()
549 { 655 {
550 HRESULT hr = S_OK; 656 HRESULT hr = S_OK;
@@ -828,6 +934,78 @@ namespace DutilTests
828 } 934 }
829 935
830 [Fact] 936 [Fact]
937 void PathGetTempPathTest()
938 {
939 HRESULT hr = S_OK;
940 LPCWSTR wzEnvName = L"TMP";
941 LPCWSTR wzEnvName2 = L"TEMP";
942 LPCWSTR wzLongTempPath = L"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\\cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\\";
943 LPWSTR sczTempPath = NULL;
944 WCHAR wzOriginalTemp[MAX_PATH + 1] = { };
945 WCHAR wzOriginalTemp2[MAX_PATH + 1] = { };
946 DWORD cch = 0;
947 DWORD cch2 = 0;
948 SIZE_T cchTemp = 0;
949 size_t cchTemp2 = 0;
950
951 try
952 {
953 cch = ::GetEnvironmentVariableW(wzEnvName, wzOriginalTemp, countof(wzOriginalTemp));
954 Assert::NotEqual<DWORD>(0, cch);
955
956 if (!::SetEnvironmentVariableW(wzEnvName, wzLongTempPath))
957 {
958 Assert::Equal<DWORD>(0xFFFFFFFF, ::GetLastError());
959 }
960
961 cch2 = ::GetEnvironmentVariableW(wzEnvName2, wzOriginalTemp2, countof(wzOriginalTemp2));
962 Assert::NotEqual<DWORD>(0, cch2);
963
964 hr = PathGetTempPath(&sczTempPath, &cchTemp);
965 NativeAssert::Succeeded(hr, "Failed to get temp path.");
966
967 PathFixedBackslashTerminate(wzOriginalTemp2, countof(wzOriginalTemp2));
968
969 hr = ::StringCchLengthW(wzOriginalTemp2, countof(wzOriginalTemp2), &cchTemp2);
970 NativeAssert::Succeeded(hr, "Failed to get temp path length.");
971
972 NativeAssert::StringEqual(wzOriginalTemp2, sczTempPath);
973 Assert::Equal<SIZE_T>(cchTemp2, cchTemp);
974 }
975 finally
976 {
977 if (cch)
978 {
979 ::SetEnvironmentVariableW(wzEnvName, wzOriginalTemp);
980 }
981
982 ReleaseStr(sczTempPath);
983 }
984 }
985
986 [Fact]
987 void PathGetVolumePathNameTest()
988 {
989 HRESULT hr = S_OK;
990 LPWSTR sczVolumePathName = NULL;
991
992 try
993 {
994 hr = StrAlloc(&sczVolumePathName, 1);
995 NativeAssert::Succeeded(hr, "Failed to alloc volume path name.");
996
997 hr = PathGetVolumePathName(L"C:\\Windows", &sczVolumePathName);
998 NativeAssert::Succeeded(hr, "PathGetVolumePathName failed.");
999
1000 NativeAssert::StringEqual(L"C:\\", sczVolumePathName);
1001 }
1002 finally
1003 {
1004 ReleaseStr(sczVolumePathName);
1005 }
1006 }
1007
1008 [Fact]
831 void PathNormalizeSlashesFixedTest() 1009 void PathNormalizeSlashesFixedTest()
832 { 1010 {
833 HRESULT hr = S_OK; 1011 HRESULT hr = S_OK;