VirtualBox

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

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

Main-OVF: address r67784

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.0 KB
Line 
1/* $Id: ApplianceImplIO.cpp 34101 2010-11-16 10:56:43Z 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/stream.h>
32#include <iprt/circbuf.h>
33#include <VBox/vd.h>
34
35/******************************************************************************
36 * Structures and Typedefs *
37 ******************************************************************************/
38
39typedef struct FILESTORAGEINTERNAL
40{
41 /** File handle. */
42 RTFILE file;
43 /** Completion callback. */
44 PFNVDCOMPLETED pfnCompleted;
45} FILESTORAGEINTERNAL, *PFILESTORAGEINTERNAL;
46
47typedef struct TARSTORAGEINTERNAL
48{
49 /** Tar handle. */
50 RTTARFILE file;
51 /** Completion callback. */
52 PFNVDCOMPLETED pfnCompleted;
53} TARSTORAGEINTERNAL, *PTARSTORAGEINTERNAL;
54
55typedef struct SHA1STORAGEINTERNAL
56{
57 /** Completion callback. */
58 PFNVDCOMPLETED pfnCompleted;
59 /** Storage handle for the next callback in chain. */
60 void *pvStorage;
61 /** Current file open mode. */
62 uint32_t fOpenMode;
63 /** Our own storage handle. */
64 PSHA1STORAGE pSha1Storage;
65 /** Circular buffer used for transferring data from/to the worker thread. */
66 PRTCIRCBUF pCircBuf;
67 /** Current absolute position (regardless of the real read/written data). */
68 uint64_t cbCurAll;
69 /** Current real position in the file. */
70 uint64_t cbCurFile;
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. */
80 RTSHA1CONTEXT ctx;
81 /** Write mode only: Memory buffer for writing zeros. */
82 void *pvZeroBuf;
83 /** Write mode only: Size of the zero memory buffer. */
84 size_t cbZeroBuf;
85 /** Read mode only: Indicate if we reached end of file. */
86 volatile bool fEOF;
87// uint64_t calls;
88// uint64_t waits;
89} SHA1STORAGEINTERNAL, *PSHA1STORAGEINTERNAL;
90
91/******************************************************************************
92 * Defined Constants And Macros *
93 ******************************************************************************/
94
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)
99
100/* Enable for getting some flow history. */
101#if 0
102# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
103#else
104# define DEBUG_PRINT_FLOW() do {} while(0)
105#endif
106
107/******************************************************************************
108 * Internal Functions *
109 ******************************************************************************/
110
111/******************************************************************************
112 * Internal: RTFile interface
113 ******************************************************************************/
114
115static int fileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen,
116 PFNVDCOMPLETED pfnCompleted, void **ppInt)
117{
118 /* Validate input. */
119 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
120 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
121
122 DEBUG_PRINT_FLOW();
123
124 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL));
125 if (!pInt)
126 return VERR_NO_MEMORY;
127
128 pInt->pfnCompleted = pfnCompleted;
129
130 int rc = RTFileOpen(&pInt->file, pszLocation, fOpen);
131
132 if (RT_FAILURE(rc))
133 RTMemFree(pInt);
134 else
135 *ppInt = pInt;
136
137 return rc;
138}
139
140static int fileCloseCallback(void * /* pvUser */, void *pvStorage)
141{
142 /* Validate input. */
143 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
144
145 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
146
147 DEBUG_PRINT_FLOW();
148
149 int rc = RTFileClose(pInt->file);
150
151 /* Cleanup */
152 RTMemFree(pInt);
153
154 return rc;
155}
156
157static int fileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
158{
159 DEBUG_PRINT_FLOW();
160
161 return RTFileDelete(pcszFilename);
162}
163
164static int fileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
165{
166 DEBUG_PRINT_FLOW();
167
168 return RTFileMove(pcszSrc, pcszDst, fMove);
169}
170
171static int fileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
172{
173 /* Validate input. */
174 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
175 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
176
177 DEBUG_PRINT_FLOW();
178
179 return VERR_NOT_IMPLEMENTED;
180}
181
182static int fileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename, PRTTIMESPEC pModificationTime)
183{
184 /* Validate input. */
185 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
186 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
187
188 DEBUG_PRINT_FLOW();
189
190 return VERR_NOT_IMPLEMENTED;
191}
192
193static int fileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
194{
195 /* Validate input. */
196 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
197
198 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
199
200 DEBUG_PRINT_FLOW();
201
202 return RTFileGetSize(pInt->file, pcbSize);
203}
204
205static int fileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
206{
207 /* Validate input. */
208 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
209
210 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
211
212 DEBUG_PRINT_FLOW();
213
214 return RTFileSetSize(pInt->file, cbSize);
215}
216
217static int fileWriteSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
218 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
219{
220 /* Validate input. */
221 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
222
223 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
224
225 return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
226}
227
228static int fileReadSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
229 void *pvBuf, size_t cbRead, size_t *pcbRead)
230{
231 /* Validate input. */
232 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
233
234// DEBUG_PRINT_FLOW();
235
236 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
237
238 return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
239}
240
241static int fileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
242{
243 /* Validate input. */
244 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
245
246 DEBUG_PRINT_FLOW();
247
248 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
249
250 return RTFileFlush(pInt->file);
251}
252
253/******************************************************************************
254 * Internal: RTTar interface
255 ******************************************************************************/
256
257static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
258 PFNVDCOMPLETED pfnCompleted, void **ppInt)
259{
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);
265
266 RTTAR tar = (RTTAR)pvUser;
267
268 DEBUG_PRINT_FLOW();
269
270 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(TARSTORAGEINTERNAL));
271 if (!pInt)
272 return VERR_NO_MEMORY;
273
274 pInt->pfnCompleted = pfnCompleted;
275
276 int rc = VINF_SUCCESS;
277
278 if ( fOpen & RTFILE_O_READ
279 && !(fOpen & RTFILE_O_WRITE))
280 {
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. */
286 /*
287 *
288 *
289 * TODO: recheck this with more VDMKs (or what else) in an test OVA.
290 *
291 *
292 */
293 bool fFound = false;
294 for(;;)
295 {
296 char *pszFilename = 0;
297 rc = RTTarCurrentFile(tar, &pszFilename);
298 if (RT_SUCCESS(rc))
299 {
300 fFound = !strcmp(pszFilename, RTPathFilename(pszLocation));
301 RTStrFree(pszFilename);
302 if (fFound)
303 break;
304 else
305 {
306 rc = RTTarSeekNextFile(tar);
307 if (RT_FAILURE(rc))
308 break;
309 }
310 }else
311 break;
312 }
313 if (fFound)
314 rc = RTTarFileOpenCurrentFile(tar, &pInt->file, 0, fOpen);
315 }
316 else
317 rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
318
319 if (RT_FAILURE(rc))
320 RTMemFree(pInt);
321 else
322 *ppInt = pInt;
323
324 return rc;
325}
326
327static int tarCloseCallback(void *pvUser, void *pvStorage)
328{
329 /* Validate input. */
330 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
331 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
332
333 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
334
335 DEBUG_PRINT_FLOW();
336
337 int rc = RTTarFileClose(pInt->file);
338
339 /* Cleanup */
340 RTMemFree(pInt);
341
342 return rc;
343}
344
345static int tarDeleteCallback(void *pvUser, const char *pcszFilename)
346{
347 /* Validate input. */
348 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
349 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
350
351 DEBUG_PRINT_FLOW();
352
353 return VERR_NOT_IMPLEMENTED;
354}
355
356static int tarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
357{
358 /* Validate input. */
359 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
360 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
361 AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
362
363 DEBUG_PRINT_FLOW();
364
365 return VERR_NOT_IMPLEMENTED;
366}
367
368static int tarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
369{
370 /* Validate input. */
371 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
372 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
373 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
374
375 DEBUG_PRINT_FLOW();
376
377 return VERR_NOT_IMPLEMENTED;
378}
379
380static int tarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
381{
382 /* Validate input. */
383 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
384 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
385 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
386
387 DEBUG_PRINT_FLOW();
388
389 return VERR_NOT_IMPLEMENTED;
390}
391
392static int tarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
393{
394 /* Validate input. */
395 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
396 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
397
398 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
399
400 DEBUG_PRINT_FLOW();
401
402 return RTTarFileGetSize(pInt->file, pcbSize);
403}
404
405static int tarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
406{
407 /* Validate input. */
408 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
409 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
410
411 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
412
413 DEBUG_PRINT_FLOW();
414
415 return RTTarFileSetSize(pInt->file, cbSize);
416}
417
418static int tarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
419 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
420{
421 /* Validate input. */
422 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
423 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
424
425 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
426
427 DEBUG_PRINT_FLOW();
428
429 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
430}
431
432static int tarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
433 void *pvBuf, size_t cbRead, size_t *pcbRead)
434{
435 /* Validate input. */
436 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
437 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
438
439 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
440
441// DEBUG_PRINT_FLOW();
442
443 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
444}
445
446static int tarFlushSyncCallback(void *pvUser, void *pvStorage)
447{
448 /* Validate input. */
449 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
450 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
451
452 DEBUG_PRINT_FLOW();
453
454 return VERR_NOT_IMPLEMENTED;
455}
456
457/******************************************************************************
458 * Internal: RTSha1 interface
459 ******************************************************************************/
460
461DECLCALLBACK(int) sha1CalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
462{
463 /* Validate input. */
464 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
465
466 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvUser;
467
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);
472
473 int rc = VINF_SUCCESS;
474 bool fLoop = true;
475 while(fLoop)
476 {
477 /* What should we do next? */
478 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
479// RTPrintf("status: %d\n", u32Status);
480 switch (u32Status)
481 {
482 case STATUS_WAIT:
483 {
484 /* Wait for new work. */
485 rc = RTSemEventWait(pInt->newStatusEvent, 100);
486 if ( RT_FAILURE(rc)
487 && rc != VERR_TIMEOUT)
488 fLoop = false;
489 break;
490 }
491 case STATUS_WRITE:
492 {
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). */
497 for(;;)
498 {
499 if ( cbMemAllRead == cbAvail
500 || fLoop == false)
501 break;
502 char *pcBuf;
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
510 * parts. */
511 for(;;)
512 {
513 if (cbAllWritten == cbMemRead)
514 break;
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);
519 if (RT_FAILURE(rc))
520 {
521 fLoop = false;
522 break;
523 }
524 cbAllWritten += cbWritten;
525 pInt->cbCurFile += cbWritten;
526 }
527 /* Update the SHA1 context with the next data block. */
528 if ( RT_SUCCESS(rc)
529 && pInt->pSha1Storage->fCreateDigest)
530 RTSha1Update(&pInt->ctx, pcBuf, cbAllWritten);
531 /* Mark the block as empty. */
532 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
533 cbMemAllRead += cbAllWritten;
534 }
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);
540 break;
541 }
542 case STATUS_READ:
543 {
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). */
548 for(;;)
549 {
550 if ( cbMemAllWrite == cbAvail
551 || fLoop == false)
552 break;
553 char *pcBuf;
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
560 * smaller parts. */
561 size_t cbAllRead = 0;
562 for(;;)
563 {
564 if (cbAllRead == cbMemWrite)
565 break;
566 size_t cbToRead = cbMemWrite - cbAllRead;
567 size_t cbRead = 0;
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);
570 if (RT_FAILURE(rc))
571 {
572 fLoop = false;
573 break;
574 }
575 /* This indicates end of file. Stop reading. */
576 if (cbRead == 0)
577 {
578 fLoop = false;
579 ASMAtomicWriteBool(&pInt->fEOF, true);
580 break;
581 }
582 cbAllRead += cbRead;
583 pInt->cbCurFile += cbRead;
584 }
585 /* Update the SHA1 context with the next data block. */
586 if ( RT_SUCCESS(rc)
587 && pInt->pSha1Storage->fCreateDigest)
588 RTSha1Update(&pInt->ctx, pcBuf, cbAllRead);
589 /* Mark the block as full. */
590 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
591 cbMemAllWrite += cbAllRead;
592 }
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);
598 break;
599 }
600 case STATUS_END:
601 {
602 /* End signaled */
603 fLoop = false;
604 break;
605 }
606 }
607 }
608 return rc;
609}
610
611DECLINLINE(int) sha1SignalManifestThread(PSHA1STORAGEINTERNAL pInt, uint32_t uStatus)
612{
613 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
614 return RTSemEventSignal(pInt->newStatusEvent);
615}
616
617DECLINLINE(int) sha1WaitForManifestThreadFinished(PSHA1STORAGEINTERNAL pInt)
618{
619// RTPrintf("start\n");
620 int rc = VINF_SUCCESS;
621 for(;;)
622 {
623// RTPrintf(" wait\n");
624 if (!( ASMAtomicReadU32(&pInt->u32Status) == STATUS_WRITE
625 || ASMAtomicReadU32(&pInt->u32Status) == STATUS_READ))
626 break;
627 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
628 }
629 if (rc == VERR_TIMEOUT)
630 rc = VINF_SUCCESS;
631 return rc;
632}
633
634DECLINLINE(int) sha1FlushCurBuf(PSHA1STORAGEINTERNAL pInt)
635{
636 int rc = VINF_SUCCESS;
637 if (pInt->fOpenMode & RTFILE_O_WRITE)
638 {
639 /* Let the write worker thread start immediately. */
640 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
641 if (RT_FAILURE(rc))
642 return rc;
643
644 /* Wait until the write worker thread has finished. */
645 rc = sha1WaitForManifestThreadFinished(pInt);
646 }
647
648 return rc;
649}
650
651static int sha1OpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
652 PFNVDCOMPLETED pfnCompleted, void **ppInt)
653{
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 */
660
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);
666
667 DEBUG_PRINT_FLOW();
668
669 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)RTMemAllocZ(sizeof(SHA1STORAGEINTERNAL));
670 if (!pInt)
671 return VERR_NO_MEMORY;
672
673 int rc = VINF_SUCCESS;
674 do
675 {
676 pInt->pfnCompleted = pfnCompleted;
677 pInt->pSha1Storage = pSha1Storage;
678 pInt->fEOF = false;
679 pInt->fOpenMode = fOpen;
680
681 /* Circular buffer in the read case. */
682 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
683 if (RT_FAILURE(rc))
684 break;
685
686 if (fOpen & RTFILE_O_WRITE)
687 {
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)
694 {
695 rc = VERR_NO_MEMORY;
696 break;
697 }
698 }
699
700 /* Create an event semaphore to indicate a state change for the worker
701 * thread. */
702 rc = RTSemEventCreate(&pInt->newStatusEvent);
703 if (RT_FAILURE(rc))
704 break;
705 /* Create an event semaphore to indicate a finished calculation of the
706 worker thread. */
707 rc = RTSemEventCreate(&pInt->workFinishedEvent);
708 if (RT_FAILURE(rc))
709 break;
710 /* Create the worker thread. */
711 rc = RTThreadCreate(&pInt->pWorkerThread, sha1CalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA1-Worker");
712 if (RT_FAILURE(rc))
713 break;
714
715 if (pSha1Storage->fCreateDigest)
716 /* Create a SHA1 context the worker thread will work with. */
717 RTSha1Init(&pInt->ctx);
718
719 /* Open the file. */
720 rc = pCallbacks->pfnOpen(pIO->pvUser, pszLocation,
721 fOpen, pInt->pfnCompleted,
722 &pInt->pvStorage);
723 if (RT_FAILURE(rc))
724 break;
725
726 if (fOpen & RTFILE_O_READ)
727 {
728 /* Immediately let the worker thread start the reading. */
729 rc = sha1SignalManifestThread(pInt, STATUS_READ);
730 }
731 }
732 while(0);
733
734 if (RT_FAILURE(rc))
735 {
736 if (pInt->pWorkerThread)
737 {
738 sha1SignalManifestThread(pInt, STATUS_END);
739 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
740 }
741 if (pInt->workFinishedEvent)
742 RTSemEventDestroy(pInt->workFinishedEvent);
743 if (pInt->newStatusEvent)
744 RTSemEventDestroy(pInt->newStatusEvent);
745 if (pInt->pCircBuf)
746 RTCircBufDestroy(pInt->pCircBuf);
747 if (pInt->pvZeroBuf)
748 RTMemFree(pInt->pvZeroBuf);
749 RTMemFree(pInt);
750 }
751 else
752 *ppInt = pInt;
753
754 return rc;
755}
756
757static int sha1CloseCallback(void *pvUser, void *pvStorage)
758{
759 /* Validate input. */
760 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
761 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
762
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);
768
769 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
770
771 DEBUG_PRINT_FLOW();
772
773 int rc = VINF_SUCCESS;
774
775 /* Make sure all pending writes are flushed */
776 rc = sha1FlushCurBuf(pInt);
777
778 if (pInt->pWorkerThread)
779 {
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);
784 }
785
786 if ( RT_SUCCESS(rc)
787 && pSha1Storage->fCreateDigest)
788 {
789 /* Finally calculate & format the SHA1 sum */
790 unsigned char auchDig[RTSHA1_HASH_SIZE];
791 char *pszDigest;
792 RTSha1Final(&pInt->ctx, auchDig);
793 rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
794 if (RT_SUCCESS(rc))
795 {
796 rc = RTSha1ToString(auchDig, pszDigest, RTSHA1_DIGEST_LEN + 1);
797 if (RT_SUCCESS(rc))
798 pSha1Storage->strDigest = pszDigest;
799 RTStrFree(pszDigest);
800 }
801 }
802
803 /* Close the file */
804 rc = pCallbacks->pfnClose(pIO->pvUser, pInt->pvStorage);
805
806// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
807
808 /* Cleanup */
809 if (pInt->workFinishedEvent)
810 RTSemEventDestroy(pInt->workFinishedEvent);
811 if (pInt->newStatusEvent)
812 RTSemEventDestroy(pInt->newStatusEvent);
813 if (pInt->pCircBuf)
814 RTCircBufDestroy(pInt->pCircBuf);
815 if (pInt->pvZeroBuf)
816 RTMemFree(pInt->pvZeroBuf);
817 RTMemFree(pInt);
818
819 return rc;
820}
821
822static int sha1DeleteCallback(void *pvUser, const char *pcszFilename)
823{
824 /* Validate input. */
825 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
826
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);
832
833 DEBUG_PRINT_FLOW();
834
835 return pCallbacks->pfnDelete(pIO->pvUser, pcszFilename);
836}
837
838static int sha1MoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
839{
840 /* Validate input. */
841 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
842
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);
848
849 DEBUG_PRINT_FLOW();
850
851 return pCallbacks->pfnMove(pIO->pvUser, pcszSrc, pcszDst, fMove);
852}
853
854static int sha1GetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
855{
856 /* Validate input. */
857 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
858
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);
864
865 DEBUG_PRINT_FLOW();
866
867 return pCallbacks->pfnGetFreeSpace(pIO->pvUser, pcszFilename, pcbFreeSpace);
868}
869
870static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
871{
872 /* Validate input. */
873 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
874
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);
880
881 DEBUG_PRINT_FLOW();
882
883 return pCallbacks->pfnGetModificationTime(pIO->pvUser, pcszFilename, pModificationTime);
884}
885
886
887static int sha1GetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
888{
889 /* Validate input. */
890 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
891 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
892
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);
898
899 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
900
901 DEBUG_PRINT_FLOW();
902
903 uint64_t cbSize;
904 int rc = pCallbacks->pfnGetSize(pIO->pvUser, pInt->pvStorage, &cbSize);
905 if (RT_FAILURE(rc))
906 return rc;
907
908 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
909
910 return VINF_SUCCESS;
911}
912
913static int sha1SetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
914{
915 /* Validate input. */
916 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
917 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
918
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);
924
925 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
926
927 DEBUG_PRINT_FLOW();
928
929 return pCallbacks->pfnSetSize(pIO->pvUser, pInt->pvStorage, cbSize);
930}
931
932static int sha1WriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
933 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
934{
935 /* Validate input. */
936 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
937 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
938
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);
944
945 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
946
947 DEBUG_PRINT_FLOW();
948
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);
951
952 int rc = VINF_SUCCESS;
953
954 /* Check if we have to add some free space at the end, before we start the
955 * real write. */
956 if (pInt->cbCurAll < uOffset)
957 {
958 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
959 size_t cbAllWritten = 0;
960 for(;;)
961 {
962 /* Finished? */
963 if (cbAllWritten == cbSize)
964 break;
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);
969 if (RT_FAILURE(rc))
970 break;
971 cbAllWritten += cbWritten;
972 }
973 if (RT_FAILURE(rc))
974 return rc;
975 }
976// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
977
978 size_t cbAllWritten = 0;
979 for(;;)
980 {
981 /* Finished? */
982 if (cbAllWritten == cbWrite)
983 break;
984 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
985 if ( cbAvail == 0
986 && pInt->fEOF)
987 return VERR_EOF;
988 /* If there isn't enough free space make sure the worker thread is
989 * writing some data. */
990 if ((cbWrite - cbAllWritten) > cbAvail)
991 {
992 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
993 if(RT_FAILURE(rc))
994 break;
995 /* If there is _no_ free space available, we have to wait until it is. */
996 if (cbAvail == 0)
997 {
998 rc = sha1WaitForManifestThreadFinished(pInt);
999 if (RT_FAILURE(rc))
1000 break;
1001 cbAvail = RTCircBufFree(pInt->pCircBuf);
1002// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1003// pInt->waits++;
1004 }
1005 }
1006 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1007 char *pcBuf;
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;
1016 }
1017
1018 if (pcbWritten)
1019 *pcbWritten = cbAllWritten;
1020
1021 /* Signal the thread to write more data in the mean time. */
1022 if ( RT_SUCCESS(rc)
1023 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1024 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
1025
1026 return rc;
1027}
1028
1029static int sha1ReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1030 void *pvBuf, size_t cbRead, size_t *pcbRead)
1031{
1032 /* Validate input. */
1033 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1034 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1035
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);
1041
1042// DEBUG_PRINT_FLOW();
1043
1044 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1045
1046 int rc = VINF_SUCCESS;
1047
1048// pInt->calls++;
1049// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1050
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)
1054 {
1055 rc = sha1ReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1056 (size_t)(uOffset - pInt->cbCurAll), 0);
1057 if (RT_FAILURE(rc))
1058 return rc;
1059 }
1060
1061 size_t cbAllRead = 0;
1062 for(;;)
1063 {
1064 /* Finished? */
1065 if (cbAllRead == cbRead)
1066 break;
1067 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1068 if ( cbAvail == 0
1069 && pInt->fEOF)
1070 {
1071 break;
1072 }
1073 /* If there isn't enough data make sure the worker thread is fetching
1074 * more. */
1075 if ((cbRead - cbAllRead) > cbAvail)
1076 {
1077 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1078 if(RT_FAILURE(rc))
1079 break;
1080 /* If there is _no_ data available, we have to wait until it is. */
1081 if (cbAvail == 0)
1082 {
1083 rc = sha1WaitForManifestThreadFinished(pInt);
1084 if (RT_FAILURE(rc))
1085 break;
1086 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1087// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1088// pInt->waits++;
1089 }
1090 }
1091 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1092 char *pcBuf;
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;
1101
1102 pInt->cbCurAll += cbMemRead;
1103 }
1104
1105 if (pcbRead)
1106 *pcbRead = cbAllRead;
1107
1108 if (rc == VERR_EOF)
1109 rc = VINF_SUCCESS;
1110
1111 /* Signal the thread to read more data in the mean time. */
1112 if ( RT_SUCCESS(rc)
1113 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1114 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1115
1116 return rc;
1117}
1118
1119static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
1120{
1121 /* Validate input. */
1122 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1123 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1124
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);
1130
1131 DEBUG_PRINT_FLOW();
1132
1133 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1134
1135 /* Check if there is still something in the buffer. If yes, flush it. */
1136 int rc = sha1FlushCurBuf(pInt);
1137 if (RT_FAILURE(rc))
1138 return rc;
1139
1140 return pCallbacks->pfnFlushSync(pIO->pvUser, pInt->pvStorage);
1141}
1142
1143/******************************************************************************
1144 * Public Functions *
1145 ******************************************************************************/
1146
1147PVDINTERFACEIO Sha1CreateInterface()
1148{
1149 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1150 if (!pCallbacks)
1151 return NULL;
1152
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;
1166
1167 return pCallbacks;
1168}
1169
1170PVDINTERFACEIO FileCreateInterface()
1171{
1172 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1173 if (!pCallbacks)
1174 return NULL;
1175
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;
1189
1190 return pCallbacks;
1191}
1192
1193PVDINTERFACEIO TarCreateInterface()
1194{
1195 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1196 if (!pCallbacks)
1197 return NULL;
1198
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;
1212
1213 return pCallbacks;
1214}
1215
1216int Sha1ReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1217{
1218 /* Validate input. */
1219 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1220 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1221 AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1222
1223 void *pvStorage;
1224 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1225 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1226 &pvStorage);
1227 if (RT_FAILURE(rc))
1228 return rc;
1229
1230 void *pvTmpBuf = 0;
1231 void *pvBuf = 0;
1232 uint64_t cbTmpSize = _1M;
1233 size_t cbAllRead = 0;
1234 do
1235 {
1236 pvTmpBuf = RTMemAlloc(cbTmpSize);
1237 if (!pvTmpBuf)
1238 {
1239 rc = VERR_NO_MEMORY;
1240 break;
1241 }
1242
1243 for(;;)
1244 {
1245 size_t cbRead = 0;
1246 rc = pCallbacks->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1247 if ( RT_FAILURE(rc)
1248 || cbRead == 0)
1249 break;
1250 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1251 if (!pvBuf)
1252 {
1253 rc = VERR_NO_MEMORY;
1254 break;
1255 }
1256 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1257 cbAllRead += cbRead;
1258 }
1259 }while(0);
1260
1261 pCallbacks->pfnClose(pvUser, pvStorage);
1262
1263 if (rc == VERR_EOF)
1264 rc = VINF_SUCCESS;
1265
1266 if (pvTmpBuf)
1267 RTMemFree(pvTmpBuf);
1268
1269 if (RT_SUCCESS(rc))
1270 {
1271 *ppvBuf = pvBuf;
1272 *pcbSize = cbAllRead;
1273 }else
1274 {
1275 if (pvBuf)
1276 RTMemFree(pvBuf);
1277 }
1278
1279 return rc;
1280}
1281
1282int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1283{
1284 /* Validate input. */
1285 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1286 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1287 AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1288
1289 void *pvStorage;
1290 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1291 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1292 &pvStorage);
1293 if (RT_FAILURE(rc))
1294 return rc;
1295
1296 size_t cbAllWritten = 0;
1297 for(;;)
1298 {
1299 if (cbAllWritten >= cbSize)
1300 break;
1301 size_t cbToWrite = cbSize - cbAllWritten;
1302 size_t cbWritten = 0;
1303 rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1304 if (RT_FAILURE(rc))
1305 break;
1306 cbAllWritten += cbWritten;
1307 }
1308
1309 pCallbacks->pfnClose(pvUser, pvStorage);
1310
1311 return rc;
1312}
1313
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