aboutsummaryrefslogtreecommitdiff
path: root/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp')
-rw-r--r--src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp
new file mode 100644
index 00000000..a7e98491
--- /dev/null
+++ b/src/libs/wcautil/WixToolset.WcaUtil/wcascript.cpp
@@ -0,0 +1,429 @@
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
6static HRESULT CaScriptFileName(
7 __in WCA_ACTION action,
8 __in WCA_CASCRIPT script,
9 __in BOOL fImpersonated,
10 __in_z LPCWSTR wzScriptKey,
11 __out LPWSTR* pwzScriptName
12 );
13
14
15/********************************************************************
16 WcaCaScriptCreateKey() - creates a unique script key for this
17 CustomAction.
18
19********************************************************************/
20extern "C" HRESULT WIXAPI WcaCaScriptCreateKey(
21 __out LPWSTR* ppwzScriptKey
22 )
23{
24 AssertSz(WcaIsInitialized(), "WcaInitialize() should have been called before calling this function.");
25 HRESULT hr = S_OK;
26
27 hr = StrAllocStringAnsi(ppwzScriptKey, WcaGetLogName(), 0, CP_ACP);
28 ExitOnFailure(hr, "Failed to create script key.");
29
30LExit:
31 return hr;
32}
33
34
35/********************************************************************
36 WcaCaScriptCreate() - creates the appropriate script for this
37 CustomAction Script Key.
38
39********************************************************************/
40extern "C" HRESULT WIXAPI WcaCaScriptCreate(
41 __in WCA_ACTION action,
42 __in WCA_CASCRIPT script,
43 __in BOOL fImpersonated,
44 __in_z LPCWSTR wzScriptKey,
45 __in BOOL fAppend,
46 __out WCA_CASCRIPT_HANDLE* phScript
47 )
48{
49 HRESULT hr = S_OK;
50 LPWSTR pwzScriptPath = NULL;
51 HANDLE hScriptFile = INVALID_HANDLE_VALUE;
52
53 hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath);
54 ExitOnFailure(hr, "Failed to calculate script file name.");
55
56 hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, fAppend ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
57 if (INVALID_HANDLE_VALUE == hScriptFile)
58 {
59 ExitWithLastError(hr, "Failed to open CaScript: %ls", pwzScriptPath);
60 }
61
62 if (fAppend && INVALID_SET_FILE_POINTER == ::SetFilePointer(hScriptFile, 0, NULL, FILE_END))
63 {
64 ExitWithLastError(hr, "Failed to seek to end of file.");
65 }
66
67 *phScript = static_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE));
68 ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle.");
69
70 (*phScript)->pwzScriptPath = pwzScriptPath;
71 pwzScriptPath = NULL;
72 (*phScript)->hScriptFile = hScriptFile;
73 hScriptFile = INVALID_HANDLE_VALUE;
74
75LExit:
76 if (INVALID_HANDLE_VALUE != hScriptFile)
77 {
78 ::CloseHandle(hScriptFile);
79 }
80
81 ReleaseStr(pwzScriptPath);
82 return hr;
83}
84
85
86/********************************************************************
87 WcaCaScriptOpen() - opens the appropriate script for this CustomAction
88 Script Key.
89
90********************************************************************/
91extern "C" HRESULT WIXAPI WcaCaScriptOpen(
92 __in WCA_ACTION action,
93 __in WCA_CASCRIPT script,
94 __in BOOL fImpersonated,
95 __in_z LPCWSTR wzScriptKey,
96 __out WCA_CASCRIPT_HANDLE* phScript
97 )
98{
99 HRESULT hr = S_OK;
100 LPWSTR pwzScriptPath = NULL;
101 HANDLE hScriptFile = INVALID_HANDLE_VALUE;
102
103 hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath);
104 ExitOnFailure(hr, "Failed to calculate script file name.");
105
106 hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
107 if (INVALID_HANDLE_VALUE == hScriptFile)
108 {
109 ExitWithLastError(hr, "Failed to open CaScript: %ls", pwzScriptPath);
110 }
111
112 *phScript = static_cast<WCA_CASCRIPT_HANDLE>(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE));
113 ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle.");
114
115 (*phScript)->pwzScriptPath = pwzScriptPath;
116 pwzScriptPath = NULL;
117 (*phScript)->hScriptFile = hScriptFile;
118 hScriptFile = INVALID_HANDLE_VALUE;
119
120LExit:
121 if (INVALID_HANDLE_VALUE != hScriptFile)
122 {
123 ::CloseHandle(hScriptFile);
124 }
125
126 ReleaseStr(pwzScriptPath);
127 return hr;
128}
129
130
131/********************************************************************
132 WcaCaScriptClose() - closes an open script handle.
133
134********************************************************************/
135extern "C" void WIXAPI WcaCaScriptClose(
136 __in_opt WCA_CASCRIPT_HANDLE hScript,
137 __in WCA_CASCRIPT_CLOSE closeOperation
138 )
139{
140 if (hScript)
141 {
142 if (INVALID_HANDLE_VALUE != hScript->hScriptFile)
143 {
144 ::CloseHandle(hScript->hScriptFile);
145 }
146
147 if (hScript->pwzScriptPath)
148 {
149 if (WCA_CASCRIPT_CLOSE_DELETE == closeOperation)
150 {
151 ::DeleteFileW(hScript->pwzScriptPath);
152 }
153
154 StrFree(hScript->pwzScriptPath);
155 }
156
157 MemFree(hScript);
158 }
159}
160
161
162/********************************************************************
163 WcaCaScriptReadAsCustomActionData() - read the ca script into a format
164 that is useable by other CA data
165 functions.
166
167********************************************************************/
168extern "C" HRESULT WIXAPI WcaCaScriptReadAsCustomActionData(
169 __in WCA_CASCRIPT_HANDLE hScript,
170 __out LPWSTR* ppwzCustomActionData
171 )
172{
173 HRESULT hr = S_OK;
174 LARGE_INTEGER liScriptSize = { 0 };
175 BYTE* pbData = NULL;
176 DWORD cbData = 0;
177
178 if (!::GetFileSizeEx(hScript->hScriptFile, &liScriptSize))
179 {
180 ExitWithLastError(hr, "Failed to get size of ca script file.");
181 }
182
183 if (0 != liScriptSize.HighPart || 0 != (liScriptSize.LowPart % sizeof(WCHAR)))
184 {
185 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
186 ExitOnRootFailure(hr, "Invalid data read from ca script.");
187 }
188
189 cbData = liScriptSize.LowPart;
190 if (cbData)
191 {
192 pbData = static_cast<BYTE*>(MemAlloc(cbData, TRUE));
193 ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read in ca script.");
194
195 if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_BEGIN))
196 {
197 ExitWithLastError(hr, "Failed to reset to beginning of ca script.");
198 }
199
200 DWORD cbTotalRead = 0;
201 DWORD cbRead = 0;
202 do
203 {
204 if (!::ReadFile(hScript->hScriptFile, pbData + cbTotalRead, cbData - cbTotalRead, &cbRead, NULL))
205 {
206 ExitWithLastError(hr, "Failed to read from ca script.");
207 }
208
209 cbTotalRead += cbRead;
210 } while (cbRead && cbTotalRead < cbData);
211
212 if (cbTotalRead != cbData)
213 {
214 hr = E_UNEXPECTED;
215 ExitOnFailure(hr, "Failed to completely read ca script.");
216 }
217 }
218
219 // Add one to the allocated space because the data stored in the script is not
220 // null terminated. After copying the memory over, we'll ensure the string is
221 // null terminated.
222 DWORD cchData = cbData / sizeof(WCHAR) + 1;
223 hr = StrAlloc(ppwzCustomActionData, cchData);
224 ExitOnFailure(hr, "Failed to copy ca script.");
225
226 if (cbData)
227 {
228 CopyMemory(*ppwzCustomActionData, pbData, cbData);
229 }
230
231 (*ppwzCustomActionData)[cchData - 1] = L'\0';
232
233LExit:
234 ReleaseMem(pbData);
235 return hr;
236}
237
238
239/********************************************************************
240 WcaCaScriptWriteString() - writes a string to the ca script.
241
242********************************************************************/
243extern "C" HRESULT WIXAPI WcaCaScriptWriteString(
244 __in WCA_CASCRIPT_HANDLE hScript,
245 __in_z LPCWSTR wzValue
246 )
247{
248 HRESULT hr = S_OK;
249 DWORD cbFile = 0;
250 WCHAR delim[] = { MAGIC_MULTISZ_DELIM }; // magic char followed by NULL terminator
251 SIZE_T cch = 0;
252
253 cbFile = ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_END);
254 if (INVALID_SET_FILE_POINTER == cbFile)
255 {
256 ExitWithLastError(hr, "Failed to move file pointer to end of file.");
257 }
258
259 // If there is existing data in the file, append on the magic delimeter
260 // before adding our new data on the end of the file.
261 if (0 < cbFile)
262 {
263 hr = FileWriteHandle(hScript->hScriptFile, reinterpret_cast<LPCBYTE>(delim), sizeof(delim));
264 ExitOnFailure(hr, "Failed to write data to ca script.");
265 }
266
267 hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cch));
268 ExitOnRootFailure(hr, "Failed to get length of ca script string.");
269
270 hr = FileWriteHandle(hScript->hScriptFile, reinterpret_cast<LPCBYTE>(wzValue), static_cast<DWORD>(cch) * sizeof(WCHAR));
271 ExitOnFailure(hr, "Failed to write data to ca script.");
272
273LExit:
274 return hr;
275}
276
277
278/********************************************************************
279 WcaCaScriptWriteNumber() - writes a number to the ca script.
280
281********************************************************************/
282extern "C" HRESULT WIXAPI WcaCaScriptWriteNumber(
283 __in WCA_CASCRIPT_HANDLE hScript,
284 __in DWORD dwValue
285 )
286{
287 HRESULT hr = S_OK;
288 WCHAR wzBuffer[13] = { 0 };
289
290 hr = ::StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%u", dwValue);
291 ExitOnFailure(hr, "Failed to convert number into string.");
292
293 hr = WcaCaScriptWriteString(hScript, wzBuffer);
294 ExitOnFailure(hr, "Failed to write number to script.");
295
296LExit:
297 return hr;
298}
299
300
301/********************************************************************
302 WcaCaScriptFlush() - best effort function to get script written to
303 disk.
304
305********************************************************************/
306extern "C" void WIXAPI WcaCaScriptFlush(
307 __in WCA_CASCRIPT_HANDLE hScript
308 )
309{
310 ::FlushFileBuffers(hScript->hScriptFile);
311}
312
313
314/********************************************************************
315 WcaCaScriptCleanup() - best effort clean-up of any cascripts left
316 over from this install/uninstall.
317
318********************************************************************/
319extern "C" void WIXAPI WcaCaScriptCleanup(
320 __in_z LPCWSTR wzProductCode,
321 __in BOOL fImpersonated
322 )
323{
324 HRESULT hr = S_OK;
325 WCHAR wzTempPath[MAX_PATH];
326 LPWSTR pwzWildCardPath = NULL;
327 WIN32_FIND_DATAW fd = { 0 };
328 HANDLE hff = INVALID_HANDLE_VALUE;
329 LPWSTR pwzDeletePath = NULL;
330
331 if (fImpersonated)
332 {
333 if (!::GetTempPathW(countof(wzTempPath), wzTempPath))
334 {
335 ExitWithLastError(hr, "Failed to get temp path.");
336 }
337 }
338 else
339 {
340 if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath)))
341 {
342 ExitWithLastError(hr, "Failed to get windows path.");
343 }
344
345 hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\");
346 ExitOnFailure(hr, "Failed to concat Installer directory on windows path string.");
347 }
348
349 hr = StrAllocFormatted(&pwzWildCardPath, L"%swix%s.*.???", wzTempPath, wzProductCode);
350 ExitOnFailure(hr, "Failed to allocate wildcard path to ca scripts.");
351
352 hff = ::FindFirstFileW(pwzWildCardPath, &fd);
353 if (INVALID_HANDLE_VALUE == hff)
354 {
355 ExitWithLastError(hr, "Failed to find files with pattern: %ls", pwzWildCardPath);
356 }
357
358 do
359 {
360 hr = StrAllocFormatted(&pwzDeletePath, L"%s%s", wzTempPath, fd.cFileName);
361 if (SUCCEEDED(hr))
362 {
363 if (!::DeleteFileW(pwzDeletePath))
364 {
365 DWORD er = ::GetLastError();
366 WcaLog(LOGMSG_VERBOSE, "Failed to clean up CAScript file: %ls, er: %d", fd.cFileName, er);
367 }
368 }
369 else
370 {
371 WcaLog(LOGMSG_VERBOSE, "Failed to allocate path to clean up CAScript file: %ls, hr: 0x%x", fd.cFileName, hr);
372 }
373 } while(::FindNextFileW(hff, &fd));
374
375LExit:
376 if (INVALID_HANDLE_VALUE == hff)
377 {
378 ::FindClose(hff);
379 }
380
381 ReleaseStr(pwzDeletePath);
382 ReleaseStr(pwzWildCardPath);
383 return;
384}
385
386
387static HRESULT CaScriptFileName(
388 __in WCA_ACTION action,
389 __in WCA_CASCRIPT script,
390 __in BOOL fImpersonated,
391 __in_z LPCWSTR wzScriptKey,
392 __out LPWSTR* ppwzScriptName
393 )
394{
395 HRESULT hr = S_OK;
396 WCHAR wzTempPath[MAX_PATH];
397 LPWSTR pwzProductCode = NULL;
398 WCHAR chInstallOrUninstall = action == WCA_ACTION_INSTALL ? L'i' : L'u';
399 WCHAR chScheduledOrRollback = script == WCA_CASCRIPT_SCHEDULED ? L's' : L'r';
400 WCHAR chUserOrMachine = fImpersonated ? L'u' : L'm';
401
402 if (fImpersonated)
403 {
404 if (!::GetTempPathW(countof(wzTempPath), wzTempPath))
405 {
406 ExitWithLastError(hr, "Failed to get temp path.");
407 }
408 }
409 else
410 {
411 if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath)))
412 {
413 ExitWithLastError(hr, "Failed to get windows path.");
414 }
415
416 hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\");
417 ExitOnFailure(hr, "Failed to concat Installer directory on windows path string.");
418 }
419
420 hr = WcaGetProperty(L"ProductCode", &pwzProductCode);
421 ExitOnFailure(hr, "Failed to get ProductCode.");
422
423 hr = StrAllocFormatted(ppwzScriptName, L"%swix%s.%s.%c%c%c", wzTempPath, pwzProductCode, wzScriptKey, chScheduledOrRollback, chUserOrMachine, chInstallOrUninstall);
424 ExitOnFailure(hr, "Failed to allocate path to ca script.");
425
426LExit:
427 ReleaseStr(pwzProductCode);
428 return hr;
429}