VirtualBox

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

Last change on this file since 42072 was 39439, checked in by vboxsync, 13 years ago

manifest3.cpp: plugged leak.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.4 KB
Line 
1/* $Id: manifest3.cpp 39439 2011-11-28 13:56:13Z vboxsync $ */
2/** @file
3 * IPRT - Manifest, the bits with the most dependencies.
4 */
5
6/*
7 * Copyright (C) 2010 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/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/file.h>
38#include <iprt/md5.h>
39#include <iprt/mem.h>
40#include <iprt/sha.h>
41#include <iprt/string.h>
42#include <iprt/vfs.h>
43#include <iprt/vfslowlevel.h>
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * Hashes data.
51 *
52 * Used when hashing a file, stream or similar.
53 */
54typedef struct RTMANIFESTHASHES
55{
56 /** The desired attribute types.
57 * Only the hashes indicated by this will be calculated. */
58 uint32_t fAttrs;
59 /** The size. */
60 RTFOFF cbStream;
61
62 /** The MD5 context. */
63 RTMD5CONTEXT Md5Ctx;
64 /** The SHA-1 context. */
65 RTSHA1CONTEXT Sha1Ctx;
66 /** The SHA-256 context. */
67 RTSHA256CONTEXT Sha256Ctx;
68 /** The SHA-512 context. */
69 RTSHA512CONTEXT Sha512Ctx;
70
71 /** The MD5 digest. */
72 uint8_t abMd5Digest[RTMD5_HASH_SIZE];
73 /** The SHA-1 digest. */
74 uint8_t abSha1Digest[RTSHA1_HASH_SIZE];
75 /** The SHA-256 digest. */
76 uint8_t abSha256Digest[RTSHA256_HASH_SIZE];
77 /** The SHA-512 digest. */
78 uint8_t abSha512Digest[RTSHA512_HASH_SIZE];
79} RTMANIFESTHASHES;
80/** Pointer to a the hashes for a stream. */
81typedef RTMANIFESTHASHES *PRTMANIFESTHASHES;
82
83
84/**
85 * The internal data of a manifest passthru I/O stream.
86 */
87typedef struct RTMANIFESTPTIOS
88{
89 /** The stream we're reading from or writing to. */
90 RTVFSIOSTREAM hVfsIos;
91 /** The hashes. */
92 PRTMANIFESTHASHES pHashes;
93 /** Whether we're reading or writing. */
94 bool fReadOrWrite;
95 /** Whether we've already added the entry to the manifest. */
96 bool fAddedEntry;
97 /** The entry name. */
98 char *pszEntry;
99 /** The manifest to add the entry to. */
100 RTMANIFEST hManifest;
101} RTMANIFESTPTIOS;
102/** Pointer to a the internal data of a manifest passthru I/O stream. */
103typedef RTMANIFESTPTIOS *PRTMANIFESTPTIOS;
104
105
106
107/**
108 * Creates a hashes structure.
109 *
110 * @returns Pointer to a hashes structure.
111 * @param fAttrs The desired hashes, RTMANIFEST_ATTR_XXX.
112 */
113static PRTMANIFESTHASHES rtManifestHashesCreate(uint32_t fAttrs)
114{
115 PRTMANIFESTHASHES pHashes = (PRTMANIFESTHASHES)RTMemTmpAllocZ(sizeof(*pHashes));
116 if (pHashes)
117 {
118 pHashes->fAttrs = fAttrs;
119 /*pHashes->cbStream = 0;*/
120 if (fAttrs & RTMANIFEST_ATTR_MD5)
121 RTMd5Init(&pHashes->Md5Ctx);
122 if (fAttrs & RTMANIFEST_ATTR_SHA1)
123 RTSha1Init(&pHashes->Sha1Ctx);
124 if (fAttrs & RTMANIFEST_ATTR_SHA256)
125 RTSha256Init(&pHashes->Sha256Ctx);
126 if (fAttrs & RTMANIFEST_ATTR_SHA512)
127 RTSha512Init(&pHashes->Sha512Ctx);
128 }
129 return pHashes;
130}
131
132
133/**
134 * Updates the hashes with a block of data.
135 *
136 * @param pHashes The hashes structure.
137 * @param pvBuf The data block.
138 * @param cbBuf The size of the data block.
139 */
140static void rtManifestHashesUpdate(PRTMANIFESTHASHES pHashes, void const *pvBuf, size_t cbBuf)
141{
142 pHashes->cbStream += cbBuf;
143 if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
144 RTMd5Update(&pHashes->Md5Ctx, pvBuf, cbBuf);
145 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
146 RTSha1Update(&pHashes->Sha1Ctx, pvBuf, cbBuf);
147 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
148 RTSha256Update(&pHashes->Sha256Ctx, pvBuf, cbBuf);
149 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
150 RTSha512Update(&pHashes->Sha512Ctx, pvBuf, cbBuf);
151}
152
153
154/**
155 * Finalizes all the hashes.
156 *
157 * @param pHashes The hashes structure.
158 */
159static void rtManifestHashesFinal(PRTMANIFESTHASHES pHashes)
160{
161 if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
162 RTMd5Final(pHashes->abMd5Digest, &pHashes->Md5Ctx);
163 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
164 RTSha1Final(&pHashes->Sha1Ctx, pHashes->abSha1Digest);
165 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
166 RTSha256Final(&pHashes->Sha256Ctx, pHashes->abSha256Digest);
167 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
168 RTSha512Final(&pHashes->Sha512Ctx, pHashes->abSha512Digest);
169}
170
171
172/**
173 * Adds the hashes to a manifest entry.
174 *
175 * @returns IPRT status code.
176 * @param pHashes The hashes structure.
177 * @param hManifest The manifest to add them to.
178 * @param pszEntry The entry name.
179 */
180static int rtManifestHashesSetAttrs(PRTMANIFESTHASHES pHashes, RTMANIFEST hManifest, const char *pszEntry)
181{
182 char szValue[RTSHA512_DIGEST_LEN + 8];
183 int rc = VINF_SUCCESS;
184 int rc2;
185
186 if (pHashes->fAttrs & RTMANIFEST_ATTR_SIZE)
187 {
188 RTStrPrintf(szValue, sizeof(szValue), "%RU64", (uint64_t)pHashes->cbStream);
189 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SIZE", szValue, RTMANIFEST_ATTR_SIZE);
190 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
191 rc = rc2;
192 }
193
194 if (pHashes->fAttrs & RTMANIFEST_ATTR_MD5)
195 {
196 rc2 = RTMd5ToString(pHashes->abMd5Digest, szValue, sizeof(szValue));
197 if (RT_SUCCESS(rc2))
198 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "MD5", szValue, RTMANIFEST_ATTR_MD5);
199 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
200 rc = rc2;
201 }
202
203 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA1)
204 {
205 rc2 = RTSha1ToString(pHashes->abSha1Digest, szValue, sizeof(szValue));
206 if (RT_SUCCESS(rc2))
207 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA1", szValue, RTMANIFEST_ATTR_SHA1);
208 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
209 rc = rc2;
210 }
211
212 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA256)
213 {
214 rc2 = RTSha256ToString(pHashes->abSha256Digest, szValue, sizeof(szValue));
215 if (RT_SUCCESS(rc2))
216 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA256", szValue, RTMANIFEST_ATTR_SHA256);
217 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
218 rc = rc2;
219 }
220
221 if (pHashes->fAttrs & RTMANIFEST_ATTR_SHA512)
222 {
223 rc2 = RTSha512ToString(pHashes->abSha512Digest, szValue, sizeof(szValue));
224 if (RT_SUCCESS(rc2))
225 rc2 = RTManifestEntrySetAttr(hManifest, pszEntry, "SHA512", szValue, RTMANIFEST_ATTR_SHA512);
226 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
227 rc = rc2;
228 }
229 return rc;
230}
231
232
233/**
234 * Destroys the hashes.
235 *
236 * @param pHashes The hashes structure. NULL is ignored.
237 */
238static void rtManifestHashesDestroy(PRTMANIFESTHASHES pHashes)
239{
240 RTMemTmpFree(pHashes);
241}
242
243
244
245/*
246 *
247 * M a n i f e s t p a s s t h r u I / O s t r e a m
248 * M a n i f e s t p a s s t h r u I / O s t r e a m
249 * M a n i f e s t p a s s t h r u I / O s t r e a m
250 *
251 */
252
253
254/**
255 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
256 */
257static DECLCALLBACK(int) rtManifestPtIos_Close(void *pvThis)
258{
259 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
260
261 int rc = VINF_SUCCESS;
262 if (!pThis->fAddedEntry)
263 {
264 rtManifestHashesFinal(pThis->pHashes);
265 rc = rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
266 }
267
268 RTVfsIoStrmRelease(pThis->hVfsIos);
269 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
270 rtManifestHashesDestroy(pThis->pHashes);
271 pThis->pHashes = NULL;
272 RTStrFree(pThis->pszEntry);
273 pThis->pszEntry = NULL;
274 RTManifestRelease(pThis->hManifest);
275 pThis->hManifest = NIL_RTMANIFEST;
276
277 return rc;
278}
279
280
281/**
282 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
283 */
284static DECLCALLBACK(int) rtManifestPtIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
285{
286 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
287 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
288}
289
290/**
291 * Updates the hashes with a scather/gather buffer.
292 *
293 * @param pThis The passthru I/O stream instance data.
294 * @param pSgBuf The scather/gather buffer.
295 * @param cbLeft The number of bytes to take from the buffer.
296 */
297static void rtManifestPtIos_UpdateHashes(PRTMANIFESTPTIOS pThis, PCRTSGBUF pSgBuf, size_t cbLeft)
298{
299 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
300 {
301 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
302 if (cbSeg > cbLeft)
303 cbSeg = cbLeft;
304 rtManifestHashesUpdate(pThis->pHashes, pSgBuf->paSegs[iSeg].pvSeg, cbSeg);
305 cbLeft -= cbSeg;
306 if (!cbLeft)
307 break;
308 }
309}
310
311/**
312 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
313 */
314static DECLCALLBACK(int) rtManifestPtIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
315{
316 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
317 int rc = RTVfsIoStrmSgRead(pThis->hVfsIos, pSgBuf, fBlocking, pcbRead);
318 if (RT_SUCCESS(rc))
319 rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbRead ? *pcbRead : ~(size_t)0);
320 Assert(off == -1); NOREF(off);
321 return rc;
322}
323
324
325/**
326 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
327 */
328static DECLCALLBACK(int) rtManifestPtIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
329{
330 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
331 int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, pSgBuf, fBlocking, pcbWritten);
332 if (RT_SUCCESS(rc))
333 rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbWritten ? *pcbWritten : ~(size_t)0);
334 Assert(off == -1); NOREF(off);
335 return rc;
336}
337
338
339/**
340 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
341 */
342static DECLCALLBACK(int) rtManifestPtIos_Flush(void *pvThis)
343{
344 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
345 return RTVfsIoStrmFlush(pThis->hVfsIos);
346}
347
348
349/**
350 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
351 */
352static DECLCALLBACK(int) rtManifestPtIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
353 uint32_t *pfRetEvents)
354{
355 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
356 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
357}
358
359
360/**
361 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
362 */
363static DECLCALLBACK(int) rtManifestPtIos_Tell(void *pvThis, PRTFOFF poffActual)
364{
365 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
366 RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos);
367 if (off < 0)
368 return (int)off;
369 *poffActual = off;
370 return VINF_SUCCESS;
371}
372
373
374/**
375 * The manifest passthru I/O stream vtable.
376 */
377static RTVFSIOSTREAMOPS g_rtManifestPassthruIosOps =
378{
379 { /* Obj */
380 RTVFSOBJOPS_VERSION,
381 RTVFSOBJTYPE_IO_STREAM,
382 "manifest passthru I/O stream",
383 rtManifestPtIos_Close,
384 rtManifestPtIos_QueryInfo,
385 RTVFSOBJOPS_VERSION
386 },
387 RTVFSIOSTREAMOPS_VERSION,
388 0,
389 rtManifestPtIos_Read,
390 rtManifestPtIos_Write,
391 rtManifestPtIos_Flush,
392 rtManifestPtIos_PollOne,
393 rtManifestPtIos_Tell,
394 NULL /* Skip */,
395 NULL /* ZeroFill */,
396 RTVFSIOSTREAMOPS_VERSION,
397};
398
399
400
401/**
402 * Add an entry for an I/O stream using a passthru stream.
403 *
404 * The passthru I/O stream will hash all the data read from or written to the
405 * stream and automatically add an entry to the manifest with the desired
406 * attributes when it is released. Alternatively one can call
407 * RTManifestPtIosAddEntryNow() to have more control over exactly when this
408 * action is performed and which status it yields.
409 *
410 * @returns IPRT status code.
411 * @param hManifest The manifest to add the entry to.
412 * @param hVfsIos The I/O stream to pass thru to/from.
413 * @param pszEntry The entry name.
414 * @param fAttrs The attributes to create for this stream.
415 * @param fReadOrWrite Whether it's a read or write I/O stream.
416 * @param phVfsIosPassthru Where to return the new handle.
417 */
418RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry,
419 uint32_t fAttrs, bool fReadOrWrite, PRTVFSIOSTREAM phVfsIosPassthru)
420{
421 /*
422 * Validate input.
423 */
424 AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
425 AssertPtr(pszEntry);
426 AssertPtr(phVfsIosPassthru);
427 uint32_t cRefs = RTManifestRetain(hManifest);
428 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
429 cRefs = RTVfsIoStrmRetain(hVfsIos);
430 AssertReturnStmt(cRefs != UINT32_MAX, VERR_INVALID_HANDLE, RTManifestRelease(hManifest));
431
432 /*
433 * Create an instace of the passthru I/O stream.
434 */
435 PRTMANIFESTPTIOS pThis;
436 RTVFSIOSTREAM hVfsPtIos;
437 int rc = RTVfsNewIoStream(&g_rtManifestPassthruIosOps, sizeof(*pThis), fReadOrWrite ? RTFILE_O_READ : RTFILE_O_WRITE,
438 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsPtIos, (void **)&pThis);
439 if (RT_SUCCESS(rc))
440 {
441 pThis->hVfsIos = hVfsIos;
442 pThis->pHashes = rtManifestHashesCreate(fAttrs);
443 pThis->hManifest = hManifest;
444 pThis->fReadOrWrite = fReadOrWrite;
445 pThis->fAddedEntry = false;
446 pThis->pszEntry = RTStrDup(pszEntry);
447 if (pThis->pszEntry && pThis->pHashes)
448 {
449 *phVfsIosPassthru = hVfsPtIos;
450 return VINF_SUCCESS;
451 }
452
453 RTVfsIoStrmRelease(hVfsPtIos);
454 }
455 else
456 {
457 RTVfsIoStrmRelease(hVfsIos);
458 RTManifestRelease(hManifest);
459 }
460 return rc;
461}
462
463
464/**
465 * Adds the entry to the manifest right now.
466 *
467 * @returns IPRT status code.
468 * @param hVfsPtIos The manifest passthru I/O stream returned by
469 * RTManifestEntryAddPassthruIoStream().
470 */
471RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos)
472{
473 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
474 AssertReturn(pThis, VERR_INVALID_HANDLE);
475 AssertReturn(!pThis->fAddedEntry, VERR_WRONG_ORDER);
476
477 pThis->fAddedEntry = true;
478 rtManifestHashesFinal(pThis->pHashes);
479 return rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
480}
481
482
483/**
484 * Adds an entry for a file with the specified set of attributes.
485 *
486 * @returns IPRT status code.
487 *
488 * @param hManifest The manifest handle.
489 * @param hVfsIos The I/O stream handle of the entry. This will
490 * be processed to its end on successful return.
491 * (Must be positioned at the start to get
492 * the expected results.)
493 * @param pszEntry The entry name.
494 * @param fAttrs The attributes to create for this stream.
495 */
496RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs)
497{
498 /*
499 * Note! This is a convenicence function, so just use the available public
500 * methods to get the job done.
501 */
502 AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
503 AssertPtr(pszEntry);
504
505 /*
506 * Allocate and initialize the hash contexts, hash digests and I/O buffer.
507 */
508 PRTMANIFESTHASHES pHashes = rtManifestHashesCreate(fAttrs);
509 if (!pHashes)
510 return VERR_NO_TMP_MEMORY;
511
512 int rc;
513 size_t cbBuf = _1M;
514 void *pvBuf = RTMemTmpAlloc(cbBuf);
515 if (RT_UNLIKELY(!pvBuf))
516 {
517 cbBuf = _4K;
518 pvBuf = RTMemTmpAlloc(cbBuf);
519 }
520 if (RT_LIKELY(pvBuf))
521 {
522 /*
523 * Process the stream data.
524 */
525 for (;;)
526 {
527 size_t cbRead;
528 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
529 if ( (rc == VINF_EOF && cbRead == 0)
530 || RT_FAILURE(rc))
531 break;
532 rtManifestHashesUpdate(pHashes, pvBuf, cbRead);
533 }
534 RTMemTmpFree(pvBuf);
535 if (RT_SUCCESS(rc))
536 {
537 /*
538 * Add the entry with the finalized hashes.
539 */
540 rtManifestHashesFinal(pHashes);
541 rc = RTManifestEntryAdd(hManifest, pszEntry);
542 if (RT_SUCCESS(rc))
543 rc = rtManifestHashesSetAttrs(pHashes, hManifest, pszEntry);
544 }
545 }
546 else
547 {
548 rtManifestHashesDestroy(pHashes);
549 rc = VERR_NO_TMP_MEMORY;
550 }
551 return rc;
552}
553
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