VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/ApplianceImplIO.cpp@ 65120

Last change on this file since 65120 was 62485, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.0 KB
Line 
1/* $Id: ApplianceImplIO.cpp 62485 2016-07-22 18:36:43Z vboxsync $ */
2/** @file
3 * IO helper for IAppliance COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2010-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22
23#include "ProgressImpl.h"
24#include "ApplianceImpl.h"
25#include "ApplianceImplPrivate.h"
26#include "VirtualBoxImpl.h"
27
28#include <iprt/zip.h>
29#include <iprt/tar.h>
30#include <iprt/sha.h>
31#include <iprt/path.h>
32#include <iprt/asm.h>
33#include <iprt/stream.h>
34#include <iprt/circbuf.h>
35#include <iprt/vfs.h>
36#include <iprt/manifest.h>
37#include <VBox/vd-ifs.h>
38#include <VBox/vd.h>
39
40#include "Logging.h"
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46typedef struct FILESTORAGEINTERNAL
47{
48 /** File handle. */
49 RTFILE file;
50 /** Completion callback. */
51 PFNVDCOMPLETED pfnCompleted;
52} FILESTORAGEINTERNAL, *PFILESTORAGEINTERNAL;
53
54typedef struct TARSTORAGEINTERNAL
55{
56 /** Tar handle. */
57 RTTARFILE hTarFile;
58 /** Completion callback. */
59 PFNVDCOMPLETED pfnCompleted;
60} TARSTORAGEINTERNAL, *PTARSTORAGEINTERNAL;
61
62
63typedef struct SHASTORAGEINTERNAL
64{
65 /** Completion callback. */
66 PFNVDCOMPLETED pfnCompleted;
67 /** Storage handle for the next callback in chain. */
68 void *pvStorage;
69 /** Current file open mode. */
70 uint32_t fOpenMode;
71 /** Our own storage handle. */
72 PSHASTORAGE pShaStorage;
73 /** Circular buffer used for transferring data from/to the worker thread. */
74 PRTCIRCBUF pCircBuf;
75 /** Current absolute position (regardless of the real read/written data). */
76 uint64_t cbCurAll;
77 /** Current real position in the file. */
78 uint64_t cbCurFile;
79 /** Handle of the worker thread. */
80 RTTHREAD pWorkerThread;
81 /** Status of the worker thread. */
82 volatile uint32_t u32Status;
83 /** Event for signaling a new status. */
84 RTSEMEVENT newStatusEvent;
85 /** Event for signaling a finished task of the worker thread. */
86 RTSEMEVENT workFinishedEvent;
87 /** SHA1/SHA256 calculation context. */
88 union
89 {
90 RTSHA1CONTEXT Sha1;
91 RTSHA256CONTEXT Sha256;
92 } ctx;
93 /** Write mode only: Memory buffer for writing zeros. */
94 void *pvZeroBuf;
95 /** Write mode only: Size of the zero memory buffer. */
96 size_t cbZeroBuf;
97 /** Read mode only: Indicate if we reached end of file. */
98 volatile bool fEOF;
99// uint64_t calls;
100// uint64_t waits;
101} SHASTORAGEINTERNAL, *PSHASTORAGEINTERNAL;
102
103
104/*********************************************************************************************************************************
105* Defined Constants And Macros *
106*********************************************************************************************************************************/
107
108#define STATUS_WAIT UINT32_C(0)
109#define STATUS_WRITE UINT32_C(1)
110#define STATUS_WRITING UINT32_C(2)
111#define STATUS_READ UINT32_C(3)
112#define STATUS_READING UINT32_C(4)
113#define STATUS_END UINT32_C(5)
114
115/* Enable for getting some flow history. */
116#if 0
117# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
118#else
119# define DEBUG_PRINT_FLOW() do {} while (0)
120#endif
121
122
123/*********************************************************************************************************************************
124* Internal Functions *
125*********************************************************************************************************************************/
126
127
128/** @name VDINTERFACEIO stubs returning not-implemented.
129 * @{
130 */
131
132/** @interface_method_impl{VDINTERFACEIO,pfnDelete} */
133static DECLCALLBACK(int) notImpl_Delete(void *pvUser, const char *pcszFilename)
134{
135 NOREF(pvUser); NOREF(pcszFilename);
136 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
137 return VERR_NOT_IMPLEMENTED;
138}
139
140/** @interface_method_impl{VDINTERFACEIO,pfnMove} */
141static DECLCALLBACK(int) notImpl_Move(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
142{
143 NOREF(pvUser); NOREF(pcszSrc); NOREF(pcszDst); NOREF(fMove);
144 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
145 return VERR_NOT_IMPLEMENTED;
146}
147
148/** @interface_method_impl{VDINTERFACEIO,pfnGetFreeSpace} */
149static DECLCALLBACK(int) notImpl_GetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
150{
151 NOREF(pvUser); NOREF(pcszFilename); NOREF(pcbFreeSpace);
152 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
153 return VERR_NOT_IMPLEMENTED;
154}
155
156/** @interface_method_impl{VDINTERFACEIO,pfnGetModificationTime} */
157static DECLCALLBACK(int) notImpl_GetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
158{
159 NOREF(pvUser); NOREF(pcszFilename); NOREF(pModificationTime);
160 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
161 return VERR_NOT_IMPLEMENTED;
162}
163
164#if 0
165/** @interface_method_impl{VDINTERFACEIO,pfnSetSize} */
166static DECLCALLBACK(int) notImpl_SetSize(void *pvUser, void *pvStorage, uint64_t cb)
167{
168 NOREF(pvUser); NOREF(pvStorage); NOREF(cb);
169 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
170 return VERR_NOT_IMPLEMENTED;
171}
172
173/** @interface_method_impl{VDINTERFACEIO,pfnWriteSync} */
174static DECLCALLBACK(int) notImpl_WriteSync(void *pvUser, void *pvStorage, uint64_t off, const void *pvBuf,
175 size_t cbWrite, size_t *pcbWritten)
176{
177 NOREF(pvUser); NOREF(pvStorage); NOREF(off); NOREF(pvBuf); NOREF(cbWrite); NOREF(pcbWritten);
178 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
179 return VERR_NOT_IMPLEMENTED;
180}
181#endif
182
183/** @interface_method_impl{VDINTERFACEIO,pfnFlushSync} */
184static DECLCALLBACK(int) notImpl_FlushSync(void *pvUser, void *pvStorage)
185{
186 NOREF(pvUser); NOREF(pvStorage);
187 Log(("%s\n", __FUNCTION__)); DEBUG_PRINT_FLOW();
188 return VERR_NOT_IMPLEMENTED;
189}
190
191/** @} */
192
193
194/******************************************************************************
195 * Internal: RTFile interface
196 ******************************************************************************/
197
198static DECLCALLBACK(int) fileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen,
199 PFNVDCOMPLETED pfnCompleted, void **ppInt)
200{
201 /* Validate input. */
202 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
203 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
204
205 DEBUG_PRINT_FLOW();
206
207 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL));
208 if (!pInt)
209 return VERR_NO_MEMORY;
210
211 pInt->pfnCompleted = pfnCompleted;
212
213 int rc = RTFileOpen(&pInt->file, pszLocation, fOpen);
214
215 if (RT_FAILURE(rc))
216 RTMemFree(pInt);
217 else
218 *ppInt = pInt;
219
220 return rc;
221}
222
223static DECLCALLBACK(int) fileCloseCallback(void * /* pvUser */, void *pvStorage)
224{
225 /* Validate input. */
226 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
227
228 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
229
230 DEBUG_PRINT_FLOW();
231
232 int rc = RTFileClose(pInt->file);
233
234 /* Cleanup */
235 RTMemFree(pInt);
236
237 return rc;
238}
239
240static DECLCALLBACK(int) fileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
241{
242 DEBUG_PRINT_FLOW();
243
244 return RTFileDelete(pcszFilename);
245}
246
247static DECLCALLBACK(int) fileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
248{
249 DEBUG_PRINT_FLOW();
250
251 return RTFileMove(pcszSrc, pcszDst, fMove);
252}
253
254static DECLCALLBACK(int) fileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
255{
256 /* Validate input. */
257 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
258 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
259
260 DEBUG_PRINT_FLOW();
261
262 return VERR_NOT_IMPLEMENTED;
263}
264
265static DECLCALLBACK(int) fileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename,
266 PRTTIMESPEC pModificationTime)
267{
268 /* Validate input. */
269 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
270 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
271
272 DEBUG_PRINT_FLOW();
273
274 return VERR_NOT_IMPLEMENTED;
275}
276
277static DECLCALLBACK(int) fileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
278{
279 /* Validate input. */
280 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
281
282 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
283
284 DEBUG_PRINT_FLOW();
285
286 return RTFileGetSize(pInt->file, pcbSize);
287}
288
289static DECLCALLBACK(int) fileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
290{
291 /* Validate input. */
292 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
293
294 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
295
296 DEBUG_PRINT_FLOW();
297
298 return RTFileSetSize(pInt->file, cbSize);
299}
300
301static DECLCALLBACK(int) fileWriteSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
302 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
303{
304 /* Validate input. */
305 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
306
307 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
308
309 return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
310}
311
312static DECLCALLBACK(int) fileReadSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
313 void *pvBuf, size_t cbRead, size_t *pcbRead)
314{
315 /* Validate input. */
316 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
317
318// DEBUG_PRINT_FLOW();
319
320 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
321
322 return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
323}
324
325static DECLCALLBACK(int) fileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
326{
327 /* Validate input. */
328 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
329
330 DEBUG_PRINT_FLOW();
331
332 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
333
334 return RTFileFlush(pInt->file);
335}
336
337
338/** @name VDINTERFACEIO implementation that writes TAR files via RTTar.
339 * @{ */
340
341static DECLCALLBACK(int) tarWriter_Open(void *pvUser, const char *pszLocation, uint32_t fOpen,
342 PFNVDCOMPLETED pfnCompleted, void **ppInt)
343{
344 /* Validate input. */
345 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
346 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
347 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
348 AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_PARAMETER); /* Only for writing. */
349
350 DEBUG_PRINT_FLOW();
351
352 /*
353 * Allocate a storage handle.
354 */
355 int rc;
356 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(TARSTORAGEINTERNAL));
357 if (pInt)
358 {
359 pInt->pfnCompleted = pfnCompleted;
360
361 /*
362 * Try open the file.
363 */
364 rc = RTTarFileOpen((RTTAR)pvUser, &pInt->hTarFile, RTPathFilename(pszLocation), fOpen);
365 if (RT_SUCCESS(rc))
366 *ppInt = pInt;
367 else
368 RTMemFree(pInt);
369 }
370 else
371 rc = VERR_NO_MEMORY;
372 return rc;
373}
374
375static DECLCALLBACK(int) tarWriter_Close(void *pvUser, void *pvStorage)
376{
377 /* Validate input. */
378 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
379 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
380
381 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
382
383 DEBUG_PRINT_FLOW();
384
385 int rc = RTTarFileClose(pInt->hTarFile);
386 pInt->hTarFile = NIL_RTTARFILE;
387
388 /* Cleanup */
389 RTMemFree(pInt);
390
391 return rc;
392}
393
394static DECLCALLBACK(int) tarWriter_GetSize(void *pvUser, void *pvStorage, uint64_t *pcbSize)
395{
396 /** @todo Not sure if this is really required, but it's not a biggie to keep
397 * around. */
398 /* Validate input. */
399 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
400 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
401
402 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
403
404 DEBUG_PRINT_FLOW();
405
406 return RTTarFileGetSize(pInt->hTarFile, pcbSize);
407}
408
409static DECLCALLBACK(int) tarWriter_SetSize(void *pvUser, void *pvStorage, uint64_t cbSize)
410{
411 /* Validate input. */
412 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
413 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
414
415 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
416
417 DEBUG_PRINT_FLOW();
418
419 return RTTarFileSetSize(pInt->hTarFile, cbSize);
420}
421
422static DECLCALLBACK(int) tarWriter_WriteSync(void *pvUser, void *pvStorage, uint64_t uOffset,
423 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
424{
425 /* Validate input. */
426 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
427 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
428
429 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
430
431 DEBUG_PRINT_FLOW();
432
433 return RTTarFileWriteAt(pInt->hTarFile, uOffset, pvBuf, cbWrite, pcbWritten);
434}
435
436static DECLCALLBACK(int) tarWriter_ReadSync(void *pvUser, void *pvStorage, uint64_t uOffset,
437 void *pvBuf, size_t cbRead, size_t *pcbRead)
438{
439 /** @todo Not sure if this is really required, but it's not a biggie to keep
440 * around. */
441 /* Validate input. */
442 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
443 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
444
445 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
446
447// DEBUG_PRINT_FLOW();
448
449 return RTTarFileReadAt(pInt->hTarFile, uOffset, pvBuf, cbRead, pcbRead);
450}
451
452
453PVDINTERFACEIO tarWriterCreateInterface(void)
454{
455 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
456 if (!pCallbacks)
457 return NULL;
458
459 pCallbacks->pfnOpen = tarWriter_Open;
460 pCallbacks->pfnClose = tarWriter_Close;
461 pCallbacks->pfnDelete = notImpl_Delete;
462 pCallbacks->pfnMove = notImpl_Move;
463 pCallbacks->pfnGetFreeSpace = notImpl_GetFreeSpace;
464 pCallbacks->pfnGetModificationTime = notImpl_GetModificationTime;
465 pCallbacks->pfnGetSize = tarWriter_GetSize;
466 pCallbacks->pfnSetSize = tarWriter_SetSize;
467 pCallbacks->pfnReadSync = tarWriter_ReadSync;
468 pCallbacks->pfnWriteSync = tarWriter_WriteSync;
469 pCallbacks->pfnFlushSync = notImpl_FlushSync;
470
471 return pCallbacks;
472}
473
474/** @} */
475
476
477/******************************************************************************
478 * Internal: RTSha interface
479 ******************************************************************************/
480
481DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
482{
483 /* Validate input. */
484 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
485
486 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvUser;
487
488 PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
489 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
490
491 int rc = VINF_SUCCESS;
492 bool fLoop = true;
493 while (fLoop)
494 {
495 /* What should we do next? */
496 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
497// RTPrintf("status: %d\n", u32Status);
498 switch (u32Status)
499 {
500 case STATUS_WAIT:
501 {
502 /* Wait for new work. */
503 rc = RTSemEventWait(pInt->newStatusEvent, 100);
504 if ( RT_FAILURE(rc)
505 && rc != VERR_TIMEOUT)
506 fLoop = false;
507 break;
508 }
509 case STATUS_WRITE:
510 {
511 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WRITING, STATUS_WRITE);
512 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
513 size_t cbMemAllRead = 0;
514 /* First loop over all the free memory in the circular
515 * memory buffer (could be turn around at the end). */
516 for (;;)
517 {
518 if ( cbMemAllRead == cbAvail
519 || fLoop == false)
520 break;
521 char *pcBuf;
522 size_t cbMemToRead = cbAvail - cbMemAllRead;
523 size_t cbMemRead = 0;
524 /* Try to acquire all the used space of the circular buffer. */
525 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
526 size_t cbAllWritten = 0;
527 /* Second, write as long as used memory is there. The write
528 * method could also split the writes up into to smaller
529 * parts. */
530 for (;;)
531 {
532 if (cbAllWritten == cbMemRead)
533 break;
534 size_t cbToWrite = cbMemRead - cbAllWritten;
535 size_t cbWritten = 0;
536 rc = vdIfIoFileWriteSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten],
537 cbToWrite, &cbWritten);
538// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
539 if (RT_FAILURE(rc))
540 {
541 fLoop = false;
542 break;
543 }
544 cbAllWritten += cbWritten;
545 pInt->cbCurFile += cbWritten;
546 }
547 /* Update the SHA1/SHA256 context with the next data block. */
548 if ( RT_SUCCESS(rc)
549 && pInt->pShaStorage->fCreateDigest)
550 {
551 if (pInt->pShaStorage->fSha256)
552 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllWritten);
553 else
554 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllWritten);
555 }
556 /* Mark the block as empty. */
557 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
558 cbMemAllRead += cbAllWritten;
559 }
560 /* Reset the thread status and signal the main thread that we
561 * are finished. Use CmpXchg, so we not overwrite other states
562 * which could be signaled in the meantime. */
563 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITING))
564 rc = RTSemEventSignal(pInt->workFinishedEvent);
565 break;
566 }
567 case STATUS_READ:
568 {
569 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
570 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
571 size_t cbMemAllWrite = 0;
572 /* First loop over all the available memory in the circular
573 * memory buffer (could be turn around at the end). */
574 for (;;)
575 {
576 if ( cbMemAllWrite == cbAvail
577 || fLoop == false)
578 break;
579 char *pcBuf;
580 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
581 size_t cbMemWrite = 0;
582 /* Try to acquire all the free space of the circular buffer. */
583 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
584 /* Second, read as long as we filled all the memory. The
585 * read method could also split the reads up into to
586 * smaller parts. */
587 size_t cbAllRead = 0;
588 for (;;)
589 {
590 if (cbAllRead == cbMemWrite)
591 break;
592 size_t cbToRead = cbMemWrite - cbAllRead;
593 size_t cbRead = 0;
594 rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
595// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
596 if (RT_FAILURE(rc))
597 {
598 fLoop = false;
599 break;
600 }
601 /* This indicates end of file. Stop reading. */
602 if (cbRead == 0)
603 {
604 fLoop = false;
605 ASMAtomicWriteBool(&pInt->fEOF, true);
606 break;
607 }
608 cbAllRead += cbRead;
609 pInt->cbCurFile += cbRead;
610 }
611 /* Update the SHA1/SHA256 context with the next data block. */
612 if ( RT_SUCCESS(rc)
613 && pInt->pShaStorage->fCreateDigest)
614 {
615 if (pInt->pShaStorage->fSha256)
616 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
617 else
618 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllRead);
619 }
620 /* Mark the block as full. */
621 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
622 cbMemAllWrite += cbAllRead;
623 }
624 /* Reset the thread status and signal the main thread that we
625 * are finished. Use CmpXchg, so we not overwrite other states
626 * which could be signaled in the meantime. */
627 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
628 rc = RTSemEventSignal(pInt->workFinishedEvent);
629 break;
630 }
631 case STATUS_END:
632 {
633 /* End signaled */
634 fLoop = false;
635 break;
636 }
637 }
638 }
639 /* Cleanup any status changes to indicate we are finished. */
640 ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
641 rc = RTSemEventSignal(pInt->workFinishedEvent);
642 return rc;
643}
644
645DECLINLINE(int) shaSignalManifestThread(PSHASTORAGEINTERNAL pInt, uint32_t uStatus)
646{
647 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
648 return RTSemEventSignal(pInt->newStatusEvent);
649}
650
651DECLINLINE(int) shaWaitForManifestThreadFinished(PSHASTORAGEINTERNAL pInt)
652{
653// RTPrintf("start\n");
654 int rc = VINF_SUCCESS;
655 for (;;)
656 {
657// RTPrintf(" wait\n");
658 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
659 if (!( u32Status == STATUS_WRITE
660 || u32Status == STATUS_WRITING
661 || u32Status == STATUS_READ
662 || u32Status == STATUS_READING))
663 break;
664 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
665 }
666 if (rc == VERR_TIMEOUT)
667 rc = VINF_SUCCESS;
668 return rc;
669}
670
671DECLINLINE(int) shaFlushCurBuf(PSHASTORAGEINTERNAL pInt)
672{
673 int rc = VINF_SUCCESS;
674 if (pInt->fOpenMode & RTFILE_O_WRITE)
675 {
676 /* Let the write worker thread start immediately. */
677 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
678 if (RT_FAILURE(rc))
679 return rc;
680
681 /* Wait until the write worker thread has finished. */
682 rc = shaWaitForManifestThreadFinished(pInt);
683 }
684
685 return rc;
686}
687
688static DECLCALLBACK(int) shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
689 PFNVDCOMPLETED pfnCompleted, void **ppInt)
690{
691 /* Validate input. */
692 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
693 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
694 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
695 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
696 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
697
698 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
699 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
700 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
701
702 DEBUG_PRINT_FLOW();
703
704 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL));
705 if (!pInt)
706 return VERR_NO_MEMORY;
707
708 int rc = VINF_SUCCESS;
709 do
710 {
711 pInt->pfnCompleted = pfnCompleted;
712 pInt->pShaStorage = pShaStorage;
713 pInt->fEOF = false;
714 pInt->fOpenMode = fOpen;
715 pInt->u32Status = STATUS_WAIT;
716
717 /* Circular buffer in the read case. */
718 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
719 if (RT_FAILURE(rc))
720 break;
721
722 if (fOpen & RTFILE_O_WRITE)
723 {
724 /* The zero buffer is used for appending empty parts at the end of the
725 * file (or our buffer) in setSize or when uOffset in writeSync is
726 * increased in steps bigger than a byte. */
727 pInt->cbZeroBuf = _1K;
728 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
729 if (!pInt->pvZeroBuf)
730 {
731 rc = VERR_NO_MEMORY;
732 break;
733 }
734 }
735
736 /* Create an event semaphore to indicate a state change for the worker
737 * thread. */
738 rc = RTSemEventCreate(&pInt->newStatusEvent);
739 if (RT_FAILURE(rc))
740 break;
741 /* Create an event semaphore to indicate a finished calculation of the
742 worker thread. */
743 rc = RTSemEventCreate(&pInt->workFinishedEvent);
744 if (RT_FAILURE(rc))
745 break;
746 /* Create the worker thread. */
747 rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER,
748 RTTHREADFLAGS_WAITABLE, "SHA-Worker");
749 if (RT_FAILURE(rc))
750 break;
751
752 if (pShaStorage->fCreateDigest)
753 {
754 /* Create a SHA1/SHA256 context the worker thread will work with. */
755 if (pShaStorage->fSha256)
756 RTSha256Init(&pInt->ctx.Sha256);
757 else
758 RTSha1Init(&pInt->ctx.Sha1);
759 }
760
761 /* Open the file. */
762 rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
763 &pInt->pvStorage);
764 if (RT_FAILURE(rc))
765 break;
766
767 if (fOpen & RTFILE_O_READ)
768 {
769 /* Immediately let the worker thread start the reading. */
770 rc = shaSignalManifestThread(pInt, STATUS_READ);
771 }
772 }
773 while (0);
774
775 if (RT_FAILURE(rc))
776 {
777 if (pInt->pWorkerThread)
778 {
779 shaSignalManifestThread(pInt, STATUS_END);
780 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
781 }
782 if (pInt->workFinishedEvent)
783 RTSemEventDestroy(pInt->workFinishedEvent);
784 if (pInt->newStatusEvent)
785 RTSemEventDestroy(pInt->newStatusEvent);
786 if (pInt->pCircBuf)
787 RTCircBufDestroy(pInt->pCircBuf);
788 if (pInt->pvZeroBuf)
789 RTMemFree(pInt->pvZeroBuf);
790 RTMemFree(pInt);
791 }
792 else
793 *ppInt = pInt;
794
795 return rc;
796}
797
798static DECLCALLBACK(int) shaCloseCallback(void *pvUser, void *pvStorage)
799{
800 /* Validate input. */
801 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
802 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
803
804 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
805 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
806 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
807
808 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
809
810 DEBUG_PRINT_FLOW();
811
812 int rc = VINF_SUCCESS;
813
814 /* Make sure all pending writes are flushed */
815 rc = shaFlushCurBuf(pInt);
816
817 if (pInt->pWorkerThread)
818 {
819 /* Signal the worker thread to end himself */
820 rc = shaSignalManifestThread(pInt, STATUS_END);
821 /* Worker thread stopped? */
822 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
823 }
824
825 if ( RT_SUCCESS(rc)
826 && pShaStorage->fCreateDigest)
827 {
828 /* Finally calculate & format the SHA1/SHA256 sum */
829 unsigned char auchDig[RTSHA256_HASH_SIZE];
830 char *pszDigest;
831 size_t cbDigest;
832 if (pShaStorage->fSha256)
833 {
834 RTSha256Final(&pInt->ctx.Sha256, auchDig);
835 cbDigest = RTSHA256_DIGEST_LEN;
836 }
837 else
838 {
839 RTSha1Final(&pInt->ctx.Sha1, auchDig);
840 cbDigest = RTSHA1_DIGEST_LEN;
841 }
842 rc = RTStrAllocEx(&pszDigest, cbDigest + 1);
843 if (RT_SUCCESS(rc))
844 {
845 if (pShaStorage->fSha256)
846 rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1);
847 else
848 rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1);
849 if (RT_SUCCESS(rc))
850 pShaStorage->strDigest = pszDigest;
851 RTStrFree(pszDigest);
852 }
853 }
854
855 /* Close the file */
856 rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
857
858// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
859
860 /* Cleanup */
861 if (pInt->workFinishedEvent)
862 RTSemEventDestroy(pInt->workFinishedEvent);
863 if (pInt->newStatusEvent)
864 RTSemEventDestroy(pInt->newStatusEvent);
865 if (pInt->pCircBuf)
866 RTCircBufDestroy(pInt->pCircBuf);
867 if (pInt->pvZeroBuf)
868 RTMemFree(pInt->pvZeroBuf);
869 RTMemFree(pInt);
870
871 return rc;
872}
873
874static DECLCALLBACK(int) shaDeleteCallback(void *pvUser, const char *pcszFilename)
875{
876 /* Validate input. */
877 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
878
879 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
880 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
881 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
882
883 DEBUG_PRINT_FLOW();
884
885 return vdIfIoFileDelete(pIfIo, pcszFilename);
886}
887
888static DECLCALLBACK(int) shaMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
889{
890 /* Validate input. */
891 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
892
893 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
894 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
895 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
896
897
898 DEBUG_PRINT_FLOW();
899
900 return vdIfIoFileMove(pIfIo, pcszSrc, pcszDst, fMove);
901}
902
903static DECLCALLBACK(int) shaGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
904{
905 /* Validate input. */
906 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
907
908 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
909 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
910 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
911
912 DEBUG_PRINT_FLOW();
913
914 return vdIfIoFileGetFreeSpace(pIfIo, pcszFilename, pcbFreeSpace);
915}
916
917static DECLCALLBACK(int) shaGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
918{
919 /* Validate input. */
920 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
921
922 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
923 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
924 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
925
926 DEBUG_PRINT_FLOW();
927
928 return vdIfIoFileGetModificationTime(pIfIo, pcszFilename, pModificationTime);
929}
930
931
932static DECLCALLBACK(int) shaGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
933{
934 /* Validate input. */
935 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
936 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
937
938 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
939 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
940 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
941
942 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
943
944 DEBUG_PRINT_FLOW();
945
946 uint64_t cbSize;
947 int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
948 if (RT_FAILURE(rc))
949 return rc;
950
951 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
952
953 return VINF_SUCCESS;
954}
955
956static DECLCALLBACK(int) shaSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
957{
958 /* Validate input. */
959 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
960 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
961
962 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
963 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
964 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
965
966 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
967
968 DEBUG_PRINT_FLOW();
969
970 return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
971}
972
973static DECLCALLBACK(int) shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
974 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
975{
976 /* Validate input. */
977 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
978 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
979
980 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
981 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
982 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
983
984 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
985
986 DEBUG_PRINT_FLOW();
987
988 /* Check that the write is linear */
989 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!",
990 uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
991
992 int rc = VINF_SUCCESS;
993
994 /* Check if we have to add some free space at the end, before we start the
995 * real write. */
996 if (pInt->cbCurAll < uOffset)
997 {
998 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
999 size_t cbAllWritten = 0;
1000 for (;;)
1001 {
1002 /* Finished? */
1003 if (cbAllWritten == cbSize)
1004 break;
1005 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
1006 size_t cbWritten = 0;
1007 rc = shaWriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
1008 pInt->pvZeroBuf, cbToWrite, &cbWritten);
1009 if (RT_FAILURE(rc))
1010 break;
1011 cbAllWritten += cbWritten;
1012 }
1013 if (RT_FAILURE(rc))
1014 return rc;
1015 }
1016// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
1017
1018 size_t cbAllWritten = 0;
1019 for (;;)
1020 {
1021 /* Finished? */
1022 if (cbAllWritten == cbWrite)
1023 break;
1024 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1025 if ( cbAvail == 0
1026 && pInt->fEOF)
1027 return VERR_EOF;
1028 /* If there isn't enough free space make sure the worker thread is
1029 * writing some data. */
1030 if ((cbWrite - cbAllWritten) > cbAvail)
1031 {
1032 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1033 if (RT_FAILURE(rc))
1034 break;
1035 /* If there is _no_ free space available, we have to wait until it is. */
1036 if (cbAvail == 0)
1037 {
1038 rc = shaWaitForManifestThreadFinished(pInt);
1039 if (RT_FAILURE(rc))
1040 break;
1041 cbAvail = RTCircBufFree(pInt->pCircBuf);
1042// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1043// pInt->waits++;
1044 }
1045 }
1046 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1047 char *pcBuf;
1048 size_t cbMemWritten = 0;
1049 /* Acquire a block for writing from our circular buffer. */
1050 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1051 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1052 /* Mark the block full. */
1053 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1054 cbAllWritten += cbMemWritten;
1055 pInt->cbCurAll += cbMemWritten;
1056 }
1057
1058 if (pcbWritten)
1059 *pcbWritten = cbAllWritten;
1060
1061 /* Signal the thread to write more data in the mean time. */
1062 if ( RT_SUCCESS(rc)
1063 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1064 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1065
1066 return rc;
1067}
1068
1069static DECLCALLBACK(int) shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1070 void *pvBuf, size_t cbRead, size_t *pcbRead)
1071{
1072 /* Validate input. */
1073 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1074 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1075
1076 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1077 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1078 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1079
1080// DEBUG_PRINT_FLOW();
1081
1082 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1083
1084 int rc = VINF_SUCCESS;
1085
1086// pInt->calls++;
1087// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1088
1089 /* Check if we jump forward in the file. If so we have to read the
1090 * remaining stuff in the gap anyway (SHA1/SHA256; streaming). */
1091 if (pInt->cbCurAll < uOffset)
1092 {
1093 rc = shaReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1094 (size_t)(uOffset - pInt->cbCurAll), 0);
1095 if (RT_FAILURE(rc))
1096 return rc;
1097// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1098 }
1099 else if (uOffset < pInt->cbCurAll)
1100 AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
1101
1102 size_t cbAllRead = 0;
1103 size_t cbAvail = 0;
1104 for (;;)
1105 {
1106 /* Finished? */
1107 if (cbAllRead == cbRead)
1108 break;
1109
1110 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1111
1112 if ( cbAvail == 0
1113 && pInt->fEOF
1114 && !RTCircBufIsWriting(pInt->pCircBuf))
1115 {
1116 rc = VINF_EOF;
1117 break;
1118 }
1119
1120 /* If there isn't enough data make sure the worker thread is fetching
1121 * more. */
1122 if ((cbRead - cbAllRead) > cbAvail)
1123 {
1124 rc = shaSignalManifestThread(pInt, STATUS_READ);
1125 if (RT_FAILURE(rc))
1126 break;
1127 /* If there is _no_ data available, we have to wait until it is. */
1128 if (cbAvail == 0)
1129 {
1130 rc = shaWaitForManifestThreadFinished(pInt);
1131 if (RT_FAILURE(rc))
1132 break;
1133 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1134// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1135// pInt->waits++;
1136 }
1137 }
1138 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1139 char *pcBuf;
1140 size_t cbMemRead = 0;
1141 /* Acquire a block for reading from our circular buffer. */
1142 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1143 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1144 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1145 /* Mark the block as empty again. */
1146 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1147 cbAllRead += cbMemRead;
1148
1149 pInt->cbCurAll += cbMemRead;
1150 }
1151
1152 if (pcbRead)
1153 *pcbRead = cbAllRead;
1154
1155 if (rc == VERR_EOF)
1156 rc = VINF_SUCCESS;
1157
1158 /* Signal the thread to read more data in the mean time. */
1159 if ( RT_SUCCESS(rc)
1160 && rc != VINF_EOF
1161 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1162 rc = shaSignalManifestThread(pInt, STATUS_READ);
1163
1164 return rc;
1165}
1166
1167static DECLCALLBACK(int) shaFlushSyncCallback(void *pvUser, void *pvStorage)
1168{
1169 /* Validate input. */
1170 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1171 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1172
1173 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1174 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1175 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1176
1177 DEBUG_PRINT_FLOW();
1178
1179 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1180
1181 /* Check if there is still something in the buffer. If yes, flush it. */
1182 int rc = shaFlushCurBuf(pInt);
1183 if (RT_FAILURE(rc))
1184 return rc;
1185
1186 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1187}
1188
1189PVDINTERFACEIO ShaCreateInterface()
1190{
1191 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1192 if (!pCallbacks)
1193 return NULL;
1194
1195 pCallbacks->pfnOpen = shaOpenCallback;
1196 pCallbacks->pfnClose = shaCloseCallback;
1197 pCallbacks->pfnDelete = shaDeleteCallback;
1198 pCallbacks->pfnMove = shaMoveCallback;
1199 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1200 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1201 pCallbacks->pfnGetSize = shaGetSizeCallback;
1202 pCallbacks->pfnSetSize = shaSetSizeCallback;
1203 pCallbacks->pfnReadSync = shaReadSyncCallback;
1204 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1205 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1206
1207 return pCallbacks;
1208}
1209
1210PVDINTERFACEIO FileCreateInterface()
1211{
1212 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1213 if (!pCallbacks)
1214 return NULL;
1215
1216 pCallbacks->pfnOpen = fileOpenCallback;
1217 pCallbacks->pfnClose = fileCloseCallback;
1218 pCallbacks->pfnDelete = fileDeleteCallback;
1219 pCallbacks->pfnMove = fileMoveCallback;
1220 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1221 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1222 pCallbacks->pfnGetSize = fileGetSizeCallback;
1223 pCallbacks->pfnSetSize = fileSetSizeCallback;
1224 pCallbacks->pfnReadSync = fileReadSyncCallback;
1225 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1226 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1227
1228 return pCallbacks;
1229}
1230
1231int writeBufferToFile(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1232{
1233 /* Validate input. */
1234 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1235 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1236 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1237
1238 void *pvStorage;
1239 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1240 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1241 &pvStorage);
1242 if (RT_FAILURE(rc))
1243 return rc;
1244
1245 size_t cbAllWritten = 0;
1246 for (;;)
1247 {
1248 if (cbAllWritten >= cbSize)
1249 break;
1250 size_t cbToWrite = cbSize - cbAllWritten;
1251 size_t cbWritten = 0;
1252 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1253 if (RT_FAILURE(rc))
1254 break;
1255 cbAllWritten += cbWritten;
1256 }
1257
1258 rc = pIfIo->pfnClose(pvUser, pvStorage);
1259
1260 return rc;
1261}
1262
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