VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/checksum/manifest3.cpp@ 63451

Last change on this file since 63451 was 62477, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.6 KB
Line 
1/* $Id: manifest3.cpp 62477 2016-07-22 18:27:37Z vboxsync $ */
2/** @file
3 * IPRT - Manifest, the bits with the most dependencies.
4 */
5
6/*
7 * Copyright (C) 2010-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/manifest.h>
33
34#include <iprt/alloca.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/err.h>
38#include <iprt/file.h>
39#include <iprt/md5.h>
40#include <iprt/mem.h>
41#include <iprt/sha.h>
42#include <iprt/string.h>
43#include <iprt/vfs.h>
44#include <iprt/vfslowlevel.h>
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * Hashes data.
52 *
53 * Used when hashing a file, stream or similar.
54 */
55typedef struct RTMANIFESTHASHES
56{
57 /** The desired attribute types.
58 * Only the hashes indicated by this will be calculated. */
59 uint32_t fAttrs;
60 /** The size. */
61 RTFOFF cbStream;
62
63 /** The MD5 context. */
64 RTMD5CONTEXT Md5Ctx;
65 /** The SHA-1 context. */
66 RTSHA1CONTEXT Sha1Ctx;
67 /** The SHA-256 context. */
68 RTSHA256CONTEXT Sha256Ctx;
69 /** The SHA-512 context. */
70 RTSHA512CONTEXT Sha512Ctx;
71
72 /** The MD5 digest. */
73 uint8_t abMd5Digest[RTMD5_HASH_SIZE];
74 /** The SHA-1 digest. */
75 uint8_t abSha1Digest[RTSHA1_HASH_SIZE];
76 /** The SHA-256 digest. */
77 uint8_t abSha256Digest[RTSHA256_HASH_SIZE];
78 /** The SHA-512 digest. */
79 uint8_t abSha512Digest[RTSHA512_HASH_SIZE];
80} RTMANIFESTHASHES;
81/** Pointer to a the hashes for a stream. */
82typedef RTMANIFESTHASHES *PRTMANIFESTHASHES;
83
84
85/**
86 * The internal data of a manifest passthru I/O stream.
87 */
88typedef struct RTMANIFESTPTIOS
89{
90 /** The stream we're reading from or writing to. */
91 RTVFSIOSTREAM hVfsIos;
92 /** The hashes. */
93 PRTMANIFESTHASHES pHashes;
94 /** The current hash position. */
95 RTFOFF offCurPos;
96 /** Whether we're reading or writing. */
97 bool fReadOrWrite;
98 /** Whether we've already added the entry to the manifest. */
99 bool fAddedEntry;
100 /** The entry name. */
101 char *pszEntry;
102 /** The manifest to add the entry to. */
103 RTMANIFEST hManifest;
104} RTMANIFESTPTIOS;
105/** Pointer to a the internal data of a manifest passthru I/O stream. */
106typedef RTMANIFESTPTIOS *PRTMANIFESTPTIOS;
107
108
109
110/**
111 * Creates a hashes structure.
112 *
113 * @returns Pointer to a hashes structure.
114 * @param fAttrs The desired hashes, RTMANIFEST_ATTR_XXX.
115 */
116static PRTMANIFESTHASHES rtManifestHashesCreate(uint32_t fAttrs)
117{
118 PRTMANIFESTHASHES pHashes = (PRTMANIFESTHASHES)RTMemTmpAllocZ(sizeof(*pHashes));
119 if (pHashes)
120 {
121 pHashes->fAttrs = fAttrs;
122 /*pHashes->cbStream = 0;*/
123 if (fAttrs & RTMANIFEST_ATTR_MD5)
124 RTMd5Init(&pHashes->Md5Ctx);
125 if (fAttrs & RTMANIFEST_ATTR_SHA1)
126 RTSha1Init(&pHashes->Sha1Ctx);
127 if (fAttrs & RTMANIFEST_ATTR_SHA256)
128 RTSha256Init(&pHashes->Sha256Ctx);
129 if (fAttrs & RTMANIFEST_ATTR_SHA512)
130 RTSha512Init(&pHashes->Sha512Ctx);
131 }
132 return pHashes;
133}
134
135
136/**
137 * Updates the hashes with a block of data.
138 *
139 * @param pHashes The hashes structure.
140 * @param pvBuf The data block.
141 * @param cbBuf The size of the data block.
142 */
143static void rtManifestHashesUpdate(PRTMANIFESTHASHES pHashes, void const *pvBuf, size_t cbBuf)
144{
145 pHashes->cbStream += cbBuf;
146 if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
147 RTMd5Update(&pHashes->Md5Ctx, pvBuf, cbBuf);
148 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
149 RTSha1Update(&pHashes->Sha1Ctx, pvBuf, cbBuf);
150 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
151 RTSha256Update(&pHashes->Sha256Ctx, pvBuf, cbBuf);
152 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
153 RTSha512Update(&pHashes->Sha512Ctx, pvBuf, cbBuf);
154}
155
156
157/**
158 * Finalizes all the hashes.
159 *
160 * @param pHashes The hashes structure.
161 */
162static void rtManifestHashesFinal(PRTMANIFESTHASHES pHashes)
163{
164 if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
165 RTMd5Final(pHashes->abMd5Digest, &pHashes->Md5Ctx);
166 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
167 RTSha1Final(&pHashes->Sha1Ctx, pHashes->abSha1Digest);
168 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
169 RTSha256Final(&pHashes->Sha256Ctx, pHashes->abSha256Digest);
170 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
171 RTSha512Final(&pHashes->Sha512Ctx, pHashes->abSha512Digest);
172}
173
174
175/**
176 * Adds the hashes to a manifest entry.
177 *
178 * @returns IPRT status code.
179 * @param pHashes The hashes structure.
180 * @param hManifest The manifest to add them to.
181 * @param pszEntry The entry name.
182 */
183static int rtManifestHashesSetAttrs(PRTMANIFESTHASHES pHashes, RTMANIFEST hManifest, const char *pszEntry)
184{
185 char szValue[RTSHA512_DIGEST_LEN + 8];
186 int rc = VINF_SUCCESS;
187 int rc2;
188
189 if (pHashes->fAttrs & RTMANIFEST_ATTR_SIZE)
190 {
191 RTStrPrintf(szValue, sizeof(szValue), "%RU64", (uint64_t)pHashes->cbStream);
192 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SIZE", szValue, RTMANIFEST_ATTR_SIZE);
193 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
194 rc = rc2;
195 }
196
197 if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
198 {
199 rc2 = RTMd5ToString(pHashes->abMd5Digest, szValue, sizeof(szValue));
200 if (RT_SUCCESS(rc2))
201 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "MD5", szValue, RTMANIFEST_ATTR_MD5);
202 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
203 rc = rc2;
204 }
205
206 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
207 {
208 rc2 = RTSha1ToString(pHashes->abSha1Digest, szValue, sizeof(szValue));
209 if (RT_SUCCESS(rc2))
210 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA1", szValue, RTMANIFEST_ATTR_SHA1);
211 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
212 rc = rc2;
213 }
214
215 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
216 {
217 rc2 = RTSha256ToString(pHashes->abSha256Digest, szValue, sizeof(szValue));
218 if (RT_SUCCESS(rc2))
219 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA256", szValue, RTMANIFEST_ATTR_SHA256);
220 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
221 rc = rc2;
222 }
223
224 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
225 {
226 rc2 = RTSha512ToString(pHashes->abSha512Digest, szValue, sizeof(szValue));
227 if (RT_SUCCESS(rc2))
228 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA512", szValue, RTMANIFEST_ATTR_SHA512);
229 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
230 rc = rc2;
231 }
232 return rc;
233}
234
235
236/**
237 * Destroys the hashes.
238 *
239 * @param pHashes The hashes structure. NULL is ignored.
240 */
241static void rtManifestHashesDestroy(PRTMANIFESTHASHES pHashes)
242{
243 RTMemTmpFree(pHashes);
244}
245
246
247
248/*
249 *
250 * M a n i f e s t p a s s t h r u I / O s t r e a m
251 * M a n i f e s t p a s s t h r u I / O s t r e a m
252 * M a n i f e s t p a s s t h r u I / O s t r e a m
253 *
254 */
255
256
257/**
258 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
259 */
260static DECLCALLBACK(int) rtManifestPtIos_Close(void *pvThis)
261{
262 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
263
264 int rc = VINF_SUCCESS;
265 if (!pThis->fAddedEntry)
266 {
267 rtManifestHashesFinal(pThis->pHashes);
268 rc = rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
269 }
270
271 RTVfsIoStrmRelease(pThis->hVfsIos);
272 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
273 rtManifestHashesDestroy(pThis->pHashes);
274 pThis->pHashes = NULL;
275 RTStrFree(pThis->pszEntry);
276 pThis->pszEntry = NULL;
277 RTManifestRelease(pThis->hManifest);
278 pThis->hManifest = NIL_RTMANIFEST;
279
280 return rc;
281}
282
283
284/**
285 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
286 */
287static DECLCALLBACK(int) rtManifestPtIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
288{
289 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
290 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
291}
292
293/**
294 * Updates the hashes with a scather/gather buffer.
295 *
296 * @param pThis The passthru I/O stream instance data.
297 * @param pSgBuf The scather/gather buffer.
298 * @param cbLeft The number of bytes to take from the buffer.
299 */
300static void rtManifestPtIos_UpdateHashes(PRTMANIFESTPTIOS pThis, PCRTSGBUF pSgBuf, size_t cbLeft)
301{
302 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
303 {
304 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
305 if (cbSeg > cbLeft)
306 cbSeg = cbLeft;
307 rtManifestHashesUpdate(pThis->pHashes, pSgBuf->paSegs[iSeg].pvSeg, cbSeg);
308 cbLeft -= cbSeg;
309 if (!cbLeft)
310 break;
311 }
312}
313
314/**
315 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
316 */
317static DECLCALLBACK(int) rtManifestPtIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
318{
319 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
320 int rc;
321
322 /*
323 * To make sure we're continuing where we left off, we must have the exact
324 * stream position since a previous read using 'off' may change it.
325 */
326 RTFOFF offActual = off == -1 ? RTVfsIoStrmTell(pThis->hVfsIos) : off;
327 if (offActual == pThis->offCurPos)
328 {
329 rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
330 if (RT_SUCCESS(rc))
331 {
332 rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbRead ? *pcbRead : ~(size_t)0);
333 if (!pcbRead)
334 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
335 pThis->offCurPos += pSgBuf->paSegs[iSeg].cbSeg;
336 else
337 pThis->offCurPos += *pcbRead;
338 }
339 Assert(RTVfsIoStrmTell(pThis->hVfsIos) == pThis->offCurPos);
340 }
341 else
342 {
343 /*
344 * If we're skipping over stuff, we need to read the gap and hash it.
345 */
346 if (pThis->offCurPos < offActual)
347 {
348 size_t cbBuf = _8K;
349 void *pvBuf = alloca(cbBuf);
350 do
351 {
352 RTFOFF cbGap = off - pThis->offCurPos;
353 size_t cbThisRead = cbGap >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbGap;
354 size_t cbActual;
355 rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offCurPos, pvBuf, cbThisRead, fBlocking, &cbActual);
356 if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN)
357 return rc;
358
359 rtManifestHashesUpdate(pThis->pHashes, pvBuf, cbActual);
360 pThis->offCurPos += cbActual;
361
362 if (rc == VINF_EOF)
363 {
364 if (pcbRead)
365 *pcbRead = 0;
366 else
367 rc = VERR_EOF;
368 return rc;
369 }
370 } while (pThis->offCurPos < offActual);
371 Assert(RTVfsIoStrmTell(pThis->hVfsIos) == offActual);
372 }
373
374 /*
375 * At this point we've eliminated any gap and can execute the requested read.
376 */
377 rc = RTVfsIoStrmSgRead(pThis->hVfsIos, off, pSgBuf, fBlocking, pcbRead);
378 if (RT_SUCCESS(rc))
379 {
380 /* See if there is anything to update the hash with. */
381 size_t cbLeft = pcbRead ? *pcbRead : ~(size_t)0;
382 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
383 {
384 size_t cbThis = pSgBuf->paSegs[iSeg].cbSeg;
385 if (cbThis > cbLeft)
386 cbThis = cbLeft;
387
388 if ( offActual >= pThis->offCurPos
389 && pThis->offCurPos < offActual + (ssize_t)cbThis)
390 {
391 size_t offSeg = (size_t)(offActual - pThis->offCurPos);
392 rtManifestHashesUpdate(pThis->pHashes, (uint8_t *)pSgBuf->paSegs[iSeg].pvSeg + offSeg, cbThis - offSeg);
393 pThis->offCurPos += cbThis - offSeg;
394 }
395
396 cbLeft -= cbThis;
397 if (!cbLeft)
398 break;
399 offActual += cbThis;
400 }
401 }
402 }
403 return rc;
404}
405
406
407/**
408 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
409 */
410static DECLCALLBACK(int) rtManifestPtIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
411{
412 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
413 AssertReturn(off == -1 || off == pThis->offCurPos, VERR_WRONG_ORDER);
414 Assert(RTVfsIoStrmTell(pThis->hVfsIos) == pThis->offCurPos);
415
416 int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
417 if (RT_SUCCESS(rc))
418 {
419 rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbWritten ? *pcbWritten : ~(size_t)0);
420 if (!pcbWritten)
421 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
422 pThis->offCurPos += pSgBuf->paSegs[iSeg].cbSeg;
423 else
424 pThis->offCurPos += *pcbWritten;
425 }
426 return rc;
427}
428
429
430/**
431 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
432 */
433static DECLCALLBACK(int) rtManifestPtIos_Flush(void *pvThis)
434{
435 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
436 return RTVfsIoStrmFlush(pThis->hVfsIos);
437}
438
439
440/**
441 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
442 */
443static DECLCALLBACK(int) rtManifestPtIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
444 uint32_t *pfRetEvents)
445{
446 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
447 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
448}
449
450
451/**
452 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
453 */
454static DECLCALLBACK(int) rtManifestPtIos_Tell(void *pvThis, PRTFOFF poffActual)
455{
456 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
457 RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos);
458 if (off < 0)
459 return (int)off;
460 *poffActual = off;
461 return VINF_SUCCESS;
462}
463
464
465/**
466 * The manifest passthru I/O stream vtable.
467 */
468static RTVFSIOSTREAMOPS g_rtManifestPassthruIosOps =
469{
470 { /* Obj */
471 RTVFSOBJOPS_VERSION,
472 RTVFSOBJTYPE_IO_STREAM,
473 "manifest passthru I/O stream",
474 rtManifestPtIos_Close,
475 rtManifestPtIos_QueryInfo,
476 RTVFSOBJOPS_VERSION
477 },
478 RTVFSIOSTREAMOPS_VERSION,
479 0,
480 rtManifestPtIos_Read,
481 rtManifestPtIos_Write,
482 rtManifestPtIos_Flush,
483 rtManifestPtIos_PollOne,
484 rtManifestPtIos_Tell,
485 NULL /* Skip */,
486 NULL /* ZeroFill */,
487 RTVFSIOSTREAMOPS_VERSION,
488};
489
490
491
492/**
493 * Add an entry for an I/O stream using a passthru stream.
494 *
495 * The passthru I/O stream will hash all the data read from or written to the
496 * stream and automatically add an entry to the manifest with the desired
497 * attributes when it is released. Alternatively one can call
498 * RTManifestPtIosAddEntryNow() to have more control over exactly when this
499 * action is performed and which status it yields.
500 *
501 * @returns IPRT status code.
502 * @param hManifest The manifest to add the entry to.
503 * @param hVfsIos The I/O stream to pass thru to/from.
504 * @param pszEntry The entry name.
505 * @param fAttrs The attributes to create for this stream.
506 * @param fReadOrWrite Whether it's a read or write I/O stream.
507 * @param phVfsIosPassthru Where to return the new handle.
508 */
509RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry,
510 uint32_t fAttrs, bool fReadOrWrite, PRTVFSIOSTREAM phVfsIosPassthru)
511{
512 /*
513 * Validate input.
514 */
515 AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
516 AssertPtr(pszEntry);
517 AssertPtr(phVfsIosPassthru);
518
519 RTFOFF const offCurPos = RTVfsIoStrmTell(hVfsIos);
520 AssertReturn(offCurPos >= 0, (int)offCurPos);
521
522 uint32_t cRefs = RTManifestRetain(hManifest);
523 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
524
525 cRefs = RTVfsIoStrmRetain(hVfsIos);
526 AssertReturnStmt(cRefs != UINT32_MAX, RTManifestRelease(hManifest), VERR_INVALID_HANDLE);
527
528 /*
529 * Create an instace of the passthru I/O stream.
530 */
531 PRTMANIFESTPTIOS pThis;
532 RTVFSIOSTREAM hVfsPtIos;
533 int rc = RTVfsNewIoStream(&g_rtManifestPassthruIosOps, sizeof(*pThis), fReadOrWrite ? RTFILE_O_READ : RTFILE_O_WRITE,
534 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsPtIos, (void **)&pThis);
535 if (RT_SUCCESS(rc))
536 {
537 pThis->hVfsIos = hVfsIos;
538 pThis->pHashes = rtManifestHashesCreate(fAttrs);
539 pThis->offCurPos = offCurPos;
540 pThis->hManifest = hManifest;
541 pThis->fReadOrWrite = fReadOrWrite;
542 pThis->fAddedEntry = false;
543 pThis->pszEntry = RTStrDup(pszEntry);
544 if (pThis->pszEntry && pThis->pHashes)
545 {
546 *phVfsIosPassthru = hVfsPtIos;
547 return VINF_SUCCESS;
548 }
549
550 RTVfsIoStrmRelease(hVfsPtIos);
551 }
552 else
553 {
554 RTVfsIoStrmRelease(hVfsIos);
555 RTManifestRelease(hManifest);
556 }
557 return rc;
558}
559
560
561/**
562 * Adds the entry to the manifest right now.
563 *
564 * @returns IPRT status code.
565 * @param hVfsPtIos The manifest passthru I/O stream returned by
566 * RTManifestEntryAddPassthruIoStream().
567 */
568RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos)
569{
570 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
571 AssertReturn(pThis, VERR_INVALID_HANDLE);
572 AssertReturn(!pThis->fAddedEntry, VERR_WRONG_ORDER);
573
574 pThis->fAddedEntry = true;
575 rtManifestHashesFinal(pThis->pHashes);
576 return rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
577}
578
579
580/**
581 * Checks if the give I/O stream is a manifest passthru instance or not.
582 *
583 * @returns true if it's a manifest passthru I/O stream, false if not.
584 * @param hVfsPtIos Possible the manifest passthru I/O stream handle.
585 */
586RTDECL(bool) RTManifestPtIosIsInstanceOf(RTVFSIOSTREAM hVfsPtIos)
587{
588 if (hVfsPtIos != NIL_RTVFSIOSTREAM)
589 {
590 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
591 if (pThis)
592 return true;
593 }
594 return false;
595}
596
597
598/**
599 * Adds an entry for a file with the specified set of attributes.
600 *
601 * @returns IPRT status code.
602 *
603 * @param hManifest The manifest handle.
604 * @param hVfsIos The I/O stream handle of the entry. This will
605 * be processed to its end on successful return.
606 * (Must be positioned at the start to get
607 * the expected results.)
608 * @param pszEntry The entry name.
609 * @param fAttrs The attributes to create for this stream.
610 */
611RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs)
612{
613 /*
614 * Note! This is a convenicence function, so just use the available public
615 * methods to get the job done.
616 */
617 AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
618 AssertPtr(pszEntry);
619
620 /*
621 * Allocate and initialize the hash contexts, hash digests and I/O buffer.
622 */
623 PRTMANIFESTHASHES pHashes = rtManifestHashesCreate(fAttrs);
624 if (!pHashes)
625 return VERR_NO_TMP_MEMORY;
626
627 int rc;
628 size_t cbBuf = _1M;
629 void *pvBuf = RTMemTmpAlloc(cbBuf);
630 if (RT_UNLIKELY(!pvBuf))
631 {
632 cbBuf = _4K;
633 pvBuf = RTMemTmpAlloc(cbBuf);
634 }
635 if (RT_LIKELY(pvBuf))
636 {
637 /*
638 * Process the stream data.
639 */
640 for (;;)
641 {
642 size_t cbRead;
643 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
644 if ( (rc == VINF_EOF && cbRead == 0)
645 || RT_FAILURE(rc))
646 break;
647 rtManifestHashesUpdate(pHashes, pvBuf, cbRead);
648 }
649 RTMemTmpFree(pvBuf);
650 if (RT_SUCCESS(rc))
651 {
652 /*
653 * Add the entry with the finalized hashes.
654 */
655 rtManifestHashesFinal(pHashes);
656 rc = RTManifestEntryAdd(hManifest, pszEntry);
657 if (RT_SUCCESS(rc))
658 rc = rtManifestHashesSetAttrs(pHashes, hManifest, pszEntry);
659 }
660 }
661 else
662 rc = VERR_NO_TMP_MEMORY;
663
664 rtManifestHashesDestroy(pHashes);
665 return rc;
666}
667
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette