VirtualBox

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

Last change on this file since 37043 was 35351, checked in by vboxsync, 14 years ago

scm cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/* $Id: manifest3.cpp 35351 2010-12-27 17:04:17Z 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 return rc;
321}
322
323
324/**
325 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
326 */
327static DECLCALLBACK(int) rtManifestPtIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
328{
329 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
330 int rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, pSgBuf, fBlocking, pcbWritten);
331 if (RT_SUCCESS(rc))
332 rtManifestPtIos_UpdateHashes(pThis, pSgBuf, pcbWritten ? *pcbWritten : ~(size_t)0);
333 return rc;
334}
335
336
337/**
338 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
339 */
340static DECLCALLBACK(int) rtManifestPtIos_Flush(void *pvThis)
341{
342 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
343 return RTVfsIoStrmFlush(pThis->hVfsIos);
344}
345
346
347/**
348 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
349 */
350static DECLCALLBACK(int) rtManifestPtIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
351 uint32_t *pfRetEvents)
352{
353 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
354 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
355}
356
357
358/**
359 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
360 */
361static DECLCALLBACK(int) rtManifestPtIos_Tell(void *pvThis, PRTFOFF poffActual)
362{
363 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis;
364 RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos);
365 if (off < 0)
366 return (int)off;
367 *poffActual = off;
368 return VINF_SUCCESS;
369}
370
371
372/**
373 * The manifest passthru I/O stream vtable.
374 */
375static RTVFSIOSTREAMOPS g_rtManifestPassthruIosOps =
376{
377 { /* Obj */
378 RTVFSOBJOPS_VERSION,
379 RTVFSOBJTYPE_IO_STREAM,
380 "manifest passthru I/O stream",
381 rtManifestPtIos_Close,
382 rtManifestPtIos_QueryInfo,
383 RTVFSOBJOPS_VERSION
384 },
385 RTVFSIOSTREAMOPS_VERSION,
386 0,
387 rtManifestPtIos_Read,
388 rtManifestPtIos_Write,
389 rtManifestPtIos_Flush,
390 rtManifestPtIos_PollOne,
391 rtManifestPtIos_Tell,
392 NULL /* Skip */,
393 NULL /* ZeroFill */,
394 RTVFSIOSTREAMOPS_VERSION,
395};
396
397
398
399/**
400 * Add an entry for an I/O stream using a passthru stream.
401 *
402 * The passthru I/O stream will hash all the data read from or written to the
403 * stream and automatically add an entry to the manifest with the desired
404 * attributes when it is released. Alternatively one can call
405 * RTManifestPtIosAddEntryNow() to have more control over exactly when this
406 * action is performed and which status it yields.
407 *
408 * @returns IPRT status code.
409 * @param hManifest The manifest to add the entry to.
410 * @param hVfsIos The I/O stream to pass thru to/from.
411 * @param pszEntry The entry name.
412 * @param fAttrs The attributes to create for this stream.
413 * @param fReadOrWrite Whether it's a read or write I/O stream.
414 * @param phVfsIosPassthru Where to return the new handle.
415 */
416RTDECL(int) RTManifestEntryAddPassthruIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry,
417 uint32_t fAttrs, bool fReadOrWrite, PRTVFSIOSTREAM phVfsIosPassthru)
418{
419 /*
420 * Validate input.
421 */
422 AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
423 AssertPtr(pszEntry);
424 AssertPtr(phVfsIosPassthru);
425 uint32_t cRefs = RTManifestRetain(hManifest);
426 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
427 cRefs = RTVfsIoStrmRetain(hVfsIos);
428 AssertReturnStmt(cRefs != UINT32_MAX, VERR_INVALID_HANDLE, RTManifestRelease(hManifest));
429
430 /*
431 * Create an instace of the passthru I/O stream.
432 */
433 PRTMANIFESTPTIOS pThis;
434 RTVFSIOSTREAM hVfsPtIos;
435 int rc = RTVfsNewIoStream(&g_rtManifestPassthruIosOps, sizeof(*pThis), fReadOrWrite ? RTFILE_O_READ : RTFILE_O_WRITE,
436 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsPtIos, (void **)&pThis);
437 if (RT_SUCCESS(rc))
438 {
439 pThis->hVfsIos = hVfsIos;
440 pThis->pHashes = rtManifestHashesCreate(fAttrs);
441 pThis->hManifest = hManifest;
442 pThis->fReadOrWrite = fReadOrWrite;
443 pThis->fAddedEntry = false;
444 pThis->pszEntry = RTStrDup(pszEntry);
445 if (pThis->pszEntry && pThis->pHashes)
446 {
447 *phVfsIosPassthru = hVfsPtIos;
448 return VINF_SUCCESS;
449 }
450
451 RTVfsIoStrmRelease(hVfsPtIos);
452 }
453 else
454 {
455 RTVfsIoStrmRelease(hVfsIos);
456 RTManifestRelease(hManifest);
457 }
458 return rc;
459}
460
461
462/**
463 * Adds the entry to the manifest right now.
464 *
465 * @returns IPRT status code.
466 * @param hVfsPtIos The manifest passthru I/O stream returned by
467 * RTManifestEntryAddPassthruIoStream().
468 */
469RTDECL(int) RTManifestPtIosAddEntryNow(RTVFSIOSTREAM hVfsPtIos)
470{
471 PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)RTVfsIoStreamToPrivate(hVfsPtIos, &g_rtManifestPassthruIosOps);
472 AssertReturn(pThis, VERR_INVALID_HANDLE);
473 AssertReturn(!pThis->fAddedEntry, VERR_WRONG_ORDER);
474
475 pThis->fAddedEntry = true;
476 rtManifestHashesFinal(pThis->pHashes);
477 return rtManifestHashesSetAttrs(pThis->pHashes, pThis->hManifest, pThis->pszEntry);
478}
479
480
481/**
482 * Adds an entry for a file with the specified set of attributes.
483 *
484 * @returns IPRT status code.
485 *
486 * @param hManifest The manifest handle.
487 * @param hVfsIos The I/O stream handle of the entry. This will
488 * be processed to its end on successful return.
489 * (Must be positioned at the start to get
490 * the expected results.)
491 * @param pszEntry The entry name.
492 * @param fAttrs The attributes to create for this stream.
493 */
494RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs)
495{
496 /*
497 * Note! This is a convenicence function, so just use the available public
498 * methods to get the job done.
499 */
500 AssertReturn(fAttrs < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
501 AssertPtr(pszEntry);
502
503 /*
504 * Allocate and initialize the hash contexts, hash digests and I/O buffer.
505 */
506 PRTMANIFESTHASHES pHashes = rtManifestHashesCreate(fAttrs);
507 if (!pHashes)
508 return VERR_NO_TMP_MEMORY;
509
510 int rc;
511 size_t cbBuf = _1M;
512 void *pvBuf = RTMemTmpAlloc(cbBuf);
513 if (RT_UNLIKELY(!pvBuf))
514 {
515 cbBuf = _4K;
516 pvBuf = RTMemTmpAlloc(cbBuf);
517 }
518 if (RT_LIKELY(pvBuf))
519 {
520 /*
521 * Process the stream data.
522 */
523 for (;;)
524 {
525 size_t cbRead;
526 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
527 if ( (rc == VINF_EOF && cbRead == 0)
528 || RT_FAILURE(rc))
529 break;
530 rtManifestHashesUpdate(pHashes, pvBuf, cbRead);
531 }
532 if (RT_SUCCESS(rc))
533 {
534 /*
535 * Add the entry with the finalized hashes.
536 */
537 rtManifestHashesFinal(pHashes);
538 rc = RTManifestEntryAdd(hManifest, pszEntry);
539 if (RT_SUCCESS(rc))
540 rc = rtManifestHashesSetAttrs(pHashes, hManifest, pszEntry);
541 }
542 }
543 else
544 {
545 rtManifestHashesDestroy(pHashes);
546 rc = VERR_NO_TMP_MEMORY;
547 }
548 return rc;
549}
550
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