diff options
author | Rob Mensching <rob@firegiant.com> | 2021-04-22 17:06:54 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2021-04-29 16:36:06 -0700 |
commit | af10c45d7b3a44af0b461a557847fe03263dcc10 (patch) | |
tree | 6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/container.cpp | |
parent | 9c2aed97299fb96aeee3f1471ce40225437aaecf (diff) | |
download | wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2 wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip |
Move burn into burn
Diffstat (limited to 'src/burn/engine/container.cpp')
-rw-r--r-- | src/burn/engine/container.cpp | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/src/burn/engine/container.cpp b/src/burn/engine/container.cpp new file mode 100644 index 00000000..0cce3131 --- /dev/null +++ b/src/burn/engine/container.cpp | |||
@@ -0,0 +1,398 @@ | |||
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 | |||
6 | // function definitions | ||
7 | |||
8 | extern "C" HRESULT ContainersParseFromXml( | ||
9 | __in BURN_CONTAINERS* pContainers, | ||
10 | __in IXMLDOMNode* pixnBundle | ||
11 | ) | ||
12 | { | ||
13 | HRESULT hr = S_OK; | ||
14 | IXMLDOMNodeList* pixnNodes = NULL; | ||
15 | IXMLDOMNode* pixnNode = NULL; | ||
16 | DWORD cNodes = 0; | ||
17 | LPWSTR scz = NULL; | ||
18 | |||
19 | // select container nodes | ||
20 | hr = XmlSelectNodes(pixnBundle, L"Container", &pixnNodes); | ||
21 | ExitOnFailure(hr, "Failed to select container nodes."); | ||
22 | |||
23 | // get container node count | ||
24 | hr = pixnNodes->get_length((long*)&cNodes); | ||
25 | ExitOnFailure(hr, "Failed to get container node count."); | ||
26 | |||
27 | if (!cNodes) | ||
28 | { | ||
29 | ExitFunction(); | ||
30 | } | ||
31 | |||
32 | // allocate memory for searches | ||
33 | pContainers->rgContainers = (BURN_CONTAINER*)MemAlloc(sizeof(BURN_CONTAINER) * cNodes, TRUE); | ||
34 | ExitOnNull(pContainers->rgContainers, hr, E_OUTOFMEMORY, "Failed to allocate memory for container structs."); | ||
35 | |||
36 | pContainers->cContainers = cNodes; | ||
37 | |||
38 | // parse search elements | ||
39 | for (DWORD i = 0; i < cNodes; ++i) | ||
40 | { | ||
41 | BURN_CONTAINER* pContainer = &pContainers->rgContainers[i]; | ||
42 | |||
43 | hr = XmlNextElement(pixnNodes, &pixnNode, NULL); | ||
44 | ExitOnFailure(hr, "Failed to get next node."); | ||
45 | |||
46 | // TODO: Read type from manifest. Today only CABINET is supported. | ||
47 | pContainer->type = BURN_CONTAINER_TYPE_CABINET; | ||
48 | |||
49 | // @Id | ||
50 | hr = XmlGetAttributeEx(pixnNode, L"Id", &pContainer->sczId); | ||
51 | ExitOnFailure(hr, "Failed to get @Id."); | ||
52 | |||
53 | // @Primary | ||
54 | hr = XmlGetYesNoAttribute(pixnNode, L"Primary", &pContainer->fPrimary); | ||
55 | if (E_NOTFOUND != hr) | ||
56 | { | ||
57 | ExitOnFailure(hr, "Failed to get @Primary."); | ||
58 | } | ||
59 | |||
60 | // @Attached | ||
61 | hr = XmlGetYesNoAttribute(pixnNode, L"Attached", &pContainer->fAttached); | ||
62 | if (E_NOTFOUND != hr || pContainer->fPrimary) // if it is a primary container, it has to be attached | ||
63 | { | ||
64 | ExitOnFailure(hr, "Failed to get @Attached."); | ||
65 | } | ||
66 | |||
67 | // @AttachedIndex | ||
68 | hr = XmlGetAttributeNumber(pixnNode, L"AttachedIndex", &pContainer->dwAttachedIndex); | ||
69 | if (E_NOTFOUND != hr || pContainer->fAttached) // if it is an attached container it must have an index | ||
70 | { | ||
71 | ExitOnFailure(hr, "Failed to get @AttachedIndex."); | ||
72 | } | ||
73 | |||
74 | // Attached containers are always found attached to the current process, so use the current proccess's | ||
75 | // name instead of what may be in the manifest. | ||
76 | if (pContainer->fAttached) | ||
77 | { | ||
78 | hr = PathForCurrentProcess(&scz, NULL); | ||
79 | ExitOnFailure(hr, "Failed to get path to current process for attached container."); | ||
80 | |||
81 | LPCWSTR wzFileName = PathFile(scz); | ||
82 | |||
83 | hr = StrAllocString(&pContainer->sczFilePath, wzFileName, 0); | ||
84 | ExitOnFailure(hr, "Failed to set attached container file path."); | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | // @FilePath | ||
89 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pContainer->sczFilePath); | ||
90 | if (E_NOTFOUND != hr) | ||
91 | { | ||
92 | ExitOnFailure(hr, "Failed to get @FilePath."); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | // The source path starts as the file path. | ||
97 | hr = StrAllocString(&pContainer->sczSourcePath, pContainer->sczFilePath, 0); | ||
98 | ExitOnFailure(hr, "Failed to copy @FilePath"); | ||
99 | |||
100 | // @DownloadUrl | ||
101 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pContainer->downloadSource.sczUrl); | ||
102 | if (E_NOTFOUND != hr || (!pContainer->fPrimary && !pContainer->sczSourcePath)) // if the package is not a primary package, it must have a source path or a download url | ||
103 | { | ||
104 | ExitOnFailure(hr, "Failed to get @DownloadUrl. Either @SourcePath or @DownloadUrl needs to be provided."); | ||
105 | } | ||
106 | |||
107 | // @Hash | ||
108 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &pContainer->sczHash); | ||
109 | if (SUCCEEDED(hr)) | ||
110 | { | ||
111 | hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash); | ||
112 | ExitOnFailure(hr, "Failed to hex decode the Container/@Hash."); | ||
113 | } | ||
114 | else if (E_NOTFOUND != hr) | ||
115 | { | ||
116 | ExitOnFailure(hr, "Failed to get @Hash."); | ||
117 | } | ||
118 | |||
119 | // prepare next iteration | ||
120 | ReleaseNullObject(pixnNode); | ||
121 | } | ||
122 | |||
123 | hr = S_OK; | ||
124 | |||
125 | LExit: | ||
126 | ReleaseObject(pixnNodes); | ||
127 | ReleaseObject(pixnNode); | ||
128 | ReleaseStr(scz); | ||
129 | |||
130 | return hr; | ||
131 | } | ||
132 | |||
133 | extern "C" HRESULT ContainersInitialize( | ||
134 | __in BURN_CONTAINERS* pContainers, | ||
135 | __in BURN_SECTION* pSection | ||
136 | ) | ||
137 | { | ||
138 | HRESULT hr = S_OK; | ||
139 | |||
140 | if (pContainers->rgContainers) | ||
141 | { | ||
142 | for (DWORD i = 0; i < pContainers->cContainers; ++i) | ||
143 | { | ||
144 | BURN_CONTAINER* pContainer = &pContainers->rgContainers[i]; | ||
145 | |||
146 | // If the container is attached, make sure the information in the section matches what the | ||
147 | // manifest contained and get the offset to the container. | ||
148 | if (pContainer->fAttached) | ||
149 | { | ||
150 | hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &pContainer->qwFileSize, &pContainer->fActuallyAttached); | ||
151 | ExitOnFailure(hr, "Failed to get attached container information."); | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | LExit: | ||
157 | return hr; | ||
158 | } | ||
159 | |||
160 | extern "C" void ContainersUninitialize( | ||
161 | __in BURN_CONTAINERS* pContainers | ||
162 | ) | ||
163 | { | ||
164 | if (pContainers->rgContainers) | ||
165 | { | ||
166 | for (DWORD i = 0; i < pContainers->cContainers; ++i) | ||
167 | { | ||
168 | BURN_CONTAINER* pContainer = &pContainers->rgContainers[i]; | ||
169 | |||
170 | ReleaseStr(pContainer->sczId); | ||
171 | ReleaseStr(pContainer->sczHash); | ||
172 | ReleaseStr(pContainer->sczSourcePath); | ||
173 | ReleaseStr(pContainer->sczFilePath); | ||
174 | ReleaseMem(pContainer->pbHash); | ||
175 | ReleaseStr(pContainer->downloadSource.sczUrl); | ||
176 | ReleaseStr(pContainer->downloadSource.sczUser); | ||
177 | ReleaseStr(pContainer->downloadSource.sczPassword); | ||
178 | ReleaseStr(pContainer->sczUnverifiedPath); | ||
179 | } | ||
180 | MemFree(pContainers->rgContainers); | ||
181 | } | ||
182 | |||
183 | // clear struct | ||
184 | memset(pContainers, 0, sizeof(BURN_CONTAINERS)); | ||
185 | } | ||
186 | |||
187 | extern "C" HRESULT ContainerOpenUX( | ||
188 | __in BURN_SECTION* pSection, | ||
189 | __in BURN_CONTAINER_CONTEXT* pContext | ||
190 | ) | ||
191 | { | ||
192 | HRESULT hr = S_OK; | ||
193 | BURN_CONTAINER container = { }; | ||
194 | LPWSTR sczExecutablePath = NULL; | ||
195 | |||
196 | // open attached container | ||
197 | container.type = BURN_CONTAINER_TYPE_CABINET; | ||
198 | container.fPrimary = TRUE; | ||
199 | container.fAttached = TRUE; | ||
200 | container.dwAttachedIndex = 0; | ||
201 | |||
202 | hr = SectionGetAttachedContainerInfo(pSection, container.dwAttachedIndex, container.type, &container.qwAttachedOffset, &container.qwFileSize, &container.fActuallyAttached); | ||
203 | ExitOnFailure(hr, "Failed to get container information for UX container."); | ||
204 | |||
205 | AssertSz(container.fActuallyAttached, "The BA container must always be found attached."); | ||
206 | |||
207 | hr = PathForCurrentProcess(&sczExecutablePath, NULL); | ||
208 | ExitOnFailure(hr, "Failed to get path for executing module."); | ||
209 | |||
210 | hr = ContainerOpen(pContext, &container, pSection->hEngineFile, sczExecutablePath); | ||
211 | ExitOnFailure(hr, "Failed to open attached container."); | ||
212 | |||
213 | LExit: | ||
214 | ReleaseStr(sczExecutablePath); | ||
215 | |||
216 | return hr; | ||
217 | } | ||
218 | |||
219 | extern "C" HRESULT ContainerOpen( | ||
220 | __in BURN_CONTAINER_CONTEXT* pContext, | ||
221 | __in BURN_CONTAINER* pContainer, | ||
222 | __in HANDLE hContainerFile, | ||
223 | __in_z LPCWSTR wzFilePath | ||
224 | ) | ||
225 | { | ||
226 | HRESULT hr = S_OK; | ||
227 | LARGE_INTEGER li = { }; | ||
228 | |||
229 | // initialize context | ||
230 | pContext->type = pContainer->type; | ||
231 | pContext->qwSize = pContainer->qwFileSize; | ||
232 | pContext->qwOffset = pContainer->qwAttachedOffset; | ||
233 | |||
234 | // If the handle to the container is not open already, open container file | ||
235 | if (INVALID_HANDLE_VALUE == hContainerFile) | ||
236 | { | ||
237 | pContext->hFile = ::CreateFileW(wzFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||
238 | ExitOnInvalidHandleWithLastError(pContext->hFile, hr, "Failed to open file: %ls", wzFilePath); | ||
239 | } | ||
240 | else // use the container file handle. | ||
241 | { | ||
242 | if (!::DuplicateHandle(::GetCurrentProcess(), hContainerFile, ::GetCurrentProcess(), &pContext->hFile, 0, FALSE, DUPLICATE_SAME_ACCESS)) | ||
243 | { | ||
244 | ExitWithLastError(hr, "Failed to duplicate handle to container: %ls", wzFilePath); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | // If it is a container attached to an executable, seek to the container offset. | ||
249 | if (pContainer->fAttached) | ||
250 | { | ||
251 | li.QuadPart = (LONGLONG)pContext->qwOffset; | ||
252 | } | ||
253 | |||
254 | if (!::SetFilePointerEx(pContext->hFile, li, NULL, FILE_BEGIN)) | ||
255 | { | ||
256 | ExitWithLastError(hr, "Failed to move file pointer to container offset."); | ||
257 | } | ||
258 | |||
259 | // open the archive | ||
260 | switch (pContext->type) | ||
261 | { | ||
262 | case BURN_CONTAINER_TYPE_CABINET: | ||
263 | hr = CabExtractOpen(pContext, wzFilePath); | ||
264 | break; | ||
265 | } | ||
266 | ExitOnFailure(hr, "Failed to open container."); | ||
267 | |||
268 | LExit: | ||
269 | return hr; | ||
270 | } | ||
271 | |||
272 | extern "C" HRESULT ContainerNextStream( | ||
273 | __in BURN_CONTAINER_CONTEXT* pContext, | ||
274 | __inout_z LPWSTR* psczStreamName | ||
275 | ) | ||
276 | { | ||
277 | HRESULT hr = S_OK; | ||
278 | |||
279 | switch (pContext->type) | ||
280 | { | ||
281 | case BURN_CONTAINER_TYPE_CABINET: | ||
282 | hr = CabExtractNextStream(pContext, psczStreamName); | ||
283 | break; | ||
284 | } | ||
285 | |||
286 | //LExit: | ||
287 | return hr; | ||
288 | } | ||
289 | |||
290 | extern "C" HRESULT ContainerStreamToFile( | ||
291 | __in BURN_CONTAINER_CONTEXT* pContext, | ||
292 | __in_z LPCWSTR wzFileName | ||
293 | ) | ||
294 | { | ||
295 | HRESULT hr = S_OK; | ||
296 | |||
297 | switch (pContext->type) | ||
298 | { | ||
299 | case BURN_CONTAINER_TYPE_CABINET: | ||
300 | hr = CabExtractStreamToFile(pContext, wzFileName); | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | //LExit: | ||
305 | return hr; | ||
306 | } | ||
307 | |||
308 | extern "C" HRESULT ContainerStreamToBuffer( | ||
309 | __in BURN_CONTAINER_CONTEXT* pContext, | ||
310 | __out BYTE** ppbBuffer, | ||
311 | __out SIZE_T* pcbBuffer | ||
312 | ) | ||
313 | { | ||
314 | HRESULT hr = S_OK; | ||
315 | |||
316 | switch (pContext->type) | ||
317 | { | ||
318 | case BURN_CONTAINER_TYPE_CABINET: | ||
319 | hr = CabExtractStreamToBuffer(pContext, ppbBuffer, pcbBuffer); | ||
320 | break; | ||
321 | |||
322 | default: | ||
323 | *ppbBuffer = NULL; | ||
324 | *pcbBuffer = 0; | ||
325 | } | ||
326 | |||
327 | //LExit: | ||
328 | return hr; | ||
329 | } | ||
330 | |||
331 | extern "C" HRESULT ContainerSkipStream( | ||
332 | __in BURN_CONTAINER_CONTEXT* pContext | ||
333 | ) | ||
334 | { | ||
335 | HRESULT hr = S_OK; | ||
336 | |||
337 | switch (pContext->type) | ||
338 | { | ||
339 | case BURN_CONTAINER_TYPE_CABINET: | ||
340 | hr = CabExtractSkipStream(pContext); | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | //LExit: | ||
345 | return hr; | ||
346 | } | ||
347 | |||
348 | extern "C" HRESULT ContainerClose( | ||
349 | __in BURN_CONTAINER_CONTEXT* pContext | ||
350 | ) | ||
351 | { | ||
352 | HRESULT hr = S_OK; | ||
353 | |||
354 | // close container | ||
355 | switch (pContext->type) | ||
356 | { | ||
357 | case BURN_CONTAINER_TYPE_CABINET: | ||
358 | hr = CabExtractClose(pContext); | ||
359 | ExitOnFailure(hr, "Failed to close cabinet."); | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | LExit: | ||
364 | ReleaseFile(pContext->hFile); | ||
365 | |||
366 | if (SUCCEEDED(hr)) | ||
367 | { | ||
368 | memset(pContext, 0, sizeof(BURN_CONTAINER_CONTEXT)); | ||
369 | } | ||
370 | |||
371 | return hr; | ||
372 | } | ||
373 | |||
374 | extern "C" HRESULT ContainerFindById( | ||
375 | __in BURN_CONTAINERS* pContainers, | ||
376 | __in_z LPCWSTR wzId, | ||
377 | __out BURN_CONTAINER** ppContainer | ||
378 | ) | ||
379 | { | ||
380 | HRESULT hr = S_OK; | ||
381 | BURN_CONTAINER* pContainer = NULL; | ||
382 | |||
383 | for (DWORD i = 0; i < pContainers->cContainers; ++i) | ||
384 | { | ||
385 | pContainer = &pContainers->rgContainers[i]; | ||
386 | |||
387 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pContainer->sczId, -1, wzId, -1)) | ||
388 | { | ||
389 | *ppContainer = pContainer; | ||
390 | ExitFunction1(hr = S_OK); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | hr = E_NOTFOUND; | ||
395 | |||
396 | LExit: | ||
397 | return hr; | ||
398 | } | ||