aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-10 16:05:23 -0700
committerRob Mensching <rob@firegiant.com>2021-04-12 09:56:15 -0700
commit0c2b4cf3a439eda3e19d20fadfc65ddc7d0394c0 (patch)
tree825272bd86d365d8f2175fd6fadd9725c8b400ff
parented0ef472c76ac0d2a3d7a138e4f3b7ad950a56bc (diff)
downloadwix-0c2b4cf3a439eda3e19d20fadfc65ddc7d0394c0.tar.gz
wix-0c2b4cf3a439eda3e19d20fadfc65ddc7d0394c0.tar.bz2
wix-0c2b4cf3a439eda3e19d20fadfc65ddc7d0394c0.zip
Integrate fixes that make dutil a little more robust to failure
-rw-r--r--src/dutil/cabutil.cpp52
-rw-r--r--src/dutil/fileutil.cpp128
-rw-r--r--src/dutil/inc/fileutil.h9
-rw-r--r--src/dutil/inc/regutil.h13
-rw-r--r--src/dutil/regutil.cpp59
-rw-r--r--src/dutil/wiutil.cpp18
6 files changed, 265 insertions, 14 deletions
diff --git a/src/dutil/cabutil.cpp b/src/dutil/cabutil.cpp
index 4a6f7b7b..5d77e483 100644
--- a/src/dutil/cabutil.cpp
+++ b/src/dutil/cabutil.cpp
@@ -102,6 +102,29 @@ LExit:
102} 102}
103 103
104 104
105static HANDLE OpenFileWithRetry(
106 __in LPCWSTR wzPath,
107 __in DWORD dwDesiredAccess,
108 __in DWORD dwCreationDisposition
109)
110{
111 HANDLE hFile = INVALID_HANDLE_VALUE;
112
113 for (DWORD i = 0; i < 30; ++i)
114 {
115 hFile = ::CreateFileW(wzPath, dwDesiredAccess, FILE_SHARE_READ, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
116 if (INVALID_HANDLE_VALUE != hFile)
117 {
118 break;
119 }
120
121 ::Sleep(100);
122 }
123
124 return hFile;
125}
126
127
105/******************************************************************** 128/********************************************************************
106 CabInitialize - initializes internal static variables 129 CabInitialize - initializes internal static variables
107 130
@@ -340,6 +363,7 @@ static __callback void DIAMONDAPI CabExtractFree(__in LPVOID pvData)
340static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __in int oflag, __in int pmode) 363static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __in int oflag, __in int pmode)
341{ 364{
342 HRESULT hr = S_OK; 365 HRESULT hr = S_OK;
366 HANDLE hFile = INVALID_HANDLE_VALUE;
343 INT_PTR pFile = -1; 367 INT_PTR pFile = -1;
344 LPWSTR sczCabFile = NULL; 368 LPWSTR sczCabFile = NULL;
345 369
@@ -353,19 +377,24 @@ static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __i
353 hr = StrAllocStringAnsi(&sczCabFile, pszFile, 0, CP_UTF8); 377 hr = StrAllocStringAnsi(&sczCabFile, pszFile, 0, CP_UTF8);
354 CabExitOnFailure(hr, "Failed to convert UTF8 cab file name to wide character string"); 378 CabExitOnFailure(hr, "Failed to convert UTF8 cab file name to wide character string");
355 379
356 pFile = reinterpret_cast<INT_PTR>(::CreateFileW(sczCabFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); 380 hFile = OpenFileWithRetry(sczCabFile, GENERIC_READ, OPEN_EXISTING);
357 if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile)) 381 if (INVALID_HANDLE_VALUE == hFile)
358 { 382 {
359 CabExitWithLastError(hr, "failed to open file: %ls", sczCabFile); 383 CabExitWithLastError(hr, "failed to open file: %ls", sczCabFile);
360 } 384 }
361 385
386 pFile = reinterpret_cast<INT_PTR>(hFile);
387
362 if (vdw64EmbeddedOffset) 388 if (vdw64EmbeddedOffset)
363 { 389 {
364 hr = CabExtractSeek(pFile, 0, 0); 390 hr = CabExtractSeek(pFile, 0, 0);
365 CabExitOnFailure(hr, "Failed to seek to embedded offset %I64d", vdw64EmbeddedOffset); 391 CabExitOnFailure(hr, "Failed to seek to embedded offset %I64d", vdw64EmbeddedOffset);
366 } 392 }
367 393
394 hFile = INVALID_HANDLE_VALUE;
395
368LExit: 396LExit:
397 ReleaseFileHandle(hFile);
369 ReleaseStr(sczCabFile); 398 ReleaseStr(sczCabFile);
370 399
371 return FAILED(hr) ? -1 : pFile; 400 return FAILED(hr) ? -1 : pFile;
@@ -460,6 +489,7 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
460 Assert(pFDINotify->pv); 489 Assert(pFDINotify->pv);
461 490
462 HRESULT hr = S_OK; 491 HRESULT hr = S_OK;
492 HANDLE hFile = INVALID_HANDLE_VALUE;
463 INT_PTR ipResult = 0; // result to return on success 493 INT_PTR ipResult = 0; // result to return on success
464 494
465 CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv); 495 CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv);
@@ -503,7 +533,6 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
503 CabExitWithLastError(hr, "failed to get time for resource: %ls", wz); 533 CabExitWithLastError(hr, "failed to get time for resource: %ls", wz);
504 } 534 }
505 ::LocalFileTimeToFileTime(&ftLocal, &ft); 535 ::LocalFileTimeToFileTime(&ftLocal, &ft);
506
507 536
508 WCHAR wzPath[MAX_PATH]; 537 WCHAR wzPath[MAX_PATH];
509 hr = ::StringCchCopyW(wzPath, countof(wzPath), pccs->pwzExtractDir); 538 hr = ::StringCchCopyW(wzPath, countof(wzPath), pccs->pwzExtractDir);
@@ -511,21 +540,24 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
511 hr = ::StringCchCatW(wzPath, countof(wzPath), wz); 540 hr = ::StringCchCatW(wzPath, countof(wzPath), wz);
512 CabExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz); 541 CabExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz);
513 542
514 ipResult = reinterpret_cast<INT_PTR>(::CreateFileW(wzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); 543 hFile = OpenFileWithRetry(wzPath, GENERIC_WRITE, CREATE_ALWAYS);
515 if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(ipResult)) 544 if (INVALID_HANDLE_VALUE == hFile)
516 { 545 {
517 CabExitWithLastError(hr, "failed to create file: %ls", wzPath); 546 CabExitWithLastError(hr, "failed to create file: %ls", wzPath);
518 } 547 }
519 548
520 ::SetFileTime(reinterpret_cast<HANDLE>(ipResult), &ft, &ft, &ft); // try to set the file time (who cares if it fails) 549 ::SetFileTime(hFile, &ft, &ft, &ft); // try to set the file time (who cares if it fails)
521 550
522 if (::SetFilePointer(reinterpret_cast<HANDLE>(ipResult), pFDINotify->cb, NULL, FILE_BEGIN)) // try to set the end of the file (don't worry if this fails) 551 if (::SetFilePointer(hFile, pFDINotify->cb, NULL, FILE_BEGIN)) // try to set the end of the file (don't worry if this fails)
523 { 552 {
524 if (::SetEndOfFile(reinterpret_cast<HANDLE>(ipResult))) 553 if (::SetEndOfFile(hFile))
525 { 554 {
526 ::SetFilePointer(reinterpret_cast<HANDLE>(ipResult), 0, NULL, FILE_BEGIN); // reset the file pointer 555 ::SetFilePointer(hFile, 0, NULL, FILE_BEGIN); // reset the file pointer
527 } 556 }
528 } 557 }
558
559 ipResult = reinterpret_cast<INT_PTR>(hFile);
560 hFile = INVALID_HANDLE_VALUE;
529 } 561 }
530 else // resource wasn't requested, skip it 562 else // resource wasn't requested, skip it
531 { 563 {
@@ -579,5 +611,7 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE
579 }; 611 };
580 612
581LExit: 613LExit:
614 ReleaseFileHandle(hFile);
615
582 return (S_OK == hr) ? ipResult : -1; 616 return (S_OK == hr) ? ipResult : -1;
583} 617}
diff --git a/src/dutil/fileutil.cpp b/src/dutil/fileutil.cpp
index c76017de..06a44b45 100644
--- a/src/dutil/fileutil.cpp
+++ b/src/dutil/fileutil.cpp
@@ -1106,6 +1106,134 @@ LExit:
1106 1106
1107 1107
1108/******************************************************************* 1108/*******************************************************************
1109 FileCopyUsingHandlesWithProgress
1110
1111*******************************************************************/
1112extern "C" HRESULT DAPI FileCopyUsingHandlesWithProgress(
1113 __in HANDLE hSource,
1114 __in HANDLE hTarget,
1115 __in DWORD64 cbCopy,
1116 __in_opt LPPROGRESS_ROUTINE lpProgressRoutine,
1117 __in_opt LPVOID lpData,
1118 __in_opt LPBOOL pbCancel,
1119 __out_opt DWORD64* pcbCopied
1120)
1121{
1122 HRESULT hr = S_OK;
1123 BOOL fStop = FALSE;
1124 BOOL fCanceled = FALSE;
1125 DWORD64 cbTotalCopied = 0;
1126 BYTE rgbData[64 * 1024];
1127 DWORD cbRead = 0;
1128
1129 LARGE_INTEGER liSourceSize = { };
1130 LARGE_INTEGER liTotalCopied = { };
1131 LARGE_INTEGER liZero = { };
1132 DWORD dwResult = 0;
1133
1134 hr = FileSizeByHandle(hSource, &liSourceSize.QuadPart);
1135 FileExitOnFailure(hr, "Failed to get size of source.");
1136
1137 if (0 < cbCopy && cbCopy < (DWORD64)liSourceSize.QuadPart)
1138 {
1139 liSourceSize.QuadPart = cbCopy;
1140 }
1141
1142 dwResult = lpProgressRoutine(liSourceSize, liTotalCopied, liZero, liZero, 0, CALLBACK_STREAM_SWITCH, hSource, hTarget, lpData);
1143 switch (dwResult)
1144 {
1145 case PROGRESS_CONTINUE:
1146 break;
1147
1148 case PROGRESS_CANCEL:
1149 fCanceled = TRUE;
1150 fStop = TRUE;
1151 break;
1152
1153 case PROGRESS_STOP:
1154 fStop = TRUE;
1155 break;
1156
1157 case PROGRESS_QUIET:
1158 lpProgressRoutine = NULL;
1159 break;
1160 }
1161
1162 // Set size of the target file.
1163 ::SetFilePointerEx(hTarget, liSourceSize, NULL, FILE_BEGIN);
1164
1165 if (!::SetEndOfFile(hTarget))
1166 {
1167 FileExitWithLastError(hr, "Failed to set end of target file.");
1168 }
1169
1170 if (!::SetFilePointerEx(hTarget, liZero, NULL, FILE_BEGIN))
1171 {
1172 FileExitWithLastError(hr, "Failed to reset target file pointer.");
1173 }
1174
1175 // Copy with progress.
1176 while (!fStop && (0 == cbCopy || cbTotalCopied < cbCopy))
1177 {
1178 cbRead = static_cast<DWORD>((0 == cbCopy) ? countof(rgbData) : min(countof(rgbData), cbCopy - cbTotalCopied));
1179 if (!::ReadFile(hSource, rgbData, cbRead, &cbRead, NULL))
1180 {
1181 FileExitWithLastError(hr, "Failed to read from source.");
1182 }
1183
1184 if (cbRead)
1185 {
1186 hr = FileWriteHandle(hTarget, rgbData, cbRead);
1187 FileExitOnFailure(hr, "Failed to write to target.");
1188
1189 cbTotalCopied += cbRead;
1190
1191 if (lpProgressRoutine)
1192 {
1193 liTotalCopied.QuadPart = cbTotalCopied;
1194 dwResult = lpProgressRoutine(liSourceSize, liTotalCopied, liZero, liZero, 0, CALLBACK_CHUNK_FINISHED, hSource, hTarget, lpData);
1195 switch (dwResult)
1196 {
1197 case PROGRESS_CONTINUE:
1198 break;
1199
1200 case PROGRESS_CANCEL:
1201 fCanceled = TRUE;
1202 fStop = TRUE;
1203 break;
1204
1205 case PROGRESS_STOP:
1206 fStop = TRUE;
1207 break;
1208
1209 case PROGRESS_QUIET:
1210 lpProgressRoutine = NULL;
1211 break;
1212 }
1213 }
1214 }
1215 else
1216 {
1217 fStop = TRUE;
1218 }
1219 }
1220
1221LExit:
1222 if (pbCancel)
1223 {
1224 *pbCancel = fCanceled;
1225 }
1226
1227 if (pcbCopied)
1228 {
1229 *pcbCopied = cbTotalCopied;
1230 }
1231
1232 return hr;
1233}
1234
1235
1236/*******************************************************************
1109 FileEnsureCopy 1237 FileEnsureCopy
1110 1238
1111*******************************************************************/ 1239*******************************************************************/
diff --git a/src/dutil/inc/fileutil.h b/src/dutil/inc/fileutil.h
index 7caa62b8..48830043 100644
--- a/src/dutil/inc/fileutil.h
+++ b/src/dutil/inc/fileutil.h
@@ -148,6 +148,15 @@ HRESULT DAPI FileCopyUsingHandles(
148 __in DWORD64 cbCopy, 148 __in DWORD64 cbCopy,
149 __out_opt DWORD64* pcbCopied 149 __out_opt DWORD64* pcbCopied
150 ); 150 );
151HRESULT DAPI FileCopyUsingHandlesWithProgress(
152 __in HANDLE hSource,
153 __in HANDLE hTarget,
154 __in DWORD64 cbCopy,
155 __in_opt LPPROGRESS_ROUTINE lpProgressRoutine,
156 __in_opt LPVOID lpData,
157 __in_opt LPBOOL pbCancel,
158 __out_opt DWORD64* pcbCopied
159 );
151HRESULT DAPI FileEnsureCopy( 160HRESULT DAPI FileEnsureCopy(
152 __in_z LPCWSTR wzSource, 161 __in_z LPCWSTR wzSource,
153 __in_z LPCWSTR wzTarget, 162 __in_z LPCWSTR wzTarget,
diff --git a/src/dutil/inc/regutil.h b/src/dutil/inc/regutil.h
index 2f09d244..75284940 100644
--- a/src/dutil/inc/regutil.h
+++ b/src/dutil/inc/regutil.h
@@ -226,6 +226,19 @@ HRESULT DAPI RegQueryKey(
226 __out_opt DWORD* pcSubKeys, 226 __out_opt DWORD* pcSubKeys,
227 __out_opt DWORD* pcValues 227 __out_opt DWORD* pcValues
228 ); 228 );
229HRESULT DAPI RegKeyReadNumber(
230 __in HKEY hk,
231 __in_z LPCWSTR wzSubKey,
232 __in_z_opt LPCWSTR wzName,
233 __in BOOL f64Bit,
234 __out DWORD* pdwValue
235 );
236BOOL DAPI RegValueExists(
237 __in HKEY hk,
238 __in_z LPCWSTR wzSubKey,
239 __in_z_opt LPCWSTR wzName,
240 __in BOOL f64Bit
241 );
229 242
230#ifdef __cplusplus 243#ifdef __cplusplus
231} 244}
diff --git a/src/dutil/regutil.cpp b/src/dutil/regutil.cpp
index e1ef19e8..afd2d089 100644
--- a/src/dutil/regutil.cpp
+++ b/src/dutil/regutil.cpp
@@ -283,7 +283,7 @@ LExit:
283 283
284 284
285/******************************************************************** 285/********************************************************************
286 RegKeyEnum - enumerates a registry key. 286 RegKeyEnum - enumerates child registry keys.
287 287
288*********************************************************************/ 288*********************************************************************/
289extern "C" HRESULT DAPI RegKeyEnum( 289extern "C" HRESULT DAPI RegKeyEnum(
@@ -340,7 +340,7 @@ LExit:
340 340
341 341
342/******************************************************************** 342/********************************************************************
343 RegValueEnum - enumerates a registry value. 343 RegValueEnum - enumerates registry values.
344 344
345*********************************************************************/ 345*********************************************************************/
346HRESULT DAPI RegValueEnum( 346HRESULT DAPI RegValueEnum(
@@ -939,6 +939,61 @@ LExit:
939 return hr; 939 return hr;
940} 940}
941 941
942/********************************************************************
943RegKeyReadNumber - reads a DWORD registry key value as a number from
944a specified subkey.
945
946*********************************************************************/
947extern "C" HRESULT DAPI RegKeyReadNumber(
948 __in HKEY hk,
949 __in_z LPCWSTR wzSubKey,
950 __in_z_opt LPCWSTR wzName,
951 __in BOOL f64Bit,
952 __out DWORD* pdwValue
953 )
954{
955 HRESULT hr = S_OK;
956 HKEY hkKey = NULL;
957
958 hr = RegOpen(hk, wzSubKey, KEY_READ | f64Bit ? KEY_WOW64_64KEY : 0, &hkKey);
959 RegExitOnFailure(hr, "Failed to open key: %ls", wzSubKey);
960
961 hr = RegReadNumber(hkKey, wzName, pdwValue);
962 RegExitOnFailure(hr, "Failed to read value: %ls/@%ls", wzSubKey, wzName);
963
964LExit:
965 ReleaseRegKey(hkKey);
966
967 return hr;
968}
969
970/********************************************************************
971RegValueExists - determines whether a named value exists in a
972specified subkey.
973
974*********************************************************************/
975extern "C" BOOL DAPI RegValueExists(
976 __in HKEY hk,
977 __in_z LPCWSTR wzSubKey,
978 __in_z_opt LPCWSTR wzName,
979 __in BOOL f64Bit
980 )
981{
982 HRESULT hr = S_OK;
983 HKEY hkKey = NULL;
984 DWORD dwType = 0;
985
986 hr = RegOpen(hk, wzSubKey, KEY_READ | f64Bit ? KEY_WOW64_64KEY : 0, &hkKey);
987 RegExitOnFailure(hr, "Failed to open key: %ls", wzSubKey);
988
989 hr = RegGetType(hkKey, wzName, &dwType);
990 RegExitOnFailure(hr, "Failed to read value type: %ls/@%ls", wzSubKey, wzName);
991
992LExit:
993 ReleaseRegKey(hkKey);
994
995 return SUCCEEDED(hr);
996}
942 997
943static HRESULT WriteStringToRegistry( 998static HRESULT WriteStringToRegistry(
944 __in HKEY hk, 999 __in HKEY hk,
diff --git a/src/dutil/wiutil.cpp b/src/dutil/wiutil.cpp
index ffbfe85a..f1984266 100644
--- a/src/dutil/wiutil.cpp
+++ b/src/dutil/wiutil.cpp
@@ -4,6 +4,7 @@
4 4
5 5
6// Exit macros 6// Exit macros
7#define WiuExitTrace(x, s, ...) ExitTraceSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__)
7#define WiuExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__) 8#define WiuExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__)
8#define WiuExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__) 9#define WiuExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__)
9#define WiuExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__) 10#define WiuExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_WIUTIL, x, s, __VA_ARGS__)
@@ -692,12 +693,23 @@ extern "C" HRESULT DAPI WiuEnumRelatedProductCodes(
692 693
693 if (fReturnHighestVersionOnly) 694 if (fReturnHighestVersionOnly)
694 { 695 {
695 // get the version 696 // try to get the version but if the product registration is broken
697 // (for whatever reason), skip this product
696 hr = WiuGetProductInfo(wzCurrentProductCode, L"VersionString", &sczInstalledVersion); 698 hr = WiuGetProductInfo(wzCurrentProductCode, L"VersionString", &sczInstalledVersion);
697 WiuExitOnFailure(hr, "Failed to get version for product code: %ls", wzCurrentProductCode); 699 if (FAILED(hr))
700 {
701 WiuExitTrace(hr, "Could not get product version for product code: %ls, skipping...", wzCurrentProductCode);
702 continue;
703 }
698 704
705 // try to parse the product version but if it is corrupt (for whatever
706 // reason), skip it
699 hr = FileVersionFromStringEx(sczInstalledVersion, 0, &qwCurrentVersion); 707 hr = FileVersionFromStringEx(sczInstalledVersion, 0, &qwCurrentVersion);
700 WiuExitOnFailure(hr, "Failed to convert version: %ls to DWORD64 for product code: %ls", sczInstalledVersion, wzCurrentProductCode); 708 if (FAILED(hr))
709 {
710 WiuExitTrace(hr, "Could not convert version: %ls to DWORD64 for product code: %ls, skipping...", sczInstalledVersion, wzCurrentProductCode);
711 continue;
712 }
701 713
702 // if this is the first product found then it is the highest version (for now) 714 // if this is the first product found then it is the highest version (for now)
703 if (0 == *pcRelatedProducts) 715 if (0 == *pcRelatedProducts)