VirtualBox

source: vbox/trunk/src/VBox/Main/ApplianceImplIO.cpp@ 33060

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

Main;OVF/OVA: online calculation of the SHA1 sum; directly stream into the ova (no temporary files anymore); cache writing

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/* $Id: ApplianceImplIO.cpp 33060 2010-10-12 12:17:49Z vboxsync $ */
2/** @file
3 *
4 * IO helper for IAppliance COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/******************************************************************************
20 * Header Files *
21 ******************************************************************************/
22
23#include "ProgressImpl.h"
24#include "ApplianceImpl.h"
25#include "ApplianceImplPrivate.h"
26
27#include <iprt/tar.h>
28#include <iprt/sha.h>
29#include <iprt/path.h>
30#include <iprt/asm.h>
31#include <iprt/semaphore.h>
32#include <iprt/stream.h>
33#include <VBox/VBoxHDD.h>
34
35#include <openssl/sha.h>
36
37/******************************************************************************
38 * Structures and Typedefs *
39 ******************************************************************************/
40
41typedef struct RTFILESTORAGEINTERNAL
42{
43 /** File handle. */
44 RTFILE file;
45 /** Completion callback. */
46 PFNVDCOMPLETED pfnCompleted;
47} RTFILESTORAGEINTERNAL, *PRTFILESTORAGEINTERNAL;
48
49typedef struct RTTARSTORAGEINTERNAL
50{
51 /** Tar handle. */
52 RTTARFILE file;
53 /** Completion callback. */
54 PFNVDCOMPLETED pfnCompleted;
55} RTTARSTORAGEINTERNAL, *PRTTARSTORAGEINTERNAL;
56
57typedef struct SHA1STORAGEINTERNAL
58{
59 /** Completion callback. */
60 PFNVDCOMPLETED pfnCompleted;
61 /** Storage handle for the next callback in chain. */
62 void *pvStorage;
63 /** Memory buffer used for caching and SHA1 calculation. */
64 char *pcBuf;
65 /** Size of the memory buffer. */
66 size_t cbBuf;
67 /** Memory buffer for writing zeros. */
68 void *pvZeroBuf;
69 /** Size of the zero memory buffer. */
70 size_t cbZeroBuf;
71 /** Current position in the caching memory buffer. */
72 size_t cbCurBuf;
73 /** Current absolute position. */
74 uint64_t cbCurAll;
75 /** Current real position in the file. */
76 uint64_t cbCurFile;
77 /** Handle of the SHA1 worker thread. */
78 RTTHREAD pMfThread;
79 /** Status of the worker thread. */
80 volatile uint32_t u32Status;
81 /** Event for signaling a new status. */
82 RTSEMEVENT newStatusEvent;
83 /** Event for signaling a finished SHA1 calculation. */
84 RTSEMEVENT calcFinishedEvent;
85 /** SHA1 calculation context. */
86 SHA_CTX ctx;
87} SHA1STORAGEINTERNAL, *PSHA1STORAGEINTERNAL;
88
89/******************************************************************************
90 * Defined Constants And Macros *
91 ******************************************************************************/
92
93#define STATUS_WAIT UINT32_C(0)
94#define STATUS_CALC UINT32_C(1)
95#define STATUS_END UINT32_C(3)
96
97/* Enable for getting some flow history. */
98#if 0
99# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
100#else
101# define DEBUG_PRINT_FLOW() do {} while(0)
102#endif
103
104/******************************************************************************
105 * Internal Functions *
106 ******************************************************************************/
107
108/******************************************************************************
109 * Internal: RTFile interface
110 ******************************************************************************/
111
112static int rtFileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen,
113 PFNVDCOMPLETED pfnCompleted, void **ppInt)
114{
115 /* Validate input. */
116 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
117 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
118
119 DEBUG_PRINT_FLOW();
120
121 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(RTFILESTORAGEINTERNAL));
122 if (!pInt)
123 return VERR_NO_MEMORY;
124
125 pInt->pfnCompleted = pfnCompleted;
126
127 int rc = RTFileOpen(&pInt->file, pszLocation, fOpen);
128
129 if (RT_FAILURE(rc))
130 RTMemFree(pInt);
131 else
132 *ppInt = pInt;
133
134 return rc;
135}
136
137static int rtFileCloseCallback(void * /* pvUser */, void *pvStorage)
138{
139 /* Validate input. */
140 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
141
142 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
143
144 DEBUG_PRINT_FLOW();
145
146 int rc = RTFileClose(pInt->file);
147
148 /* Cleanup */
149 RTMemFree(pInt);
150
151 return rc;
152}
153
154static int rtFileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
155{
156 DEBUG_PRINT_FLOW();
157
158 return RTFileDelete(pcszFilename);
159}
160
161static int rtFileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
162{
163 DEBUG_PRINT_FLOW();
164
165 return RTFileMove(pcszSrc, pcszDst, fMove);
166}
167
168static int rtFileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
169{
170 /* Validate input. */
171 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
172 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
173
174 DEBUG_PRINT_FLOW();
175
176 return VERR_NOT_IMPLEMENTED;
177}
178
179static int rtFileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename, PRTTIMESPEC pModificationTime)
180{
181 /* Validate input. */
182 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
183 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
184
185 DEBUG_PRINT_FLOW();
186
187 return VERR_NOT_IMPLEMENTED;
188}
189
190static int rtFileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
191{
192 /* Validate input. */
193 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
194
195 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
196
197// DEBUG_PRINT_FLOW();
198
199 return RTFileGetSize(pInt->file, pcbSize);
200}
201
202static int rtFileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
203{
204 /* Validate input. */
205 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
206
207 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
208
209 DEBUG_PRINT_FLOW();
210
211 return RTFileSetSize(pInt->file, cbSize);
212}
213
214static int rtFileWriteSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
215 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
216{
217 /* Validate input. */
218 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
219
220 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
221
222 return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
223}
224
225static int rtFileReadSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
226 void *pvBuf, size_t cbRead, size_t *pcbRead)
227{
228 /* Validate input. */
229 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
230
231 DEBUG_PRINT_FLOW();
232
233 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
234
235 return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
236}
237
238static int rtFileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
239{
240 /* Validate input. */
241 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
242
243 DEBUG_PRINT_FLOW();
244
245 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
246
247 return RTFileFlush(pInt->file);
248}
249
250/******************************************************************************
251 * Internal: RTTar interface
252 ******************************************************************************/
253
254static int rtTarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
255 PFNVDCOMPLETED pfnCompleted, void **ppInt)
256{
257 /* Validate input. */
258 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
259 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
260 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
261
262 RTTAR tar = (RTTAR)pvUser;
263
264 DEBUG_PRINT_FLOW();
265
266 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(RTTARSTORAGEINTERNAL));
267 if (!pInt)
268 return VERR_NO_MEMORY;
269
270 pInt->pfnCompleted = pfnCompleted;
271
272 int rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
273
274 if (RT_FAILURE(rc))
275 RTMemFree(pInt);
276 else
277 *ppInt = pInt;
278
279 return rc;
280}
281
282static int rtTarCloseCallback(void *pvUser, void *pvStorage)
283{
284 /* Validate input. */
285 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
286 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
287
288 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
289
290 DEBUG_PRINT_FLOW();
291
292 int rc = RTTarFileClose(pInt->file);
293
294 /* Cleanup */
295 RTMemFree(pInt);
296
297 return rc;
298}
299
300static int rtTarDeleteCallback(void *pvUser, const char *pcszFilename)
301{
302 /* Validate input. */
303 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
304 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
305
306 DEBUG_PRINT_FLOW();
307
308 return VERR_NOT_IMPLEMENTED;
309}
310
311static int rtTarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
312{
313 /* Validate input. */
314 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
315 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
316 AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
317
318 DEBUG_PRINT_FLOW();
319
320 return VERR_NOT_IMPLEMENTED;
321}
322
323static int rtTarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
324{
325 /* Validate input. */
326 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
327 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
328 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
329
330 DEBUG_PRINT_FLOW();
331
332 return VERR_NOT_IMPLEMENTED;
333}
334
335static int rtTarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
336{
337 /* Validate input. */
338 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
339 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
340 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
341
342 DEBUG_PRINT_FLOW();
343
344 return VERR_NOT_IMPLEMENTED;
345}
346
347static int rtTarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
348{
349 /* Validate input. */
350 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
351 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
352
353 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
354
355// DEBUG_PRINT_FLOW();
356
357 return RTTarFileGetSize(pInt->file, pcbSize);
358}
359
360static int rtTarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
361{
362 /* Validate input. */
363 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
364 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
365
366 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
367
368 DEBUG_PRINT_FLOW();
369
370 return RTTarFileSetSize(pInt->file, cbSize);
371}
372
373static int rtTarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
374 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
375{
376 /* Validate input. */
377 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
378 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
379
380 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
381
382 DEBUG_PRINT_FLOW();
383
384 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
385}
386
387static int rtTarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
388 void *pvBuf, size_t cbRead, size_t *pcbRead)
389{
390 /* Validate input. */
391 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
392 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
393
394 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
395
396 DEBUG_PRINT_FLOW();
397
398 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
399}
400
401static int rtTarFlushSyncCallback(void *pvUser, void *pvStorage)
402{
403 /* Validate input. */
404 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
405 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
406
407 DEBUG_PRINT_FLOW();
408
409 return VERR_NOT_IMPLEMENTED;
410}
411
412/******************************************************************************
413 * Internal: Sha1 interface
414 ******************************************************************************/
415
416DECLCALLBACK(int) sha1CalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
417{
418 /* Validate input. */
419 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
420
421 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvUser;
422
423 int rc = VINF_SUCCESS;
424 bool fLoop = true;
425 while(fLoop)
426 {
427 /* What should we do next? */
428 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
429 switch (u32Status)
430 {
431 case STATUS_WAIT:
432 {
433 /* Wait for new work. */
434 rc = RTSemEventWait(pInt->newStatusEvent, 100);
435 if ( RT_FAILURE(rc)
436 && rc != VERR_TIMEOUT)
437 fLoop = false;
438 break;
439 }
440 case STATUS_CALC:
441 {
442 /* Update the SHA1 context with the next data block. */
443 if(!SHA1_Update(&pInt->ctx, pInt->pcBuf, pInt->cbCurBuf))
444 {
445 rc = VERR_INTERNAL_ERROR;
446 fLoop = false;
447 }
448 /* Reset the thread status and signal the main thread that we
449 are finished. */
450 ASMAtomicWriteU32(&pInt->u32Status, STATUS_WAIT);
451 rc = RTSemEventSignal(pInt->calcFinishedEvent);
452 break;
453 }
454 case STATUS_END:
455 {
456 /* End signaled */
457 fLoop = false;
458 break;
459 }
460 }
461 }
462 return rc;
463}
464
465DECLINLINE(int) sha1SignalManifestThread(PSHA1STORAGEINTERNAL pInt, uint32_t uStatus)
466{
467 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
468 return RTSemEventSignal(pInt->newStatusEvent);
469}
470
471DECLINLINE(int) sha1WaitForManifestThreadFinished(PSHA1STORAGEINTERNAL pInt)
472{
473// RTPrintf("start\n");
474 int rc = VINF_SUCCESS;
475 for(;;)
476 {
477// RTPrintf(" wait\n");
478 if (ASMAtomicReadU32(&pInt->u32Status) != STATUS_CALC)
479 break;
480 rc = RTSemEventWait(pInt->calcFinishedEvent, 100);
481 }
482 if (rc == VERR_TIMEOUT)
483 rc = VINF_SUCCESS;
484 return rc;
485}
486
487DECLINLINE(int) sha1FlushCurBuf(PVDINTERFACE pIO, PVDINTERFACEIO pCallbacks, PSHA1STORAGEINTERNAL pInt, bool fCreateDigest)
488{
489 int rc = VINF_SUCCESS;
490 if (fCreateDigest)
491 {
492 /* Let the sha1 worker thread start immediately. */
493 rc = sha1SignalManifestThread(pInt, STATUS_CALC);
494 if (RT_FAILURE(rc))
495 return rc;
496 }
497 /* Write the buffer content to disk. */
498 size_t cbAllWritten = 0;
499 for(;;)
500 {
501 /* Finished? */
502 if (cbAllWritten == pInt->cbCurBuf)
503 break;
504 size_t cbToWrite = pInt->cbCurBuf - cbAllWritten;
505 size_t cbWritten = 0;
506 rc = pCallbacks->pfnWriteSync(pIO->pvUser, pInt->pvStorage, pInt->cbCurFile, &pInt->pcBuf[cbAllWritten], cbToWrite, &cbWritten);
507 if (RT_FAILURE(rc))
508 return rc;
509 pInt->cbCurFile += cbWritten;
510 cbAllWritten += cbWritten;
511 }
512 if (fCreateDigest)
513 {
514 /* Wait until the sha1 worker thread has finished. */
515 rc = sha1WaitForManifestThreadFinished(pInt);
516 }
517 if (RT_SUCCESS(rc))
518 pInt->cbCurBuf = 0;
519
520 return rc;
521}
522
523static int sha1OpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
524 PFNVDCOMPLETED pfnCompleted, void **ppInt)
525{
526 /* Validate input. */
527 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
528 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
529 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
530 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
531
532 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
533 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
534 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
535 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
536 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
537
538 DEBUG_PRINT_FLOW();
539
540 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)RTMemAllocZ(sizeof(SHA1STORAGEINTERNAL));
541 if (!pInt)
542 return VERR_NO_MEMORY;
543
544 int rc = VINF_SUCCESS;
545 do
546 {
547 pInt->pfnCompleted = pfnCompleted;
548 /* For caching reasons and to be able to calculate the sha1 sum of the
549 data we need a memory buffer. */
550 pInt->cbBuf = _1M;
551 pInt->pcBuf = (char*)RTMemAlloc(pInt->cbBuf);
552 if (!pInt->pcBuf)
553 {
554 rc = VERR_NO_MEMORY;
555 break;
556 }
557 /* The zero buffer is used for appending empty parts at the end of the
558 * file (or our buffer) in setSize or when uOffset in writeSync is
559 * increased in steps bigger than a byte. */
560 pInt->cbZeroBuf = _1K;
561 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
562 if (!pInt->pvZeroBuf)
563 {
564 rc = VERR_NO_MEMORY;
565 break;
566 }
567
568 if (pSha1Storage->fCreateDigest)
569 {
570 /* Create a sha1 context the sha1 worker thread will work with. */
571 if (!SHA1_Init(&pInt->ctx))
572 {
573 rc = VERR_INTERNAL_ERROR;
574 break;
575 }
576 /* Create an event semaphore to indicate a state change for the sha1
577 worker thread. */
578 rc = RTSemEventCreate(&pInt->newStatusEvent);
579 if (RT_FAILURE(rc))
580 break;
581 /* Create an event semaphore to indicate a finished calculation of the
582 sha1 worker thread. */
583 rc = RTSemEventCreate(&pInt->calcFinishedEvent);
584 if (RT_FAILURE(rc))
585 break;
586 /* Create the sha1 worker thread. */
587 rc = RTThreadCreate(&pInt->pMfThread, sha1CalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA1-Worker");
588 if (RT_FAILURE(rc))
589 break;
590 }
591 /* Open the file. */
592 rc = pCallbacks->pfnOpen(pIO->pvUser, pszLocation,
593 fOpen, pInt->pfnCompleted,
594 &pInt->pvStorage);
595 }
596 while(0);
597
598 if (RT_FAILURE(rc))
599 {
600 if (pSha1Storage->fCreateDigest)
601 {
602 if (pInt->pMfThread)
603 {
604 sha1SignalManifestThread(pInt, STATUS_END);
605 RTThreadWait(pInt->pMfThread, RT_INDEFINITE_WAIT, 0);
606 }
607 if (pInt->calcFinishedEvent)
608 RTSemEventDestroy(pInt->calcFinishedEvent);
609 if (pInt->newStatusEvent)
610 RTSemEventDestroy(pInt->newStatusEvent);
611 }
612 if (pInt->pvZeroBuf)
613 RTMemFree(pInt->pvZeroBuf);
614 if (pInt->pcBuf)
615 RTMemFree(pInt->pcBuf);
616 RTMemFree(pInt);
617 }
618 else
619 *ppInt = pInt;
620
621 return rc;
622}
623
624static int sha1CloseCallback(void *pvUser, void *pvStorage)
625{
626 /* Validate input. */
627 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
628 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
629
630 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
631 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
632 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
633 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
634 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
635
636 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
637
638 DEBUG_PRINT_FLOW();
639
640 int rc = VINF_SUCCESS;
641
642 /* Make sure all pending writes are flushed */
643 if (pInt->cbCurBuf > 0)
644 rc = sha1FlushCurBuf(pIO, pCallbacks, pInt, pSha1Storage->fCreateDigest);
645
646 if (pSha1Storage->fCreateDigest)
647 {
648 /* Signal the worker thread to end himself */
649 rc = sha1SignalManifestThread(pInt, STATUS_END);
650 /* Finally calculate & format the SHA1 sum */
651 unsigned char auchDig[RTSHA1_HASH_SIZE];
652 char *pszDigest;
653 if (!SHA1_Final(auchDig, &pInt->ctx))
654 rc = VERR_INTERNAL_ERROR;
655 rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
656 if (RT_SUCCESS(rc))
657 {
658 rc = RTSha1ToString(auchDig, pszDigest, RTSHA1_DIGEST_LEN + 1);
659 if (RT_SUCCESS(rc))
660 pSha1Storage->strDigest = pszDigest;
661 RTStrFree(pszDigest);
662 }
663 /* Worker thread stopped? */
664 rc = RTThreadWait(pInt->pMfThread, RT_INDEFINITE_WAIT, 0);
665 }
666 /* Close the file */
667 rc = pCallbacks->pfnClose(pIO->pvUser, pInt->pvStorage);
668
669 /* Cleanup */
670 if (pSha1Storage->fCreateDigest)
671 {
672 if (pInt->calcFinishedEvent)
673 RTSemEventDestroy(pInt->calcFinishedEvent);
674 if (pInt->newStatusEvent)
675 RTSemEventDestroy(pInt->newStatusEvent);
676 }
677 if (pInt->pvZeroBuf)
678 RTMemFree(pInt->pvZeroBuf);
679 if (pInt->pcBuf)
680 RTMemFree(pInt->pcBuf);
681 RTMemFree(pInt);
682
683 return rc;
684}
685
686static int sha1DeleteCallback(void *pvUser, const char *pcszFilename)
687{
688 /* Validate input. */
689 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
690
691 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
692 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
693 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
694 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
695 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
696
697 DEBUG_PRINT_FLOW();
698
699 return pCallbacks->pfnDelete(pIO->pvUser, pcszFilename);
700}
701
702static int sha1MoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
703{
704 /* Validate input. */
705 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
706
707 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
708 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
709 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
710 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
711 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
712
713 DEBUG_PRINT_FLOW();
714
715 return pCallbacks->pfnMove(pIO->pvUser, pcszSrc, pcszDst, fMove);
716}
717
718static int sha1GetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
719{
720 /* Validate input. */
721 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
722
723 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
724 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
725 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
726 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
727 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
728
729 DEBUG_PRINT_FLOW();
730
731 return pCallbacks->pfnGetFreeSpace(pIO->pvUser, pcszFilename, pcbFreeSpace);
732}
733
734static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
735{
736 /* Validate input. */
737 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
738
739 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
740 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
741 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
742 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
743 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
744
745 DEBUG_PRINT_FLOW();
746
747 return pCallbacks->pfnGetModificationTime(pIO->pvUser, pcszFilename, pModificationTime);
748}
749
750
751static int sha1GetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
752{
753 /* Validate input. */
754 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
755 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
756
757 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
758 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
759 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
760 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
761 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
762
763 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
764
765// DEBUG_PRINT_FLOW();
766
767 uint64_t cbSize;
768 int rc = pCallbacks->pfnGetSize(pIO->pvUser, pInt->pvStorage, &cbSize);
769 if (RT_FAILURE(rc))
770 return rc;
771
772 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
773 return VINF_SUCCESS;
774}
775
776static int sha1SetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
777{
778 /* Validate input. */
779 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
780 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
781
782 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
783 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
784 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
785 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
786 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
787
788 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
789
790 DEBUG_PRINT_FLOW();
791
792 return pCallbacks->pfnSetSize(pIO->pvUser, pInt->pvStorage, cbSize);
793}
794
795static int sha1WriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
796 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
797{
798 /* Validate input. */
799 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
800 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
801
802 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
803 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
804 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
805 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
806 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
807
808 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
809
810// DEBUG_PRINT_FLOW();
811
812 /* Check that the write is linear */
813 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
814
815 int rc = VINF_SUCCESS;
816
817 /* Check if we have to add some free space at the end, before we start the
818 * real write. */
819 if (pInt->cbCurAll < uOffset)
820 {
821 size_t cbSize = uOffset - pInt->cbCurAll;
822 size_t cbAllWritten = 0;
823 for(;;)
824 {
825 /* Finished? */
826 if (cbAllWritten == cbSize)
827 break;
828 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
829 size_t cbWritten = 0;
830 rc = sha1WriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
831 pInt->pvZeroBuf, cbToWrite, &cbWritten);
832 if (RT_FAILURE(rc))
833 break;
834 cbAllWritten += cbWritten;
835 }
836 if (RT_FAILURE(rc))
837 return rc;
838 }
839// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
840
841 size_t cbAllWritten = 0;
842 for(;;)
843 {
844 /* Finished? */
845 if (cbAllWritten == cbWrite)
846 break;
847 size_t cbToWrite = RT_MIN(pInt->cbBuf - pInt->cbCurBuf, cbWrite - cbAllWritten);
848 memcpy(&pInt->pcBuf[pInt->cbCurBuf], &((char*)pvBuf)[cbAllWritten], cbToWrite);
849 pInt->cbCurBuf += cbToWrite;
850 pInt->cbCurAll += cbToWrite;
851 cbAllWritten += cbToWrite;
852 /* Need to start a real write? */
853 if (pInt->cbCurBuf == pInt->cbBuf)
854 {
855 rc = sha1FlushCurBuf(pIO, pCallbacks, pInt, pSha1Storage->fCreateDigest);
856 if (RT_FAILURE(rc))
857 break;
858 }
859 }
860 if (pcbWritten)
861 *pcbWritten = cbAllWritten;
862
863 return rc;
864}
865
866static int sha1ReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
867 void *pvBuf, size_t cbRead, size_t *pcbRead)
868{
869 /* Validate input. */
870 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
871 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
872
873 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
874 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
875 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
876 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
877 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
878
879 DEBUG_PRINT_FLOW();
880
881 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
882
883 return pCallbacks->pfnReadSync(pIO->pvUser, pInt->pvStorage, uOffset, pvBuf, cbRead, pcbRead);
884}
885
886static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
887{
888 /* Validate input. */
889 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
890 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
891
892 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
893 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
894 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
895 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
896 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
897
898 DEBUG_PRINT_FLOW();
899
900 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
901
902 int rc = VINF_SUCCESS;
903
904 /* Check if there is still something in the buffer. If yes, flush it. */
905 if (pInt->cbCurBuf > 0)
906 {
907 rc = sha1FlushCurBuf(pIO, pCallbacks, pInt, pSha1Storage->fCreateDigest);
908 if (RT_FAILURE(rc))
909 return rc;
910 }
911
912 return pCallbacks->pfnFlushSync(pIO->pvUser, pInt->pvStorage);
913}
914
915/******************************************************************************
916 * Public Functions *
917 ******************************************************************************/
918
919PVDINTERFACEIO Sha1CreateInterface()
920{
921 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
922 if (!pCallbacks)
923 return NULL;
924
925 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
926 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
927 pCallbacks->pfnOpen = sha1OpenCallback;
928 pCallbacks->pfnClose = sha1CloseCallback;
929 pCallbacks->pfnDelete = sha1DeleteCallback;
930 pCallbacks->pfnMove = sha1MoveCallback;
931 pCallbacks->pfnGetFreeSpace = sha1GetFreeSpaceCallback;
932 pCallbacks->pfnGetModificationTime = sha1GetModificationTimeCallback;
933 pCallbacks->pfnGetSize = sha1GetSizeCallback;
934 pCallbacks->pfnSetSize = sha1SetSizeCallback;
935 pCallbacks->pfnReadSync = sha1ReadSyncCallback;
936 pCallbacks->pfnWriteSync = sha1WriteSyncCallback;
937 pCallbacks->pfnFlushSync = sha1FlushSyncCallback;
938
939 return pCallbacks;
940}
941
942PVDINTERFACEIO RTFileCreateInterface()
943{
944 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
945 if (!pCallbacks)
946 return NULL;
947
948 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
949 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
950 pCallbacks->pfnOpen = rtFileOpenCallback;
951 pCallbacks->pfnClose = rtFileCloseCallback;
952 pCallbacks->pfnDelete = rtFileDeleteCallback;
953 pCallbacks->pfnMove = rtFileMoveCallback;
954 pCallbacks->pfnGetFreeSpace = rtFileGetFreeSpaceCallback;
955 pCallbacks->pfnGetModificationTime = rtFileGetModificationTimeCallback;
956 pCallbacks->pfnGetSize = rtFileGetSizeCallback;
957 pCallbacks->pfnSetSize = rtFileSetSizeCallback;
958 pCallbacks->pfnReadSync = rtFileReadSyncCallback;
959 pCallbacks->pfnWriteSync = rtFileWriteSyncCallback;
960 pCallbacks->pfnFlushSync = rtFileFlushSyncCallback;
961
962 return pCallbacks;
963}
964
965PVDINTERFACEIO RTTarCreateInterface()
966{
967 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
968 if (!pCallbacks)
969 return NULL;
970
971 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
972 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
973 pCallbacks->pfnOpen = rtTarOpenCallback;
974 pCallbacks->pfnClose = rtTarCloseCallback;
975 pCallbacks->pfnDelete = rtTarDeleteCallback;
976 pCallbacks->pfnMove = rtTarMoveCallback;
977 pCallbacks->pfnGetFreeSpace = rtTarGetFreeSpaceCallback;
978 pCallbacks->pfnGetModificationTime = rtTarGetModificationTimeCallback;
979 pCallbacks->pfnGetSize = rtTarGetSizeCallback;
980 pCallbacks->pfnSetSize = rtTarSetSizeCallback;
981 pCallbacks->pfnReadSync = rtTarReadSyncCallback;
982 pCallbacks->pfnWriteSync = rtTarWriteSyncCallback;
983 pCallbacks->pfnFlushSync = rtTarFlushSyncCallback;
984
985 return pCallbacks;
986}
987
988int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
989{
990 /* Validate input. */
991 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
992
993 void *pvStorage;
994 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
995 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
996 &pvStorage);
997 if (RT_FAILURE(rc))
998 return rc;
999
1000 size_t cbAllWritten = 0;
1001 for(;;)
1002 {
1003 if (cbAllWritten >= cbSize)
1004 break;
1005 size_t cbToWrite = cbSize - cbAllWritten;
1006 size_t cbWritten = 0;
1007 rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1008 if (RT_FAILURE(rc))
1009 break;
1010 cbAllWritten += cbWritten;
1011 }
1012
1013 pCallbacks->pfnClose(pvUser, pvStorage);
1014
1015 return rc;
1016}
1017
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