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
{