1
/* $Id: ApplianceImplIO.cpp 35368 2010-12-30 13:38:23Z vboxsync $ */
4
* IO helper for IAppliance COM class implementations.
8
* Copyright (C) 2010 Oracle Corporation
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.
19
/******************************************************************************
21
******************************************************************************/
23
#include "ProgressImpl.h"
24
#include "ApplianceImpl.h"
25
#include "ApplianceImplPrivate.h"
29
#include <iprt/path.h>
31
#include <iprt/stream.h>
32
#include <iprt/circbuf.h>
35
/******************************************************************************
36
* Structures and Typedefs *
37
******************************************************************************/
39
typedef struct FILESTORAGEINTERNAL
43
/** Completion callback. */
44
PFNVDCOMPLETED pfnCompleted;
45
} FILESTORAGEINTERNAL, *PFILESTORAGEINTERNAL;
47
typedef struct TARSTORAGEINTERNAL
51
/** Completion callback. */
52
PFNVDCOMPLETED pfnCompleted;
53
} TARSTORAGEINTERNAL, *PTARSTORAGEINTERNAL;
55
typedef struct SHA1STORAGEINTERNAL
57
/** Completion callback. */
58
PFNVDCOMPLETED pfnCompleted;
59
/** Storage handle for the next callback in chain. */
61
/** Current file open mode. */
63
/** Our own storage handle. */
64
PSHA1STORAGE pSha1Storage;
65
/** Circular buffer used for transferring data from/to the worker thread. */
67
/** Current absolute position (regardless of the real read/written data). */
69
/** Current real position in the file. */
71
/** Handle of the worker thread. */
72
RTTHREAD pWorkerThread;
73
/** Status of the worker thread. */
74
volatile uint32_t u32Status;
75
/** Event for signaling a new status. */
76
RTSEMEVENT newStatusEvent;
77
/** Event for signaling a finished task of the worker thread. */
78
RTSEMEVENT workFinishedEvent;
79
/** SHA1 calculation context. */
81
/** Write mode only: Memory buffer for writing zeros. */
83
/** Write mode only: Size of the zero memory buffer. */
85
/** Read mode only: Indicate if we reached end of file. */
89
} SHA1STORAGEINTERNAL, *PSHA1STORAGEINTERNAL;
91
/******************************************************************************
92
* Defined Constants And Macros *
93
******************************************************************************/
95
#define STATUS_WAIT UINT32_C(0)
96
#define STATUS_WRITE UINT32_C(1)
97
#define STATUS_READ UINT32_C(2)
98
#define STATUS_END UINT32_C(3)
100
/* Enable for getting some flow history. */
102
# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
104
# define DEBUG_PRINT_FLOW() do {} while(0)
107
/******************************************************************************
108
* Internal Functions *
109
******************************************************************************/
111
/******************************************************************************
112
* Internal: RTFile interface
113
******************************************************************************/
115
static int fileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen,
116
PFNVDCOMPLETED pfnCompleted, void **ppInt)
118
/* Validate input. */
119
AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
120
AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
124
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL));
126
return VERR_NO_MEMORY;
128
pInt->pfnCompleted = pfnCompleted;
130
int rc = RTFileOpen(&pInt->file, pszLocation, fOpen);
140
static int fileCloseCallback(void * /* pvUser */, void *pvStorage)
142
/* Validate input. */
143
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
145
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
149
int rc = RTFileClose(pInt->file);
157
static int fileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
161
return RTFileDelete(pcszFilename);
164
static int fileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
168
return RTFileMove(pcszSrc, pcszDst, fMove);
171
static int fileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
173
/* Validate input. */
174
AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
175
AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
179
return VERR_NOT_IMPLEMENTED;
182
static int fileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename, PRTTIMESPEC pModificationTime)
184
/* Validate input. */
185
AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
186
AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
190
return VERR_NOT_IMPLEMENTED;
193
static int fileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
195
/* Validate input. */
196
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
198
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
202
return RTFileGetSize(pInt->file, pcbSize);
205
static int fileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
207
/* Validate input. */
208
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
210
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
214
return RTFileSetSize(pInt->file, cbSize);
217
static int fileWriteSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
218
const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
220
/* Validate input. */
221
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
223
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
225
return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
228
static int fileReadSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
229
void *pvBuf, size_t cbRead, size_t *pcbRead)
231
/* Validate input. */
232
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
234
// DEBUG_PRINT_FLOW();
236
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
238
return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
241
static int fileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
243
/* Validate input. */
244
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
248
PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
250
return RTFileFlush(pInt->file);
253
/******************************************************************************
254
* Internal: RTTar interface
255
******************************************************************************/
257
static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
258
PFNVDCOMPLETED pfnCompleted, void **ppInt)
260
/* Validate input. */
261
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
262
AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
263
AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
264
// AssertReturn(!(fOpen & RTFILE_O_READWRITE), VERR_INVALID_PARAMETER);
266
RTTAR tar = (RTTAR)pvUser;
270
PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(TARSTORAGEINTERNAL));
272
return VERR_NO_MEMORY;
274
pInt->pfnCompleted = pfnCompleted;
276
int rc = VINF_SUCCESS;
278
if ( fOpen & RTFILE_O_READ
279
&& !(fOpen & RTFILE_O_WRITE))
281
/* Read only is a little bit more complicated than writing, cause we
282
* need streaming functionality. First try to open the file on the
283
* current file position. If this is the file the caller requested, we
284
* are fine. If not seek to the next file in the stream and check
285
* again. This is repeated until EOF of the OVA. */
289
* TODO: recheck this with more VDMKs (or what else) in an test OVA.
296
char *pszFilename = 0;
297
rc = RTTarCurrentFile(tar, &pszFilename);
300
fFound = !strcmp(pszFilename, RTPathFilename(pszLocation));
301
RTStrFree(pszFilename);
306
rc = RTTarSeekNextFile(tar);
314
rc = RTTarFileOpenCurrentFile(tar, &pInt->file, 0, fOpen);
317
rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
327
static int tarCloseCallback(void *pvUser, void *pvStorage)
329
/* Validate input. */
330
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
331
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
333
PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
337
int rc = RTTarFileClose(pInt->file);
345
static int tarDeleteCallback(void *pvUser, const char *pcszFilename)
347
/* Validate input. */
348
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
349
AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
353
return VERR_NOT_IMPLEMENTED;
356
static int tarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
358
/* Validate input. */
359
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
360
AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
361
AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
365
return VERR_NOT_IMPLEMENTED;
368
static int tarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
370
/* Validate input. */
371
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
372
AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
373
AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
377
return VERR_NOT_IMPLEMENTED;
380
static int tarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
382
/* Validate input. */
383
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
384
AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
385
AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
389
return VERR_NOT_IMPLEMENTED;
392
static int tarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
394
/* Validate input. */
395
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
396
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
398
PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
402
return RTTarFileGetSize(pInt->file, pcbSize);
405
static int tarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
407
/* Validate input. */
408
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
409
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
411
PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
415
return RTTarFileSetSize(pInt->file, cbSize);
418
static int tarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
419
const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
421
/* Validate input. */
422
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
423
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
425
PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
429
return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
432
static int tarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
433
void *pvBuf, size_t cbRead, size_t *pcbRead)
435
/* Validate input. */
436
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
437
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
439
PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
441
// DEBUG_PRINT_FLOW();
443
return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
446
static int tarFlushSyncCallback(void *pvUser, void *pvStorage)
448
/* Validate input. */
449
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
450
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
454
return VERR_NOT_IMPLEMENTED;
457
/******************************************************************************
458
* Internal: RTSha1 interface
459
******************************************************************************/
461
DECLCALLBACK(int) sha1CalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
463
/* Validate input. */
464
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
466
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvUser;
468
PVDINTERFACE pIO = VDInterfaceGet(pInt->pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
469
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
470
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
471
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
473
int rc = VINF_SUCCESS;
477
/* What should we do next? */
478
uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
479
// RTPrintf("status: %d\n", u32Status);
484
/* Wait for new work. */
485
rc = RTSemEventWait(pInt->newStatusEvent, 100);
487
&& rc != VERR_TIMEOUT)
493
size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
494
size_t cbMemAllRead = 0;
495
/* First loop over all the free memory in the circular
496
* memory buffer (could be turn around at the end). */
499
if ( cbMemAllRead == cbAvail
503
size_t cbMemToRead = cbAvail - cbMemAllRead;
504
size_t cbMemRead = 0;
505
/* Try to acquire all the used space of the circular buffer. */
506
RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
507
size_t cbAllWritten = 0;
508
/* Second, write as long as used memory is there. The write
509
* method could also split the writes up into to smaller
513
if (cbAllWritten == cbMemRead)
515
size_t cbToWrite = cbMemRead - cbAllWritten;
516
size_t cbWritten = 0;
517
rc = pCallbacks->pfnWriteSync(pIO->pvUser, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten], cbToWrite, &cbWritten);
518
// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
524
cbAllWritten += cbWritten;
525
pInt->cbCurFile += cbWritten;
527
/* Update the SHA1 context with the next data block. */
529
&& pInt->pSha1Storage->fCreateDigest)
530
RTSha1Update(&pInt->ctx, pcBuf, cbAllWritten);
531
/* Mark the block as empty. */
532
RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
533
cbMemAllRead += cbAllWritten;
535
/* Reset the thread status and signal the main thread that we
536
* are finished. Use CmpXchg, so we not overwrite other states
537
* which could be signaled in the meantime. */
538
ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITE);
539
rc = RTSemEventSignal(pInt->workFinishedEvent);
544
size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
545
size_t cbMemAllWrite = 0;
546
/* First loop over all the available memory in the circular
547
* memory buffer (could be turn around at the end). */
550
if ( cbMemAllWrite == cbAvail
554
size_t cbMemToWrite = cbAvail - cbMemAllWrite;
555
size_t cbMemWrite = 0;
556
/* Try to acquire all the free space of the circular buffer. */
557
RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
558
/* Second, read as long as we filled all the memory. The
559
* read method could also split the reads up into to
561
size_t cbAllRead = 0;
564
if (cbAllRead == cbMemWrite)
566
size_t cbToRead = cbMemWrite - cbAllRead;
568
rc = pCallbacks->pfnReadSync(pIO->pvUser, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
569
// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
575
/* This indicates end of file. Stop reading. */
579
ASMAtomicWriteBool(&pInt->fEOF, true);
583
pInt->cbCurFile += cbRead;
585
/* Update the SHA1 context with the next data block. */
587
&& pInt->pSha1Storage->fCreateDigest)
588
RTSha1Update(&pInt->ctx, pcBuf, cbAllRead);
589
/* Mark the block as full. */
590
RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
591
cbMemAllWrite += cbAllRead;
593
/* Reset the thread status and signal the main thread that we
594
* are finished. Use CmpXchg, so we not overwrite other states
595
* which could be signaled in the meantime. */
596
ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READ);
597
rc = RTSemEventSignal(pInt->workFinishedEvent);
611
DECLINLINE(int) sha1SignalManifestThread(PSHA1STORAGEINTERNAL pInt, uint32_t uStatus)
613
ASMAtomicWriteU32(&pInt->u32Status, uStatus);
614
return RTSemEventSignal(pInt->newStatusEvent);
617
DECLINLINE(int) sha1WaitForManifestThreadFinished(PSHA1STORAGEINTERNAL pInt)
619
// RTPrintf("start\n");
620
int rc = VINF_SUCCESS;
623
// RTPrintf(" wait\n");
624
if (!( ASMAtomicReadU32(&pInt->u32Status) == STATUS_WRITE
625
|| ASMAtomicReadU32(&pInt->u32Status) == STATUS_READ))
627
rc = RTSemEventWait(pInt->workFinishedEvent, 100);
629
if (rc == VERR_TIMEOUT)
634
DECLINLINE(int) sha1FlushCurBuf(PSHA1STORAGEINTERNAL pInt)
636
int rc = VINF_SUCCESS;
637
if (pInt->fOpenMode & RTFILE_O_WRITE)
639
/* Let the write worker thread start immediately. */
640
rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
644
/* Wait until the write worker thread has finished. */
645
rc = sha1WaitForManifestThreadFinished(pInt);
651
static int sha1OpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
652
PFNVDCOMPLETED pfnCompleted, void **ppInt)
654
/* Validate input. */
655
AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
656
AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
657
AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
658
AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
659
AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
661
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
662
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
663
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
664
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
665
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
669
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)RTMemAllocZ(sizeof(SHA1STORAGEINTERNAL));
671
return VERR_NO_MEMORY;
673
int rc = VINF_SUCCESS;
676
pInt->pfnCompleted = pfnCompleted;
677
pInt->pSha1Storage = pSha1Storage;
679
pInt->fOpenMode = fOpen;
681
/* Circular buffer in the read case. */
682
rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
686
if (fOpen & RTFILE_O_WRITE)
688
/* The zero buffer is used for appending empty parts at the end of the
689
* file (or our buffer) in setSize or when uOffset in writeSync is
690
* increased in steps bigger than a byte. */
691
pInt->cbZeroBuf = _1K;
692
pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
693
if (!pInt->pvZeroBuf)
700
/* Create an event semaphore to indicate a state change for the worker
702
rc = RTSemEventCreate(&pInt->newStatusEvent);
705
/* Create an event semaphore to indicate a finished calculation of the
707
rc = RTSemEventCreate(&pInt->workFinishedEvent);
710
/* Create the worker thread. */
711
rc = RTThreadCreate(&pInt->pWorkerThread, sha1CalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA1-Worker");
715
if (pSha1Storage->fCreateDigest)
716
/* Create a SHA1 context the worker thread will work with. */
717
RTSha1Init(&pInt->ctx);
720
rc = pCallbacks->pfnOpen(pIO->pvUser, pszLocation,
721
fOpen, pInt->pfnCompleted,
726
if (fOpen & RTFILE_O_READ)
728
/* Immediately let the worker thread start the reading. */
729
rc = sha1SignalManifestThread(pInt, STATUS_READ);
736
if (pInt->pWorkerThread)
738
sha1SignalManifestThread(pInt, STATUS_END);
739
RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
741
if (pInt->workFinishedEvent)
742
RTSemEventDestroy(pInt->workFinishedEvent);
743
if (pInt->newStatusEvent)
744
RTSemEventDestroy(pInt->newStatusEvent);
746
RTCircBufDestroy(pInt->pCircBuf);
748
RTMemFree(pInt->pvZeroBuf);
757
static int sha1CloseCallback(void *pvUser, void *pvStorage)
759
/* Validate input. */
760
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
761
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
763
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
764
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
765
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
766
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
767
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
769
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
773
int rc = VINF_SUCCESS;
775
/* Make sure all pending writes are flushed */
776
rc = sha1FlushCurBuf(pInt);
778
if (pInt->pWorkerThread)
780
/* Signal the worker thread to end himself */
781
rc = sha1SignalManifestThread(pInt, STATUS_END);
782
/* Worker thread stopped? */
783
rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
787
&& pSha1Storage->fCreateDigest)
789
/* Finally calculate & format the SHA1 sum */
790
unsigned char auchDig[RTSHA1_HASH_SIZE];
792
RTSha1Final(&pInt->ctx, auchDig);
793
rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
796
rc = RTSha1ToString(auchDig, pszDigest, RTSHA1_DIGEST_LEN + 1);
798
pSha1Storage->strDigest = pszDigest;
799
RTStrFree(pszDigest);
804
rc = pCallbacks->pfnClose(pIO->pvUser, pInt->pvStorage);
806
// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
809
if (pInt->workFinishedEvent)
810
RTSemEventDestroy(pInt->workFinishedEvent);
811
if (pInt->newStatusEvent)
812
RTSemEventDestroy(pInt->newStatusEvent);
814
RTCircBufDestroy(pInt->pCircBuf);
816
RTMemFree(pInt->pvZeroBuf);
822
static int sha1DeleteCallback(void *pvUser, const char *pcszFilename)
824
/* Validate input. */
825
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
827
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
828
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
829
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
830
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
831
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
835
return pCallbacks->pfnDelete(pIO->pvUser, pcszFilename);
838
static int sha1MoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
840
/* Validate input. */
841
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
843
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
844
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
845
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
846
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
847
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
851
return pCallbacks->pfnMove(pIO->pvUser, pcszSrc, pcszDst, fMove);
854
static int sha1GetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
856
/* Validate input. */
857
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
859
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
860
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
861
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
862
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
863
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
867
return pCallbacks->pfnGetFreeSpace(pIO->pvUser, pcszFilename, pcbFreeSpace);
870
static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
872
/* Validate input. */
873
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
875
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
876
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
877
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
878
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
879
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
883
return pCallbacks->pfnGetModificationTime(pIO->pvUser, pcszFilename, pModificationTime);
887
static int sha1GetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
889
/* Validate input. */
890
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
891
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
893
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
894
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
895
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
896
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
897
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
899
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
904
int rc = pCallbacks->pfnGetSize(pIO->pvUser, pInt->pvStorage, &cbSize);
908
*pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
913
static int sha1SetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
915
/* Validate input. */
916
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
917
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
919
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
920
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
921
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
922
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
923
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
925
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
929
return pCallbacks->pfnSetSize(pIO->pvUser, pInt->pvStorage, cbSize);
932
static int sha1WriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
933
const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
935
/* Validate input. */
936
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
937
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
939
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
940
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
941
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
942
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
943
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
945
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
949
/* Check that the write is linear */
950
AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
952
int rc = VINF_SUCCESS;
954
/* Check if we have to add some free space at the end, before we start the
956
if (pInt->cbCurAll < uOffset)
958
size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
959
size_t cbAllWritten = 0;
963
if (cbAllWritten == cbSize)
965
size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
966
size_t cbWritten = 0;
967
rc = sha1WriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
968
pInt->pvZeroBuf, cbToWrite, &cbWritten);
971
cbAllWritten += cbWritten;
976
// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
978
size_t cbAllWritten = 0;
982
if (cbAllWritten == cbWrite)
984
size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
988
/* If there isn't enough free space make sure the worker thread is
989
* writing some data. */
990
if ((cbWrite - cbAllWritten) > cbAvail)
992
rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
995
/* If there is _no_ free space available, we have to wait until it is. */
998
rc = sha1WaitForManifestThreadFinished(pInt);
1001
cbAvail = RTCircBufFree(pInt->pCircBuf);
1002
// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1006
size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1008
size_t cbMemWritten = 0;
1009
/* Acquire a block for writing from our circular buffer. */
1010
RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1011
memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1012
/* Mark the block full. */
1013
RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1014
cbAllWritten += cbMemWritten;
1015
pInt->cbCurAll += cbMemWritten;
1019
*pcbWritten = cbAllWritten;
1021
/* Signal the thread to write more data in the mean time. */
1023
&& RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1024
rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
1029
static int sha1ReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1030
void *pvBuf, size_t cbRead, size_t *pcbRead)
1032
/* Validate input. */
1033
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1034
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1036
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1037
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
1038
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
1039
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
1040
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
1042
// DEBUG_PRINT_FLOW();
1044
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1046
int rc = VINF_SUCCESS;
1049
// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1051
/* Check if we jump forward in the file. If so we have to read the
1052
* remaining stuff in the gap anyway (SHA1; streaming). */
1053
if (pInt->cbCurAll < uOffset)
1055
rc = sha1ReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1056
(size_t)(uOffset - pInt->cbCurAll), 0);
1061
size_t cbAllRead = 0;
1065
if (cbAllRead == cbRead)
1067
size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1073
/* If there isn't enough data make sure the worker thread is fetching
1075
if ((cbRead - cbAllRead) > cbAvail)
1077
rc = sha1SignalManifestThread(pInt, STATUS_READ);
1080
/* If there is _no_ data available, we have to wait until it is. */
1083
rc = sha1WaitForManifestThreadFinished(pInt);
1086
cbAvail = RTCircBufUsed(pInt->pCircBuf);
1087
// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1091
size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1093
size_t cbMemRead = 0;
1094
/* Acquire a block for reading from our circular buffer. */
1095
RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1096
if (pvBuf) /* Make it possible to blind read data (for skipping) */
1097
memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1098
/* Mark the block as empty again. */
1099
RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1100
cbAllRead += cbMemRead;
1102
pInt->cbCurAll += cbMemRead;
1106
*pcbRead = cbAllRead;
1111
/* Signal the thread to read more data in the mean time. */
1113
&& RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1114
rc = sha1SignalManifestThread(pInt, STATUS_READ);
1119
static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
1121
/* Validate input. */
1122
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1123
AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1125
PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1126
PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
1127
AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
1128
PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
1129
AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
1133
PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1135
/* Check if there is still something in the buffer. If yes, flush it. */
1136
int rc = sha1FlushCurBuf(pInt);
1140
return pCallbacks->pfnFlushSync(pIO->pvUser, pInt->pvStorage);
1143
/******************************************************************************
1144
* Public Functions *
1145
******************************************************************************/
1147
PVDINTERFACEIO Sha1CreateInterface()
1149
PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1153
pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1154
pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1155
pCallbacks->pfnOpen = sha1OpenCallback;
1156
pCallbacks->pfnClose = sha1CloseCallback;
1157
pCallbacks->pfnDelete = sha1DeleteCallback;
1158
pCallbacks->pfnMove = sha1MoveCallback;
1159
pCallbacks->pfnGetFreeSpace = sha1GetFreeSpaceCallback;
1160
pCallbacks->pfnGetModificationTime = sha1GetModificationTimeCallback;
1161
pCallbacks->pfnGetSize = sha1GetSizeCallback;
1162
pCallbacks->pfnSetSize = sha1SetSizeCallback;
1163
pCallbacks->pfnReadSync = sha1ReadSyncCallback;
1164
pCallbacks->pfnWriteSync = sha1WriteSyncCallback;
1165
pCallbacks->pfnFlushSync = sha1FlushSyncCallback;
1170
PVDINTERFACEIO FileCreateInterface()
1172
PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1176
pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1177
pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1178
pCallbacks->pfnOpen = fileOpenCallback;
1179
pCallbacks->pfnClose = fileCloseCallback;
1180
pCallbacks->pfnDelete = fileDeleteCallback;
1181
pCallbacks->pfnMove = fileMoveCallback;
1182
pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1183
pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1184
pCallbacks->pfnGetSize = fileGetSizeCallback;
1185
pCallbacks->pfnSetSize = fileSetSizeCallback;
1186
pCallbacks->pfnReadSync = fileReadSyncCallback;
1187
pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1188
pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1193
PVDINTERFACEIO TarCreateInterface()
1195
PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1199
pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1200
pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1201
pCallbacks->pfnOpen = tarOpenCallback;
1202
pCallbacks->pfnClose = tarCloseCallback;
1203
pCallbacks->pfnDelete = tarDeleteCallback;
1204
pCallbacks->pfnMove = tarMoveCallback;
1205
pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1206
pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1207
pCallbacks->pfnGetSize = tarGetSizeCallback;
1208
pCallbacks->pfnSetSize = tarSetSizeCallback;
1209
pCallbacks->pfnReadSync = tarReadSyncCallback;
1210
pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1211
pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1216
int Sha1ReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1218
/* Validate input. */
1219
AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1220
AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1221
AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1224
int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1225
RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1232
uint64_t cbTmpSize = _1M;
1233
size_t cbAllRead = 0;
1236
pvTmpBuf = RTMemAlloc(cbTmpSize);
1239
rc = VERR_NO_MEMORY;
1246
rc = pCallbacks->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1250
pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1253
rc = VERR_NO_MEMORY;
1256
memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1257
cbAllRead += cbRead;
1261
pCallbacks->pfnClose(pvUser, pvStorage);
1267
RTMemFree(pvTmpBuf);
1272
*pcbSize = cbAllRead;
1282
int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1284
/* Validate input. */
1285
AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1286
AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1287
AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1290
int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1291
RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1296
size_t cbAllWritten = 0;
1299
if (cbAllWritten >= cbSize)
1301
size_t cbToWrite = cbSize - cbAllWritten;
1302
size_t cbWritten = 0;
1303
rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1306
cbAllWritten += cbWritten;
1309
pCallbacks->pfnClose(pvUser, pvStorage);