diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-06-24 12:28:27 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-06-27 11:14:21 -0500 |
| commit | eb53852d7ae6838e54525eb57df1d8ce8a722f9b (patch) | |
| tree | 7fa05bd6df1bce2e20d87c5fbacc1c658dc000aa /src/libs/dutil/WixToolset.DUtil/cabcutil.cpp | |
| parent | 6ee12a64cb75097a238e60d4fd0ea542e8312214 (diff) | |
| download | wix-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/dutil/WixToolset.DUtil/cabcutil.cpp')
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/cabcutil.cpp | 86 |
1 files changed, 35 insertions, 51 deletions
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 | ||
| 360 | LExit: | 334 | LExit: |
| 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 | ||
| 649 | LExit: | 625 | LExit: |
| @@ -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 | ||
| 1161 | LExit: | 1140 | LExit: |
| @@ -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 | { |
