summaryrefslogtreecommitdiff
path: root/src/burn/engine/container.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine/container.cpp')
-rw-r--r--src/burn/engine/container.cpp398
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
8extern "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
125LExit:
126 ReleaseObject(pixnNodes);
127 ReleaseObject(pixnNode);
128 ReleaseStr(scz);
129
130 return hr;
131}
132
133extern "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
156LExit:
157 return hr;
158}
159
160extern "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
187extern "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
213LExit:
214 ReleaseStr(sczExecutablePath);
215
216 return hr;
217}
218
219extern "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
268LExit:
269 return hr;
270}
271
272extern "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
290extern "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
308extern "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
331extern "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
348extern "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
363LExit:
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
374extern "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
396LExit:
397 return hr;
398}