VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 6 weeks ago

Copyright year updates by scm.

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