VirtualBox

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

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

Main-OVF: Use the circular buffer on export and move the write operation to the
worker thread as well.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.5 KB
Line 
1/* $Id: ApplianceImplIO.cpp 33536 2010-10-28 08:30:48Z 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/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 /** 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 rtFileOpenCallback(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 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(RTFILESTORAGEINTERNAL));
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 rtFileCloseCallback(void * /* pvUser */, void *pvStorage)
141{
142 /* Validate input. */
143 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
144
145 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)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 rtFileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
158{
159 DEBUG_PRINT_FLOW();
160
161 return RTFileDelete(pcszFilename);
162}
163
164static int rtFileMoveCallback(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 rtFileGetFreeSpaceCallback(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 rtFileGetModificationTimeCallback(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 rtFileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
194{
195 /* Validate input. */
196 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
197
198 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
199
200 DEBUG_PRINT_FLOW();
201
202 return RTFileGetSize(pInt->file, pcbSize);
203}
204
205static int rtFileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
206{
207 /* Validate input. */
208 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
209
210 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
211
212 DEBUG_PRINT_FLOW();
213
214 return RTFileSetSize(pInt->file, cbSize);
215}
216
217static int rtFileWriteSyncCallback(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 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
224
225 return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
226}
227
228static int rtFileReadSyncCallback(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 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
237
238 return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
239}
240
241static int rtFileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
242{
243 /* Validate input. */
244 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
245
246 DEBUG_PRINT_FLOW();
247
248 PRTFILESTORAGEINTERNAL pInt = (PRTFILESTORAGEINTERNAL)pvStorage;
249
250 return RTFileFlush(pInt->file);
251}
252
253/******************************************************************************
254 * Internal: RTTar interface
255 ******************************************************************************/
256
257static int rtTarOpenCallback(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 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(RTTARSTORAGEINTERNAL));
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 rtTarCloseCallback(void *pvUser, void *pvStorage)
328{
329 /* Validate input. */
330 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
331 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
332
333 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)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 rtTarDeleteCallback(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 rtTarMoveCallback(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 rtTarGetFreeSpaceCallback(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 rtTarGetModificationTimeCallback(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 rtTarGetSizeCallback(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 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
399
400 DEBUG_PRINT_FLOW();
401
402 return RTTarFileGetSize(pInt->file, pcbSize);
403}
404
405static int rtTarSetSizeCallback(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 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
412
413 DEBUG_PRINT_FLOW();
414
415 return RTTarFileSetSize(pInt->file, cbSize);
416}
417
418static int rtTarWriteSyncCallback(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 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
426
427 DEBUG_PRINT_FLOW();
428
429 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
430}
431
432static int rtTarReadSyncCallback(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 PRTTARSTORAGEINTERNAL pInt = (PRTTARSTORAGEINTERNAL)pvStorage;
440
441 DEBUG_PRINT_FLOW();
442
443 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
444}
445
446static int rtTarFlushSyncCallback(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: Sha1 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 bool fStop = false;
496 bool fEOF = false;
497 /* First loop over all the free memory in the circular
498 * memory buffer (could be turn around at the end). */
499 for(;;)
500 {
501 if ( cbMemAllRead == cbAvail
502 || fStop == true)
503 break;
504 char *pcBuf;
505 size_t cbMemToRead = cbAvail - cbMemAllRead;
506 size_t cbMemRead = 0;
507 /* Try to acquire all the used space of the circular buffer. */
508 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
509 size_t cbAllWritten = 0;
510 /* Second, write as long as used memory is there. The write
511 * method could also split the writes up into to smaller
512 * parts. */
513 for(;;)
514 {
515 if (cbAllWritten == cbMemRead)
516 break;
517 size_t cbToWrite = cbMemRead - cbAllWritten;
518 size_t cbWritten = 0;
519 rc = pCallbacks->pfnWriteSync(pIO->pvUser, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten], cbToWrite, &cbWritten);
520// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
521 if (RT_FAILURE(rc))
522 {
523 fStop = true;
524 fLoop = false;
525 break;
526 }
527 if (cbWritten == 0)
528 {
529 fStop = true;
530 fLoop = false;
531 fEOF = true;
532// RTPrintf("EOF\n");
533 break;
534 }
535 cbAllWritten += cbWritten;
536 pInt->cbCurFile += cbWritten;
537 }
538 /* Update the SHA1 context with the next data block. */
539 if (pInt->pSha1Storage->fCreateDigest)
540 RTSha1Update(&pInt->ctx, pcBuf, cbAllWritten);
541 /* Mark the block as empty. */
542 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
543 cbMemAllRead += cbAllWritten;
544 }
545 /* Reset the thread status and signal the main thread that we
546 * are finished. Use CmpXchg, so we not overwrite other states
547 * which could be signaled in the meantime. */
548 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITE);
549 rc = RTSemEventSignal(pInt->workFinishedEvent);
550 break;
551 }
552 case STATUS_READ:
553 {
554 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
555 size_t cbMemAllWrite = 0;
556 bool fStop = false;
557 bool fEOF = false;
558 /* First loop over all the available memory in the circular
559 * memory buffer (could be turn around at the end). */
560 for(;;)
561 {
562 if ( cbMemAllWrite == cbAvail
563 || fStop == true)
564 break;
565 char *pcBuf;
566 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
567 size_t cbMemWrite = 0;
568 /* Try to acquire all the free space of the circular buffer. */
569 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
570 /* Second, read as long as we filled all the memory. The
571 * read method could also split the reads up into to
572 * smaller parts. */
573 size_t cbAllRead = 0;
574 for(;;)
575 {
576 if (cbAllRead == cbMemWrite)
577 break;
578 size_t cbToRead = cbMemWrite - cbAllRead;
579 size_t cbRead = 0;
580 rc = pCallbacks->pfnReadSync(pIO->pvUser, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
581// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
582 if (RT_FAILURE(rc))
583 {
584 fStop = true;
585 fLoop = false;
586 break;
587 }
588 if (cbRead == 0)
589 {
590 fStop = true;
591 fLoop = false;
592 fEOF = true;
593// RTPrintf("EOF\n");
594 break;
595 }
596 cbAllRead += cbRead;
597 pInt->cbCurFile += cbRead;
598 }
599 /* Update the SHA1 context with the next data block. */
600 if (pInt->pSha1Storage->fCreateDigest)
601 RTSha1Update(&pInt->ctx, pcBuf, cbAllRead);
602 /* Mark the block as full. */
603 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
604 cbMemAllWrite += cbAllRead;
605 }
606 if (fEOF)
607 ASMAtomicWriteBool(&pInt->fEOF, true);
608 /* Reset the thread status and signal the main thread that we
609 * are finished. Use CmpXchg, so we not overwrite other states
610 * which could be signaled in the meantime. */
611 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READ);
612 rc = RTSemEventSignal(pInt->workFinishedEvent);
613 break;
614 }
615 case STATUS_END:
616 {
617 /* End signaled */
618 fLoop = false;
619 break;
620 }
621 }
622 }
623 return rc;
624}
625
626DECLINLINE(int) sha1SignalManifestThread(PSHA1STORAGEINTERNAL pInt, uint32_t uStatus)
627{
628 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
629 return RTSemEventSignal(pInt->newStatusEvent);
630}
631
632DECLINLINE(int) sha1WaitForManifestThreadFinished(PSHA1STORAGEINTERNAL pInt)
633{
634// RTPrintf("start\n");
635 int rc = VINF_SUCCESS;
636 for(;;)
637 {
638// RTPrintf(" wait\n");
639 if (!( ASMAtomicReadU32(&pInt->u32Status) == STATUS_WRITE
640 || ASMAtomicReadU32(&pInt->u32Status) == STATUS_READ))
641 break;
642 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
643 }
644 if (rc == VERR_TIMEOUT)
645 rc = VINF_SUCCESS;
646 return rc;
647}
648
649DECLINLINE(int) sha1FlushCurBuf(PSHA1STORAGEINTERNAL pInt)
650{
651 int rc = VINF_SUCCESS;
652 if (pInt->fOpenMode & RTFILE_O_WRITE)
653 {
654 /* Let the write worker thread start immediately. */
655 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
656 if (RT_FAILURE(rc))
657 return rc;
658
659 /* Wait until the write worker thread has finished. */
660 rc = sha1WaitForManifestThreadFinished(pInt);
661 }
662
663 return rc;
664}
665
666static int sha1OpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
667 PFNVDCOMPLETED pfnCompleted, void **ppInt)
668{
669 /* Validate input. */
670 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
671 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
672 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
673 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
674 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
675
676 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
677 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
678 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
679 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
680 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
681
682 DEBUG_PRINT_FLOW();
683
684 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)RTMemAllocZ(sizeof(SHA1STORAGEINTERNAL));
685 if (!pInt)
686 return VERR_NO_MEMORY;
687
688 int rc = VINF_SUCCESS;
689 do
690 {
691 pInt->pfnCompleted = pfnCompleted;
692 pInt->pSha1Storage = pSha1Storage;
693 pInt->fEOF = false;
694 pInt->fOpenMode = fOpen;
695
696 /* Circular buffer in the read case. */
697 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
698 if (RT_FAILURE(rc))
699 break;
700
701 if (fOpen & RTFILE_O_WRITE)
702 {
703 /* The zero buffer is used for appending empty parts at the end of the
704 * file (or our buffer) in setSize or when uOffset in writeSync is
705 * increased in steps bigger than a byte. */
706 pInt->cbZeroBuf = _1K;
707 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
708 if (!pInt->pvZeroBuf)
709 {
710 rc = VERR_NO_MEMORY;
711 break;
712 }
713 }
714
715 /* Create an event semaphore to indicate a state change for the worker
716 * thread. */
717 rc = RTSemEventCreate(&pInt->newStatusEvent);
718 if (RT_FAILURE(rc))
719 break;
720 /* Create an event semaphore to indicate a finished calculation of the
721 worker thread. */
722 rc = RTSemEventCreate(&pInt->workFinishedEvent);
723 if (RT_FAILURE(rc))
724 break;
725 /* Create the worker thread. */
726 rc = RTThreadCreate(&pInt->pWorkerThread, sha1CalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA1-Worker");
727 if (RT_FAILURE(rc))
728 break;
729
730 if (pSha1Storage->fCreateDigest)
731 /* Create a sha1 context the worker thread will work with. */
732 RTSha1Init(&pInt->ctx);
733
734 /* Open the file. */
735 rc = pCallbacks->pfnOpen(pIO->pvUser, pszLocation,
736 fOpen, pInt->pfnCompleted,
737 &pInt->pvStorage);
738 if (RT_FAILURE(rc))
739 break;
740
741 if (fOpen & RTFILE_O_READ)
742 {
743 /* Immediately let the worker thread start the reading. */
744 rc = sha1SignalManifestThread(pInt, STATUS_READ);
745 }
746 }
747 while(0);
748
749 if (RT_FAILURE(rc))
750 {
751 if (pInt->pWorkerThread)
752 {
753 sha1SignalManifestThread(pInt, STATUS_END);
754 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
755 }
756 if (pInt->workFinishedEvent)
757 RTSemEventDestroy(pInt->workFinishedEvent);
758 if (pInt->newStatusEvent)
759 RTSemEventDestroy(pInt->newStatusEvent);
760 if (pInt->pCircBuf)
761 RTCircBufDestroy(pInt->pCircBuf);
762 if (pInt->pvZeroBuf)
763 RTMemFree(pInt->pvZeroBuf);
764 RTMemFree(pInt);
765 }
766 else
767 *ppInt = pInt;
768
769 return rc;
770}
771
772static int sha1CloseCallback(void *pvUser, void *pvStorage)
773{
774 /* Validate input. */
775 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
776 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
777
778 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
779 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
780 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
781 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
782 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
783
784 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
785
786 DEBUG_PRINT_FLOW();
787
788 int rc = VINF_SUCCESS;
789
790 /* Make sure all pending writes are flushed */
791 rc = sha1FlushCurBuf(pInt);
792
793 if (pInt->pWorkerThread)
794 {
795 /* Signal the worker thread to end himself */
796 rc = sha1SignalManifestThread(pInt, STATUS_END);
797 /* Worker thread stopped? */
798 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
799 }
800
801 if ( RT_SUCCESS(rc)
802 && pSha1Storage->fCreateDigest)
803 {
804 /* Finally calculate & format the SHA1 sum */
805 unsigned char auchDig[RTSHA1_HASH_SIZE];
806 char *pszDigest;
807 RTSha1Final(&pInt->ctx, auchDig);
808 rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
809 if (RT_SUCCESS(rc))
810 {
811 rc = RTSha1ToString(auchDig, pszDigest, RTSHA1_DIGEST_LEN + 1);
812 if (RT_SUCCESS(rc))
813 pSha1Storage->strDigest = pszDigest;
814 RTStrFree(pszDigest);
815 }
816 }
817
818 /* Close the file */
819 rc = pCallbacks->pfnClose(pIO->pvUser, pInt->pvStorage);
820
821// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
822
823 /* Cleanup */
824 if (pInt->workFinishedEvent)
825 RTSemEventDestroy(pInt->workFinishedEvent);
826 if (pInt->newStatusEvent)
827 RTSemEventDestroy(pInt->newStatusEvent);
828 if (pInt->pCircBuf)
829 RTCircBufDestroy(pInt->pCircBuf);
830 if (pInt->pvZeroBuf)
831 RTMemFree(pInt->pvZeroBuf);
832 RTMemFree(pInt);
833
834 return rc;
835}
836
837static int sha1DeleteCallback(void *pvUser, const char *pcszFilename)
838{
839 /* Validate input. */
840 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
841
842 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
843 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
844 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
845 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
846 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
847
848 DEBUG_PRINT_FLOW();
849
850 return pCallbacks->pfnDelete(pIO->pvUser, pcszFilename);
851}
852
853static int sha1MoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
854{
855 /* Validate input. */
856 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
857
858 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
859 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
860 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
861 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
862 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
863
864 DEBUG_PRINT_FLOW();
865
866 return pCallbacks->pfnMove(pIO->pvUser, pcszSrc, pcszDst, fMove);
867}
868
869static int sha1GetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
870{
871 /* Validate input. */
872 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
873
874 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
875 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
876 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
877 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
878 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
879
880 DEBUG_PRINT_FLOW();
881
882 return pCallbacks->pfnGetFreeSpace(pIO->pvUser, pcszFilename, pcbFreeSpace);
883}
884
885static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
886{
887 /* Validate input. */
888 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
889
890 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
891 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
892 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
893 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
894 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
895
896 DEBUG_PRINT_FLOW();
897
898 return pCallbacks->pfnGetModificationTime(pIO->pvUser, pcszFilename, pModificationTime);
899}
900
901
902static int sha1GetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
903{
904 /* Validate input. */
905 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
906 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
907
908 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
909 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
910 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
911 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
912 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
913
914 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
915
916 DEBUG_PRINT_FLOW();
917
918 uint64_t cbSize;
919 int rc = pCallbacks->pfnGetSize(pIO->pvUser, pInt->pvStorage, &cbSize);
920 if (RT_FAILURE(rc))
921 return rc;
922
923 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
924
925 return VINF_SUCCESS;
926}
927
928static int sha1SetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
929{
930 /* Validate input. */
931 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
932 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
933
934 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
935 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
936 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
937 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
938 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
939
940 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
941
942 DEBUG_PRINT_FLOW();
943
944 return pCallbacks->pfnSetSize(pIO->pvUser, pInt->pvStorage, cbSize);
945}
946
947static int sha1WriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
948 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
949{
950 /* Validate input. */
951 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
952 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
953
954 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
955 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
956 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
957 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
958 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
959
960 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
961
962 DEBUG_PRINT_FLOW();
963
964 /* Check that the write is linear */
965 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
966
967 int rc = VINF_SUCCESS;
968
969 /* Check if we have to add some free space at the end, before we start the
970 * real write. */
971 if (pInt->cbCurAll < uOffset)
972 {
973 size_t cbSize = uOffset - pInt->cbCurAll;
974 size_t cbAllWritten = 0;
975 for(;;)
976 {
977 /* Finished? */
978 if (cbAllWritten == cbSize)
979 break;
980 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
981 size_t cbWritten = 0;
982 rc = sha1WriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
983 pInt->pvZeroBuf, cbToWrite, &cbWritten);
984 if (RT_FAILURE(rc))
985 break;
986 cbAllWritten += cbWritten;
987 }
988 if (RT_FAILURE(rc))
989 return rc;
990 }
991// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
992
993 size_t cbAllWritten = 0;
994 for(;;)
995 {
996 /* Finished? */
997 if (cbAllWritten == cbWrite)
998 break;
999 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1000 if ( cbAvail == 0
1001 && pInt->fEOF)
1002 return VERR_EOF;
1003 /* If there isn't enough free space make sure the worker thread is
1004 * writing some data. */
1005 if ((cbWrite - cbAllWritten) > cbAvail)
1006 {
1007 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
1008 if(RT_FAILURE(rc))
1009 break;
1010 /* If there is _no_ free space available, we have to wait until it is. */
1011 if (cbAvail == 0)
1012 {
1013 rc = sha1WaitForManifestThreadFinished(pInt);
1014 if (RT_FAILURE(rc))
1015 break;
1016 cbAvail = RTCircBufFree(pInt->pCircBuf);
1017// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1018// pInt->waits++;
1019 }
1020 }
1021 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1022 char *pcBuf;
1023 size_t cbMemWritten = 0;
1024 /* Acquire a block for writing from our circular buffer. */
1025 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1026 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1027 /* Mark the block full. */
1028 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1029 cbAllWritten += cbMemWritten;
1030 pInt->cbCurAll += cbMemWritten;
1031 }
1032
1033 if (pcbWritten)
1034 *pcbWritten = cbAllWritten;
1035
1036 /* Signal the thread to write more data in the mean time. */
1037 if ( RT_SUCCESS(rc)
1038 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1039 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
1040
1041 return rc;
1042}
1043
1044static int sha1ReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1045 void *pvBuf, size_t cbRead, size_t *pcbRead)
1046{
1047 /* Validate input. */
1048 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1049 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1050
1051 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1052 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
1053 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
1054 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
1055 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
1056
1057 DEBUG_PRINT_FLOW();
1058
1059 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1060
1061 int rc = VINF_SUCCESS;
1062
1063// pInt->calls++;
1064// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1065
1066 /* Check if we jump forward in the file. If so we have to read the
1067 * remaining stuff in the gap anyway (SHA1; streaming). */
1068 if (pInt->cbCurAll < uOffset)
1069 {
1070 rc = sha1ReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0, uOffset - pInt->cbCurAll, 0);
1071 if (RT_FAILURE(rc))
1072 return rc;
1073 }
1074
1075 size_t cbAllRead = 0;
1076 for(;;)
1077 {
1078 /* Finished? */
1079 if (cbAllRead == cbRead)
1080 break;
1081 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1082 if ( cbAvail == 0
1083 && pInt->fEOF)
1084 return VERR_EOF;
1085 /* If there isn't enough data make sure the worker thread is fetching
1086 * more. */
1087 if ((cbRead - cbAllRead) > cbAvail)
1088 {
1089 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1090 if(RT_FAILURE(rc))
1091 break;
1092 /* If there is _no_ data available, we have to wait until it is. */
1093 if (cbAvail == 0)
1094 {
1095 rc = sha1WaitForManifestThreadFinished(pInt);
1096 if (RT_FAILURE(rc))
1097 break;
1098 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1099// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1100// pInt->waits++;
1101 }
1102 }
1103 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1104 char *pcBuf;
1105 size_t cbMemRead = 0;
1106 /* Acquire a block for reading from our circular buffer. */
1107 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1108 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1109 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1110 /* Mark the block as empty again. */
1111 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1112 cbAllRead += cbMemRead;
1113 pInt->cbCurAll += cbMemRead;
1114 }
1115
1116 if (pcbRead)
1117 *pcbRead = cbAllRead;
1118
1119 if (rc == VERR_EOF)
1120 rc = VINF_SUCCESS;
1121
1122 /* Signal the thread to read more data in the mean time. */
1123 if ( RT_SUCCESS(rc)
1124 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1125 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1126
1127 return rc;
1128}
1129
1130static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
1131{
1132 /* Validate input. */
1133 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1134 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1135
1136 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1137 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
1138 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
1139 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
1140 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
1141
1142 DEBUG_PRINT_FLOW();
1143
1144 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1145
1146 /* Check if there is still something in the buffer. If yes, flush it. */
1147 int rc = sha1FlushCurBuf(pInt);
1148 if (RT_FAILURE(rc))
1149 return rc;
1150
1151 return pCallbacks->pfnFlushSync(pIO->pvUser, pInt->pvStorage);
1152}
1153
1154/******************************************************************************
1155 * Public Functions *
1156 ******************************************************************************/
1157
1158PVDINTERFACEIO Sha1CreateInterface()
1159{
1160 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1161 if (!pCallbacks)
1162 return NULL;
1163
1164 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1165 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1166 pCallbacks->pfnOpen = sha1OpenCallback;
1167 pCallbacks->pfnClose = sha1CloseCallback;
1168 pCallbacks->pfnDelete = sha1DeleteCallback;
1169 pCallbacks->pfnMove = sha1MoveCallback;
1170 pCallbacks->pfnGetFreeSpace = sha1GetFreeSpaceCallback;
1171 pCallbacks->pfnGetModificationTime = sha1GetModificationTimeCallback;
1172 pCallbacks->pfnGetSize = sha1GetSizeCallback;
1173 pCallbacks->pfnSetSize = sha1SetSizeCallback;
1174 pCallbacks->pfnReadSync = sha1ReadSyncCallback;
1175 pCallbacks->pfnWriteSync = sha1WriteSyncCallback;
1176 pCallbacks->pfnFlushSync = sha1FlushSyncCallback;
1177
1178 return pCallbacks;
1179}
1180
1181PVDINTERFACEIO RTFileCreateInterface()
1182{
1183 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1184 if (!pCallbacks)
1185 return NULL;
1186
1187 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1188 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1189 pCallbacks->pfnOpen = rtFileOpenCallback;
1190 pCallbacks->pfnClose = rtFileCloseCallback;
1191 pCallbacks->pfnDelete = rtFileDeleteCallback;
1192 pCallbacks->pfnMove = rtFileMoveCallback;
1193 pCallbacks->pfnGetFreeSpace = rtFileGetFreeSpaceCallback;
1194 pCallbacks->pfnGetModificationTime = rtFileGetModificationTimeCallback;
1195 pCallbacks->pfnGetSize = rtFileGetSizeCallback;
1196 pCallbacks->pfnSetSize = rtFileSetSizeCallback;
1197 pCallbacks->pfnReadSync = rtFileReadSyncCallback;
1198 pCallbacks->pfnWriteSync = rtFileWriteSyncCallback;
1199 pCallbacks->pfnFlushSync = rtFileFlushSyncCallback;
1200
1201 return pCallbacks;
1202}
1203
1204PVDINTERFACEIO RTTarCreateInterface()
1205{
1206 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1207 if (!pCallbacks)
1208 return NULL;
1209
1210 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1211 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1212 pCallbacks->pfnOpen = rtTarOpenCallback;
1213 pCallbacks->pfnClose = rtTarCloseCallback;
1214 pCallbacks->pfnDelete = rtTarDeleteCallback;
1215 pCallbacks->pfnMove = rtTarMoveCallback;
1216 pCallbacks->pfnGetFreeSpace = rtTarGetFreeSpaceCallback;
1217 pCallbacks->pfnGetModificationTime = rtTarGetModificationTimeCallback;
1218 pCallbacks->pfnGetSize = rtTarGetSizeCallback;
1219 pCallbacks->pfnSetSize = rtTarSetSizeCallback;
1220 pCallbacks->pfnReadSync = rtTarReadSyncCallback;
1221 pCallbacks->pfnWriteSync = rtTarWriteSyncCallback;
1222 pCallbacks->pfnFlushSync = rtTarFlushSyncCallback;
1223
1224 return pCallbacks;
1225}
1226
1227int Sha1ReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1228{
1229 /* Validate input. */
1230 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1231 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1232 AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1233
1234 void *pvStorage;
1235 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1236 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1237 &pvStorage);
1238 if (RT_FAILURE(rc))
1239 return rc;
1240
1241 void *pvBuf = 0;
1242 uint64_t cbSize = 0;
1243 do
1244 {
1245 rc = pCallbacks->pfnGetSize(pvUser, pvStorage, &cbSize);
1246 if (RT_FAILURE(rc))
1247 break;
1248
1249 pvBuf = RTMemAlloc(cbSize);
1250 if (!pvBuf)
1251 {
1252 rc = VERR_NO_MEMORY;
1253 break;
1254 }
1255
1256 size_t cbAllRead = 0;
1257 for(;;)
1258 {
1259 if (cbAllRead == cbSize)
1260 break;
1261 size_t cbToRead = cbSize - cbAllRead;
1262 size_t cbRead = 0;
1263 rc = pCallbacks->pfnReadSync(pvUser, pvStorage, cbAllRead, &((char*)pvBuf)[cbAllRead], cbToRead, &cbRead);
1264 if (RT_FAILURE(rc))
1265 break;
1266 cbAllRead += cbRead;
1267 }
1268 }while(0);
1269
1270 pCallbacks->pfnClose(pvUser, pvStorage);
1271
1272 if (RT_SUCCESS(rc))
1273 {
1274 *ppvBuf = pvBuf;
1275 *pcbSize = cbSize;
1276 }else
1277 {
1278 if (pvBuf)
1279 RTMemFree(pvBuf);
1280 }
1281
1282 return rc;
1283}
1284
1285int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1286{
1287 /* Validate input. */
1288 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1289 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1290 AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1291
1292 void *pvStorage;
1293 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1294 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1295 &pvStorage);
1296 if (RT_FAILURE(rc))
1297 return rc;
1298
1299 size_t cbAllWritten = 0;
1300 for(;;)
1301 {
1302 if (cbAllWritten >= cbSize)
1303 break;
1304 size_t cbToWrite = cbSize - cbAllWritten;
1305 size_t cbWritten = 0;
1306 rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1307 if (RT_FAILURE(rc))
1308 break;
1309 cbAllWritten += cbWritten;
1310 }
1311
1312 pCallbacks->pfnClose(pvUser, pvStorage);
1313
1314 return rc;
1315}
1316
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