VirtualBox

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

Last change on this file since 59621 was 59621, checked in by vboxsync, 9 years ago

ApplianceImplImport.cpp,++: Pushed the IPRT VFS stuff futher down, only going to the VD I/O wrappers when start getting down into the media code during import. Reworked the OVA releated import code to skip files it doesn't care about (like message resource xml files which we don't implement) and not be picky about which order files the OVF, MF and CERT files come in (todo: make sure it isn't picky about the order of disks either). Read the manifest and certificate file during the read() method.

  • 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 59621 2016-02-10 00:51:35Z vboxsync $ */
2/** @file
3 * IO helper for IAppliance COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2010-2013 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