diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-15 21:46:30 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-15 21:46:30 -0600 |
| commit | f7020c0d16baf2b960e7123e233e20c519f6a340 (patch) | |
| tree | d2cd464ee15b2b3f304ff780c531b39bb292d331 /src/ca/RemoveFoldersEx.cpp | |
| parent | 6ed8d107e6edf16956c778bda3573f8d7a7690fc (diff) | |
| download | wix-f7020c0d16baf2b960e7123e233e20c519f6a340.tar.gz wix-f7020c0d16baf2b960e7123e233e20c519f6a340.tar.bz2 wix-f7020c0d16baf2b960e7123e233e20c519f6a340.zip | |
Import implementation of UtilCA from old repo's WixCA/scasched/scaexec. (#3)
Diffstat (limited to 'src/ca/RemoveFoldersEx.cpp')
| -rw-r--r-- | src/ca/RemoveFoldersEx.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/ca/RemoveFoldersEx.cpp b/src/ca/RemoveFoldersEx.cpp new file mode 100644 index 00000000..194c6662 --- /dev/null +++ b/src/ca/RemoveFoldersEx.cpp | |||
| @@ -0,0 +1,197 @@ | |||
| 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 = L"SELECT `WixRemoveFolderEx`, `Component_`, `Property`, `InstallMode` FROM `WixRemoveFolderEx`"; | ||
| 6 | enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, feqMode }; | ||
| 7 | |||
| 8 | static HRESULT RecursePath( | ||
| 9 | __in_z LPCWSTR wzPath, | ||
| 10 | __in_z LPCWSTR wzId, | ||
| 11 | __in_z LPCWSTR wzComponent, | ||
| 12 | __in_z LPCWSTR wzProperty, | ||
| 13 | __in int iMode, | ||
| 14 | __inout DWORD* pdwCounter, | ||
| 15 | __inout MSIHANDLE* phTable, | ||
| 16 | __inout MSIHANDLE* phColumns | ||
| 17 | ) | ||
| 18 | { | ||
| 19 | HRESULT hr = S_OK; | ||
| 20 | DWORD er; | ||
| 21 | LPWSTR sczSearch = NULL; | ||
| 22 | LPWSTR sczProperty = NULL; | ||
| 23 | HANDLE hFind = INVALID_HANDLE_VALUE; | ||
| 24 | WIN32_FIND_DATAW wfd; | ||
| 25 | LPWSTR sczNext = NULL; | ||
| 26 | |||
| 27 | // First recurse down to all the child directories. | ||
| 28 | hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath); | ||
| 29 | ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath); | ||
| 30 | |||
| 31 | hFind = ::FindFirstFileW(sczSearch, &wfd); | ||
| 32 | if (INVALID_HANDLE_VALUE == hFind) | ||
| 33 | { | ||
| 34 | er = ::GetLastError(); | ||
| 35 | if (ERROR_PATH_NOT_FOUND == er) | ||
| 36 | { | ||
| 37 | WcaLog(LOGMSG_STANDARD, "Search path not found: %ls", sczSearch); | ||
| 38 | ExitFunction1(hr = S_FALSE); | ||
| 39 | } | ||
| 40 | else | ||
| 41 | { | ||
| 42 | hr = HRESULT_FROM_WIN32(er); | ||
| 43 | } | ||
| 44 | ExitOnFailure(hr, "Failed to find all files in path: %S", wzPath); | ||
| 45 | } | ||
| 46 | |||
| 47 | do | ||
| 48 | { | ||
| 49 | // Skip files and the dot directories. | ||
| 50 | 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]))) | ||
| 51 | { | ||
| 52 | continue; | ||
| 53 | } | ||
| 54 | |||
| 55 | hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName); | ||
| 56 | ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath); | ||
| 57 | |||
| 58 | hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, pdwCounter, phTable, phColumns); | ||
| 59 | ExitOnFailure(hr, "Failed to recurse path: %S", sczNext); | ||
| 60 | } while (::FindNextFileW(hFind, &wfd)); | ||
| 61 | |||
| 62 | er = ::GetLastError(); | ||
| 63 | if (ERROR_NO_MORE_FILES == er) | ||
| 64 | { | ||
| 65 | hr = S_OK; | ||
| 66 | } | ||
| 67 | else | ||
| 68 | { | ||
| 69 | hr = HRESULT_FROM_WIN32(er); | ||
| 70 | ExitOnFailure(hr, "Failed while looping through files in directory: %S", wzPath); | ||
| 71 | } | ||
| 72 | |||
| 73 | // Finally, set a property that points at our path. | ||
| 74 | hr = StrAllocFormatted(&sczProperty, L"_%s_%u", wzProperty, *pdwCounter); | ||
| 75 | ExitOnFailure(hr, "Failed to allocate Property for RemoveFile table with property: %S.", wzProperty); | ||
| 76 | |||
| 77 | ++(*pdwCounter); | ||
| 78 | |||
| 79 | hr = WcaSetProperty(sczProperty, wzPath); | ||
| 80 | ExitOnFailure(hr, "Failed to set Property: %S with path: %S", sczProperty, wzPath); | ||
| 81 | |||
| 82 | // Add the row to remove any files and another row to remove the folder. | ||
| 83 | hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode); | ||
| 84 | ExitOnFailure(hr, "Failed to add row to remove all files for WixRemoveFolderEx row: %S under path:", wzId, wzPath); | ||
| 85 | |||
| 86 | hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode); | ||
| 87 | ExitOnFailure(hr, "Failed to add row to remove folder for WixRemoveFolderEx row: %S under path: %S", wzId, wzPath); | ||
| 88 | |||
| 89 | LExit: | ||
| 90 | if (INVALID_HANDLE_VALUE != hFind) | ||
| 91 | { | ||
| 92 | ::FindClose(hFind); | ||
| 93 | } | ||
| 94 | |||
| 95 | ReleaseStr(sczNext); | ||
| 96 | ReleaseStr(sczProperty); | ||
| 97 | ReleaseStr(sczSearch); | ||
| 98 | return hr; | ||
| 99 | } | ||
| 100 | |||
| 101 | extern "C" UINT WINAPI WixRemoveFoldersEx( | ||
| 102 | __in MSIHANDLE hInstall | ||
| 103 | ) | ||
| 104 | { | ||
| 105 | //AssertSz(FALSE, "debug WixRemoveFoldersEx"); | ||
| 106 | |||
| 107 | HRESULT hr = S_OK; | ||
| 108 | PMSIHANDLE hView; | ||
| 109 | PMSIHANDLE hRec; | ||
| 110 | LPWSTR sczId = NULL; | ||
| 111 | LPWSTR sczComponent = NULL; | ||
| 112 | LPWSTR sczProperty = NULL; | ||
| 113 | LPWSTR sczPath = NULL; | ||
| 114 | LPWSTR sczExpandedPath = NULL; | ||
| 115 | int iMode = 0; | ||
| 116 | DWORD dwCounter = 0; | ||
| 117 | DWORD_PTR cchLen = 0; | ||
| 118 | MSIHANDLE hTable = NULL; | ||
| 119 | MSIHANDLE hColumns = NULL; | ||
| 120 | |||
| 121 | hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); | ||
| 122 | ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); | ||
| 123 | |||
| 124 | // anything to do? | ||
| 125 | if (S_OK != WcaTableExists(L"WixRemoveFolderEx")) | ||
| 126 | { | ||
| 127 | WcaLog(LOGMSG_STANDARD, "WixRemoveFolderEx table doesn't exist, so there are no folders to remove."); | ||
| 128 | ExitFunction(); | ||
| 129 | } | ||
| 130 | |||
| 131 | // query and loop through all the remove folders exceptions | ||
| 132 | hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView); | ||
| 133 | ExitOnFailure(hr, "Failed to open view on WixRemoveFolderEx table"); | ||
| 134 | |||
| 135 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
| 136 | { | ||
| 137 | hr = WcaGetRecordString(hRec, rfqId, &sczId); | ||
| 138 | ExitOnFailure(hr, "Failed to get remove folder identity."); | ||
| 139 | |||
| 140 | hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); | ||
| 141 | ExitOnFailure(hr, "Failed to get remove folder component."); | ||
| 142 | |||
| 143 | hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); | ||
| 144 | ExitOnFailure(hr, "Failed to get remove folder property."); | ||
| 145 | |||
| 146 | hr = WcaGetRecordInteger(hRec, feqMode, &iMode); | ||
| 147 | ExitOnFailure(hr, "Failed to get remove folder mode"); | ||
| 148 | |||
| 149 | hr = WcaGetProperty(sczProperty, &sczPath); | ||
| 150 | ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); | ||
| 151 | |||
| 152 | // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder | ||
| 153 | // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null | ||
| 154 | hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen)); | ||
| 155 | if (SUCCEEDED(hr)) | ||
| 156 | { | ||
| 157 | ExitOnFailure(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId); | ||
| 158 | } | ||
| 159 | |||
| 160 | hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT); | ||
| 161 | ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId); | ||
| 162 | |||
| 163 | hr = PathBackslashTerminate(&sczExpandedPath); | ||
| 164 | ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); | ||
| 165 | |||
| 166 | WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); | ||
| 167 | hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, &dwCounter, &hTable, &hColumns); | ||
| 168 | ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); | ||
| 169 | } | ||
| 170 | |||
| 171 | // reaching the end of the list is actually a good thing, not an error | ||
| 172 | if (E_NOMOREITEMS == hr) | ||
| 173 | { | ||
| 174 | hr = S_OK; | ||
| 175 | } | ||
| 176 | ExitOnFailure(hr, "Failure occured while processing WixRemoveFolderEx table"); | ||
| 177 | |||
| 178 | LExit: | ||
| 179 | if (hColumns) | ||
| 180 | { | ||
| 181 | ::MsiCloseHandle(hColumns); | ||
| 182 | } | ||
| 183 | |||
| 184 | if (hTable) | ||
| 185 | { | ||
| 186 | ::MsiCloseHandle(hTable); | ||
| 187 | } | ||
| 188 | |||
| 189 | ReleaseStr(sczExpandedPath); | ||
| 190 | ReleaseStr(sczPath); | ||
| 191 | ReleaseStr(sczProperty); | ||
| 192 | ReleaseStr(sczComponent); | ||
| 193 | ReleaseStr(sczId); | ||
| 194 | |||
| 195 | DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 196 | return WcaFinalize(er); | ||
| 197 | } | ||
