diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-05-03 09:55:22 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-05-03 09:55:22 -0700 |
| commit | ff659159e041bf6c083e6b7fcb9b726065a9dd73 (patch) | |
| tree | ea95bf3d3e031edcee65de33b9e6954178be669c /src/ext/Util/ca/RemoveFoldersEx.cpp | |
| parent | 8a8a25695351ee542f08886a9d0957c78c6af366 (diff) | |
| download | wix-ff659159e041bf6c083e6b7fcb9b726065a9dd73.tar.gz wix-ff659159e041bf6c083e6b7fcb9b726065a9dd73.tar.bz2 wix-ff659159e041bf6c083e6b7fcb9b726065a9dd73.zip | |
Move Util.wixext into ext
Diffstat (limited to 'src/ext/Util/ca/RemoveFoldersEx.cpp')
| -rw-r--r-- | src/ext/Util/ca/RemoveFoldersEx.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/src/ext/Util/ca/RemoveFoldersEx.cpp b/src/ext/Util/ca/RemoveFoldersEx.cpp new file mode 100644 index 00000000..cbc7f4bb --- /dev/null +++ b/src/ext/Util/ca/RemoveFoldersEx.cpp | |||
| @@ -0,0 +1,243 @@ | |||
| 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 | LPCWSTR vcsRemoveFolderExQuery = | ||
| 6 | L"SELECT `Wix4RemoveFolderEx`, `Component_`, `Property`, `InstallMode`, `WixRemoveFolderEx`.`Condition`, `Component`.`Attributes`" | ||
| 7 | L"FROM `Wix4RemoveFolderEx``,`Component` " | ||
| 8 | L"WHERE `Wix4RemoveFolderEx`.`Component_`=`Component`.`Component`"; | ||
| 9 | enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, rfqMode, rfqCondition, rfqComponentAttributes }; | ||
| 10 | |||
| 11 | static HRESULT RecursePath( | ||
| 12 | __in_z LPCWSTR wzPath, | ||
| 13 | __in_z LPCWSTR wzId, | ||
| 14 | __in_z LPCWSTR wzComponent, | ||
| 15 | __in_z LPCWSTR wzProperty, | ||
| 16 | __in int iMode, | ||
| 17 | __in BOOL fDisableWow64Redirection, | ||
| 18 | __inout DWORD* pdwCounter, | ||
| 19 | __inout MSIHANDLE* phTable, | ||
| 20 | __inout MSIHANDLE* phColumns | ||
| 21 | ) | ||
| 22 | { | ||
| 23 | HRESULT hr = S_OK; | ||
| 24 | DWORD er; | ||
| 25 | LPWSTR sczSearch = NULL; | ||
| 26 | LPWSTR sczProperty = NULL; | ||
| 27 | HANDLE hFind = INVALID_HANDLE_VALUE; | ||
| 28 | WIN32_FIND_DATAW wfd; | ||
| 29 | LPWSTR sczNext = NULL; | ||
| 30 | |||
| 31 | if (fDisableWow64Redirection) | ||
| 32 | { | ||
| 33 | hr = WcaDisableWow64FSRedirection(); | ||
| 34 | ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); | ||
| 35 | } | ||
| 36 | |||
| 37 | // First recurse down to all the child directories. | ||
| 38 | hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath); | ||
| 39 | ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath); | ||
| 40 | |||
| 41 | hFind = ::FindFirstFileW(sczSearch, &wfd); | ||
| 42 | if (INVALID_HANDLE_VALUE == hFind) | ||
| 43 | { | ||
| 44 | er = ::GetLastError(); | ||
| 45 | if (ERROR_PATH_NOT_FOUND == er) | ||
| 46 | { | ||
| 47 | WcaLog(LOGMSG_STANDARD, "Search path not found: %ls; skipping", sczSearch); | ||
| 48 | ExitFunction1(hr = S_FALSE); | ||
| 49 | } | ||
| 50 | else | ||
| 51 | { | ||
| 52 | hr = HRESULT_FROM_WIN32(er); | ||
| 53 | } | ||
| 54 | ExitOnFailure(hr, "Failed to find all files in path: %S", wzPath); | ||
| 55 | } | ||
| 56 | |||
| 57 | do | ||
| 58 | { | ||
| 59 | // Skip files and the dot directories. | ||
| 60 | if (FILE_ATTRIBUTE_DIRECTORY != (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || L'.' == wfd.cFileName[0] && (L'\0' == wfd.cFileName[1] || (L'.' == wfd.cFileName[1] && L'\0' == wfd.cFileName[2]))) | ||
| 61 | { | ||
| 62 | continue; | ||
| 63 | } | ||
| 64 | |||
| 65 | hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName); | ||
| 66 | ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath); | ||
| 67 | |||
| 68 | // Don't re-disable redirection; if it was necessary, we've already done it. | ||
| 69 | hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, FALSE, pdwCounter, phTable, phColumns); | ||
| 70 | ExitOnFailure(hr, "Failed to recurse path: %S", sczNext); | ||
| 71 | } while (::FindNextFileW(hFind, &wfd)); | ||
| 72 | |||
| 73 | er = ::GetLastError(); | ||
| 74 | if (ERROR_NO_MORE_FILES == er) | ||
| 75 | { | ||
| 76 | hr = S_OK; | ||
| 77 | } | ||
| 78 | else | ||
| 79 | { | ||
| 80 | hr = HRESULT_FROM_WIN32(er); | ||
| 81 | ExitOnFailure(hr, "Failed while looping through files in directory: %S", wzPath); | ||
| 82 | } | ||
| 83 | |||
| 84 | // Finally, set a property that points at our path. | ||
| 85 | hr = StrAllocFormatted(&sczProperty, L"_%s_%u", wzProperty, *pdwCounter); | ||
| 86 | ExitOnFailure(hr, "Failed to allocate Property for RemoveFile table with property: %S.", wzProperty); | ||
| 87 | |||
| 88 | ++(*pdwCounter); | ||
| 89 | |||
| 90 | hr = WcaSetProperty(sczProperty, wzPath); | ||
| 91 | ExitOnFailure(hr, "Failed to set Property: %S with path: %S", sczProperty, wzPath); | ||
| 92 | |||
| 93 | // Add the row to remove any files and another row to remove the folder. | ||
| 94 | hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode); | ||
| 95 | ExitOnFailure(hr, "Failed to add row to remove all files for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath); | ||
| 96 | |||
| 97 | hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode); | ||
| 98 | ExitOnFailure(hr, "Failed to add row to remove folder for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath); | ||
| 99 | |||
| 100 | LExit: | ||
| 101 | if (INVALID_HANDLE_VALUE != hFind) | ||
| 102 | { | ||
| 103 | ::FindClose(hFind); | ||
| 104 | } | ||
| 105 | |||
| 106 | if (fDisableWow64Redirection) | ||
| 107 | { | ||
| 108 | WcaRevertWow64FSRedirection(); | ||
| 109 | } | ||
| 110 | |||
| 111 | ReleaseStr(sczNext); | ||
| 112 | ReleaseStr(sczProperty); | ||
| 113 | ReleaseStr(sczSearch); | ||
| 114 | return hr; | ||
| 115 | } | ||
| 116 | |||
| 117 | extern "C" UINT WINAPI WixRemoveFoldersEx( | ||
| 118 | __in MSIHANDLE hInstall | ||
| 119 | ) | ||
| 120 | { | ||
| 121 | //AssertSz(FALSE, "debug WixRemoveFoldersEx"); | ||
| 122 | |||
| 123 | HRESULT hr = S_OK; | ||
| 124 | PMSIHANDLE hView; | ||
| 125 | PMSIHANDLE hRec; | ||
| 126 | LPWSTR sczId = NULL; | ||
| 127 | LPWSTR sczComponent = NULL; | ||
| 128 | LPWSTR sczProperty = NULL; | ||
| 129 | LPWSTR sczCondition = NULL; | ||
| 130 | LPWSTR sczPath = NULL; | ||
| 131 | LPWSTR sczExpandedPath = NULL; | ||
| 132 | int iMode = 0; | ||
| 133 | int iComponentAttributes; | ||
| 134 | BOOL f64BitComponent = FALSE; | ||
| 135 | DWORD dwCounter = 0; | ||
| 136 | DWORD_PTR cchLen = 0; | ||
| 137 | MSIHANDLE hTable = NULL; | ||
| 138 | MSIHANDLE hColumns = NULL; | ||
| 139 | |||
| 140 | hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); | ||
| 141 | ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); | ||
| 142 | |||
| 143 | WcaInitializeWow64(); | ||
| 144 | |||
| 145 | // anything to do? | ||
| 146 | if (S_OK != WcaTableExists(L"Wix4RemoveFolderEx")) | ||
| 147 | { | ||
| 148 | WcaLog(LOGMSG_STANDARD, "Wix4RemoveFolderEx table doesn't exist, so there are no folders to remove."); | ||
| 149 | ExitFunction(); | ||
| 150 | } | ||
| 151 | |||
| 152 | // query and loop through all the remove folders exceptions | ||
| 153 | hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView); | ||
| 154 | ExitOnFailure(hr, "Failed to open view on Wix4RemoveFolderEx table"); | ||
| 155 | |||
| 156 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
| 157 | { | ||
| 158 | hr = WcaGetRecordString(hRec, rfqId, &sczId); | ||
| 159 | ExitOnFailure(hr, "Failed to get remove folder identity."); | ||
| 160 | |||
| 161 | hr = WcaGetRecordString(hRec, rfqCondition, &sczCondition); | ||
| 162 | ExitOnFailure(hr, "Failed to get remove folder condition."); | ||
| 163 | |||
| 164 | if (sczCondition && *sczCondition) | ||
| 165 | { | ||
| 166 | MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition); | ||
| 167 | if (MSICONDITION_TRUE == condition) | ||
| 168 | { | ||
| 169 | WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition); | ||
| 170 | } | ||
| 171 | else | ||
| 172 | { | ||
| 173 | WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition); | ||
| 174 | continue; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); | ||
| 179 | ExitOnFailure(hr, "Failed to get remove folder component."); | ||
| 180 | |||
| 181 | hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); | ||
| 182 | ExitOnFailure(hr, "Failed to get remove folder property."); | ||
| 183 | |||
| 184 | hr = WcaGetRecordInteger(hRec, rfqMode, &iMode); | ||
| 185 | ExitOnFailure(hr, "Failed to get remove folder mode"); | ||
| 186 | |||
| 187 | hr = WcaGetProperty(sczProperty, &sczPath); | ||
| 188 | ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); | ||
| 189 | |||
| 190 | hr = WcaGetRecordInteger(hRec, rfqComponentAttributes, &iComponentAttributes); | ||
| 191 | ExitOnFailure(hr, "failed to get component attributes for row: %ls", sczId); | ||
| 192 | |||
| 193 | f64BitComponent = iComponentAttributes & msidbComponentAttributes64bit; | ||
| 194 | |||
| 195 | // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder | ||
| 196 | // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null | ||
| 197 | hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen)); | ||
| 198 | if (SUCCEEDED(hr)) | ||
| 199 | { | ||
| 200 | ExitOnFailure(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId); | ||
| 201 | } | ||
| 202 | |||
| 203 | hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT); | ||
| 204 | ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId); | ||
| 205 | |||
| 206 | hr = PathBackslashTerminate(&sczExpandedPath); | ||
| 207 | ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); | ||
| 208 | |||
| 209 | WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); | ||
| 210 | hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns); | ||
| 211 | ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); | ||
| 212 | } | ||
| 213 | |||
| 214 | // reaching the end of the list is actually a good thing, not an error | ||
| 215 | if (E_NOMOREITEMS == hr) | ||
| 216 | { | ||
| 217 | hr = S_OK; | ||
| 218 | } | ||
| 219 | ExitOnFailure(hr, "Failure occured while processing Wix4RemoveFolderEx table"); | ||
| 220 | |||
| 221 | LExit: | ||
| 222 | WcaFinalizeWow64(); | ||
| 223 | |||
| 224 | if (hColumns) | ||
| 225 | { | ||
| 226 | ::MsiCloseHandle(hColumns); | ||
| 227 | } | ||
| 228 | |||
| 229 | if (hTable) | ||
| 230 | { | ||
| 231 | ::MsiCloseHandle(hTable); | ||
| 232 | } | ||
| 233 | |||
| 234 | ReleaseStr(sczExpandedPath); | ||
| 235 | ReleaseStr(sczPath); | ||
| 236 | ReleaseStr(sczProperty); | ||
| 237 | ReleaseStr(sczComponent); | ||
| 238 | ReleaseStr(sczCondition); | ||
| 239 | ReleaseStr(sczId); | ||
| 240 | |||
| 241 | DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 242 | return WcaFinalize(er); | ||
| 243 | } | ||
