diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-06-03 17:48:39 -0500 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-06-07 19:44:36 -0500 |
commit | 6b0f2d978504da82070523eb6adb0b59f9812e93 (patch) | |
tree | 6f0b258519a0f51bf589e4313206b3ffeaa32a41 | |
parent | b652e93a460b4b822a01382e5992f96f1d805ffe (diff) | |
download | wix-6b0f2d978504da82070523eb6adb0b59f9812e93.tar.gz wix-6b0f2d978504da82070523eb6adb0b59f9812e93.tar.bz2 wix-6b0f2d978504da82070523eb6adb0b59f9812e93.zip |
Add PathSkipPastRoot.
-rw-r--r-- | src/burn/engine/bundlepackageengine.cpp | 2 | ||||
-rw-r--r-- | src/burn/engine/exeengine.cpp | 2 | ||||
-rw-r--r-- | src/burn/engine/logging.cpp | 6 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/dirutil.cpp | 20 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | 55 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/logutil.cpp | 2 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/path2utl.cpp | 53 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/pathutil.cpp | 296 | ||||
-rw-r--r-- | src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | 288 |
9 files changed, 414 insertions, 310 deletions
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 97861436..8ba8e0d2 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp | |||
@@ -763,7 +763,7 @@ static HRESULT ExecuteBundle( | |||
763 | 763 | ||
764 | if (fPseudoPackage) | 764 | if (fPseudoPackage) |
765 | { | 765 | { |
766 | if (!PathIsFullyQualified(pPackagePayload->sczFilePath, NULL)) | 766 | if (!PathIsFullyQualified(pPackagePayload->sczFilePath)) |
767 | { | 767 | { |
768 | ExitWithRootFailure(hr, E_INVALIDSTATE, "Related bundles must have a fully qualified target path."); | 768 | ExitWithRootFailure(hr, E_INVALIDSTATE, "Related bundles must have a fully qualified target path."); |
769 | } | 769 | } |
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index c3757e92..fb852c78 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp | |||
@@ -363,7 +363,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
363 | 363 | ||
364 | if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) | 364 | if (pPackage->Exe.fPseudoPackage && BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE != pPackagePayload->verification) |
365 | { | 365 | { |
366 | if (!PathIsFullyQualified(pPackagePayload->sczFilePath, NULL)) | 366 | if (!PathIsFullyQualified(pPackagePayload->sczFilePath)) |
367 | { | 367 | { |
368 | ExitWithRootFailure(hr, E_INVALIDSTATE, "Pseudo ExePackages must have a fully qualified target path."); | 368 | ExitWithRootFailure(hr, E_INVALIDSTATE, "Pseudo ExePackages must have a fully qualified target path."); |
369 | } | 369 | } |
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 3a403025..77f5079c 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp | |||
@@ -134,10 +134,12 @@ extern "C" HRESULT LoggingOpen( | |||
134 | 134 | ||
135 | if (sczPrefixFormatted && *sczPrefixFormatted) | 135 | if (sczPrefixFormatted && *sczPrefixFormatted) |
136 | { | 136 | { |
137 | // Best effort to open default logging. | ||
137 | LPCWSTR wzPrefix = sczPrefixFormatted; | 138 | LPCWSTR wzPrefix = sczPrefixFormatted; |
139 | LPCWSTR wzPastRoot = PathSkipPastRoot(sczPrefixFormatted, NULL, NULL, NULL); | ||
138 | 140 | ||
139 | // Best effort to open default logging. | 141 | // If the log path is rooted and has a file component, then use that path as is. |
140 | if (PathIsRooted(sczPrefixFormatted)) | 142 | if (wzPastRoot && *wzPastRoot) |
141 | { | 143 | { |
142 | hr = PathGetDirectory(sczPrefixFormatted, &sczLoggingBaseFolder); | 144 | hr = PathGetDirectory(sczPrefixFormatted, &sczLoggingBaseFolder); |
143 | ExitOnFailure(hr, "Failed to get parent directory from '%ls'.", sczPrefixFormatted); | 145 | ExitOnFailure(hr, "Failed to get parent directory from '%ls'.", sczPrefixFormatted); |
diff --git a/src/libs/dutil/WixToolset.DUtil/dirutil.cpp b/src/libs/dutil/WixToolset.DUtil/dirutil.cpp index c106a467..94eab9e7 100644 --- a/src/libs/dutil/WixToolset.DUtil/dirutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/dirutil.cpp | |||
@@ -364,17 +364,27 @@ extern "C" DWORD DAPI DirDeleteEmptyDirectoriesToRoot( | |||
364 | __in DWORD /*dwFlags*/ | 364 | __in DWORD /*dwFlags*/ |
365 | ) | 365 | ) |
366 | { | 366 | { |
367 | HRESULT hr = S_OK; | ||
367 | DWORD cDeletedDirs = 0; | 368 | DWORD cDeletedDirs = 0; |
368 | LPWSTR sczPath = NULL; | 369 | LPWSTR sczPath = NULL; |
370 | LPCWSTR wzPastRoot = NULL; | ||
371 | SIZE_T cchRoot = 0; | ||
372 | |||
373 | // Make sure the path is normalized and prefixed. | ||
374 | hr = PathExpand(&sczPath, wzPath, PATH_EXPAND_FULLPATH); | ||
375 | DirExitOnFailure(hr, "Failed to get full path for: %ls", wzPath); | ||
376 | |||
377 | wzPastRoot = PathSkipPastRoot(sczPath, NULL, NULL, NULL); | ||
378 | DirExitOnNull(wzPastRoot, hr, E_INVALIDARG, "Full path was not rooted: %ls", sczPath); | ||
369 | 379 | ||
370 | while (wzPath && *wzPath && ::RemoveDirectoryW(wzPath)) | 380 | cchRoot = wzPastRoot - sczPath; |
381 | |||
382 | while (sczPath && sczPath[cchRoot] && ::RemoveDirectoryW(sczPath)) | ||
371 | { | 383 | { |
372 | ++cDeletedDirs; | 384 | ++cDeletedDirs; |
373 | 385 | ||
374 | HRESULT hr = PathGetParentPath(wzPath, &sczPath); | 386 | hr = PathGetParentPath(sczPath, &sczPath, &cchRoot); |
375 | DirExitOnFailure(hr, "Failed to get parent directory for path: %ls", wzPath); | 387 | DirExitOnFailure(hr, "Failed to get parent directory for path: %ls", sczPath); |
376 | |||
377 | wzPath = sczPath; | ||
378 | } | 388 | } |
379 | 389 | ||
380 | LExit: | 390 | LExit: |
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index e64c8ef3..727318f2 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | |||
@@ -8,8 +8,8 @@ extern "C" { | |||
8 | 8 | ||
9 | typedef enum _PATH_CANONICALIZE | 9 | typedef enum _PATH_CANONICALIZE |
10 | { | 10 | { |
11 | // Always prefix fully qualified paths with the long path prefix (\\?\). | 11 | // Always prefix fully qualified paths with the extended path prefix (\\?\). |
12 | PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX = 0x0001, | 12 | PATH_CANONICALIZE_APPEND_EXTENDED_PATH_PREFIX = 0x0001, |
13 | // Always terminate the path with \. | 13 | // Always terminate the path with \. |
14 | PATH_CANONICALIZE_BACKSLASH_TERMINATE = 0x0002, | 14 | PATH_CANONICALIZE_BACKSLASH_TERMINATE = 0x0002, |
15 | // Don't collapse . or .. in the \\server\share portion of a UNC path. | 15 | // Don't collapse . or .. in the \\server\share portion of a UNC path. |
@@ -22,6 +22,14 @@ typedef enum _PATH_EXPAND | |||
22 | PATH_EXPAND_FULLPATH = 0x0002, | 22 | PATH_EXPAND_FULLPATH = 0x0002, |
23 | } PATH_EXPAND; | 23 | } PATH_EXPAND; |
24 | 24 | ||
25 | typedef enum _PATH_PREFIX | ||
26 | { | ||
27 | // Add prefix even if the path is not longer than MAX_PATH. | ||
28 | PATH_PREFIX_SHORT_PATHS = 0x0001, | ||
29 | // Error with E_INVALIDARG if the path is not fully qualified. | ||
30 | PATH_PREFIX_EXPECT_FULLY_QUALIFIED = 0x0002, | ||
31 | } PATH_PREFIX; | ||
32 | |||
25 | 33 | ||
26 | /******************************************************************* | 34 | /******************************************************************* |
27 | PathFile - returns a pointer to the file part of the path. | 35 | PathFile - returns a pointer to the file part of the path. |
@@ -40,8 +48,9 @@ DAPI_(LPCWSTR) PathExtension( | |||
40 | 48 | ||
41 | /******************************************************************* | 49 | /******************************************************************* |
42 | PathGetDirectory - extracts the directory from a path including the directory separator. | 50 | PathGetDirectory - extracts the directory from a path including the directory separator. |
43 | This means calling the function again with the previous result returns the same result. | 51 | Calling the function again with the previous result returns the same result. |
44 | Returns S_FALSE if the path only contains a file name. | 52 | Returns S_FALSE if the path only contains a file name. |
53 | For example, C:\a\b -> C:\a\ -> C:\a\ | ||
45 | ********************************************************************/ | 54 | ********************************************************************/ |
46 | DAPI_(HRESULT) PathGetDirectory( | 55 | DAPI_(HRESULT) PathGetDirectory( |
47 | __in_z LPCWSTR wzPath, | 56 | __in_z LPCWSTR wzPath, |
@@ -49,12 +58,18 @@ DAPI_(HRESULT) PathGetDirectory( | |||
49 | ); | 58 | ); |
50 | 59 | ||
51 | /******************************************************************* | 60 | /******************************************************************* |
52 | PathGetParentPath - extracts the parent directory from a full path. | 61 | PathGetParentPath - extracts the parent directory from a path |
53 | *psczDirectory is NULL if the path only contains a file name. | 62 | ignoring a trailing slash so that when called repeatedly, |
63 | it eventually returns the root portion of the path. | ||
64 | *psczDirectory is NULL if the path only contains a file name or | ||
65 | the path only contains the root. | ||
66 | *pcchRoot is the length of the root part of the path. | ||
67 | For example, C:\a\b -> C:\a\ -> C:\ -> NULL | ||
54 | ********************************************************************/ | 68 | ********************************************************************/ |
55 | DAPI_(HRESULT) PathGetParentPath( | 69 | DAPI_(HRESULT) PathGetParentPath( |
56 | __in_z LPCWSTR wzPath, | 70 | __in_z LPCWSTR wzPath, |
57 | __out_z LPWSTR *psczDirectory | 71 | __out_z LPWSTR *psczDirectory, |
72 | __out_opt SIZE_T* pcchRoot | ||
58 | ); | 73 | ); |
59 | 74 | ||
60 | /******************************************************************* | 75 | /******************************************************************* |
@@ -78,11 +93,14 @@ DAPI_(HRESULT) PathGetFullPathName( | |||
78 | ); | 93 | ); |
79 | 94 | ||
80 | /******************************************************************* | 95 | /******************************************************************* |
81 | PathPrefix - prefixes a full path with \\?\ or \\?\UNC as | 96 | PathPrefix - prefixes a path with \\?\ or \\?\UNC if it doesn't |
82 | appropriate. | 97 | already have an extended prefix, is longer than MAX_PATH, |
98 | and is fully qualified. | ||
83 | ********************************************************************/ | 99 | ********************************************************************/ |
84 | DAPI_(HRESULT) PathPrefix( | 100 | DAPI_(HRESULT) PathPrefix( |
85 | __inout LPWSTR *psczFullPath | 101 | __inout_z LPWSTR *psczFullPath, |
102 | __in SIZE_T cchFullPath, | ||
103 | __in DWORD dwPrefixFlags | ||
86 | ); | 104 | ); |
87 | 105 | ||
88 | /******************************************************************* | 106 | /******************************************************************* |
@@ -204,14 +222,27 @@ DAPI_(HRESULT) PathGetKnownFolder( | |||
204 | ); | 222 | ); |
205 | 223 | ||
206 | /******************************************************************* | 224 | /******************************************************************* |
225 | PathSkipPastRoot - returns a pointer to the first character after | ||
226 | the root portion of the path or NULL if the path has no root. | ||
227 | For example, the pointer will point to the "a" in "after": | ||
228 | C:\after, C:after, \after, \\server\share\after, | ||
229 | \\?\C:\afterroot, \\?\UNC\server\share\after | ||
230 | *******************************************************************/ | ||
231 | DAPI_(LPCWSTR) PathSkipPastRoot( | ||
232 | __in_z LPCWSTR wzPath, | ||
233 | __out_opt BOOL* pfHasExtendedPrefix, | ||
234 | __out_opt BOOL* pfFullyQualified, | ||
235 | __out_opt BOOL* pfUNC | ||
236 | ); | ||
237 | |||
238 | /******************************************************************* | ||
207 | PathIsFullyQualified - returns true if the path is fully qualified; false otherwise. | 239 | PathIsFullyQualified - returns true if the path is fully qualified; false otherwise. |
208 | Note that some rooted paths like C:dir are not fully qualified. | 240 | Note that some rooted paths like C:dir are not fully qualified. |
209 | For example, these are all fully qualified: C:\dir, C:/dir, \\server\share, \\?\C:\dir. | 241 | For example, these are all fully qualified: C:\dir, C:/dir, \\server\share, \\?\C:\dir. |
210 | For example, these are not fully qualified: C:dir, C:, \dir, dir, dir\subdir. | 242 | For example, these are not fully qualified: C:dir, C:, \dir, dir, dir\subdir. |
211 | *******************************************************************/ | 243 | *******************************************************************/ |
212 | DAPI_(BOOL) PathIsFullyQualified( | 244 | DAPI_(BOOL) PathIsFullyQualified( |
213 | __in_z LPCWSTR wzPath, | 245 | __in_z LPCWSTR wzPath |
214 | __out_opt BOOL* pfHasLongPathPrefix | ||
215 | ); | 246 | ); |
216 | 247 | ||
217 | /******************************************************************* | 248 | /******************************************************************* |
diff --git a/src/libs/dutil/WixToolset.DUtil/logutil.cpp b/src/libs/dutil/WixToolset.DUtil/logutil.cpp index 94c21374..88a90d8c 100644 --- a/src/libs/dutil/WixToolset.DUtil/logutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/logutil.cpp | |||
@@ -133,7 +133,7 @@ extern "C" HRESULT DAPI LogOpen( | |||
133 | hr = PathConcat(wzDirectory, wzLog, &sczCombined); | 133 | hr = PathConcat(wzDirectory, wzLog, &sczCombined); |
134 | LoguExitOnFailure(hr, "Failed to combine the log path."); | 134 | LoguExitOnFailure(hr, "Failed to combine the log path."); |
135 | 135 | ||
136 | if (!PathIsFullyQualified(sczCombined, NULL)) | 136 | if (!PathIsFullyQualified(sczCombined)) |
137 | { | 137 | { |
138 | hr = PathExpand(&LogUtil_sczLogPath, sczCombined, PATH_EXPAND_FULLPATH); | 138 | hr = PathExpand(&LogUtil_sczLogPath, sczCombined, PATH_EXPAND_FULLPATH); |
139 | LoguExitOnFailure(hr, "Failed to expand the log path."); | 139 | LoguExitOnFailure(hr, "Failed to expand the log path."); |
diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp index 1957a8c5..9e48f9d5 100644 --- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp +++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp | |||
@@ -64,31 +64,12 @@ DAPI_(HRESULT) PathCanonicalizeForComparison( | |||
64 | 64 | ||
65 | if (PATH_CANONICALIZE_KEEP_UNC_ROOT & dwCanonicalizeFlags) | 65 | if (PATH_CANONICALIZE_KEEP_UNC_ROOT & dwCanonicalizeFlags) |
66 | { | 66 | { |
67 | if (L'\\' == sczNormalizedPath[0] && (L'\\' == sczNormalizedPath[1] || L'?' == sczNormalizedPath[1]) && L'?' == sczNormalizedPath[2] && L'\\' == sczNormalizedPath[3]) | 67 | BOOL fUNC = FALSE; |
68 | LPCWSTR wzPastRoot = PathSkipPastRoot(sczNormalizedPath, NULL, NULL, &fUNC); | ||
69 | if (fUNC) | ||
68 | { | 70 | { |
69 | if (L'U' == sczNormalizedPath[4] && L'N' == sczNormalizedPath[5] && L'C' == sczNormalizedPath[6] && L'\\' == sczNormalizedPath[7]) | 71 | wzNormalizedPath = wzPastRoot; |
70 | { | 72 | cchUncRootLength = wzPastRoot - sczNormalizedPath; |
71 | cchUncRootLength = 8; | ||
72 | } | ||
73 | } | ||
74 | else if (L'\\' == sczNormalizedPath[0] && L'\\' == sczNormalizedPath[1]) | ||
75 | { | ||
76 | cchUncRootLength = 2; | ||
77 | } | ||
78 | |||
79 | if (cchUncRootLength) | ||
80 | { | ||
81 | DWORD dwRemainingSlashes = 2; | ||
82 | |||
83 | for (wzNormalizedPath += cchUncRootLength; *wzNormalizedPath && dwRemainingSlashes; ++wzNormalizedPath) | ||
84 | { | ||
85 | ++cchUncRootLength; | ||
86 | |||
87 | if (L'\\' == *wzNormalizedPath) | ||
88 | { | ||
89 | --dwRemainingSlashes; | ||
90 | } | ||
91 | } | ||
92 | } | 73 | } |
93 | } | 74 | } |
94 | 75 | ||
@@ -115,22 +96,24 @@ DAPI_(HRESULT) PathCanonicalizeForComparison( | |||
115 | if (PATH_CANONICALIZE_BACKSLASH_TERMINATE & dwCanonicalizeFlags) | 96 | if (PATH_CANONICALIZE_BACKSLASH_TERMINATE & dwCanonicalizeFlags) |
116 | { | 97 | { |
117 | hr = PathBackslashTerminate(psczCanonicalized); | 98 | hr = PathBackslashTerminate(psczCanonicalized); |
118 | PathExitOnFailure(hr, "Failed to backslash terminate the canonicalized path"); | 99 | PathExitOnFailure(hr, "Failed to backslash terminate the canonicalized path."); |
119 | } | 100 | } |
120 | 101 | ||
121 | if (PathIsFullyQualified(*psczCanonicalized, &fHasPrefix) && !fHasPrefix && | 102 | if (PATH_CANONICALIZE_APPEND_EXTENDED_PATH_PREFIX & dwCanonicalizeFlags) |
122 | (PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX & dwCanonicalizeFlags)) | ||
123 | { | 103 | { |
124 | hr = PathPrefix(psczCanonicalized); | 104 | hr = PathPrefix(psczCanonicalized, 0, PATH_PREFIX_SHORT_PATHS); |
125 | PathExitOnFailure(hr, "Failed to ensure the long path prefix on the canonicalized path"); | 105 | PathExitOnFailure(hr, "Failed to ensure the extended path prefix on the canonicalized path."); |
126 | |||
127 | fHasPrefix = TRUE; | ||
128 | } | 106 | } |
129 | 107 | ||
108 | PathSkipPastRoot(*psczCanonicalized, &fHasPrefix, NULL, NULL); | ||
109 | |||
130 | if (fHasPrefix) | 110 | if (fHasPrefix) |
131 | { | 111 | { |
132 | // Canonicalize \??\ into \\?\. | 112 | // Canonicalize prefix into \\?\. |
113 | (*psczCanonicalized)[0] = L'\\'; | ||
133 | (*psczCanonicalized)[1] = L'\\'; | 114 | (*psczCanonicalized)[1] = L'\\'; |
115 | (*psczCanonicalized)[2] = L'?'; | ||
116 | (*psczCanonicalized)[3] = L'\\'; | ||
134 | } | 117 | } |
135 | 118 | ||
136 | LExit: | 119 | LExit: |
@@ -188,7 +171,7 @@ DAPI_(HRESULT) PathCompareCanonicalized( | |||
188 | HRESULT hr = S_OK; | 171 | HRESULT hr = S_OK; |
189 | LPWSTR sczCanonicalized1 = NULL; | 172 | LPWSTR sczCanonicalized1 = NULL; |
190 | LPWSTR sczCanonicalized2 = NULL; | 173 | LPWSTR sczCanonicalized2 = NULL; |
191 | DWORD dwDefaultFlags = PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX | PATH_CANONICALIZE_KEEP_UNC_ROOT; | 174 | DWORD dwDefaultFlags = PATH_CANONICALIZE_APPEND_EXTENDED_PATH_PREFIX | PATH_CANONICALIZE_KEEP_UNC_ROOT; |
192 | int nResult = 0; | 175 | int nResult = 0; |
193 | 176 | ||
194 | if (!wzPath1 || !wzPath2) | 177 | if (!wzPath1 || !wzPath2) |
@@ -221,7 +204,7 @@ DAPI_(HRESULT) PathDirectoryContainsPath( | |||
221 | HRESULT hr = S_OK; | 204 | HRESULT hr = S_OK; |
222 | LPWSTR sczCanonicalizedDirectory = NULL; | 205 | LPWSTR sczCanonicalizedDirectory = NULL; |
223 | LPWSTR sczCanonicalizedPath = NULL; | 206 | LPWSTR sczCanonicalizedPath = NULL; |
224 | DWORD dwDefaultFlags = PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX | PATH_CANONICALIZE_KEEP_UNC_ROOT; | 207 | DWORD dwDefaultFlags = PATH_CANONICALIZE_APPEND_EXTENDED_PATH_PREFIX | PATH_CANONICALIZE_KEEP_UNC_ROOT; |
225 | size_t cchDirectory = 0; | 208 | size_t cchDirectory = 0; |
226 | 209 | ||
227 | if (!wzDirectory || !*wzDirectory) | 210 | if (!wzDirectory || !*wzDirectory) |
@@ -239,7 +222,7 @@ DAPI_(HRESULT) PathDirectoryContainsPath( | |||
239 | hr = PathCanonicalizeForComparison(wzPath, dwDefaultFlags, &sczCanonicalizedPath); | 222 | hr = PathCanonicalizeForComparison(wzPath, dwDefaultFlags, &sczCanonicalizedPath); |
240 | PathExitOnFailure(hr, "Failed to canonicalize the path."); | 223 | PathExitOnFailure(hr, "Failed to canonicalize the path."); |
241 | 224 | ||
242 | if (!PathIsFullyQualified(sczCanonicalizedDirectory, NULL)) | 225 | if (!PathIsFullyQualified(sczCanonicalizedDirectory)) |
243 | { | 226 | { |
244 | PathExitWithRootFailure(hr, E_INVALIDARG, "wzDirectory must be a fully qualified path."); | 227 | PathExitWithRootFailure(hr, E_INVALIDARG, "wzDirectory must be a fully qualified path."); |
245 | } | 228 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp index abbf4d4b..1ac76626 100644 --- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp | |||
@@ -120,13 +120,34 @@ LExit: | |||
120 | 120 | ||
121 | DAPI_(HRESULT) PathGetParentPath( | 121 | DAPI_(HRESULT) PathGetParentPath( |
122 | __in_z LPCWSTR wzPath, | 122 | __in_z LPCWSTR wzPath, |
123 | __out_z LPWSTR *psczParent | 123 | __out_z LPWSTR* psczParent, |
124 | __out_opt SIZE_T* pcchRoot | ||
124 | ) | 125 | ) |
125 | { | 126 | { |
126 | HRESULT hr = S_OK; | 127 | HRESULT hr = S_OK; |
128 | LPCWSTR wzPastRoot = NULL; | ||
127 | LPCWSTR wzParent = NULL; | 129 | LPCWSTR wzParent = NULL; |
130 | LPCWSTR wz = NULL; | ||
128 | 131 | ||
129 | for (LPCWSTR wz = wzPath; *wz; ++wz) | 132 | wzPastRoot = PathSkipPastRoot(wzPath, NULL, NULL, NULL); |
133 | |||
134 | if (pcchRoot) | ||
135 | { | ||
136 | *pcchRoot = !wzPastRoot ? 0 : wzPastRoot - wzPath; | ||
137 | } | ||
138 | |||
139 | if (wzPastRoot && *wzPastRoot) | ||
140 | { | ||
141 | Assert(wzPastRoot > wzPath); | ||
142 | wz = wzPastRoot; | ||
143 | wzParent = wzPastRoot - 1; | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | wz = wzPath; | ||
148 | } | ||
149 | |||
150 | for (; *wz; ++wz) | ||
130 | { | 151 | { |
131 | if (IsPathSeparatorChar(*wz) && wz[1]) | 152 | if (IsPathSeparatorChar(*wz) && wz[1]) |
132 | { | 153 | { |
@@ -143,7 +164,7 @@ DAPI_(HRESULT) PathGetParentPath( | |||
143 | } | 164 | } |
144 | else | 165 | else |
145 | { | 166 | { |
146 | ReleaseNullStr(psczParent); | 167 | ReleaseNullStr(*psczParent); |
147 | } | 168 | } |
148 | 169 | ||
149 | LExit: | 170 | LExit: |
@@ -164,9 +185,8 @@ DAPI_(HRESULT) PathExpand( | |||
164 | LPWSTR sczExpandedPath = NULL; | 185 | LPWSTR sczExpandedPath = NULL; |
165 | SIZE_T cchWritten = 0; | 186 | SIZE_T cchWritten = 0; |
166 | DWORD cchExpandedPath = 0; | 187 | DWORD cchExpandedPath = 0; |
167 | SIZE_T cbSize = 0; | ||
168 | |||
169 | LPWSTR sczFullPath = NULL; | 188 | LPWSTR sczFullPath = NULL; |
189 | DWORD dwPrefixFlags = 0; | ||
170 | 190 | ||
171 | // | 191 | // |
172 | // First, expand any environment variables. | 192 | // First, expand any environment variables. |
@@ -201,20 +221,7 @@ DAPI_(HRESULT) PathExpand( | |||
201 | } | 221 | } |
202 | } | 222 | } |
203 | 223 | ||
204 | if (MAX_PATH < cch) | 224 | cchWritten = cch; |
205 | { | ||
206 | hr = PathPrefix(&sczExpandedPath); // ignore invald arg from path prefix because this may not be a complete path yet | ||
207 | if (E_INVALIDARG == hr) | ||
208 | { | ||
209 | hr = S_OK; | ||
210 | } | ||
211 | PathExitOnFailure(hr, "Failed to prefix long path after expanding environment variables."); | ||
212 | |||
213 | hr = StrMaxLength(sczExpandedPath, &cbSize); | ||
214 | PathExitOnFailure(hr, "Failed to get max length of expanded path."); | ||
215 | |||
216 | cchExpandedPath = (DWORD)min(DWORD_MAX, cbSize); | ||
217 | } | ||
218 | } | 225 | } |
219 | 226 | ||
220 | // | 227 | // |
@@ -227,11 +234,7 @@ DAPI_(HRESULT) PathExpand( | |||
227 | hr = PathGetFullPathName(wzPath, &sczFullPath, NULL, &cchWritten); | 234 | hr = PathGetFullPathName(wzPath, &sczFullPath, NULL, &cchWritten); |
228 | PathExitOnFailure(hr, "Failed to get full path for string: %ls", wzPath); | 235 | PathExitOnFailure(hr, "Failed to get full path for string: %ls", wzPath); |
229 | 236 | ||
230 | if (MAX_PATH < cchWritten) | 237 | dwPrefixFlags |= PATH_PREFIX_EXPECT_FULLY_QUALIFIED; |
231 | { | ||
232 | hr = PathPrefix(&sczFullPath); | ||
233 | PathExitOnFailure(hr, "Failed to prefix long path after expanding."); | ||
234 | } | ||
235 | } | 238 | } |
236 | else | 239 | else |
237 | { | 240 | { |
@@ -239,6 +242,12 @@ DAPI_(HRESULT) PathExpand( | |||
239 | sczExpandedPath = NULL; | 242 | sczExpandedPath = NULL; |
240 | } | 243 | } |
241 | 244 | ||
245 | if (dwResolveFlags) | ||
246 | { | ||
247 | hr = PathPrefix(&sczFullPath, cchWritten, dwPrefixFlags); | ||
248 | PathExitOnFailure(hr, "Failed to prefix path after expanding."); | ||
249 | } | ||
250 | |||
242 | hr = StrAllocString(psczFullPath, sczFullPath ? sczFullPath : wzRelativePath, 0); | 251 | hr = StrAllocString(psczFullPath, sczFullPath ? sczFullPath : wzRelativePath, 0); |
243 | PathExitOnFailure(hr, "Failed to copy relative path into full path."); | 252 | PathExitOnFailure(hr, "Failed to copy relative path into full path."); |
244 | 253 | ||
@@ -319,29 +328,54 @@ LExit: | |||
319 | 328 | ||
320 | 329 | ||
321 | DAPI_(HRESULT) PathPrefix( | 330 | DAPI_(HRESULT) PathPrefix( |
322 | __inout LPWSTR *psczFullPath | 331 | __inout_z LPWSTR* psczFullPath, |
332 | __in SIZE_T cchFullPath, | ||
333 | __in DWORD dwPrefixFlags | ||
323 | ) | 334 | ) |
324 | { | 335 | { |
325 | Assert(psczFullPath && *psczFullPath); | 336 | Assert(psczFullPath); |
326 | 337 | ||
327 | HRESULT hr = S_OK; | 338 | HRESULT hr = S_OK; |
328 | LPWSTR wzFullPath = *psczFullPath; | 339 | LPWSTR wzFullPath = *psczFullPath; |
329 | BOOL fFullyQualified = FALSE; | 340 | BOOL fFullyQualified = FALSE; |
330 | BOOL fHasPrefix = FALSE; | 341 | BOOL fHasPrefix = FALSE; |
342 | BOOL fUNC = FALSE; | ||
331 | SIZE_T cbFullPath = 0; | 343 | SIZE_T cbFullPath = 0; |
332 | 344 | ||
333 | fFullyQualified = PathIsFullyQualified(wzFullPath, &fHasPrefix); | 345 | PathSkipPastRoot(wzFullPath, &fHasPrefix, &fFullyQualified, &fUNC); |
346 | |||
334 | if (fHasPrefix) | 347 | if (fHasPrefix) |
335 | { | 348 | { |
336 | ExitFunction(); | 349 | ExitFunction(); |
337 | } | 350 | } |
338 | 351 | ||
339 | if (fFullyQualified && L':' == wzFullPath[1]) // normal path | 352 | // The prefix is only allowed on fully qualified paths. |
353 | if (!fFullyQualified) | ||
340 | { | 354 | { |
341 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\", 4); | 355 | if (dwPrefixFlags & PATH_PREFIX_EXPECT_FULLY_QUALIFIED) |
342 | PathExitOnFailure(hr, "Failed to add prefix to file path."); | 356 | { |
357 | PathExitWithRootFailure(hr, E_INVALIDARG, "Expected fully qualified path provided to prefix: %ls.", wzFullPath); | ||
358 | } | ||
359 | |||
360 | ExitFunction(); | ||
361 | } | ||
362 | |||
363 | if (!(dwPrefixFlags & PATH_PREFIX_SHORT_PATHS)) | ||
364 | { | ||
365 | // The prefix is not necessary unless the path is longer than MAX_PATH. | ||
366 | if (!cchFullPath) | ||
367 | { | ||
368 | hr = ::StringCchLengthW(wzFullPath, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchFullPath)); | ||
369 | PathExitOnFailure(hr, "Failed to get length of path to prefix."); | ||
370 | } | ||
371 | |||
372 | if (MAX_PATH >= cchFullPath) | ||
373 | { | ||
374 | ExitFunction(); | ||
375 | } | ||
343 | } | 376 | } |
344 | else if (fFullyQualified && IsPathSeparatorChar(wzFullPath[1])) // UNC | 377 | |
378 | if (fUNC) | ||
345 | { | 379 | { |
346 | hr = StrSize(*psczFullPath, &cbFullPath); | 380 | hr = StrSize(*psczFullPath, &cbFullPath); |
347 | PathExitOnFailure(hr, "Failed to get size of full path."); | 381 | PathExitOnFailure(hr, "Failed to get size of full path."); |
@@ -352,10 +386,10 @@ DAPI_(HRESULT) PathPrefix( | |||
352 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\UNC", 7); | 386 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\UNC", 7); |
353 | PathExitOnFailure(hr, "Failed to add prefix to UNC path."); | 387 | PathExitOnFailure(hr, "Failed to add prefix to UNC path."); |
354 | } | 388 | } |
355 | else | 389 | else // must be a normal path |
356 | { | 390 | { |
357 | hr = E_INVALIDARG; | 391 | hr = StrAllocPrefix(psczFullPath, L"\\\\?\\", 4); |
358 | PathExitOnFailure(hr, "Invalid path provided to prefix: %ls.", wzFullPath); | 392 | PathExitOnFailure(hr, "Failed to add prefix to file path."); |
359 | } | 393 | } |
360 | 394 | ||
361 | LExit: | 395 | LExit: |
@@ -970,55 +1004,114 @@ LExit: | |||
970 | } | 1004 | } |
971 | 1005 | ||
972 | 1006 | ||
973 | DAPI_(BOOL) PathIsFullyQualified( | 1007 | DAPI_(LPCWSTR) PathSkipPastRoot( |
974 | __in_z LPCWSTR wzPath, | 1008 | __in_z_opt LPCWSTR wzPath, |
975 | __out_opt BOOL* pfHasLongPathPrefix | 1009 | __out_opt BOOL* pfHasExtendedPrefix, |
1010 | __out_opt BOOL* pfFullyQualified, | ||
1011 | __out_opt BOOL* pfUNC | ||
976 | ) | 1012 | ) |
977 | { | 1013 | { |
1014 | LPCWSTR wzPastRoot = NULL; | ||
1015 | BOOL fHasPrefix = FALSE; | ||
978 | BOOL fFullyQualified = FALSE; | 1016 | BOOL fFullyQualified = FALSE; |
979 | BOOL fHasLongPathPrefix = FALSE; | 1017 | BOOL fUNC = FALSE; |
1018 | DWORD dwRootMissingSlashes = 0; | ||
980 | 1019 | ||
981 | if (!wzPath || !wzPath[0] || !wzPath[1]) | 1020 | if (!wzPath || !*wzPath) |
982 | { | 1021 | { |
983 | // There is no way to specify a fully qualified path with one character (or less). | ||
984 | ExitFunction(); | 1022 | ExitFunction(); |
985 | } | 1023 | } |
986 | 1024 | ||
987 | if (!IsPathSeparatorChar(wzPath[0])) | 1025 | if (IsPathSeparatorChar(wzPath[0])) |
988 | { | 1026 | { |
989 | // The only way to specify a fully qualified path that doesn't begin with a slash | 1027 | if (IsPathSeparatorChar(wzPath[1]) && (L'?' == wzPath[2] || L'.' == wzPath[2]) && IsPathSeparatorChar(wzPath[3]) || |
990 | // is the drive, colon, slash format (C:\). | 1028 | L'?' == wzPath[1] && L'?' == wzPath[2] && IsPathSeparatorChar(wzPath[3])) |
991 | if (IsValidDriveChar(wzPath[0]) && | ||
992 | L':' == wzPath[1] && | ||
993 | IsPathSeparatorChar(wzPath[2])) | ||
994 | { | 1029 | { |
995 | fFullyQualified = TRUE; | 1030 | fHasPrefix = TRUE; |
996 | } | ||
997 | 1031 | ||
998 | ExitFunction(); | 1032 | if (L'U' == wzPath[4] && L'N' == wzPath[5] && L'C' == wzPath[6] && IsPathSeparatorChar(wzPath[7])) |
1033 | { | ||
1034 | fUNC = TRUE; | ||
1035 | wzPastRoot = wzPath + 8; | ||
1036 | dwRootMissingSlashes = 2; | ||
1037 | } | ||
1038 | else | ||
1039 | { | ||
1040 | wzPastRoot = wzPath + 4; | ||
1041 | dwRootMissingSlashes = 1; | ||
1042 | } | ||
1043 | } | ||
1044 | else if (IsPathSeparatorChar(wzPath[1])) | ||
1045 | { | ||
1046 | fUNC = TRUE; | ||
1047 | wzPastRoot = wzPath + 2; | ||
1048 | dwRootMissingSlashes = 2; | ||
1049 | } | ||
999 | } | 1050 | } |
1000 | 1051 | ||
1001 | // Non-drive fully qualified paths must start with \\ or \?. | 1052 | if (dwRootMissingSlashes) |
1002 | // \??\ is an archaic form of \\?\. | ||
1003 | if (L'?' != wzPath[1] && !IsPathSeparatorChar(wzPath[1])) | ||
1004 | { | 1053 | { |
1005 | ExitFunction(); | 1054 | Assert(wzPastRoot); |
1055 | fFullyQualified = TRUE; | ||
1056 | |||
1057 | for (; *wzPastRoot && dwRootMissingSlashes; ++wzPastRoot) | ||
1058 | { | ||
1059 | if (IsPathSeparatorChar(*wzPastRoot)) | ||
1060 | { | ||
1061 | --dwRootMissingSlashes; | ||
1062 | } | ||
1063 | } | ||
1006 | } | 1064 | } |
1065 | else | ||
1066 | { | ||
1067 | Assert(!wzPastRoot); | ||
1007 | 1068 | ||
1008 | fFullyQualified = TRUE; | 1069 | if (IsPathSeparatorChar(wzPath[0])) |
1070 | { | ||
1071 | wzPastRoot = wzPath + 1; | ||
1072 | } | ||
1073 | else if (IsValidDriveChar(wzPath[0]) && wzPath[1] == L':') | ||
1074 | { | ||
1075 | if (IsPathSeparatorChar(wzPath[2])) | ||
1076 | { | ||
1077 | fFullyQualified = TRUE; | ||
1078 | wzPastRoot = wzPath + 3; | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | wzPastRoot = wzPath + 2; | ||
1083 | } | ||
1084 | } | ||
1085 | } | ||
1009 | 1086 | ||
1010 | if (L'?' == wzPath[2] && IsPathSeparatorChar(wzPath[3])) | 1087 | LExit: |
1088 | if (pfHasExtendedPrefix) | ||
1011 | { | 1089 | { |
1012 | fHasLongPathPrefix = TRUE; | 1090 | *pfHasExtendedPrefix = fHasPrefix; |
1013 | } | 1091 | } |
1014 | 1092 | ||
1093 | if (pfFullyQualified) | ||
1094 | { | ||
1095 | *pfFullyQualified = fFullyQualified; | ||
1096 | } | ||
1015 | 1097 | ||
1016 | LExit: | 1098 | if (pfUNC) |
1017 | if (pfHasLongPathPrefix) | ||
1018 | { | 1099 | { |
1019 | *pfHasLongPathPrefix = fHasLongPathPrefix; | 1100 | *pfUNC = fUNC; |
1020 | } | 1101 | } |
1021 | 1102 | ||
1103 | return wzPastRoot; | ||
1104 | } | ||
1105 | |||
1106 | |||
1107 | DAPI_(BOOL) PathIsFullyQualified( | ||
1108 | __in_z LPCWSTR wzPath | ||
1109 | ) | ||
1110 | { | ||
1111 | BOOL fFullyQualified = FALSE; | ||
1112 | |||
1113 | PathSkipPastRoot(wzPath, NULL, &fFullyQualified, NULL); | ||
1114 | |||
1022 | return fFullyQualified; | 1115 | return fFullyQualified; |
1023 | } | 1116 | } |
1024 | 1117 | ||
@@ -1027,9 +1120,7 @@ DAPI_(BOOL) PathIsRooted( | |||
1027 | __in_z LPCWSTR wzPath | 1120 | __in_z LPCWSTR wzPath |
1028 | ) | 1121 | ) |
1029 | { | 1122 | { |
1030 | return wzPath && | 1123 | return NULL != PathSkipPastRoot(wzPath, NULL, NULL, NULL); |
1031 | (IsPathSeparatorChar(wzPath[0]) || | ||
1032 | IsValidDriveChar(wzPath[0]) && wzPath[1] == L':'); | ||
1033 | } | 1124 | } |
1034 | 1125 | ||
1035 | 1126 | ||
@@ -1118,78 +1209,47 @@ DAPI_(HRESULT) PathGetHierarchyArray( | |||
1118 | ) | 1209 | ) |
1119 | { | 1210 | { |
1120 | HRESULT hr = S_OK; | 1211 | HRESULT hr = S_OK; |
1121 | LPWSTR sczPathCopy = NULL; | 1212 | LPCWSTR wz = NULL; |
1122 | LPWSTR sczNewPathCopy = NULL; | 1213 | SIZE_T cch = 0; |
1123 | DWORD cArraySpacesNeeded = 0; | 1214 | *pcPathArray = 0; |
1124 | size_t cchPath = 0; | ||
1125 | 1215 | ||
1126 | hr = ::StringCchLengthW(wzPath, STRSAFE_MAX_LENGTH, &cchPath); | 1216 | PathExitOnNull(wzPath, hr, E_INVALIDARG, "wzPath is required."); |
1127 | PathExitOnRootFailure(hr, "Failed to get string length of path: %ls", wzPath); | ||
1128 | 1217 | ||
1129 | if (!cchPath) | 1218 | wz = PathSkipPastRoot(wzPath, NULL, NULL, NULL); |
1219 | if (wz) | ||
1130 | { | 1220 | { |
1131 | ExitFunction1(hr = E_INVALIDARG); | 1221 | cch = wz - wzPath; |
1132 | } | ||
1133 | 1222 | ||
1134 | for (size_t i = 0; i < cchPath; ++i) | 1223 | hr = MemEnsureArraySize(reinterpret_cast<void**>(prgsczPathArray), 1, sizeof(LPWSTR), 5); |
1135 | { | 1224 | PathExitOnFailure(hr, "Failed to allocate array."); |
1136 | if (IsPathSeparatorChar(wzPath[i])) | ||
1137 | { | ||
1138 | ++cArraySpacesNeeded; | ||
1139 | } | ||
1140 | } | ||
1141 | 1225 | ||
1142 | if (!IsPathSeparatorChar(wzPath[cchPath - 1])) | 1226 | hr = StrAllocString(*prgsczPathArray, wzPath, cch); |
1143 | { | 1227 | PathExitOnFailure(hr, "Failed to copy root into array."); |
1144 | ++cArraySpacesNeeded; | ||
1145 | } | ||
1146 | 1228 | ||
1147 | // If it's a UNC path, cut off the first three paths, 2 because it starts with a double backslash, and another because the first ("\\servername\") isn't a path. | 1229 | *pcPathArray += 1; |
1148 | if (IsPathSeparatorChar(wzPath[0]) && IsPathSeparatorChar(wzPath[1])) | 1230 | } |
1231 | else | ||
1149 | { | 1232 | { |
1150 | if (3 > cArraySpacesNeeded) | 1233 | wz = wzPath; |
1151 | { | ||
1152 | ExitFunction1(hr = E_INVALIDARG); | ||
1153 | } | ||
1154 | |||
1155 | cArraySpacesNeeded -= 3; | ||
1156 | } | 1234 | } |
1157 | 1235 | ||
1158 | Assert(cArraySpacesNeeded >= 1); | 1236 | for (; *wz; ++wz) |
1159 | |||
1160 | hr = MemEnsureArraySize(reinterpret_cast<void **>(prgsczPathArray), cArraySpacesNeeded, sizeof(LPWSTR), 0); | ||
1161 | PathExitOnFailure(hr, "Failed to allocate array of size %u for parent directories", cArraySpacesNeeded); | ||
1162 | *pcPathArray = cArraySpacesNeeded; | ||
1163 | |||
1164 | hr = StrAllocString(&sczPathCopy, wzPath, 0); | ||
1165 | PathExitOnFailure(hr, "Failed to allocate copy of original path"); | ||
1166 | |||
1167 | for (DWORD i = 0; i < cArraySpacesNeeded; ++i) | ||
1168 | { | 1237 | { |
1169 | hr = StrAllocString((*prgsczPathArray) + cArraySpacesNeeded - 1 - i, sczPathCopy, 0); | 1238 | ++cch; |
1170 | PathExitOnFailure(hr, "Failed to copy path"); | ||
1171 | 1239 | ||
1172 | DWORD cchPathCopy = lstrlenW(sczPathCopy); | 1240 | if (IsPathSeparatorChar(*wz) || !wz[1]) |
1173 | |||
1174 | // If it ends in a backslash, it's a directory path, so cut off everything the last backslash before we get the directory portion of the path | ||
1175 | if (IsPathSeparatorChar(wzPath[cchPathCopy - 1])) | ||
1176 | { | 1241 | { |
1177 | sczPathCopy[cchPathCopy - 1] = L'\0'; | 1242 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<void**>(prgsczPathArray), *pcPathArray, 1, sizeof(LPWSTR), 5); |
1178 | } | 1243 | PathExitOnFailure(hr, "Failed to allocate array."); |
1179 | |||
1180 | hr = PathGetDirectory(sczPathCopy, &sczNewPathCopy); | ||
1181 | PathExitOnFailure(hr, "Failed to get directory portion of path"); | ||
1182 | 1244 | ||
1183 | ReleaseStr(sczPathCopy); | 1245 | hr = StrAllocString(*prgsczPathArray + *pcPathArray, wzPath, cch); |
1184 | sczPathCopy = sczNewPathCopy; | 1246 | PathExitOnFailure(hr, "Failed to copy path into array."); |
1185 | sczNewPathCopy = NULL; | ||
1186 | } | ||
1187 | 1247 | ||
1188 | hr = S_OK; | 1248 | *pcPathArray += 1; |
1249 | } | ||
1250 | } | ||
1189 | 1251 | ||
1190 | LExit: | 1252 | LExit: |
1191 | ReleaseStr(sczPathCopy); | ||
1192 | |||
1193 | return hr; | 1253 | return hr; |
1194 | } | 1254 | } |
1195 | 1255 | ||
diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index 2505c6bf..d1d304d3 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | |||
@@ -135,14 +135,22 @@ namespace DutilTests | |||
135 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 135 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
136 | NativeAssert::StringEqual(L"\\\\server\\share\\", sczCanonicalized); | 136 | NativeAssert::StringEqual(L"\\\\server\\share\\", sczCanonicalized); |
137 | 137 | ||
138 | hr = PathCanonicalizeForComparison(L"\\\\.\\share\\otherdir\\unc.exe", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); | 138 | hr = PathCanonicalizeForComparison(L"\\\\.\\UNC\\server\\share\\..\\unc.exe", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); |
139 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 139 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
140 | NativeAssert::StringEqual(L"\\\\.\\share\\otherdir\\unc.exe", sczCanonicalized); | 140 | NativeAssert::StringEqual(L"\\\\?\\UNC\\server\\share\\unc.exe", sczCanonicalized); |
141 | 141 | ||
142 | hr = PathCanonicalizeForComparison(L"\\\\.\\share\\otherdir\\unc.exe", 0, &sczCanonicalized); | 142 | hr = PathCanonicalizeForComparison(L"\\\\..\\share\\otherdir\\unc.exe", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); |
143 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
144 | NativeAssert::StringEqual(L"\\\\..\\share\\otherdir\\unc.exe", sczCanonicalized); | ||
145 | |||
146 | hr = PathCanonicalizeForComparison(L"\\\\..\\share\\otherdir\\unc.exe", 0, &sczCanonicalized); | ||
143 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 147 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
144 | NativeAssert::StringEqual(L"\\\\share\\otherdir\\unc.exe", sczCanonicalized); | 148 | NativeAssert::StringEqual(L"\\\\share\\otherdir\\unc.exe", sczCanonicalized); |
145 | 149 | ||
150 | hr = PathCanonicalizeForComparison(L"\\\\.\\UNC\\share\\otherdir\\unc.exe", 0, &sczCanonicalized); | ||
151 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
152 | NativeAssert::StringEqual(L"\\\\UNC\\share\\otherdir\\unc.exe", sczCanonicalized); | ||
153 | |||
146 | hr = PathCanonicalizeForComparison(L"\\\\server\\share\\..\\..\\otherdir\\unc.exe", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); | 154 | hr = PathCanonicalizeForComparison(L"\\\\server\\share\\..\\..\\otherdir\\unc.exe", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); |
147 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 155 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
148 | NativeAssert::StringEqual(L"\\\\server\\share\\otherdir\\unc.exe", sczCanonicalized); | 156 | NativeAssert::StringEqual(L"\\\\server\\share\\otherdir\\unc.exe", sczCanonicalized); |
@@ -215,7 +223,7 @@ namespace DutilTests | |||
215 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 223 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
216 | NativeAssert::StringEqual(L"C:\\invalid:pathchars?.exe", sczCanonicalized); | 224 | NativeAssert::StringEqual(L"C:\\invalid:pathchars?.exe", sczCanonicalized); |
217 | 225 | ||
218 | hr = PathCanonicalizeForComparison(L"C:\\addprefix.exe", PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX, &sczCanonicalized); | 226 | hr = PathCanonicalizeForComparison(L"C:\\addprefix.exe", PATH_CANONICALIZE_APPEND_EXTENDED_PATH_PREFIX, &sczCanonicalized); |
219 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 227 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
220 | NativeAssert::StringEqual(L"\\\\?\\C:\\addprefix.exe", sczCanonicalized); | 228 | NativeAssert::StringEqual(L"\\\\?\\C:\\addprefix.exe", sczCanonicalized); |
221 | 229 | ||
@@ -312,7 +320,7 @@ namespace DutilTests | |||
312 | LPCWSTR rgwzPaths[8] = | 320 | LPCWSTR rgwzPaths[8] = |
313 | { | 321 | { |
314 | L"C:\\simplepath", L"D:\\simplepath", | 322 | L"C:\\simplepath", L"D:\\simplepath", |
315 | L"\\\\.\\share\\otherdir\\unc.exe", L"\\\\share\\otherdir\\unc.exe", | 323 | L"\\\\..\\share\\otherdir\\unc.exe", L"\\\\share\\otherdir\\unc.exe", |
316 | L"\\\\server\\.\\otherdir\\unc.exe", L"\\\\server\\otherdir\\unc.exe", | 324 | L"\\\\server\\.\\otherdir\\unc.exe", L"\\\\server\\otherdir\\unc.exe", |
317 | L"\\\\server\\\\otherdir\\unc.exe", L"\\\\server\\otherdir\\unc.exe", | 325 | L"\\\\server\\\\otherdir\\unc.exe", L"\\\\server\\otherdir\\unc.exe", |
318 | }; | 326 | }; |
@@ -541,9 +549,10 @@ namespace DutilTests | |||
541 | { | 549 | { |
542 | HRESULT hr = S_OK; | 550 | HRESULT hr = S_OK; |
543 | LPWSTR sczPath = NULL; | 551 | LPWSTR sczPath = NULL; |
544 | LPCWSTR rgwzPaths[18] = | 552 | LPCWSTR rgwzPaths[20] = |
545 | { | 553 | { |
546 | L"C:\\a\\b", L"C:\\a\\", | 554 | L"C:\\a\\b", L"C:\\a\\", |
555 | L"C:\\a\\b\\", L"C:\\a\\b\\", | ||
547 | L"C:\\a", L"C:\\", | 556 | L"C:\\a", L"C:\\", |
548 | L"C:\\", L"C:\\", | 557 | L"C:\\", L"C:\\", |
549 | L"\"C:\\a\\b\\c\"", L"\"C:\\a\\b\\", | 558 | L"\"C:\\a\\b\\c\"", L"\"C:\\a\\b\\", |
@@ -570,6 +579,40 @@ namespace DutilTests | |||
570 | } | 579 | } |
571 | 580 | ||
572 | [Fact] | 581 | [Fact] |
582 | void PathGetParentPathTest() | ||
583 | { | ||
584 | HRESULT hr = S_OK; | ||
585 | LPWSTR sczPath = NULL; | ||
586 | LPCWSTR rgwzPaths[20] = | ||
587 | { | ||
588 | L"C:\\a\\b", L"C:\\a\\", | ||
589 | L"C:\\a\\b\\", L"C:\\a\\", | ||
590 | L"C:\\a", L"C:\\", | ||
591 | L"C:\\", NULL, | ||
592 | L"\"C:\\a\\b\\c\"", L"\"C:\\a\\b\\", | ||
593 | L"\"C:\\a\\b\\\"c", L"\"C:\\a\\b\\", | ||
594 | L"\"C:\\a\\b\"\\c", L"\"C:\\a\\b\"\\", | ||
595 | L"\"C:\\a\\\"b\\c", L"\"C:\\a\\\"b\\", | ||
596 | L"C:\\a\"\\\"b\\c", L"C:\\a\"\\\"b\\", | ||
597 | L"C:\\a\"\\b\\c\"", L"C:\\a\"\\b\\", | ||
598 | }; | ||
599 | |||
600 | try | ||
601 | { | ||
602 | for (DWORD i = 0; i < countof(rgwzPaths); i += 2) | ||
603 | { | ||
604 | hr = PathGetParentPath(rgwzPaths[i], &sczPath, NULL); | ||
605 | NativeAssert::Succeeded(hr, "PathGetParentPath: {0}", rgwzPaths[i]); | ||
606 | NativeAssert::StringEqual(rgwzPaths[i + 1], sczPath); | ||
607 | } | ||
608 | } | ||
609 | finally | ||
610 | { | ||
611 | ReleaseStr(sczPath); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | [Fact] | ||
573 | void PathGetFullPathNameTest() | 616 | void PathGetFullPathNameTest() |
574 | { | 617 | { |
575 | HRESULT hr = S_OK; | 618 | HRESULT hr = S_OK; |
@@ -693,6 +736,12 @@ namespace DutilTests | |||
693 | NativeAssert::StringEqual(L"Software\\Microsoft\\Windows\\", rgsczPaths[2]); | 736 | NativeAssert::StringEqual(L"Software\\Microsoft\\Windows\\", rgsczPaths[2]); |
694 | ReleaseNullStrArray(rgsczPaths, cPaths); | 737 | ReleaseNullStrArray(rgsczPaths, cPaths); |
695 | 738 | ||
739 | hr = PathGetHierarchyArray(L"Software", &rgsczPaths, &cPaths); | ||
740 | NativeAssert::Succeeded(hr, "Failed to get parent directories array for relative path"); | ||
741 | Assert::Equal<DWORD>(1, cPaths); | ||
742 | NativeAssert::StringEqual(L"Software", rgsczPaths[0]); | ||
743 | ReleaseNullStrArray(rgsczPaths, cPaths); | ||
744 | |||
696 | hr = PathGetHierarchyArray(L"c:/foo/bar/bas/a.txt", &rgsczPaths, &cPaths); | 745 | hr = PathGetHierarchyArray(L"c:/foo/bar/bas/a.txt", &rgsczPaths, &cPaths); |
697 | NativeAssert::Succeeded(hr, "Failed to get parent directories array for regular file path"); | 746 | NativeAssert::Succeeded(hr, "Failed to get parent directories array for regular file path"); |
698 | Assert::Equal<DWORD>(5, cPaths); | 747 | Assert::Equal<DWORD>(5, cPaths); |
@@ -832,8 +881,12 @@ namespace DutilTests | |||
832 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | 881 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); |
833 | NativeAssert::Succeeded(hr, "Failed to copy string"); | 882 | NativeAssert::Succeeded(hr, "Failed to copy string"); |
834 | 883 | ||
835 | hr = PathPrefix(&sczPath); | 884 | hr = PathPrefix(&sczPath, 0, 0); |
836 | NativeAssert::Succeeded(hr, "PathPrefix: {0}", rgwzPaths[i]); | 885 | NativeAssert::Succeeded(hr, "PathPrefix: {0}", rgwzPaths[i]); |
886 | NativeAssert::StringEqual(rgwzPaths[i], sczPath); | ||
887 | |||
888 | hr = PathPrefix(&sczPath, 0, PATH_PREFIX_SHORT_PATHS); | ||
889 | NativeAssert::Succeeded(hr, "PathPrefix (SHORT_PATHS): {0}", rgwzPaths[i]); | ||
837 | NativeAssert::StringEqual(rgwzPaths[i + 1], sczPath); | 890 | NativeAssert::StringEqual(rgwzPaths[i + 1], sczPath); |
838 | } | 891 | } |
839 | } | 892 | } |
@@ -871,7 +924,7 @@ namespace DutilTests | |||
871 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | 924 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); |
872 | NativeAssert::Succeeded(hr, "Failed to copy string"); | 925 | NativeAssert::Succeeded(hr, "Failed to copy string"); |
873 | 926 | ||
874 | hr = PathPrefix(&sczPath); | 927 | hr = PathPrefix(&sczPath, 0, PATH_PREFIX_EXPECT_FULLY_QUALIFIED); |
875 | NativeAssert::SpecificReturnCode(E_INVALIDARG, hr, "PathPrefix: {0}, {1}", rgwzPaths[i], sczPath); | 928 | NativeAssert::SpecificReturnCode(E_INVALIDARG, hr, "PathPrefix: {0}, {1}", rgwzPaths[i], sczPath); |
876 | } | 929 | } |
877 | } | 930 | } |
@@ -884,187 +937,152 @@ namespace DutilTests | |||
884 | [Fact] | 937 | [Fact] |
885 | void PathIsRootedAndFullyQualifiedTest() | 938 | void PathIsRootedAndFullyQualifiedTest() |
886 | { | 939 | { |
887 | HRESULT hr = S_OK; | 940 | LPCWSTR rgwzPaths[30] = |
888 | LPWSTR sczPath = NULL; | 941 | { |
889 | LPCWSTR rgwzPaths[15] = | 942 | L"//", L"", |
890 | { | 943 | L"///", L"", |
891 | L"//", | 944 | L"C:/", L"", |
892 | L"///", | 945 | L"C://", L"/", |
893 | L"C:/", | 946 | L"C:/foo1", L"foo1", |
894 | L"C://", | 947 | L"C://foo2", L"/foo2", |
895 | L"C:/foo1", | 948 | L"//test/unc/path/to/something", L"path/to/something", |
896 | L"C://foo2", | 949 | L"//a/b/c/d/e", L"c/d/e", |
897 | L"//test/unc/path/to/something", | 950 | L"//a/b/", L"", |
898 | L"//a/b/c/d/e", | 951 | L"//a/b", L"", |
899 | L"//a/b/", | 952 | L"//test/unc", L"", |
900 | L"//a/b", | 953 | L"//Server", L"", |
901 | L"//test/unc", | 954 | L"//Server/Foo.txt", L"", |
902 | L"//Server", | 955 | L"//Server/Share/Foo.txt", L"Foo.txt", |
903 | L"//Server/Foo.txt", | 956 | L"//Server/Share/Test/Foo.txt", L"Test/Foo.txt", |
904 | L"//Server/Share/Foo.txt", | ||
905 | L"//Server/Share/Test/Foo.txt", | ||
906 | }; | 957 | }; |
907 | 958 | ||
908 | try | 959 | ValidateSkipPastRoot(rgwzPaths, countof(rgwzPaths), FALSE, TRUE, TRUE); |
909 | { | ||
910 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
911 | { | ||
912 | ValidateFullyQualifiedPath(rgwzPaths[i], TRUE, FALSE); | ||
913 | ValidateRootedPath(rgwzPaths[i], TRUE); | ||
914 | |||
915 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | ||
916 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
917 | |||
918 | PathFixedReplaceForwardSlashes(sczPath); | ||
919 | ValidateFullyQualifiedPath(sczPath, TRUE, FALSE); | ||
920 | ValidateRootedPath(sczPath, TRUE); | ||
921 | } | ||
922 | } | ||
923 | finally | ||
924 | { | ||
925 | ReleaseStr(sczPath); | ||
926 | } | ||
927 | } | 960 | } |
928 | 961 | ||
929 | [Fact] | 962 | [Fact] |
930 | void PathIsRootedAndFullyQualifiedWithPrefixTest() | 963 | void PathIsRootedAndFullyQualifiedWithPrefixTest() |
931 | { | 964 | { |
932 | HRESULT hr = S_OK; | 965 | LPCWSTR rgwzPaths[12] = |
933 | LPWSTR sczPath = NULL; | ||
934 | LPCWSTR rgwzPaths[6] = | ||
935 | { | 966 | { |
936 | L"//?/UNC/test/unc/path/to/something", | 967 | L"//?/UNC/test/unc/path/to/something", L"path/to/something", |
937 | L"//?/UNC/test/unc", | 968 | L"//?/UNC/test/unc", L"", |
938 | L"//?/UNC/a/b1", | 969 | L"//?/UNC/a/b1", L"", |
939 | L"//?/UNC/a/b2/", | 970 | L"//?/UNC/a/b2/", L"", |
940 | L"//?/C:/foo/bar.txt", | 971 | L"//?/C:/foo/bar.txt", L"foo/bar.txt", |
941 | L"/??/C:/foo/bar.txt", | 972 | L"/??/C:/foo/bar.txt", L"foo/bar.txt", |
942 | }; | 973 | }; |
943 | 974 | ||
944 | try | 975 | ValidateSkipPastRoot(rgwzPaths, countof(rgwzPaths), TRUE, TRUE, TRUE); |
945 | { | ||
946 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
947 | { | ||
948 | ValidateFullyQualifiedPath(rgwzPaths[i], TRUE, TRUE); | ||
949 | ValidateRootedPath(rgwzPaths[i], TRUE); | ||
950 | |||
951 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | ||
952 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
953 | |||
954 | PathFixedReplaceForwardSlashes(sczPath); | ||
955 | ValidateFullyQualifiedPath(sczPath, TRUE, TRUE); | ||
956 | ValidateRootedPath(sczPath, TRUE); | ||
957 | } | ||
958 | } | ||
959 | finally | ||
960 | { | ||
961 | ReleaseStr(sczPath); | ||
962 | } | ||
963 | } | 976 | } |
964 | 977 | ||
965 | [Fact] | 978 | [Fact] |
966 | void PathIsRootedButNotFullyQualifiedTest() | 979 | void PathIsRootedButNotFullyQualifiedTest() |
967 | { | 980 | { |
968 | HRESULT hr = S_OK; | 981 | LPCWSTR rgwzPaths[14] = |
969 | LPWSTR sczPath = NULL; | ||
970 | LPCWSTR rgwzPaths[7] = | ||
971 | { | 982 | { |
972 | L"/", | 983 | L"/", L"", |
973 | L"a:", | 984 | L"a:", L"", |
974 | L"A:", | 985 | L"A:", L"", |
975 | L"z:", | 986 | L"z:", L"", |
976 | L"Z:", | 987 | L"Z:", L"", |
977 | L"C:foo.txt", | 988 | L"C:foo.txt", L"foo.txt", |
978 | L"/dir", | 989 | L"/dir", L"dir", |
979 | }; | 990 | }; |
980 | 991 | ||
981 | try | 992 | ValidateSkipPastRoot(rgwzPaths, countof(rgwzPaths), FALSE, FALSE, TRUE); |
982 | { | ||
983 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | ||
984 | { | ||
985 | ValidateFullyQualifiedPath(rgwzPaths[i], FALSE, FALSE); | ||
986 | ValidateRootedPath(rgwzPaths[i], TRUE); | ||
987 | |||
988 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | ||
989 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
990 | |||
991 | PathFixedReplaceForwardSlashes(sczPath); | ||
992 | ValidateFullyQualifiedPath(sczPath, FALSE, FALSE); | ||
993 | ValidateRootedPath(sczPath, TRUE); | ||
994 | } | ||
995 | } | ||
996 | finally | ||
997 | { | ||
998 | ReleaseStr(sczPath); | ||
999 | } | ||
1000 | } | 993 | } |
1001 | 994 | ||
1002 | [Fact] | 995 | [Fact] |
1003 | void PathIsNotRootedAndNotFullyQualifiedTest() | 996 | void PathIsNotRootedAndNotFullyQualifiedTest() |
1004 | { | 997 | { |
1005 | HRESULT hr = S_OK; | 998 | LPCWSTR rgwzPaths[18] = |
1006 | LPWSTR sczPath = NULL; | ||
1007 | LPCWSTR rgwzPaths[9] = | ||
1008 | { | 999 | { |
1009 | NULL, | 1000 | NULL, NULL, |
1010 | L"", | 1001 | L"", NULL, |
1011 | L"dir", | 1002 | L"dir", NULL, |
1012 | L"dir/subdir", | 1003 | L"dir/subdir", NULL, |
1013 | L"@:/foo", // 064 = @ 065 = A | 1004 | L"@:/foo", NULL, // 064 = @ 065 = A |
1014 | L"[://", // 091 = [ 090 = Z | 1005 | L"[://", NULL, // 091 = [ 090 = Z |
1015 | L"`:/foo ", // 096 = ` 097 = a | 1006 | L"`:/foo ", NULL, // 096 = ` 097 = a |
1016 | L"{://", // 123 = { 122 = z | 1007 | L"{://", NULL, // 123 = { 122 = z |
1017 | L"[:", | 1008 | L"[:", NULL, |
1018 | }; | 1009 | }; |
1019 | 1010 | ||
1011 | ValidateSkipPastRoot(rgwzPaths, countof(rgwzPaths), FALSE, FALSE, FALSE); | ||
1012 | } | ||
1013 | |||
1014 | void ValidateSkipPastRoot(LPCWSTR* rgwzPaths, DWORD cPaths, BOOL fExpectedPrefix, BOOL fExpectedFullyQualified, BOOL fExpectedRooted) | ||
1015 | { | ||
1016 | HRESULT hr = S_OK; | ||
1017 | LPWSTR sczPath = NULL; | ||
1018 | LPWSTR sczSkipRootPath = NULL; | ||
1019 | LPCWSTR wzSkipRootPath = NULL; | ||
1020 | BOOL fHasPrefix = FALSE; | ||
1021 | |||
1020 | try | 1022 | try |
1021 | { | 1023 | { |
1022 | for (DWORD i = 0; i < countof(rgwzPaths); ++i) | 1024 | for (DWORD i = 0; i < cPaths; i += 2) |
1023 | { | 1025 | { |
1024 | ValidateFullyQualifiedPath(rgwzPaths[i], FALSE, FALSE); | 1026 | wzSkipRootPath = PathSkipPastRoot(rgwzPaths[i], &fHasPrefix, NULL, NULL); |
1025 | ValidateRootedPath(rgwzPaths[i], FALSE); | 1027 | NativeAssert::StringEqual(rgwzPaths[i + 1], wzSkipRootPath); |
1028 | ValidateExtendedPrefixPath(rgwzPaths[i], fExpectedPrefix, fHasPrefix); | ||
1029 | ValidateFullyQualifiedPath(rgwzPaths[i], fExpectedFullyQualified); | ||
1030 | ValidateRootedPath(rgwzPaths[i], fExpectedRooted); | ||
1026 | 1031 | ||
1027 | if (!rgwzPaths[i]) | 1032 | if (rgwzPaths[i]) |
1028 | { | 1033 | { |
1029 | continue; | 1034 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); |
1035 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
1036 | |||
1037 | PathFixedReplaceForwardSlashes(sczPath); | ||
1030 | } | 1038 | } |
1031 | 1039 | ||
1032 | hr = StrAllocString(&sczPath, rgwzPaths[i], 0); | 1040 | if (rgwzPaths[i + 1]) |
1033 | NativeAssert::Succeeded(hr, "Failed to copy string"); | 1041 | { |
1042 | hr = StrAllocString(&sczSkipRootPath, rgwzPaths[i + 1], 0); | ||
1043 | NativeAssert::Succeeded(hr, "Failed to copy string"); | ||
1034 | 1044 | ||
1035 | PathFixedReplaceForwardSlashes(sczPath); | 1045 | PathFixedReplaceForwardSlashes(sczSkipRootPath); |
1036 | ValidateFullyQualifiedPath(sczPath, FALSE, FALSE); | 1046 | } |
1037 | ValidateRootedPath(sczPath, FALSE); | 1047 | |
1048 | wzSkipRootPath = PathSkipPastRoot(sczPath, &fHasPrefix, NULL, NULL); | ||
1049 | NativeAssert::StringEqual(sczSkipRootPath, wzSkipRootPath); | ||
1050 | ValidateExtendedPrefixPath(sczPath, fExpectedPrefix, fHasPrefix); | ||
1051 | ValidateFullyQualifiedPath(sczPath, fExpectedFullyQualified); | ||
1052 | ValidateRootedPath(sczPath, fExpectedRooted); | ||
1038 | } | 1053 | } |
1039 | } | 1054 | } |
1040 | finally | 1055 | finally |
1041 | { | 1056 | { |
1042 | ReleaseStr(sczPath); | 1057 | ReleaseStr(sczPath); |
1058 | ReleaseStr(sczSkipRootPath); | ||
1043 | } | 1059 | } |
1044 | } | 1060 | } |
1045 | 1061 | ||
1046 | void ValidateFullyQualifiedPath(LPCWSTR wzPath, BOOL fExpected, BOOL fExpectedHasPrefix) | 1062 | void ValidateExtendedPrefixPath(LPCWSTR wzPath, BOOL fExpected, BOOL fHasExtendedPrefix) |
1047 | { | 1063 | { |
1048 | BOOL fHasLongPathPrefix = FALSE; | 1064 | String^ message = String::Format("HasExtendedPrefix: {0}", gcnew String(wzPath)); |
1049 | BOOL fRooted = PathIsFullyQualified(wzPath, &fHasLongPathPrefix); | ||
1050 | String^ message = String::Format("IsFullyQualified: {0}", gcnew String(wzPath)); | ||
1051 | if (fExpected) | 1065 | if (fExpected) |
1052 | { | 1066 | { |
1053 | Assert::True(fRooted, message); | 1067 | Assert::True(fHasExtendedPrefix, message); |
1054 | } | 1068 | } |
1055 | else | 1069 | else |
1056 | { | 1070 | { |
1057 | Assert::False(fRooted, message); | 1071 | Assert::False(fHasExtendedPrefix, message); |
1058 | } | 1072 | } |
1073 | } | ||
1059 | 1074 | ||
1060 | message = String::Format("HasLongPathPrefix: {0}", gcnew String(wzPath)); | 1075 | void ValidateFullyQualifiedPath(LPCWSTR wzPath, BOOL fExpected) |
1061 | if (fExpectedHasPrefix) | 1076 | { |
1077 | BOOL fRooted = PathIsFullyQualified(wzPath); | ||
1078 | String^ message = String::Format("IsFullyQualified: {0}", gcnew String(wzPath)); | ||
1079 | if (fExpected) | ||
1062 | { | 1080 | { |
1063 | Assert::True(fHasLongPathPrefix, message); | 1081 | Assert::True(fRooted, message); |
1064 | } | 1082 | } |
1065 | else | 1083 | else |
1066 | { | 1084 | { |
1067 | Assert::False(fHasLongPathPrefix, message); | 1085 | Assert::False(fRooted, message); |
1068 | } | 1086 | } |
1069 | } | 1087 | } |
1070 | 1088 | ||