From dea25f58e6119ef1acc5c5cc2a7c98e52cdff519 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Thu, 26 May 2022 17:33:41 -0500 Subject: Add PathCanonicalizeForComparison. --- src/libs/dutil/WixToolset.DUtil/path2utl.cpp | 149 ++++++++++++++++++++------- 1 file changed, 114 insertions(+), 35 deletions(-) (limited to 'src/libs/dutil/WixToolset.DUtil/path2utl.cpp') diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp index ff3a946d..45157d0b 100644 --- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp +++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp @@ -9,6 +9,7 @@ #define PathExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) #define PathExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) #define PathExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) +#define PathExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, e, s, __VA_ARGS__) #define PathExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__) #define PathExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__) #define PathExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__) @@ -42,63 +43,141 @@ LExit: return hr; } -DAPI_(HRESULT) PathDirectoryContainsPath( - __in_z LPCWSTR wzDirectory, - __in_z LPCWSTR wzPath +DAPI_(HRESULT) PathCanonicalizeForComparison( + __in_z LPCWSTR wzPath, + __in DWORD dwCanonicalizeFlags, + __deref_out_z LPWSTR* psczCanonicalized ) { HRESULT hr = S_OK; - LPWSTR sczPath = NULL; - LPWSTR sczDirectory = NULL; - LPWSTR sczOriginalPath = NULL; - LPWSTR sczOriginalDirectory = NULL; + LPWSTR sczNormalizedPath = NULL; + LPCWSTR wzNormalizedPath = NULL; + SIZE_T cchUncRootLength = 0; + BOOL fHasPrefix = FALSE; - hr = PathCanonicalizePath(wzPath, &sczOriginalPath); - PathExitOnFailure(hr, "Failed to canonicalize the path."); + hr = StrAllocString(&sczNormalizedPath, wzPath, 0); + PathExitOnFailure(hr, "Failed to allocate string for the normalized path."); - hr = PathCanonicalizePath(wzDirectory, &sczOriginalDirectory); - PathExitOnFailure(hr, "Failed to canonicalize the directory."); + PathFixedNormalizeSlashes(sczNormalizedPath); + + wzNormalizedPath = sczNormalizedPath; - if (!sczOriginalPath || !*sczOriginalPath) + if (PATH_CANONICALIZE_KEEP_UNC_ROOT & dwCanonicalizeFlags) { - ExitFunction1(hr = S_FALSE); + if (L'\\' == sczNormalizedPath[0] && (L'\\' == sczNormalizedPath[1] || L'?' == sczNormalizedPath[1]) && L'?' == sczNormalizedPath[2] && L'\\' == sczNormalizedPath[3]) + { + if (L'U' == sczNormalizedPath[4] && L'N' == sczNormalizedPath[5] && L'C' == sczNormalizedPath[6] && L'\\' == sczNormalizedPath[7]) + { + cchUncRootLength = 8; + } + } + else if (L'\\' == sczNormalizedPath[0] && L'\\' == sczNormalizedPath[1]) + { + cchUncRootLength = 2; + } + + if (cchUncRootLength) + { + DWORD dwRemainingSlashes = 2; + + for (wzNormalizedPath += cchUncRootLength; *wzNormalizedPath && dwRemainingSlashes; ++wzNormalizedPath) + { + ++cchUncRootLength; + + if (L'\\' == *wzNormalizedPath) + { + --dwRemainingSlashes; + } + } + } + } + + if (*wzNormalizedPath) + { + hr = PathCanonicalizePath(wzNormalizedPath, psczCanonicalized); + PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzNormalizedPath); } - if (!sczOriginalDirectory || !*sczOriginalDirectory) + else { - ExitFunction1(hr = S_FALSE); + Assert(cchUncRootLength); + ReleaseStr(*psczCanonicalized); + *psczCanonicalized = sczNormalizedPath; + sczNormalizedPath = NULL; + cchUncRootLength = 0; } - sczPath = sczOriginalPath; - sczDirectory = sczOriginalDirectory; + if (cchUncRootLength) + { + hr = StrAllocPrefix(psczCanonicalized, sczNormalizedPath, cchUncRootLength); + PathExitOnFailure(hr, "Failed to prefix the UNC root to the canonicalized path."); + } - for (; *sczDirectory;) + if (PATH_CANONICALIZE_BACKSLASH_TERMINATE & dwCanonicalizeFlags) { - if (!*sczPath) - { - ExitFunction1(hr = S_FALSE); - } + hr = PathBackslashTerminate(psczCanonicalized); + PathExitOnFailure(hr, "Failed to backslash terminate the canonicalized path"); + } - if (CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, sczDirectory, 1, sczPath, 1)) - { - ExitFunction1(hr = S_FALSE); - } + if ((PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX & dwCanonicalizeFlags) && + PathIsFullyQualified(*psczCanonicalized, &fHasPrefix) && !fHasPrefix) + { + hr = PathPrefix(psczCanonicalized); + PathExitOnFailure(hr, "Failed to ensure the long path prefix on the canonicalized path"); + } + +LExit: + ReleaseStr(sczNormalizedPath); - ++sczDirectory; - ++sczPath; + return hr; +} + +DAPI_(HRESULT) PathDirectoryContainsPath( + __in_z LPCWSTR wzDirectory, + __in_z LPCWSTR wzPath + ) +{ + HRESULT hr = S_OK; + LPWSTR sczCanonicalizedDirectory = NULL; + LPWSTR sczCanonicalizedPath = NULL; + DWORD dwDefaultFlags = PATH_CANONICALIZE_APPEND_LONG_PATH_PREFIX | PATH_CANONICALIZE_KEEP_UNC_ROOT; + size_t cchDirectory = 0; + + if (!wzDirectory || !*wzDirectory) + { + PathExitWithRootFailure(hr, E_INVALIDARG, "wzDirectory is required."); } + if (!wzPath || !*wzPath) + { + PathExitWithRootFailure(hr, E_INVALIDARG, "wzPath is required."); + } + + hr = PathCanonicalizeForComparison(wzDirectory, dwDefaultFlags | PATH_CANONICALIZE_BACKSLASH_TERMINATE, &sczCanonicalizedDirectory); + PathExitOnFailure(hr, "Failed to canonicalize the directory."); - --sczDirectory; - if (('\\' == *sczDirectory && *sczPath) || '\\' == *sczPath) + hr = PathCanonicalizeForComparison(wzPath, dwDefaultFlags, &sczCanonicalizedPath); + PathExitOnFailure(hr, "Failed to canonicalize the path."); + + if (!PathIsFullyQualified(sczCanonicalizedDirectory, NULL)) { - hr = S_OK; + PathExitWithRootFailure(hr, E_INVALIDARG, "wzDirectory must be a fully qualified path."); } - else + if (!sczCanonicalizedPath || !*sczCanonicalizedPath) { - hr = S_FALSE; + ExitFunction1(hr = S_FALSE); } + hr = ::StringCchLengthW(sczCanonicalizedDirectory, STRSAFE_MAX_CCH, &cchDirectory); + PathExitOnFailure(hr, "Failed to get length of canonicalized directory."); + + if (CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, sczCanonicalizedDirectory, (DWORD)cchDirectory, sczCanonicalizedPath, (DWORD)cchDirectory)) + { + ExitFunction1(hr = S_FALSE); + } + + hr = sczCanonicalizedPath[cchDirectory] ? S_OK : S_FALSE; + LExit: - ReleaseStr(sczOriginalPath); - ReleaseStr(sczOriginalDirectory); + ReleaseStr(sczCanonicalizedPath); + ReleaseStr(sczCanonicalizedDirectory); return hr; } -- cgit v1.2.3-55-g6feb