VirtualBox

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

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

Main-OVF: disable digest creation for the manifest file

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