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