diff options
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 | } | ||