aboutsummaryrefslogtreecommitdiff
path: root/src/ca/RemoveFoldersEx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca/RemoveFoldersEx.cpp')
-rw-r--r--src/ca/RemoveFoldersEx.cpp197
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
5LPCWSTR vcsRemoveFolderExQuery = L"SELECT `WixRemoveFolderEx`, `Component_`, `Property`, `InstallMode` FROM `WixRemoveFolderEx`";
6enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, feqMode };
7
8static 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
89LExit:
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
101extern "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
178LExit:
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}