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