VirtualBox

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

Last change on this file since 72426 was 69111, checked in by vboxsync, 7 years ago

(C) year

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