diff options
Diffstat (limited to 'src/ext/Util/ca/FormatFiles.cpp')
-rw-r--r-- | src/ext/Util/ca/FormatFiles.cpp | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/ext/Util/ca/FormatFiles.cpp b/src/ext/Util/ca/FormatFiles.cpp new file mode 100644 index 00000000..d1533999 --- /dev/null +++ b/src/ext/Util/ca/FormatFiles.cpp | |||
@@ -0,0 +1,221 @@ | |||
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 | const UINT COST_FILEFORMATTING = 2000; | ||
6 | |||
7 | |||
8 | // | ||
9 | // WixSchedFormatFiles - immediate CA to schedule format files CAs | ||
10 | // | ||
11 | extern "C" UINT __stdcall WixSchedFormatFiles( | ||
12 | __in MSIHANDLE hInstall | ||
13 | ) | ||
14 | { | ||
15 | HRESULT hr = S_OK; | ||
16 | UINT er = ERROR_SUCCESS; | ||
17 | PSCZ sczBinaryKey; | ||
18 | PSCZ sczFileKey; | ||
19 | PSCZ sczComponentKey; | ||
20 | PSCZ sczFormattedFile; | ||
21 | PSCZ sczFilePath; | ||
22 | PMSIHANDLE hView; | ||
23 | PMSIHANDLE hRec; | ||
24 | PSCZ sczFileContent; | ||
25 | PSCZ sczFormattedContent; | ||
26 | PSCZ sczExecCustomActionData; | ||
27 | PSCZ sczRollbackCustomActionData; | ||
28 | |||
29 | LPCWSTR wzQuery = | ||
30 | L"SELECT `Wix4FormatFile`.`Binary_`, `Wix4FormatFile`.`File_`, `File`.`Component_` " | ||
31 | L"FROM `Wix4FormatFile`, `File` " | ||
32 | L"WHERE `Wix4FormatFile`.`File_` = `File`.`File`"; | ||
33 | enum eQuery { eqBinaryKey = 1, eqFileKey, eqComponentKey }; | ||
34 | |||
35 | // initialize | ||
36 | hr = WcaInitialize(hInstall, "WixSchedFormatFiles"); | ||
37 | ExitOnFailure(hr, "Failed to initialize for WixSchedFormatFiles."); | ||
38 | |||
39 | // query and loop through all the files | ||
40 | hr = WcaOpenExecuteView(wzQuery, &hView); | ||
41 | ExitOnFailure(hr, "Failed to open view on Wix4FormatFile table"); | ||
42 | |||
43 | DWORD cFiles = 0; | ||
44 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
45 | { | ||
46 | ++cFiles; | ||
47 | |||
48 | hr = WcaGetRecordString(hRec, eqBinaryKey, &sczBinaryKey); | ||
49 | ExitOnFailure(hr, "Failed to get Binary table key."); | ||
50 | |||
51 | hr = WcaGetRecordString(hRec, eqFileKey, &sczFileKey); | ||
52 | ExitOnFailure(hr, "Failed to get File table key."); | ||
53 | |||
54 | hr = WcaGetRecordString(hRec, eqComponentKey, &sczComponentKey); | ||
55 | ExitOnFailure(hr, "Failed to get Component table key."); | ||
56 | |||
57 | // we need to know if the component's being installed, uninstalled, or reinstalled | ||
58 | WCA_TODO todo = WcaGetComponentToDo(sczComponentKey); | ||
59 | if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) | ||
60 | { | ||
61 | // turn the file key into the path to the target file | ||
62 | hr = StrAllocFormatted(&sczFormattedFile, L"[#%ls]", sczFileKey); | ||
63 | ExitOnFailure(hr, "Failed to format file string for file: %ls", sczFileKey); | ||
64 | hr = WcaGetFormattedString(sczFormattedFile, &sczFilePath); | ||
65 | ExitOnFailure(hr, "Failed to get path for file: %ls", sczFileKey); | ||
66 | |||
67 | // extract binary to string | ||
68 | WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN; | ||
69 | hr = WcaExtractBinaryToString(sczBinaryKey, &sczFileContent, &encoding); | ||
70 | ExitOnFailure(hr, "Failed to extract binary: %ls", sczBinaryKey); | ||
71 | |||
72 | // format string | ||
73 | hr = WcaGetFormattedString(sczFileContent, &sczFormattedContent); | ||
74 | ExitOnFailure(hr, "Failed to format file content: %ls", sczFileContent); | ||
75 | |||
76 | // write to deferred custom action data | ||
77 | hr = WcaWriteStringToCaData(sczFilePath, &sczExecCustomActionData); | ||
78 | ExitOnFailure(hr, "Failed to write deferred custom action data for file: %ls", sczFilePath); | ||
79 | |||
80 | hr = WcaWriteIntegerToCaData(encoding, &sczExecCustomActionData); | ||
81 | ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding); | ||
82 | |||
83 | hr = WcaWriteStringToCaData(sczFormattedContent, &sczExecCustomActionData); | ||
84 | ExitOnFailure(hr, "Failed to write deferred custom action data for file content: %ls", sczFilePath); | ||
85 | |||
86 | // write to rollback custom action data | ||
87 | hr = WcaWriteStringToCaData(sczFilePath, &sczRollbackCustomActionData); | ||
88 | ExitOnFailure(hr, "Failed to write rollback custom action data for file: %ls", sczFilePath); | ||
89 | |||
90 | hr = WcaWriteIntegerToCaData(encoding, &sczRollbackCustomActionData); | ||
91 | ExitOnFailure(hr, "Failed to write deferred custom action data for encoding: %d", encoding); | ||
92 | |||
93 | hr = WcaWriteStringToCaData(sczFileContent, &sczRollbackCustomActionData); | ||
94 | ExitOnFailure(hr, "Failed to write rollback custom action data for file content: %ls", sczFilePath); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | // reaching the end of the list is actually a good thing, not an error | ||
99 | if (E_NOMOREITEMS == hr) | ||
100 | { | ||
101 | hr = S_OK; | ||
102 | } | ||
103 | ExitOnFailure(hr, "Failure occurred while processing Wix4FormatFile table"); | ||
104 | |||
105 | // schedule deferred CAs if there's anything to do | ||
106 | if (sczRollbackCustomActionData && *sczRollbackCustomActionData) | ||
107 | { | ||
108 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackFormatFiles"), sczRollbackCustomActionData, cFiles * COST_FILEFORMATTING); | ||
109 | ExitOnFailure(hr, "Failed to schedule RollbackFormatFiles"); | ||
110 | } | ||
111 | |||
112 | if (sczExecCustomActionData && *sczExecCustomActionData) | ||
113 | { | ||
114 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ExecFormatFiles"), sczExecCustomActionData, cFiles * COST_FILEFORMATTING); | ||
115 | ExitOnFailure(hr, "Failed to schedule ExecFormatFiles"); | ||
116 | } | ||
117 | |||
118 | LExit: | ||
119 | return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); | ||
120 | } | ||
121 | |||
122 | |||
123 | // | ||
124 | // WixExecFormatFiles - deferred and rollback CAs to write formatted files | ||
125 | // | ||
126 | extern "C" UINT __stdcall WixExecFormatFiles( | ||
127 | __in MSIHANDLE hInstall | ||
128 | ) | ||
129 | { | ||
130 | HRESULT hr = S_OK; | ||
131 | UINT er = ERROR_SUCCESS; | ||
132 | PSCZ sczCustomActionData; | ||
133 | LPWSTR pwz = NULL; | ||
134 | PSCZ sczFilePath; | ||
135 | PSCZ sczFileContent; | ||
136 | LPSTR psz = NULL; | ||
137 | |||
138 | // initialize | ||
139 | hr = WcaInitialize(hInstall, "WixExecFormatFiles"); | ||
140 | ExitOnFailure(hr, "Failed to initialize for WixExecFormatFiles."); | ||
141 | |||
142 | hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData); | ||
143 | ExitOnFailure(hr, "Failed to get CustomActionData."); | ||
144 | #ifdef _DEBUG | ||
145 | WcaLog(LOGMSG_STANDARD, "CustomActionData: %ls", sczCustomActionData); | ||
146 | #endif | ||
147 | |||
148 | // loop through all the passed in data | ||
149 | pwz = sczCustomActionData; | ||
150 | while (pwz && *pwz) | ||
151 | { | ||
152 | // extract the custom action data | ||
153 | hr = WcaReadStringFromCaData(&pwz, &sczFilePath); | ||
154 | ExitOnFailure(hr, "Failed to read file path from custom action data"); | ||
155 | |||
156 | WCA_ENCODING encoding = WCA_ENCODING_UNKNOWN; | ||
157 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&encoding)); | ||
158 | ExitOnFailure(hr, "Failed to read encoding from custom action data"); | ||
159 | |||
160 | hr = WcaReadStringFromCaData(&pwz, &sczFileContent); | ||
161 | ExitOnFailure(hr, "Failed to read file content from custom action data"); | ||
162 | |||
163 | // re-encode content | ||
164 | LPCBYTE pbData = NULL; | ||
165 | size_t cbData = 0; | ||
166 | switch (encoding) | ||
167 | { | ||
168 | case WCA_ENCODING_UTF_16: | ||
169 | pbData = reinterpret_cast<LPCBYTE>(LPCWSTR(sczFileContent)); | ||
170 | cbData = lstrlenW(sczFileContent) * sizeof(WCHAR); | ||
171 | break; | ||
172 | |||
173 | case WCA_ENCODING_UTF_8: | ||
174 | hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_UTF8); | ||
175 | ExitOnFailure(hr, "Failed to convert Unicode to UTF-8."); | ||
176 | pbData = reinterpret_cast<LPCBYTE>(psz); | ||
177 | |||
178 | hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData); | ||
179 | ExitOnFailure(hr, "Failed to count UTF-8 bytes."); | ||
180 | break; | ||
181 | |||
182 | case WCA_ENCODING_ANSI: | ||
183 | hr = StrAnsiAllocString(&psz, sczFileContent, 0, CP_ACP); | ||
184 | ExitOnFailure(hr, "Failed to convert Unicode to ANSI."); | ||
185 | pbData = reinterpret_cast<LPCBYTE>(psz); | ||
186 | |||
187 | hr = ::StringCbLengthA(psz, STRSAFE_MAX_CCH, &cbData); | ||
188 | ExitOnFailure(hr, "Failed to count UTF-8 bytes."); | ||
189 | break; | ||
190 | |||
191 | default: | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | #ifdef _DEBUG | ||
196 | WcaLog(LOGMSG_STANDARD, "File: %ls", sczCustomActionData); | ||
197 | WcaLog(LOGMSG_STANDARD, "Content: %ls", sczFileContent); | ||
198 | #endif | ||
199 | |||
200 | // write file and preserve modified time | ||
201 | FILETIME filetime; | ||
202 | |||
203 | hr = FileGetTime(sczFilePath, NULL, NULL, &filetime); | ||
204 | ExitOnFailure(hr, "Failed to get modified time of file : %ls", sczFilePath); | ||
205 | |||
206 | hr = FileWrite(sczFilePath, FILE_ATTRIBUTE_NORMAL, pbData, cbData, NULL); | ||
207 | ExitOnFailure(hr, "Failed to write file content: %ls", sczFilePath); | ||
208 | |||
209 | hr = FileSetTime(sczFilePath, NULL, NULL, &filetime); | ||
210 | ExitOnFailure(hr, "Failed to set modified time of file : %ls", sczFilePath); | ||
211 | |||
212 | // Tick the progress bar | ||
213 | hr = WcaProgressMessage(COST_FILEFORMATTING, FALSE); | ||
214 | ExitOnFailure(hr, "Failed to tick progress bar for file: %ls", sczFilePath); | ||
215 | } | ||
216 | |||
217 | LExit: | ||
218 | ReleaseStr(psz); | ||
219 | |||
220 | return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); | ||
221 | } | ||