@joebigelow / wix-1 / commits / b652e93a

Replace PathCompare with PathCompareCanonicalized.

Sean Hall committed Jun 3, 2022 at 17:47 UTC b652e93a460b4b822a01382e5992f96f1d805ffe
10 files changed +301 -203
src/burn/engine/apply.cpp
+6 -6
@@ -1350,7 +1350,7 @@ static HRESULT LayoutBundle(
1350 LPWSTR sczBundlePath = NULL;
1351 LPWSTR sczBundleDownloadUrl = NULL;
1352 LPWSTR sczDestinationPath = NULL;
1353 - int nEquivalentPaths = 0;
1353 + BOOL fPathEqual = FALSE;
1354 BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1355 BURN_CACHE_PROGRESS_CONTEXT progress = { };
1356 BOOL fRetry = FALSE;
@@ -1375,10 +1375,10 @@ static HRESULT LayoutBundle(
1375 ExitOnFailure(hr, "Failed to concat layout path for bundle.");
1376
1377 // If the destination path is the currently running bundle, bail.
1378 - hr = PathCompare(sczBundlePath, sczDestinationPath, &nEquivalentPaths);
1378 + hr = PathCompareCanonicalized(sczBundlePath, sczDestinationPath, &fPathEqual);
1379 ExitOnFailure(hr, "Failed to determine if layout bundle path was equivalent with current process path.");
1380
1381 - if (CSTR_EQUAL == nEquivalentPaths && FileExistsEx(sczDestinationPath, NULL))
1381 + if (fPathEqual && FileExistsEx(sczDestinationPath, NULL))
1382 {
1383 hr = UserExperienceOnCacheContainerOrPayloadVerifyBegin(pContext->pUX, NULL, NULL);
1384 if (FAILED(hr))
@@ -1533,7 +1533,7 @@ static HRESULT AcquireContainerOrPayload(
1533 AssertSz(pContainer || pPayload, "Must provide a container or a payload.");
1534
1535 HRESULT hr = S_OK;
1536 - int nEquivalentPaths = 0;
1536 + BOOL fPathEqual = FALSE;
1537 LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : NULL;
1538 LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : NULL;
1539 LPCWSTR wzPayloadContainerId = pPayload && pPayload->pContainer ? pPayload->pContainer->sczId : NULL;
@@ -1673,10 +1673,10 @@ static HRESULT AcquireContainerOrPayload(
1673 {
1674 case BOOTSTRAPPER_CACHE_OPERATION_COPY:
1675 // If the source path and destination path are different, do the copy (otherwise there's no point).
1676 - hr = PathCompare(pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath, &nEquivalentPaths);
1676 + hr = PathCompareCanonicalized(pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath, &fPathEqual);
1677 ExitOnFailure(hr, "Failed to determine if payload paths were equivalent, source: %ls, destination: %ls.", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1678
1679 - if (CSTR_EQUAL != nEquivalentPaths)
1679 + if (!fPathEqual)
1680 {
1681 hr = CopyPayload(pProgress, INVALID_HANDLE_VALUE, pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1682 ExitOnFailure(hr, "Failed to copy payload: %ls", wzPayloadId);
src/burn/engine/cache.cpp
+9 -9
@@ -170,7 +170,7 @@ extern "C" HRESULT CacheInitialize(
170
171 HRESULT hr = S_OK;
172 LPWSTR sczAppData = NULL;
173 - int nCompare = 0;
173 + BOOL fPathEqual = FALSE;
174
175 // Cache paths are initialized once so they cannot be changed while the engine is caching payloads.
176 // Always construct the default machine package cache path so we can determine if we're redirected.
@@ -199,10 +199,10 @@ extern "C" HRESULT CacheInitialize(
199 ExitOnFailure(hr, "Failed to copy default package cache directory to current package cache directory.");
200 }
201
202 - hr = PathCompare(pCache->sczDefaultMachinePackageCache, pCache->sczCurrentMachinePackageCache, &nCompare);
202 + hr = PathCompareCanonicalized(pCache->sczDefaultMachinePackageCache, pCache->sczCurrentMachinePackageCache, &fPathEqual);
203 ExitOnFailure(hr, "Failed to compare default and current package cache directories.");
204
205 - pCache->fCustomMachinePackageCache = CSTR_EQUAL != nCompare;
205 + pCache->fCustomMachinePackageCache = !fPathEqual;
206
207
208 hr = PathGetKnownFolder(CSIDL_LOCAL_APPDATA, &sczAppData);
@@ -241,7 +241,7 @@ extern "C" HRESULT CacheInitializeSources(
241 LPWSTR sczCompletedPath = NULL;
242 LPWSTR sczOriginalSource = NULL;
243 LPWSTR sczOriginalSourceFolder = NULL;
244 - int nCompare = 0;
244 + BOOL fPathEqual = FALSE;
245 LPCWSTR wzSourceProcessPath = pInternalCommand->sczSourceProcessPath;
246
247 hr = PathForCurrentProcess(&sczCurrentPath, NULL);
@@ -254,10 +254,10 @@ extern "C" HRESULT CacheInitializeSources(
254 hr = PathConcatRelativeToBase(sczCompletedFolder, pRegistration->sczExecutableName, &sczCompletedPath);
255 ExitOnFailure(hr, "Failed to combine working path with engine file name.");
256
257 - hr = PathCompare(sczCurrentPath, sczCompletedPath, &nCompare);
257 + hr = PathCompareCanonicalized(sczCurrentPath, sczCompletedPath, &fPathEqual);
258 ExitOnFailure(hr, "Failed to compare current path for bundle: %ls", sczCurrentPath);
259
260 - pCache->fRunningFromCache = (CSTR_EQUAL == nCompare);
260 + pCache->fRunningFromCache = fPathEqual;
261
262 // If a source process path was not provided (e.g. we are not being
263 // run in a clean room) then use the current process path as the
@@ -959,7 +959,7 @@ extern "C" HRESULT CacheCompleteBundle(
959 )
960 {
961 HRESULT hr = S_OK;
962 - int nCompare = 0;
962 + BOOL fPathEqual = FALSE;
963 LPWSTR sczTargetDirectory = NULL;
964 LPWSTR sczTargetPath = NULL;
965 LPWSTR sczSourceDirectory = NULL;
@@ -976,10 +976,10 @@ extern "C" HRESULT CacheCompleteBundle(
976
977 // If the bundle is running out of the package cache then we don't need to copy it there
978 // (and don't want to since it'll be in use) so bail.
979 - hr = PathCompare(wzSourceBundlePath, sczTargetPath, &nCompare);
979 + hr = PathCompareCanonicalized(wzSourceBundlePath, sczTargetPath, &fPathEqual);
980 ExitOnFailure(hr, "Failed to compare completed cache path for bundle: %ls", wzSourceBundlePath);
981
982 - if (CSTR_EQUAL == nCompare)
982 + if (fPathEqual)
983 {
984 ExitFunction();
985 }
src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+1
@@ -66,6 +66,7 @@
66 <DisableSpecificWarnings>4091;4458</DisableSpecificWarnings>
67 </ClCompile>
68 <ClCompile Include="eseutil.cpp" />
69 + <ClCompile Include="file2utl.cpp" />
70 <ClCompile Include="fileutil.cpp" />
71 <ClCompile Include="gdiputil.cpp" />
72 <ClCompile Include="guidutil.cpp" />
src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+3
@@ -69,6 +69,9 @@
69 <ClCompile Include="eseutil.cpp">
70 <Filter>Source Files</Filter>
71 </ClCompile>
72 + <ClCompile Include="file2utl.cpp">
73 + <Filter>Source Files</Filter>
74 + </ClCompile>
75 <ClCompile Include="fileutil.cpp">
76 <Filter>Source Files</Filter>
77 </ClCompile>
src/libs/dutil/WixToolset.DUtil/file2utl.cpp new
+164
@@ -0,0 +1,164 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +#include "precomp.h"
4 +
5 +
6 +// Exit macros
7 +#define FileExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
8 +#define FileExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
9 +#define FileExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
10 +#define FileExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
11 +#define FileExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
12 +#define FileExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
13 +#define FileExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_FILEUTIL, p, x, e, s, __VA_ARGS__)
14 +#define FileExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_FILEUTIL, p, x, s, __VA_ARGS__)
15 +#define FileExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_FILEUTIL, p, x, e, s, __VA_ARGS__)
16 +#define FileExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_FILEUTIL, p, x, s, __VA_ARGS__)
17 +#define FileExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_FILEUTIL, e, x, s, __VA_ARGS__)
18 +#define FileExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_FILEUTIL, g, x, s, __VA_ARGS__)
19 +
20 +// constants
21 +
22 +const LPCWSTR REGISTRY_PENDING_FILE_RENAME_KEY = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager";
23 +const LPCWSTR REGISTRY_PENDING_FILE_RENAME_VALUE = L"PendingFileRenameOperations";
24 +
25 +
26 +/*******************************************************************
27 + FileExistsAfterRestart - checks that a file exists and will continue
28 + to exist after restart.
29 +
30 +********************************************************************/
31 +extern "C" BOOL DAPI FileExistsAfterRestart(
32 + __in_z LPCWSTR wzPath,
33 + __out_opt DWORD *pdwAttributes
34 + )
35 +{
36 + HRESULT hr = S_OK;
37 + BOOL fExists = FALSE;
38 + HKEY hkPendingFileRename = NULL;
39 + LPWSTR* rgsczRenames = NULL;
40 + DWORD cRenames = 0;
41 + BOOL fPathEqual = FALSE;
42 +
43 + fExists = FileExistsEx(wzPath, pdwAttributes);
44 + if (fExists)
45 + {
46 + hr = RegOpen(HKEY_LOCAL_MACHINE, REGISTRY_PENDING_FILE_RENAME_KEY, KEY_QUERY_VALUE, &hkPendingFileRename);
47 + if (E_FILENOTFOUND == hr)
48 + {
49 + ExitFunction1(hr = S_OK);
50 + }
51 + FileExitOnFailure(hr, "Failed to open pending file rename registry key.");
52 +
53 + hr = RegReadStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, &rgsczRenames, &cRenames);
54 + if (E_FILENOTFOUND == hr)
55 + {
56 + ExitFunction1(hr = S_OK);
57 + }
58 + FileExitOnFailure(hr, "Failed to read pending file renames.");
59 +
60 + // The pending file renames array is pairs of source and target paths. We only care
61 + // about checking the source paths so skip the target paths (i += 2).
62 + for (DWORD i = 0; i < cRenames; i += 2)
63 + {
64 + LPWSTR wzRename = rgsczRenames[i];
65 + if (wzRename && *wzRename)
66 + {
67 + hr = PathCompareCanonicalized(wzPath, wzRename, &fPathEqual);
68 + FileExitOnFailure(hr, "Failed to compare path from pending file rename to check path.");
69 +
70 + if (fPathEqual)
71 + {
72 + fExists = FALSE;
73 + break;
74 + }
75 + }
76 + }
77 + }
78 +
79 +LExit:
80 + ReleaseStrArray(rgsczRenames, cRenames);
81 + ReleaseRegKey(hkPendingFileRename);
82 +
83 + return fExists;
84 +}
85 +
86 +
87 +/*******************************************************************
88 + FileRemoveFromPendingRename - removes the file path from the pending
89 + file rename list.
90 +
91 +********************************************************************/
92 +extern "C" HRESULT DAPI FileRemoveFromPendingRename(
93 + __in_z LPCWSTR wzPath
94 + )
95 +{
96 + HRESULT hr = S_OK;
97 + HKEY hkPendingFileRename = NULL;
98 + LPWSTR* rgsczRenames = NULL;
99 + DWORD cRenames = 0;
100 + BOOL fPathEqual = FALSE;
101 + BOOL fRemoved = FALSE;
102 + DWORD cNewRenames = 0;
103 +
104 + hr = RegOpen(HKEY_LOCAL_MACHINE, REGISTRY_PENDING_FILE_RENAME_KEY, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkPendingFileRename);
105 + if (E_FILENOTFOUND == hr)
106 + {
107 + ExitFunction1(hr = S_OK);
108 + }
109 + FileExitOnFailure(hr, "Failed to open pending file rename registry key.");
110 +
111 + hr = RegReadStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, &rgsczRenames, &cRenames);
112 + if (E_FILENOTFOUND == hr)
113 + {
114 + ExitFunction1(hr = S_OK);
115 + }
116 + FileExitOnFailure(hr, "Failed to read pending file renames.");
117 +
118 + // The pending file renames array is pairs of source and target paths. We only care
119 + // about checking the source paths so skip the target paths (i += 2).
120 + for (DWORD i = 0; i < cRenames; i += 2)
121 + {
122 + LPWSTR wzRename = rgsczRenames[i];
123 + if (wzRename && *wzRename)
124 + {
125 + hr = PathCompareCanonicalized(wzPath, wzRename, &fPathEqual);
126 + FileExitOnFailure(hr, "Failed to compare path from pending file rename to check path.");
127 +
128 + // If we find our path in the list, null out the source and target slot and
129 + // we'll compact the array next.
130 + if (fPathEqual)
131 + {
132 + ReleaseNullStr(rgsczRenames[i]);
133 + ReleaseNullStr(rgsczRenames[i + 1]);
134 + fRemoved = TRUE;
135 + }
136 + }
137 + }
138 +
139 + if (fRemoved)
140 + {
141 + // Compact the array by removing any nulls.
142 + for (DWORD i = 0; i < cRenames; ++i)
143 + {
144 + LPWSTR wzRename = rgsczRenames[i];
145 + if (wzRename)
146 + {
147 + rgsczRenames[cNewRenames] = wzRename;
148 + ++cNewRenames;
149 + }
150 + }
151 +
152 + cRenames = cNewRenames; // ignore the pointers on the end of the array since an early index points to them already.
153 +
154 + // Write the new array back to the pending file rename key.
155 + hr = RegWriteStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, rgsczRenames, cRenames);
156 + FileExitOnFailure(hr, "Failed to update pending file renames.");
157 + }
158 +
159 +LExit:
160 + ReleaseStrArray(rgsczRenames, cRenames);
161 + ReleaseRegKey(hkPendingFileRename);
162 +
163 + return hr;
164 +}
src/libs/dutil/WixToolset.DUtil/fileutil.cpp
-156
@@ -22,9 +22,6 @@
22 const BYTE UTF8BOM[] = {0xEF, 0xBB, 0xBF};
23 const BYTE UTF16BOM[] = {0xFF, 0xFE};
24
25 -const LPCWSTR REGISTRY_PENDING_FILE_RENAME_KEY = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager";
26 -const LPCWSTR REGISTRY_PENDING_FILE_RENAME_VALUE = L"PendingFileRenameOperations";
27 -
25
26 /*******************************************************************
27 FileStripExtension - Strip extension from filename
@@ -526,159 +523,6 @@ extern "C" BOOL DAPI FileExistsEx(
523 }
524
525
529 -/*******************************************************************
530 - FileExistsAfterRestart - checks that a file exists and will continue
531 - to exist after restart.
532 -
533 -********************************************************************/
534 -extern "C" BOOL DAPI FileExistsAfterRestart(
535 - __in_z LPCWSTR wzPath,
536 - __out_opt DWORD *pdwAttributes
537 - )
538 -{
539 - HRESULT hr = S_OK;
540 - BOOL fExists = FALSE;
541 - HKEY hkPendingFileRename = NULL;
542 - LPWSTR* rgsczRenames = NULL;
543 - DWORD cRenames = 0;
544 - int nCompare = 0;
545 -
546 - fExists = FileExistsEx(wzPath, pdwAttributes);
547 - if (fExists)
548 - {
549 - hr = RegOpen(HKEY_LOCAL_MACHINE, REGISTRY_PENDING_FILE_RENAME_KEY, KEY_QUERY_VALUE, &hkPendingFileRename);
550 - if (E_FILENOTFOUND == hr)
551 - {
552 - ExitFunction1(hr = S_OK);
553 - }
554 - FileExitOnFailure(hr, "Failed to open pending file rename registry key.");
555 -
556 - hr = RegReadStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, &rgsczRenames, &cRenames);
557 - if (E_FILENOTFOUND == hr)
558 - {
559 - ExitFunction1(hr = S_OK);
560 - }
561 - FileExitOnFailure(hr, "Failed to read pending file renames.");
562 -
563 - // The pending file renames array is pairs of source and target paths. We only care
564 - // about checking the source paths so skip the target paths (i += 2).
565 - for (DWORD i = 0; i < cRenames; i += 2)
566 - {
567 - LPWSTR wzRename = rgsczRenames[i];
568 - if (wzRename && *wzRename)
569 - {
570 - // Skip the long path designator if present.
571 - if (L'\\' == wzRename[0] && L'?' == wzRename[1] && L'?' == wzRename[2] && L'\\' == wzRename[3])
572 - {
573 - wzRename += 4;
574 - }
575 -
576 - hr = PathCompare(wzPath, wzRename, &nCompare);
577 - FileExitOnFailure(hr, "Failed to compare path from pending file rename to check path.");
578 -
579 - if (CSTR_EQUAL == nCompare)
580 - {
581 - fExists = FALSE;
582 - break;
583 - }
584 - }
585 - }
586 - }
587 -
588 -LExit:
589 - ReleaseStrArray(rgsczRenames, cRenames);
590 - ReleaseRegKey(hkPendingFileRename);
591 -
592 - return fExists;
593 -}
594 -
595 -
596 -/*******************************************************************
597 - FileRemoveFromPendingRename - removes the file path from the pending
598 - file rename list.
599 -
600 -********************************************************************/
601 -extern "C" HRESULT DAPI FileRemoveFromPendingRename(
602 - __in_z LPCWSTR wzPath
603 - )
604 -{
605 - HRESULT hr = S_OK;
606 - HKEY hkPendingFileRename = NULL;
607 - LPWSTR* rgsczRenames = NULL;
608 - DWORD cRenames = 0;
609 - int nCompare = 0;
610 - BOOL fRemoved = FALSE;
611 - DWORD cNewRenames = 0;
612 -
613 - hr = RegOpen(HKEY_LOCAL_MACHINE, REGISTRY_PENDING_FILE_RENAME_KEY, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkPendingFileRename);
614 - if (E_FILENOTFOUND == hr)
615 - {
616 - ExitFunction1(hr = S_OK);
617 - }
618 - FileExitOnFailure(hr, "Failed to open pending file rename registry key.");
619 -
620 - hr = RegReadStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, &rgsczRenames, &cRenames);
621 - if (E_FILENOTFOUND == hr)
622 - {
623 - ExitFunction1(hr = S_OK);
624 - }
625 - FileExitOnFailure(hr, "Failed to read pending file renames.");
626 -
627 - // The pending file renames array is pairs of source and target paths. We only care
628 - // about checking the source paths so skip the target paths (i += 2).
629 - for (DWORD i = 0; i < cRenames; i += 2)
630 - {
631 - LPWSTR wzRename = rgsczRenames[i];
632 - if (wzRename && *wzRename)
633 - {
634 - // Skip the long path designator if present.
635 - if (L'\\' == wzRename[0] && L'?' == wzRename[1] && L'?' == wzRename[2] && L'\\' == wzRename[3])
636 - {
637 - wzRename += 4;
638 - }
639 -
640 - hr = PathCompare(wzPath, wzRename, &nCompare);
641 - FileExitOnFailure(hr, "Failed to compare path from pending file rename to check path.");
642 -
643 - // If we find our path in the list, null out the source and target slot and
644 - // we'll compact the array next.
645 - if (CSTR_EQUAL == nCompare)
646 - {
647 - ReleaseNullStr(rgsczRenames[i]);
648 - ReleaseNullStr(rgsczRenames[i + 1]);
649 - fRemoved = TRUE;
650 - }
651 - }
652 - }
653 -
654 - if (fRemoved)
655 - {
656 - // Compact the array by removing any nulls.
657 - for (DWORD i = 0; i < cRenames; ++i)
658 - {
659 - LPWSTR wzRename = rgsczRenames[i];
660 - if (wzRename)
661 - {
662 - rgsczRenames[cNewRenames] = wzRename;
663 - ++cNewRenames;
664 - }
665 - }
666 -
667 - cRenames = cNewRenames; // ignore the pointers on the end of the array since an early index points to them already.
668 -
669 - // Write the new array back to the pending file rename key.
670 - hr = RegWriteStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, rgsczRenames, cRenames);
671 - FileExitOnFailure(hr, "Failed to update pending file renames.");
672 - }
673 -
674 -LExit:
675 - ReleaseStrArray(rgsczRenames, cRenames);
676 - ReleaseRegKey(hkPendingFileRename);
677 -
678 - return hr;
679 -}
680 -
681 -
526 /*******************************************************************
527 FileRead - read a file into memory
528
src/libs/dutil/WixToolset.DUtil/inc/pathutil.h
+5 -4
@@ -258,13 +258,14 @@ DAPI_(HRESULT) PathConcatRelativeToBase(
258 );
259
260 /*******************************************************************
261 - PathCompare - compares the fully expanded path of the two paths using
262 - ::CompareStringW().
261 + PathCompareCanonicalized - canonicalizes the two paths using PathCanonicalizeForComparison
262 + which does not resolve relative paths into fully qualified paths.
263 + The strings are then compared using ::CompareStringW().
264 *******************************************************************/
264 -DAPI_(HRESULT) PathCompare(
265 +DAPI_(HRESULT) PathCompareCanonicalized(
266 __in_z LPCWSTR wzPath1,
267 __in_z LPCWSTR wzPath2,
267 - __out int* pnResult
268 + __out BOOL* pfEqual
269 );
270
271 /*******************************************************************
src/libs/dutil/WixToolset.DUtil/path2utl.cpp
+44 -2
@@ -118,11 +118,19 @@ DAPI_(HRESULT) PathCanonicalizeForComparison(
118 PathExitOnFailure(hr, "Failed to backslash terminate the canonicalized path");
119 }
120
121 - if ((PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX & dwCanonicalizeFlags) &&
122 - PathIsFullyQualified(*psczCanonicalized, &fHasPrefix) && !fHasPrefix)
121 + if (PathIsFullyQualified(*psczCanonicalized, &fHasPrefix) && !fHasPrefix &&
122 + (PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX & dwCanonicalizeFlags))
123 {
124 hr = PathPrefix(psczCanonicalized);
125 PathExitOnFailure(hr, "Failed to ensure the long path prefix on the canonicalized path");
126 +
127 + fHasPrefix = TRUE;
128 + }
129 +
130 + if (fHasPrefix)
131 + {
132 + // Canonicalize \??\ into \\?\.
133 + (*psczCanonicalized)[1] = L'\\';
134 }
135
136 LExit:
@@ -171,6 +179,40 @@ LExit:
179 return hr;
180 }
181
182 +DAPI_(HRESULT) PathCompareCanonicalized(
183 + __in_z LPCWSTR wzPath1,
184 + __in_z LPCWSTR wzPath2,
185 + __out BOOL* pfEqual
186 + )
187 +{
188 + HRESULT hr = S_OK;
189 + LPWSTR sczCanonicalized1 = NULL;
190 + LPWSTR sczCanonicalized2 = NULL;
191 + DWORD dwDefaultFlags = PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX | PATH_CANONICALIZE_KEEP_UNC_ROOT;
192 + int nResult = 0;
193 +
194 + if (!wzPath1 || !wzPath2)
195 + {
196 + PathExitWithRootFailure(hr, E_INVALIDARG, "Both paths are required.");
197 + }
198 +
199 + hr = PathCanonicalizeForComparison(wzPath1, dwDefaultFlags, &sczCanonicalized1);
200 + PathExitOnFailure(hr, "Failed to canonicalize wzPath1.");
201 +
202 + hr = PathCanonicalizeForComparison(wzPath2, dwDefaultFlags, &sczCanonicalized2);
203 + PathExitOnFailure(hr, "Failed to canonicalize wzPath2.");
204 +
205 + nResult = ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, sczCanonicalized1, -1, sczCanonicalized2, -1);
206 + PathExitOnNullWithLastError(nResult, hr, "Failed to compare canonicalized paths.");
207 +
208 + *pfEqual = CSTR_EQUAL == nResult;
209 +
210 +LExit:
211 + ReleaseStr(sczCanonicalized1);
212 + ReleaseStr(sczCanonicalized2);
213 + return hr;
214 +}
215 +
216 DAPI_(HRESULT) PathDirectoryContainsPath(
217 __in_z LPCWSTR wzDirectory,
218 __in_z LPCWSTR wzPath
src/libs/dutil/WixToolset.DUtil/pathutil.cpp
-26
@@ -1080,32 +1080,6 @@ LExit:
1080 }
1081
1082
1083 -DAPI_(HRESULT) PathCompare(
1084 - __in_z LPCWSTR wzPath1,
1085 - __in_z LPCWSTR wzPath2,
1086 - __out int* pnResult
1087 - )
1088 -{
1089 - HRESULT hr = S_OK;
1090 - LPWSTR sczPath1 = NULL;
1091 - LPWSTR sczPath2 = NULL;
1092 -
1093 - hr = PathExpand(&sczPath1, wzPath1, PATH_EXPAND_ENVIRONMENT | PATH_EXPAND_FULLPATH);
1094 - PathExitOnFailure(hr, "Failed to expand path1.");
1095 -
1096 - hr = PathExpand(&sczPath2, wzPath2, PATH_EXPAND_ENVIRONMENT | PATH_EXPAND_FULLPATH);
1097 - PathExitOnFailure(hr, "Failed to expand path2.");
1098 -
1099 - *pnResult = ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, sczPath1, -1, sczPath2, -1);
1100 -
1101 -LExit:
1102 - ReleaseStr(sczPath2);
1103 - ReleaseStr(sczPath1);
1104 -
1105 - return hr;
1106 -}
1107 -
1108 -
1083 DAPI_(HRESULT) PathCompress(
1084 __in_z LPCWSTR wzPath
1085 )
src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp
+69
@@ -151,6 +151,10 @@ namespace DutilTests
151 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
152 NativeAssert::StringEqual(L"\\\\otherdir\\unc.exe", sczCanonicalized);
153
154 + hr = PathCanonicalizeForComparison(L"\\??\\UNC\\server\\share\\dir", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized);
155 + NativeAssert::Succeeded(hr, "Failed to canonicalize path");
156 + NativeAssert::StringEqual(L"\\\\?\\UNC\\server\\share\\dir", sczCanonicalized);
157 +
158 hr = PathCanonicalizeForComparison(L"\\\\?\\UNC\\server\\share\\..\\..\\otherdir\\unc.exe", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized);
159 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
160 NativeAssert::StringEqual(L"\\\\?\\UNC\\server\\share\\otherdir\\unc.exe", sczCanonicalized);
@@ -203,6 +207,10 @@ namespace DutilTests
207 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
208 NativeAssert::StringEqual(L"\\\\?\\invalidlongpath.exe", sczCanonicalized);
209
210 + hr = PathCanonicalizeForComparison(L"\\??\\test\\..\\invalidlongpath.exe", 0, &sczCanonicalized);
211 + NativeAssert::Succeeded(hr, "Failed to canonicalize path");
212 + NativeAssert::StringEqual(L"\\\\?\\invalidlongpath.exe", sczCanonicalized);
213 +
214 hr = PathCanonicalizeForComparison(L"C:\\.\\invalid:pathchars?.exe", 0, &sczCanonicalized);
215 NativeAssert::Succeeded(hr, "Failed to canonicalize path");
216 NativeAssert::StringEqual(L"C:\\invalid:pathchars?.exe", sczCanonicalized);
@@ -263,6 +271,67 @@ namespace DutilTests
271 }
272 }
273
274 + [Fact]
275 + void PathCompareCanonicalizeEqualTest()
276 + {
277 + HRESULT hr = S_OK;
278 + LPWSTR sczPath = NULL;
279 + BOOL fEqual = FALSE;
280 + LPCWSTR rgwzPaths[14] =
281 + {
282 + L"C:\\simplepath", L"C:\\simplepath",
283 + L"\\\\server\\share\\dir\\dir2\\..\\otherdir\\unc.exe", L"\\\\server\\share\\dir\\otherdir\\unc.exe",
284 + L"\\\\server\\share\\..\\..\\otherdir\\unc.exe", L"\\\\server\\share\\otherdir\\unc.exe",
285 + L"\\\\?\\UNC\\server\\share\\..\\..\\otherdir\\unc.exe", L"\\\\?\\UNC\\server\\share\\otherdir\\unc.exe",
286 + L"C:\\dir\\subdir\\..\\..\\..\\otherdir\\pastroot.exe", L"C:\\otherdir\\pastroot.exe",
287 + L"\\\\?\\C:\\dir\\subdir\\..\\..\\..\\otherdir\\pastroot.exe", L"C:\\..\\otherdir\\pastroot.exe",
288 + L"\\??\\C:\\dir", L"\\\\?\\C:\\dir",
289 + };
290 +
291 + try
292 + {
293 + for (DWORD i = 0; i < countof(rgwzPaths); i += 2)
294 + {
295 + hr = PathCompareCanonicalized(rgwzPaths[i], rgwzPaths[i + 1], &fEqual);
296 + NativeAssert::Succeeded(hr, "PathCompareCanonicalized: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]);
297 + Assert::True(fEqual, String::Format("PathCompareCanonicalized: {0}, {1}", gcnew String(rgwzPaths[i]), gcnew String(rgwzPaths[i + 1])));
298 + }
299 + }
300 + finally
301 + {
302 + ReleaseStr(sczPath);
303 + }
304 + }
305 +
306 + [Fact]
307 + void PathCompareCanonicalizeNotEqualTest()
308 + {
309 + HRESULT hr = S_OK;
310 + LPWSTR sczPath = NULL;
311 + BOOL fEqual = FALSE;
312 + LPCWSTR rgwzPaths[8] =
313 + {
314 + L"C:\\simplepath", L"D:\\simplepath",
315 + L"\\\\.\\share\\otherdir\\unc.exe", L"\\\\share\\otherdir\\unc.exe",
316 + L"\\\\server\\.\\otherdir\\unc.exe", L"\\\\server\\otherdir\\unc.exe",
317 + L"\\\\server\\\\otherdir\\unc.exe", L"\\\\server\\otherdir\\unc.exe",
318 + };
319 +
320 + try
321 + {
322 + for (DWORD i = 0; i < countof(rgwzPaths); i += 2)
323 + {
324 + hr = PathCompareCanonicalized(rgwzPaths[i], rgwzPaths[i + 1], &fEqual);
325 + NativeAssert::Succeeded(hr, "PathCompareCanonicalized: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]);
326 + Assert::False(fEqual, String::Format("PathCompareCanonicalized: {0}, {1}", gcnew String(rgwzPaths[i]), gcnew String(rgwzPaths[i + 1])));
327 + }
328 + }
329 + finally
330 + {
331 + ReleaseStr(sczPath);
332 + }
333 + }
334 +
335 [Fact]
336 void PathConcatRelativeToBaseTest()
337 {