From 90982fbf1c887a3ed3454f9ab3ab8dfbd57a1383 Mon Sep 17 00:00:00 2001 From: Sean Hall <r.sean.hall@gmail.com> Date: Thu, 26 May 2022 17:34:48 -0500 Subject: Add PathConcatRelativeToBase and use it in Burn. Fixes 6707 --- src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | 11 +++ src/libs/dutil/WixToolset.DUtil/path2utl.cpp | 40 ++++++++ src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | 107 +++++++++++++++++++++ 3 files changed, 158 insertions(+) (limited to 'src/libs') diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index fc6bb3bb..941793f8 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h @@ -236,6 +236,17 @@ DAPI_(HRESULT) PathConcatCch( __deref_out_z LPWSTR* psczCombined ); +/******************************************************************* + PathConcatRelativeToBase - canonicalizes a relative path before + concatenating it to the base path to ensure the resulting path + is inside the base path. +*******************************************************************/ +DAPI_(HRESULT) PathConcatRelativeToBase( + __in LPCWSTR wzBase, + __in_opt LPCWSTR wzRelative, + __deref_out_z LPWSTR* psczCombined + ); + /******************************************************************* PathCompare - compares the fully expanded path of the two paths using ::CompareStringW(). diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp index 45157d0b..61c1803a 100644 --- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp +++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp @@ -131,6 +131,46 @@ LExit: return hr; } +DAPI_(HRESULT) PathConcatRelativeToBase( + __in LPCWSTR wzBase, + __in_opt LPCWSTR wzRelative, + __deref_out_z LPWSTR* psczCombined + ) +{ + HRESULT hr = S_OK; + LPWSTR sczCanonicalizedRelative = NULL; + + if (!wzBase || !*wzBase) + { + PathExitWithRootFailure(hr, E_INVALIDARG, "wzBase is required."); + } + + if (PathIsRooted(wzRelative)) + { + PathExitWithRootFailure(hr, E_INVALIDARG, "wzRelative cannot be rooted."); + } + + hr = StrAllocString(psczCombined, wzBase, 0); + PathExitOnFailure(hr, "Failed to copy base to output."); + + if (wzRelative && *wzRelative) + { + hr = PathBackslashTerminate(psczCombined); + PathExitOnFailure(hr, "Failed to backslashify."); + + hr = PathCanonicalizeForComparison(wzRelative, 0, &sczCanonicalizedRelative); + PathExitOnFailure(hr, "Failed to canonicalize wzRelative."); + + hr = StrAllocConcat(psczCombined, sczCanonicalizedRelative, 0); + PathExitOnFailure(hr, "Failed to append relative to output."); + } + +LExit: + ReleaseStr(sczCanonicalizedRelative); + + return hr; +} + DAPI_(HRESULT) PathDirectoryContainsPath( __in_z LPCWSTR wzDirectory, __in_z LPCWSTR wzPath diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index 04d0b447..52698b98 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp @@ -220,6 +220,113 @@ namespace DutilTests } } + [Fact] + void PathConcatTest() + { + HRESULT hr = S_OK; + LPWSTR sczPath = NULL; + LPCWSTR rgwzPaths[54] = + { + L"a", NULL, L"a", + L"a", L"", L"a", + L"C:\\", L"a", L"C:\\a", + L"\\a", L"b", L"\\a\\b", + L"a", L"b", L"a\\b", + L"C:\\", L"..\\a", L"C:\\..\\a", + L"C:\\a", L"..\\b", L"C:\\a\\..\\b", + L"\\\\server\\share", L"..\\a", L"\\\\server\\share\\..\\a", + L"\\\\server\\share\\a", L"..\\b", L"\\\\server\\share\\a\\..\\b", + NULL, L"b", L"b", + L"", L"b", L"b", + L"a", L"\\b", L"\\b", + L"a", L"b:", L"b:", + L"a", L"b:\\", L"b:\\", + L"a", L"\\\\?\\b", L"\\\\?\\b", + L"a", L"\\\\?\\UNC\\b", L"\\\\?\\UNC\\b", + L"a", L"\\b", L"\\b", + L"a", L"\\\\", L"\\\\", + }; + + try + { + for (DWORD i = 0; i < countof(rgwzPaths); i += 3) + { + hr = PathConcat(rgwzPaths[i], rgwzPaths[i + 1], &sczPath); + NativeAssert::Succeeded(hr, "PathConcat: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]); + NativeAssert::StringEqual(rgwzPaths[i + 2], sczPath); + } + } + finally + { + ReleaseStr(sczPath); + } + } + + [Fact] + void PathConcatRelativeToBaseTest() + { + HRESULT hr = S_OK; + LPWSTR sczPath = NULL; + LPCWSTR rgwzPaths[27] = + { + L"a", NULL, L"a", + L"a", L"", L"a", + L"C:\\", L"a", L"C:\\a", + L"\\a", L"b", L"\\a\\b", + L"a", L"b", L"a\\b", + L"C:\\", L"..\\a", L"C:\\a", + L"C:\\a", L"..\\b", L"C:\\a\\b", + L"\\\\server\\share", L"..\\a", L"\\\\server\\share\\a", + L"\\\\server\\share\\a", L"..\\b", L"\\\\server\\share\\a\\b", + }; + + try + { + for (DWORD i = 0; i < countof(rgwzPaths); i += 3) + { + hr = PathConcatRelativeToBase(rgwzPaths[i], rgwzPaths[i + 1], &sczPath); + NativeAssert::Succeeded(hr, "PathConcatRelativeToBase: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]); + NativeAssert::StringEqual(rgwzPaths[i + 2], sczPath); + } + } + finally + { + ReleaseStr(sczPath); + } + } + + [Fact] + void PathConcatRelativeToBaseFailureTest() + { + HRESULT hr = S_OK; + LPWSTR sczPath = NULL; + LPCWSTR rgwzPaths[18] = + { + NULL, L"b", + L"", L"b", + L"a", L"\\b", + L"a", L"b:", + L"a", L"b:\\", + L"a", L"\\\\?\\b", + L"a", L"\\\\?\\UNC\\b", + L"a", L"\\b", + L"a", L"\\\\", + }; + + try + { + for (DWORD i = 0; i < countof(rgwzPaths); i += 2) + { + hr = PathConcatRelativeToBase(rgwzPaths[i], rgwzPaths[i + 1], &sczPath); + NativeAssert::SpecificReturnCode(hr, E_INVALIDARG, "PathConcatRelativeToBase: {0}, {1}", rgwzPaths[i], rgwzPaths[i + 1]); + } + } + finally + { + ReleaseStr(sczPath); + } + } + [Fact] void PathDirectoryContainsPathTest() { -- cgit v1.2.3-55-g6feb