VirtualBox

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

Last change on this file since 47340 was 47340, checked in by vboxsync, 12 years ago

pr6022. OVA appliance don't fail when a certificate file exists. GZIP support has been implemented (first version).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.1 KB
Line 
1/* $Id: ApplianceImplIO.cpp 47340 2013-07-23 12:27:35Z vboxsync $ */
2/** @file
3 *
4 * IO helper for IAppliance COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2010-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. 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#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 <VBox/vd.h>
36#include <zlib.h>
37
38/******************************************************************************
39 * Structures and Typedefs *
40 ******************************************************************************/
41typedef struct FILESTORAGEINTERNAL
42{
43 /** File handle. */
44 RTFILE file;
45 /** Completion callback. */
46 PFNVDCOMPLETED pfnCompleted;
47} FILESTORAGEINTERNAL, *PFILESTORAGEINTERNAL;
48
49typedef struct TARSTORAGEINTERNAL
50{
51 /** Tar handle. */
52 RTTARFILE file;
53 /** Completion callback. */
54 PFNVDCOMPLETED pfnCompleted;
55} TARSTORAGEINTERNAL, *PTARSTORAGEINTERNAL;
56
57typedef struct SHASTORAGEINTERNAL
58{
59 /** Completion callback. */
60 PFNVDCOMPLETED pfnCompleted;
61 /** Storage handle for the next callback in chain. */
62 void *pvStorage;
63 /** Current file open mode. */
64 uint32_t fOpenMode;
65 /** Our own storage handle. */
66 PSHASTORAGE pShaStorage;
67 /** Circular buffer used for transferring data from/to the worker thread. */
68 PRTCIRCBUF pCircBuf;
69 /** Current absolute position (regardless of the real read/written data). */
70 uint64_t cbCurAll;
71 /** Current real position in the file. */
72 uint64_t cbCurFile;
73 /** Handle of the worker thread. */
74 RTTHREAD pWorkerThread;
75 /** Status of the worker thread. */
76 volatile uint32_t u32Status;
77 /** Event for signaling a new status. */
78 RTSEMEVENT newStatusEvent;
79 /** Event for signaling a finished task of the worker thread. */
80 RTSEMEVENT workFinishedEvent;
81 /** SHA1/SHA256 calculation context. */
82 union
83 {
84 RTSHA1CONTEXT Sha1;
85 RTSHA256CONTEXT Sha256;
86 } ctx;
87 /** Write mode only: Memory buffer for writing zeros. */
88 void *pvZeroBuf;
89 /** Write mode only: Size of the zero memory buffer. */
90 size_t cbZeroBuf;
91 /** Read mode only: Indicate if we reached end of file. */
92 volatile bool fEOF;
93// uint64_t calls;
94// uint64_t waits;
95} SHASTORAGEINTERNAL, *PSHASTORAGEINTERNAL;
96
97typedef struct GZIPSTORAGEINTERNAL
98{
99 /** Completion callback. */
100 PFNVDCOMPLETED pfnCompleted;
101 /** Storage handle for the next callback in chain. */
102 void *pvStorage;
103 /** Current file open mode. */
104 uint32_t fOpenMode;
105 /** Circular buffer used for transferring data from/to the worker thread. */
106 PRTCIRCBUF pCircBuf;
107 /** Current absolute position (regardless of the real read/written data). */
108 uint64_t cbCurAll;
109 /** Current real position in the file. */
110 uint64_t cbCurFile;
111 /** Handle of the worker thread. */
112 RTTHREAD pWorkerThread;
113 /** Status of the worker thread. */
114 volatile uint32_t u32Status;
115 /** Event for signaling a new status. */
116 RTSEMEVENT newStatusEvent;
117 /** Event for signaling a finished task of the worker thread. */
118 RTSEMEVENT workFinishedEvent;
119 /** Write mode only: Memory buffer for writing zeros. */
120 void *pvZeroBuf;
121 /** Write mode only: Size of the zero memory buffer. */
122 size_t cbZeroBuf;
123 /** Read mode only: Indicate if we reached end of file. */
124 volatile bool fEOF;
125// uint64_t calls;
126// uint64_t waits;
127} GZIPSTORAGEINTERNAL, *PGZIPSTORAGEINTERNAL;
128
129/******************************************************************************
130 * Defined Constants And Macros *
131 ******************************************************************************/
132
133#define STATUS_WAIT UINT32_C(0)
134#define STATUS_WRITE UINT32_C(1)
135#define STATUS_WRITING UINT32_C(2)
136#define STATUS_READ UINT32_C(3)
137#define STATUS_READING UINT32_C(4)
138#define STATUS_END UINT32_C(5)
139
140/* Enable for getting some flow history. */
141#if 0
142# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
143#else
144# define DEBUG_PRINT_FLOW() do {} while (0)
145#endif
146
147/** Buffer for the decompressed data. */
148//static uint8_t *compressedBuffer;
149/** The current size of the compressed data*/
150static size_t cbComprData;
151/** The current offset into the compressed data */
152static size_t offComprData;
153
154/******************************************************************************
155 * Internal Functions *
156 ******************************************************************************/
157//static DECLCALLBACK(int) CopyCompressedDataToBuffer(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbRead);
158
159/******************************************************************************
160 * Internal: RTFile interface
161 ******************************************************************************/
162
163static int fileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen,
164 PFNVDCOMPLETED pfnCompleted, void **ppInt)
165{
166 /* Validate input. */
167 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
168 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
169
170 DEBUG_PRINT_FLOW();
171
172 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL));
173 if (!pInt)
174 return VERR_NO_MEMORY;
175
176 pInt->pfnCompleted = pfnCompleted;
177
178 int rc = RTFileOpen(&pInt->file, pszLocation, fOpen);
179
180 if (RT_FAILURE(rc))
181 RTMemFree(pInt);
182 else
183 *ppInt = pInt;
184
185 return rc;
186}
187
188static int fileCloseCallback(void * /* pvUser */, void *pvStorage)
189{
190 /* Validate input. */
191 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
192
193 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
194
195 DEBUG_PRINT_FLOW();
196
197 int rc = RTFileClose(pInt->file);
198
199 /* Cleanup */
200 RTMemFree(pInt);
201
202 return rc;
203}
204
205static int fileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
206{
207 DEBUG_PRINT_FLOW();
208
209 return RTFileDelete(pcszFilename);
210}
211
212static int fileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
213{
214 DEBUG_PRINT_FLOW();
215
216 return RTFileMove(pcszSrc, pcszDst, fMove);
217}
218
219static int fileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
220{
221 /* Validate input. */
222 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
223 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
224
225 DEBUG_PRINT_FLOW();
226
227 return VERR_NOT_IMPLEMENTED;
228}
229
230static int fileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename, PRTTIMESPEC pModificationTime)
231{
232 /* Validate input. */
233 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
234 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
235
236 DEBUG_PRINT_FLOW();
237
238 return VERR_NOT_IMPLEMENTED;
239}
240
241static int fileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
242{
243 /* Validate input. */
244 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
245
246 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
247
248 DEBUG_PRINT_FLOW();
249
250 return RTFileGetSize(pInt->file, pcbSize);
251}
252
253static int fileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
254{
255 /* Validate input. */
256 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
257
258 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
259
260 DEBUG_PRINT_FLOW();
261
262 return RTFileSetSize(pInt->file, cbSize);
263}
264
265static int fileWriteSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
266 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
267{
268 /* Validate input. */
269 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
270
271 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
272
273 return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
274}
275
276static int fileReadSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
277 void *pvBuf, size_t cbRead, size_t *pcbRead)
278{
279 /* Validate input. */
280 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
281
282// DEBUG_PRINT_FLOW();
283
284 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
285
286 return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
287}
288
289static int fileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
290{
291 /* Validate input. */
292 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
293
294 DEBUG_PRINT_FLOW();
295
296 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
297
298 return RTFileFlush(pInt->file);
299}
300
301/******************************************************************************
302 * Internal: RTTar interface
303 ******************************************************************************/
304
305static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
306 PFNVDCOMPLETED pfnCompleted, void **ppInt)
307{
308 /* Validate input. */
309 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
310 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
311 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
312// AssertReturn(!(fOpen & RTFILE_O_READWRITE), VERR_INVALID_PARAMETER);
313
314 RTTAR tar = (RTTAR)pvUser;
315
316 DEBUG_PRINT_FLOW();
317
318 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(TARSTORAGEINTERNAL));
319 if (!pInt)
320 return VERR_NO_MEMORY;
321
322 pInt->pfnCompleted = pfnCompleted;
323
324 int rc = VINF_SUCCESS;
325
326 if (fOpen & RTFILE_O_READ
327 && !(fOpen & RTFILE_O_WRITE))
328 {
329 /* Read only is a little bit more complicated than writing, cause we
330 * need streaming functionality. First try to open the file on the
331 * current file position. If this is the file the caller requested, we
332 * are fine. If not seek to the next file in the stream and check
333 * again. This is repeated until EOF of the OVA. */
334 /*
335 *
336 *
337 * TODO: recheck this with more VDMKs (or what else) in an test OVA.
338 *
339 *
340 */
341 bool fFound = false;
342
343 for (;;)
344 {
345 char *pszFilename = 0;
346 rc = RTTarCurrentFile(tar, &pszFilename);
347 if (RT_SUCCESS(rc))
348 {
349 if (rc == VINF_TAR_DIR_PATH)
350 {
351 break;
352 }
353
354 fFound = !RTStrICmp(pszFilename, pszLocation);
355
356 RTStrFree(pszFilename);
357 if (fFound)
358 break;
359 else
360 {
361 rc = RTTarSeekNextFile(tar);
362 if (RT_FAILURE(rc))
363 {
364 break;
365 }
366 }
367 }
368 else
369 break;
370 }
371 if (fFound)
372 rc = RTTarFileOpenCurrentFile(tar, &pInt->file, 0, fOpen);
373 }
374 else
375 rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
376
377 if (RT_FAILURE(rc))
378 RTMemFree(pInt);
379 else
380 *ppInt = pInt;
381
382 return rc;
383}
384
385static int tarCloseCallback(void *pvUser, void *pvStorage)
386{
387 /* Validate input. */
388 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
389 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
390
391 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
392
393 DEBUG_PRINT_FLOW();
394
395 int rc = RTTarFileClose(pInt->file);
396
397 /* Cleanup */
398 RTMemFree(pInt);
399
400 return rc;
401}
402
403static int tarDeleteCallback(void *pvUser, const char *pcszFilename)
404{
405 /* Validate input. */
406 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
407 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
408
409 DEBUG_PRINT_FLOW();
410
411 return VERR_NOT_IMPLEMENTED;
412}
413
414static int tarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
415{
416 /* Validate input. */
417 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
418 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
419 AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
420
421 DEBUG_PRINT_FLOW();
422
423 return VERR_NOT_IMPLEMENTED;
424}
425
426static int tarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
427{
428 /* Validate input. */
429 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
430 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
431 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
432
433 DEBUG_PRINT_FLOW();
434
435 return VERR_NOT_IMPLEMENTED;
436}
437
438static int tarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
439{
440 /* Validate input. */
441 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
442 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
443 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
444
445 DEBUG_PRINT_FLOW();
446
447 return VERR_NOT_IMPLEMENTED;
448}
449
450static int tarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
451{
452 /* Validate input. */
453 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
454 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
455
456 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
457
458 DEBUG_PRINT_FLOW();
459
460 return RTTarFileGetSize(pInt->file, pcbSize);
461}
462
463static int tarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
464{
465 /* Validate input. */
466 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
467 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
468
469 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
470
471 DEBUG_PRINT_FLOW();
472
473 return RTTarFileSetSize(pInt->file, cbSize);
474}
475
476static int tarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
477 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
478{
479 /* Validate input. */
480 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
481 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
482
483 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
484
485 DEBUG_PRINT_FLOW();
486
487 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
488}
489
490static int tarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
491 void *pvBuf, size_t cbRead, size_t *pcbRead)
492{
493 /* Validate input. */
494 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
495 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
496
497 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
498
499// DEBUG_PRINT_FLOW();
500
501 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
502}
503
504static int tarFlushSyncCallback(void *pvUser, void *pvStorage)
505{
506 /* Validate input. */
507 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
508 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
509
510 DEBUG_PRINT_FLOW();
511
512 return VERR_NOT_IMPLEMENTED;
513}
514
515/******************************************************************************
516 * Internal: RTSha interface
517 ******************************************************************************/
518
519DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
520{
521 /* Validate input. */
522 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
523
524 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvUser;
525
526 PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
527 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
528
529 int rc = VINF_SUCCESS;
530 bool fLoop = true;
531 while (fLoop)
532 {
533 /* What should we do next? */
534 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
535// RTPrintf("status: %d\n", u32Status);
536 switch (u32Status)
537 {
538 case STATUS_WAIT:
539 {
540 /* Wait for new work. */
541 rc = RTSemEventWait(pInt->newStatusEvent, 100);
542 if ( RT_FAILURE(rc)
543 && rc != VERR_TIMEOUT)
544 fLoop = false;
545 break;
546 }
547 case STATUS_WRITE:
548 {
549 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WRITING, STATUS_WRITE);
550 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
551 size_t cbMemAllRead = 0;
552 /* First loop over all the free memory in the circular
553 * memory buffer (could be turn around at the end). */
554 for (;;)
555 {
556 if ( cbMemAllRead == cbAvail
557 || fLoop == false)
558 break;
559 char *pcBuf;
560 size_t cbMemToRead = cbAvail - cbMemAllRead;
561 size_t cbMemRead = 0;
562 /* Try to acquire all the used space of the circular buffer. */
563 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
564 size_t cbAllWritten = 0;
565 /* Second, write as long as used memory is there. The write
566 * method could also split the writes up into to smaller
567 * parts. */
568 for (;;)
569 {
570 if (cbAllWritten == cbMemRead)
571 break;
572 size_t cbToWrite = cbMemRead - cbAllWritten;
573 size_t cbWritten = 0;
574 rc = vdIfIoFileWriteSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten], cbToWrite, &cbWritten);
575// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
576 if (RT_FAILURE(rc))
577 {
578 fLoop = false;
579 break;
580 }
581 cbAllWritten += cbWritten;
582 pInt->cbCurFile += cbWritten;
583 }
584 /* Update the SHA1/SHA256 context with the next data block. */
585 if ( RT_SUCCESS(rc)
586 && pInt->pShaStorage->fCreateDigest)
587 {
588 if (pInt->pShaStorage->fSha256)
589 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllWritten);
590 else
591 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllWritten);
592 }
593 /* Mark the block as empty. */
594 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
595 cbMemAllRead += cbAllWritten;
596 }
597 /* Reset the thread status and signal the main thread that we
598 * are finished. Use CmpXchg, so we not overwrite other states
599 * which could be signaled in the meantime. */
600 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITING))
601 rc = RTSemEventSignal(pInt->workFinishedEvent);
602 break;
603 }
604 case STATUS_READ:
605 {
606 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
607 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
608 size_t cbMemAllWrite = 0;
609 /* First loop over all the available memory in the circular
610 * memory buffer (could be turn around at the end). */
611 for (;;)
612 {
613 if ( cbMemAllWrite == cbAvail
614 || fLoop == false)
615 break;
616 char *pcBuf;
617 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
618 size_t cbMemWrite = 0;
619 /* Try to acquire all the free space of the circular buffer. */
620 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
621 /* Second, read as long as we filled all the memory. The
622 * read method could also split the reads up into to
623 * smaller parts. */
624 size_t cbAllRead = 0;
625 for (;;)
626 {
627 if (cbAllRead == cbMemWrite)
628 break;
629 size_t cbToRead = cbMemWrite - cbAllRead;
630 size_t cbRead = 0;
631 rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
632// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
633 if (RT_FAILURE(rc))
634 {
635 fLoop = false;
636 break;
637 }
638 /* This indicates end of file. Stop reading. */
639 if (cbRead == 0)
640 {
641 fLoop = false;
642 ASMAtomicWriteBool(&pInt->fEOF, true);
643 break;
644 }
645 cbAllRead += cbRead;
646 pInt->cbCurFile += cbRead;
647 }
648 /* Update the SHA1/SHA256 context with the next data block. */
649 if ( RT_SUCCESS(rc)
650 && pInt->pShaStorage->fCreateDigest)
651 {
652 if (pInt->pShaStorage->fSha256)
653 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
654 else
655 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllRead);
656 }
657 /* Mark the block as full. */
658 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
659 cbMemAllWrite += cbAllRead;
660 }
661 /* Reset the thread status and signal the main thread that we
662 * are finished. Use CmpXchg, so we not overwrite other states
663 * which could be signaled in the meantime. */
664 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
665 rc = RTSemEventSignal(pInt->workFinishedEvent);
666 break;
667 }
668 case STATUS_END:
669 {
670 /* End signaled */
671 fLoop = false;
672 break;
673 }
674 }
675 }
676 /* Cleanup any status changes to indicate we are finished. */
677 ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
678 rc = RTSemEventSignal(pInt->workFinishedEvent);
679 return rc;
680}
681
682DECLINLINE(int) shaSignalManifestThread(PSHASTORAGEINTERNAL pInt, uint32_t uStatus)
683{
684 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
685 return RTSemEventSignal(pInt->newStatusEvent);
686}
687
688DECLINLINE(int) shaWaitForManifestThreadFinished(PSHASTORAGEINTERNAL pInt)
689{
690// RTPrintf("start\n");
691 int rc = VINF_SUCCESS;
692 for (;;)
693 {
694// RTPrintf(" wait\n");
695 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
696 if (!( u32Status == STATUS_WRITE
697 || u32Status == STATUS_WRITING
698 || u32Status == STATUS_READ
699 || u32Status == STATUS_READING))
700 break;
701 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
702 }
703 if (rc == VERR_TIMEOUT)
704 rc = VINF_SUCCESS;
705 return rc;
706}
707
708DECLINLINE(int) shaFlushCurBuf(PSHASTORAGEINTERNAL pInt)
709{
710 int rc = VINF_SUCCESS;
711 if (pInt->fOpenMode & RTFILE_O_WRITE)
712 {
713 /* Let the write worker thread start immediately. */
714 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
715 if (RT_FAILURE(rc))
716 return rc;
717
718 /* Wait until the write worker thread has finished. */
719 rc = shaWaitForManifestThreadFinished(pInt);
720 }
721
722 return rc;
723}
724
725static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
726 PFNVDCOMPLETED pfnCompleted, void **ppInt)
727{
728 /* Validate input. */
729 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
730 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
731 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
732 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
733 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
734
735 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
736 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
737 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
738
739 DEBUG_PRINT_FLOW();
740
741 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL));
742 if (!pInt)
743 return VERR_NO_MEMORY;
744
745 int rc = VINF_SUCCESS;
746 do
747 {
748 pInt->pfnCompleted = pfnCompleted;
749 pInt->pShaStorage = pShaStorage;
750 pInt->fEOF = false;
751 pInt->fOpenMode = fOpen;
752 pInt->u32Status = STATUS_WAIT;
753
754 /* Circular buffer in the read case. */
755 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
756 if (RT_FAILURE(rc))
757 break;
758
759 if (fOpen & RTFILE_O_WRITE)
760 {
761 /* The zero buffer is used for appending empty parts at the end of the
762 * file (or our buffer) in setSize or when uOffset in writeSync is
763 * increased in steps bigger than a byte. */
764 pInt->cbZeroBuf = _1K;
765 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
766 if (!pInt->pvZeroBuf)
767 {
768 rc = VERR_NO_MEMORY;
769 break;
770 }
771 }
772
773 /* Create an event semaphore to indicate a state change for the worker
774 * thread. */
775 rc = RTSemEventCreate(&pInt->newStatusEvent);
776 if (RT_FAILURE(rc))
777 break;
778 /* Create an event semaphore to indicate a finished calculation of the
779 worker thread. */
780 rc = RTSemEventCreate(&pInt->workFinishedEvent);
781 if (RT_FAILURE(rc))
782 break;
783 /* Create the worker thread. */
784 rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA-Worker");
785 if (RT_FAILURE(rc))
786 break;
787
788 if (pShaStorage->fCreateDigest)
789 {
790 /* Create a SHA1/SHA256 context the worker thread will work with. */
791 if (pShaStorage->fSha256)
792 RTSha256Init(&pInt->ctx.Sha256);
793 else
794 RTSha1Init(&pInt->ctx.Sha1);
795 }
796
797 /* Open the file. */
798 rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
799 &pInt->pvStorage);
800 if (RT_FAILURE(rc))
801 break;
802
803 if (fOpen & RTFILE_O_READ)
804 {
805 /* Immediately let the worker thread start the reading. */
806 rc = shaSignalManifestThread(pInt, STATUS_READ);
807 }
808 }
809 while (0);
810
811 if (RT_FAILURE(rc))
812 {
813 if (pInt->pWorkerThread)
814 {
815 shaSignalManifestThread(pInt, STATUS_END);
816 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
817 }
818 if (pInt->workFinishedEvent)
819 RTSemEventDestroy(pInt->workFinishedEvent);
820 if (pInt->newStatusEvent)
821 RTSemEventDestroy(pInt->newStatusEvent);
822 if (pInt->pCircBuf)
823 RTCircBufDestroy(pInt->pCircBuf);
824 if (pInt->pvZeroBuf)
825 RTMemFree(pInt->pvZeroBuf);
826 RTMemFree(pInt);
827 }
828 else
829 *ppInt = pInt;
830
831 return rc;
832}
833
834static int shaCloseCallback(void *pvUser, void *pvStorage)
835{
836 /* Validate input. */
837 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
838 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
839
840 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
841 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
842 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
843
844 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
845
846 DEBUG_PRINT_FLOW();
847
848 int rc = VINF_SUCCESS;
849
850 /* Make sure all pending writes are flushed */
851 rc = shaFlushCurBuf(pInt);
852
853 if (pInt->pWorkerThread)
854 {
855 /* Signal the worker thread to end himself */
856 rc = shaSignalManifestThread(pInt, STATUS_END);
857 /* Worker thread stopped? */
858 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
859 }
860
861 if ( RT_SUCCESS(rc)
862 && pShaStorage->fCreateDigest)
863 {
864 /* Finally calculate & format the SHA1/SHA256 sum */
865 unsigned char auchDig[RTSHA256_HASH_SIZE];
866 char *pszDigest;
867 size_t cbDigest;
868 if (pShaStorage->fSha256)
869 {
870 RTSha256Final(&pInt->ctx.Sha256, auchDig);
871 cbDigest = RTSHA256_DIGEST_LEN;
872 }
873 else
874 {
875 RTSha1Final(&pInt->ctx.Sha1, auchDig);
876 cbDigest = RTSHA1_DIGEST_LEN;
877 }
878 rc = RTStrAllocEx(&pszDigest, cbDigest + 1);
879 if (RT_SUCCESS(rc))
880 {
881 if (pShaStorage->fSha256)
882 rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1);
883 else
884 rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1);
885 if (RT_SUCCESS(rc))
886 pShaStorage->strDigest = pszDigest;
887 RTStrFree(pszDigest);
888 }
889 }
890
891 /* Close the file */
892 rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
893
894// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
895
896 /* Cleanup */
897 if (pInt->workFinishedEvent)
898 RTSemEventDestroy(pInt->workFinishedEvent);
899 if (pInt->newStatusEvent)
900 RTSemEventDestroy(pInt->newStatusEvent);
901 if (pInt->pCircBuf)
902 RTCircBufDestroy(pInt->pCircBuf);
903 if (pInt->pvZeroBuf)
904 RTMemFree(pInt->pvZeroBuf);
905 RTMemFree(pInt);
906
907 return rc;
908}
909
910static int shaDeleteCallback(void *pvUser, const char *pcszFilename)
911{
912 /* Validate input. */
913 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
914
915 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
916 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
917 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
918
919 DEBUG_PRINT_FLOW();
920
921 return vdIfIoFileDelete(pIfIo, pcszFilename);
922}
923
924static int shaMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
925{
926 /* Validate input. */
927 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
928
929 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
930 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
931 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
932
933
934 DEBUG_PRINT_FLOW();
935
936 return vdIfIoFileMove(pIfIo, pcszSrc, pcszDst, fMove);
937}
938
939static int shaGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
940{
941 /* Validate input. */
942 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
943
944 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
945 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
946 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
947
948 DEBUG_PRINT_FLOW();
949
950 return vdIfIoFileGetFreeSpace(pIfIo, pcszFilename, pcbFreeSpace);
951}
952
953static int shaGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
954{
955 /* Validate input. */
956 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
957
958 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
959 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
960 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
961
962 DEBUG_PRINT_FLOW();
963
964 return vdIfIoFileGetModificationTime(pIfIo, pcszFilename, pModificationTime);
965}
966
967
968static int shaGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
969{
970 /* Validate input. */
971 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
972 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
973
974 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
975 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
976 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
977
978 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
979
980 DEBUG_PRINT_FLOW();
981
982 uint64_t cbSize;
983 int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
984 if (RT_FAILURE(rc))
985 return rc;
986
987 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
988
989 return VINF_SUCCESS;
990}
991
992static int shaSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
993{
994 /* Validate input. */
995 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
996 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
997
998 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
999 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1000 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1001
1002 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1003
1004 DEBUG_PRINT_FLOW();
1005
1006 return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
1007}
1008
1009static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1010 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
1011{
1012 /* Validate input. */
1013 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1014 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1015
1016 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1017 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1018 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1019
1020 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1021
1022 DEBUG_PRINT_FLOW();
1023
1024 /* Check that the write is linear */
1025 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
1026
1027 int rc = VINF_SUCCESS;
1028
1029 /* Check if we have to add some free space at the end, before we start the
1030 * real write. */
1031 if (pInt->cbCurAll < uOffset)
1032 {
1033 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
1034 size_t cbAllWritten = 0;
1035 for (;;)
1036 {
1037 /* Finished? */
1038 if (cbAllWritten == cbSize)
1039 break;
1040 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
1041 size_t cbWritten = 0;
1042 rc = shaWriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
1043 pInt->pvZeroBuf, cbToWrite, &cbWritten);
1044 if (RT_FAILURE(rc))
1045 break;
1046 cbAllWritten += cbWritten;
1047 }
1048 if (RT_FAILURE(rc))
1049 return rc;
1050 }
1051// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
1052
1053 size_t cbAllWritten = 0;
1054 for (;;)
1055 {
1056 /* Finished? */
1057 if (cbAllWritten == cbWrite)
1058 break;
1059 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1060 if ( cbAvail == 0
1061 && pInt->fEOF)
1062 return VERR_EOF;
1063 /* If there isn't enough free space make sure the worker thread is
1064 * writing some data. */
1065 if ((cbWrite - cbAllWritten) > cbAvail)
1066 {
1067 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1068 if (RT_FAILURE(rc))
1069 break;
1070 /* If there is _no_ free space available, we have to wait until it is. */
1071 if (cbAvail == 0)
1072 {
1073 rc = shaWaitForManifestThreadFinished(pInt);
1074 if (RT_FAILURE(rc))
1075 break;
1076 cbAvail = RTCircBufFree(pInt->pCircBuf);
1077// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1078// pInt->waits++;
1079 }
1080 }
1081 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1082 char *pcBuf;
1083 size_t cbMemWritten = 0;
1084 /* Acquire a block for writing from our circular buffer. */
1085 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1086 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1087 /* Mark the block full. */
1088 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1089 cbAllWritten += cbMemWritten;
1090 pInt->cbCurAll += cbMemWritten;
1091 }
1092
1093 if (pcbWritten)
1094 *pcbWritten = cbAllWritten;
1095
1096 /* Signal the thread to write more data in the mean time. */
1097 if ( RT_SUCCESS(rc)
1098 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1099 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1100
1101 return rc;
1102}
1103
1104static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1105 void *pvBuf, size_t cbRead, size_t *pcbRead)
1106{
1107 /* Validate input. */
1108 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1109 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1110
1111 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1112 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1113 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1114
1115// DEBUG_PRINT_FLOW();
1116
1117 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1118
1119 int rc = VINF_SUCCESS;
1120
1121// pInt->calls++;
1122// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1123
1124 /* Check if we jump forward in the file. If so we have to read the
1125 * remaining stuff in the gap anyway (SHA1/SHA256; streaming). */
1126 if (pInt->cbCurAll < uOffset)
1127 {
1128 rc = shaReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1129 (size_t)(uOffset - pInt->cbCurAll), 0);
1130 if (RT_FAILURE(rc))
1131 return rc;
1132// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1133 }
1134 else if (uOffset < pInt->cbCurAll)
1135 AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
1136
1137 size_t cbAllRead = 0;
1138 for (;;)
1139 {
1140 /* Finished? */
1141 if (cbAllRead == cbRead)
1142 break;
1143 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1144 if ( cbAvail == 0
1145 && pInt->fEOF
1146 && !RTCircBufIsWriting(pInt->pCircBuf))
1147 {
1148 break;
1149 }
1150 /* If there isn't enough data make sure the worker thread is fetching
1151 * more. */
1152 if ((cbRead - cbAllRead) > cbAvail)
1153 {
1154 rc = shaSignalManifestThread(pInt, STATUS_READ);
1155 if (RT_FAILURE(rc))
1156 break;
1157 /* If there is _no_ data available, we have to wait until it is. */
1158 if (cbAvail == 0)
1159 {
1160 rc = shaWaitForManifestThreadFinished(pInt);
1161 if (RT_FAILURE(rc))
1162 break;
1163 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1164// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1165// pInt->waits++;
1166 }
1167 }
1168 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1169 char *pcBuf;
1170 size_t cbMemRead = 0;
1171 /* Acquire a block for reading from our circular buffer. */
1172 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1173 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1174 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1175 /* Mark the block as empty again. */
1176 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1177 cbAllRead += cbMemRead;
1178
1179 pInt->cbCurAll += cbMemRead;
1180 }
1181
1182 if (pcbRead)
1183 *pcbRead = cbAllRead;
1184
1185 if (rc == VERR_EOF)
1186 rc = VINF_SUCCESS;
1187
1188 /* Signal the thread to read more data in the mean time. */
1189 if ( RT_SUCCESS(rc)
1190 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1191 rc = shaSignalManifestThread(pInt, STATUS_READ);
1192
1193 return rc;
1194}
1195
1196static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1197{
1198 /* Validate input. */
1199 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1200 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1201
1202 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1203 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1204 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1205
1206 DEBUG_PRINT_FLOW();
1207
1208 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1209
1210 /* Check if there is still something in the buffer. If yes, flush it. */
1211 int rc = shaFlushCurBuf(pInt);
1212 if (RT_FAILURE(rc))
1213 return rc;
1214
1215 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1216}
1217
1218/******************************************************************************
1219 * Internal: RTGZIP interface
1220 ******************************************************************************/
1221
1222//DECLCALLBACK(int) gzipCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
1223//{
1224// /* Validate input. */
1225// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1226//
1227// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)pvUser;
1228//
1229// PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
1230// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1231//
1232// int rc = VINF_SUCCESS;
1233// bool fLoop = true;
1234// while (fLoop)
1235// {
1236// /* What should we do next? */
1237// uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
1238//// RTPrintf("status: %d\n", u32Status);
1239// switch (u32Status)
1240// {
1241// case STATUS_WAIT:
1242// {
1243// /* Wait for new work. */
1244// rc = RTSemEventWait(pInt->newStatusEvent, 100);
1245// if ( RT_FAILURE(rc)
1246// && rc != VERR_TIMEOUT)
1247// fLoop = false;
1248// break;
1249// }
1250// case STATUS_READ:
1251// {
1252// ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
1253// size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1254// size_t cbMemAllWrite = 0;
1255// /* First loop over all the available memory in the circular
1256// * memory buffer (could be turn around at the end). */
1257// for (;;)
1258// {
1259// if ( cbMemAllWrite == cbAvail
1260// || fLoop == false)
1261// break;
1262// char *pcBuf;
1263// size_t cbMemToWrite = cbAvail - cbMemAllWrite;
1264// size_t cbMemWrite = 0;
1265// /* Try to acquire all the free space of the circular buffer. */
1266// RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
1267// /* Second, read as long as we filled all the memory. The
1268// * read method could also split the reads up into to
1269// * smaller parts. */
1270// size_t cbAllRead = 0;
1271// for (;;)
1272// {
1273// if (cbAllRead == cbMemWrite)
1274// break;
1275// size_t cbToRead = cbMemWrite - cbAllRead;
1276// size_t cbRead = 0;
1277// rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
1278// if (RT_FAILURE(rc))
1279// {
1280// fLoop = false;
1281// break;
1282// }
1283// /* This indicates end of file. Stop reading. */
1284// if (cbRead == 0)
1285// {
1286// fLoop = false;
1287// ASMAtomicWriteBool(&pInt->fEOF, true);
1288// break;
1289// }
1290// cbAllRead += cbRead;
1291// pInt->cbCurFile += cbRead;
1292// }
1293// /* Update the GZIP context with the next data block. */
1294// if (RT_SUCCESS(rc))
1295// {
1296// RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
1297// }
1298// /* Mark the block as full. */
1299// RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
1300// cbMemAllWrite += cbAllRead;
1301// }
1302// /* Reset the thread status and signal the main thread that we
1303// * are finished. Use CmpXchg, so we not overwrite other states
1304// * which could be signaled in the meantime. */
1305// if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
1306// rc = RTSemEventSignal(pInt->workFinishedEvent);
1307// break;
1308// }
1309// case STATUS_END:
1310// {
1311// /* End signaled */
1312// fLoop = false;
1313// break;
1314// }
1315// }
1316// }
1317// /* Cleanup any status changes to indicate we are finished. */
1318// ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
1319// rc = RTSemEventSignal(pInt->workFinishedEvent);
1320// return rc;
1321//}
1322//
1323//DECLINLINE(int) gzipSignalManifestThread(PGZIPSTORAGEINTERNAL pInt, uint32_t uStatus)
1324//{
1325// ASMAtomicWriteU32(&pInt->u32Status, uStatus);
1326// return RTSemEventSignal(pInt->newStatusEvent);
1327//}
1328//
1329//DECLINLINE(int) gzipWaitForManifestThreadFinished(PGZIPSTORAGEINTERNAL pInt)
1330//{
1331//// RTPrintf("start\n");
1332// int rc = VINF_SUCCESS;
1333// for (;;)
1334// {
1335//// RTPrintf(" wait\n");
1336// uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
1337// if (!( u32Status == STATUS_WRITE
1338// || u32Status == STATUS_WRITING
1339// || u32Status == STATUS_READ
1340// || u32Status == STATUS_READING))
1341// break;
1342// rc = RTSemEventWait(pInt->workFinishedEvent, 100);
1343// }
1344// if (rc == VERR_TIMEOUT)
1345// rc = VINF_SUCCESS;
1346// return rc;
1347//}
1348//
1349//DECLINLINE(int) gzipFlushCurBuf(PGZIPSTORAGEINTERNAL pInt)
1350//{
1351// int rc = VINF_SUCCESS;
1352// if (pInt->fOpenMode & RTFILE_O_WRITE)
1353// {
1354// /* Let the write worker thread start immediately. */
1355// rc = gzipSignalManifestThread(pInt, STATUS_WRITE);
1356// if (RT_FAILURE(rc))
1357// return rc;
1358//
1359// /* Wait until the write worker thread has finished. */
1360// rc = gzipWaitForManifestThreadFinished(pInt);
1361// }
1362//
1363// return rc;
1364//}
1365//
1366//static int gzipOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
1367// PFNVDCOMPLETED pfnCompleted, void **ppInt)
1368//{
1369// /* Validate input. */
1370// AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
1371// AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
1372// AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
1373// AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
1374// AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
1375//
1376// DEBUG_PRINT_FLOW();
1377//
1378// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)RTMemAllocZ(sizeof(GZIPSTORAGEINTERNAL));
1379// if (!pInt)
1380// return VERR_NO_MEMORY;
1381//
1382// int rc = VINF_SUCCESS;
1383// do
1384// {
1385// pInt->pfnCompleted = pfnCompleted;
1386// pInt->fEOF = false;
1387// pInt->fOpenMode = fOpen;
1388// pInt->u32Status = STATUS_WAIT;
1389//
1390// /* Circular buffer in the read case. */
1391// rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
1392// if (RT_FAILURE(rc))
1393// break;
1394//
1395// /* Create an event semaphore to indicate a state change for the worker
1396// * thread. */
1397// rc = RTSemEventCreate(&pInt->newStatusEvent);
1398// if (RT_FAILURE(rc))
1399// break;
1400// /* Create an event semaphore to indicate a finished calculation of the
1401// worker thread. */
1402// rc = RTSemEventCreate(&pInt->workFinishedEvent);
1403// if (RT_FAILURE(rc))
1404// break;
1405// /* Create the worker thread. */
1406// rc = RTThreadCreate(&pInt->pWorkerThread, gziCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER,
1407// RTTHREADFLAGS_WAITABLE, "GZIP-Worker");
1408// if (RT_FAILURE(rc))
1409// break;
1410//
1411// /* Open the file. */
1412// rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
1413// &pInt->pvStorage);
1414// if (RT_FAILURE(rc))
1415// break;
1416//
1417// if (fOpen & RTFILE_O_READ)
1418// {
1419// /* Immediately let the worker thread start the reading. */
1420// rc = gzipSignalManifestThread(pInt, STATUS_READ);
1421// }
1422// }
1423// while (0);
1424//
1425// if (RT_FAILURE(rc))
1426// {
1427// if (pInt->pWorkerThread)
1428// {
1429// gzipSignalManifestThread(pInt, STATUS_END);
1430// RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
1431// }
1432// if (pInt->workFinishedEvent)
1433// RTSemEventDestroy(pInt->workFinishedEvent);
1434// if (pInt->newStatusEvent)
1435// RTSemEventDestroy(pInt->newStatusEvent);
1436// if (pInt->pCircBuf)
1437// RTCircBufDestroy(pInt->pCircBuf);
1438// if (pInt->pvZeroBuf)
1439// RTMemFree(pInt->pvZeroBuf);
1440// RTMemFree(pInt);
1441// }
1442// else
1443// *ppInt = pInt;
1444//
1445// return rc;
1446//}
1447//
1448//static int gzipCloseCallback(void *pvUser, void *pvStorage)
1449//{
1450// /* Validate input. */
1451// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1452// AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1453//
1454// PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1455// PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1456// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1457//
1458// PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1459//
1460// DEBUG_PRINT_FLOW();
1461//
1462// int rc = VINF_SUCCESS;
1463//
1464// /* Make sure all pending writes are flushed */
1465// rc = gzipFlushCurBuf(pInt);
1466//
1467// if (pInt->pWorkerThread)
1468// {
1469// /* Signal the worker thread to end himself */
1470// rc = gzipSignalManifestThread(pInt, STATUS_END);
1471// /* Worker thread stopped? */
1472// rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
1473// }
1474//
1475// /* Close the file */
1476// rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
1477//
1478// /* Cleanup */
1479// if (pInt->workFinishedEvent)
1480// RTSemEventDestroy(pInt->workFinishedEvent);
1481// if (pInt->newStatusEvent)
1482// RTSemEventDestroy(pInt->newStatusEvent);
1483// if (pInt->pCircBuf)
1484// RTCircBufDestroy(pInt->pCircBuf);
1485// if (pInt->pvZeroBuf)
1486// RTMemFree(pInt->pvZeroBuf);
1487// RTMemFree(pInt);
1488//
1489// return rc;
1490//}
1491//
1492//static int gzipDeleteCallback(void *pvUser, const char *pcszFilename)
1493//{
1494// /* Validate input. */
1495// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1496//
1497// DEBUG_PRINT_FLOW();
1498//
1499// return VERR_NOT_IMPLEMENTED;
1500//}
1501//
1502//static int gzipMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
1503//{
1504// /* Validate input. */
1505// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1506//
1507// DEBUG_PRINT_FLOW();
1508//
1509// return VERR_NOT_IMPLEMENTED;
1510//}
1511//
1512//static int gzipGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
1513//{
1514// /* Validate input. */
1515// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1516//
1517// DEBUG_PRINT_FLOW();
1518//
1519// return VERR_NOT_IMPLEMENTED;
1520//}
1521//
1522//static int gzipGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
1523//{
1524// /* Validate input. */
1525// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1526//
1527// DEBUG_PRINT_FLOW();
1528//
1529// return VERR_NOT_IMPLEMENTED;
1530//}
1531//
1532//
1533//static int gzipGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
1534//{
1535// /* Validate input. */
1536// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1537// AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1538//
1539// PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1540// PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1541// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1542//
1543// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)pvStorage;
1544//
1545// DEBUG_PRINT_FLOW();
1546//
1547// uint64_t cbSize;
1548// int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
1549// if (RT_FAILURE(rc))
1550// return rc;
1551//
1552// *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
1553//
1554// return VINF_SUCCESS;
1555//}
1556//
1557//static int gzipSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
1558//{
1559// /* Validate input. */
1560// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1561// AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1562//
1563// PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1564// PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1565// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1566//
1567// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)pvStorage;
1568//
1569// DEBUG_PRINT_FLOW();
1570//
1571// return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
1572//}
1573//
1574//static int gzipWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1575// const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
1576//{
1577// /* Validate input. */
1578// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1579// AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1580//
1581// PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1582// PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1583// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1584//
1585// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)pvStorage;
1586//
1587// DEBUG_PRINT_FLOW();
1588//
1589// int rc = VINF_SUCCESS;
1590//
1591// return VERR_NOT_IMPLEMENTED;
1592//}
1593//
1594//static int gzipReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1595// void *pvBuf, size_t cbRead, size_t *pcbRead)
1596//{
1597// /* Validate input. */
1598// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1599// AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1600//
1601// PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1602// PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1603// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1604//
1605// DEBUG_PRINT_FLOW();
1606//
1607// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)pvStorage;
1608//
1609// int rc = VINF_SUCCESS;
1610//
1611// return rc;
1612//}
1613//
1614//static int gzipFlushSyncCallback(void *pvUser, void *pvStorage)
1615//{
1616// /* Validate input. */
1617// AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1618// AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1619//
1620// PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1621// PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1622// AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1623//
1624// DEBUG_PRINT_FLOW();
1625//
1626// PGZIPSTORAGEINTERNAL pInt = (PGZIPSTORAGEINTERNAL)pvStorage;
1627//
1628// /* Check if there is still something in the buffer. If yes, flush it. */
1629// int rc = gzipFlushCurBuf(pInt);
1630// if (RT_FAILURE(rc))
1631// return rc;
1632//
1633// return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1634//}
1635
1636/******************************************************************************
1637 * Public Functions *
1638 ******************************************************************************/
1639//PVDINTERFACEIO GzipCreateInterface()
1640//{
1641// PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1642// if (!pCallbacks)
1643// return NULL;
1644//
1645// pCallbacks->pfnOpen = gzipOpenCallback;
1646// pCallbacks->pfnClose = gzipCloseCallback;
1647// pCallbacks->pfnDelete = gzipDeleteCallback;
1648// pCallbacks->pfnMove = gzipMoveCallback;
1649// pCallbacks->pfnGetFreeSpace = gzipGetFreeSpaceCallback;
1650// pCallbacks->pfnGetModificationTime = gzipGetModificationTimeCallback;
1651// pCallbacks->pfnGetSize = gzipGetSizeCallback;
1652// pCallbacks->pfnSetSize = gzipSetSizeCallback;
1653// pCallbacks->pfnReadSync = gzipReadSyncCallback;
1654// pCallbacks->pfnWriteSync = gzipWriteSyncCallback;
1655// pCallbacks->pfnFlushSync = gzipFlushSyncCallback;
1656//
1657// return pCallbacks;
1658//}
1659
1660PVDINTERFACEIO ShaCreateInterface()
1661{
1662 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1663 if (!pCallbacks)
1664 return NULL;
1665
1666 pCallbacks->pfnOpen = shaOpenCallback;
1667 pCallbacks->pfnClose = shaCloseCallback;
1668 pCallbacks->pfnDelete = shaDeleteCallback;
1669 pCallbacks->pfnMove = shaMoveCallback;
1670 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1671 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1672 pCallbacks->pfnGetSize = shaGetSizeCallback;
1673 pCallbacks->pfnSetSize = shaSetSizeCallback;
1674 pCallbacks->pfnReadSync = shaReadSyncCallback;
1675 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1676 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1677
1678 return pCallbacks;
1679}
1680
1681PVDINTERFACEIO FileCreateInterface()
1682{
1683 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1684 if (!pCallbacks)
1685 return NULL;
1686
1687 pCallbacks->pfnOpen = fileOpenCallback;
1688 pCallbacks->pfnClose = fileCloseCallback;
1689 pCallbacks->pfnDelete = fileDeleteCallback;
1690 pCallbacks->pfnMove = fileMoveCallback;
1691 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1692 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1693 pCallbacks->pfnGetSize = fileGetSizeCallback;
1694 pCallbacks->pfnSetSize = fileSetSizeCallback;
1695 pCallbacks->pfnReadSync = fileReadSyncCallback;
1696 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1697 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1698
1699 return pCallbacks;
1700}
1701
1702PVDINTERFACEIO TarCreateInterface()
1703{
1704 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1705 if (!pCallbacks)
1706 return NULL;
1707
1708 pCallbacks->pfnOpen = tarOpenCallback;
1709 pCallbacks->pfnClose = tarCloseCallback;
1710 pCallbacks->pfnDelete = tarDeleteCallback;
1711 pCallbacks->pfnMove = tarMoveCallback;
1712 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1713 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1714 pCallbacks->pfnGetSize = tarGetSizeCallback;
1715 pCallbacks->pfnSetSize = tarSetSizeCallback;
1716 pCallbacks->pfnReadSync = tarReadSyncCallback;
1717 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1718 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1719
1720 return pCallbacks;
1721}
1722
1723int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1724{
1725 /* Validate input. */
1726 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1727 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1728 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1729
1730 void *pvStorage;
1731 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1732 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1733 &pvStorage);
1734 if (RT_FAILURE(rc))
1735 return rc;
1736
1737 void *pvTmpBuf = 0;
1738 void *pvBuf = 0;
1739 uint64_t cbTmpSize = _1M;
1740 size_t cbAllRead = 0;
1741 do
1742 {
1743 pvTmpBuf = RTMemAlloc(cbTmpSize);
1744 if (!pvTmpBuf)
1745 {
1746 rc = VERR_NO_MEMORY;
1747 break;
1748 }
1749
1750 for (;;)
1751 {
1752 size_t cbRead = 0;
1753 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1754 if ( RT_FAILURE(rc)
1755 || cbRead == 0)
1756 break;
1757 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1758 if (!pvBuf)
1759 {
1760 rc = VERR_NO_MEMORY;
1761 break;
1762 }
1763 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1764 cbAllRead += cbRead;
1765 }
1766 } while (0);
1767
1768 pIfIo->pfnClose(pvUser, pvStorage);
1769
1770 if (rc == VERR_EOF)
1771 rc = VINF_SUCCESS;
1772
1773 if (pvTmpBuf)
1774 RTMemFree(pvTmpBuf);
1775
1776 if (RT_SUCCESS(rc))
1777 {
1778 *ppvBuf = pvBuf;
1779 *pcbSize = cbAllRead;
1780 }
1781 else
1782 {
1783 if (pvBuf)
1784 RTMemFree(pvBuf);
1785 }
1786
1787 return rc;
1788}
1789
1790int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1791{
1792 /* Validate input. */
1793 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1794 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1795 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1796
1797 void *pvStorage;
1798 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1799 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1800 &pvStorage);
1801 if (RT_FAILURE(rc))
1802 return rc;
1803
1804 size_t cbAllWritten = 0;
1805 for (;;)
1806 {
1807 if (cbAllWritten >= cbSize)
1808 break;
1809 size_t cbToWrite = cbSize - cbAllWritten;
1810 size_t cbWritten = 0;
1811 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1812 if (RT_FAILURE(rc))
1813 break;
1814 cbAllWritten += cbWritten;
1815 }
1816
1817 rc = pIfIo->pfnClose(pvUser, pvStorage);
1818
1819 return rc;
1820}
1821
1822int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
1823{
1824 /* Validate input. */
1825 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1826
1827 void *pvStorage;
1828 int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
1829 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1830 &pvStorage);
1831 if (RT_FAILURE(rc))
1832 return rc;
1833
1834 Bytef *decompressedBuffer = 0;
1835 Bytef *compressedBuffer = 0;
1836 uint64_t cbTmpSize = _1M;
1837 size_t cbAllRead = 0;
1838 size_t cbAllWritten = 0;
1839 RTFILE pFile = NULL;
1840 z_stream gzipStream;
1841
1842 Utf8Str pathOut(pcszFullFilenameOut);
1843 pathOut = pathOut.stripFilename();
1844
1845 Utf8Str fileIn(pcszFullFilenameIn);
1846 fileIn = fileIn.stripPath();
1847
1848 do
1849 {
1850 if (RTFileExists(pcszFullFilenameOut) == false)
1851 {
1852 /* ensure the directory exists */
1853 rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true);
1854 if (FAILED(rc))
1855 {
1856 rc = VBOX_E_FILE_ERROR;
1857 break;
1858 }
1859
1860 rc = RTFileOpen(&pFile, pcszFullFilenameOut, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1861 }
1862 else
1863 {
1864 rc = RTFileOpen(&pFile, pcszFullFilenameOut, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1865 }
1866
1867 if (FAILED(rc) || pFile == NULL)
1868 {
1869 rc = VBOX_E_FILE_ERROR;
1870 break;
1871 }
1872
1873 compressedBuffer = (Bytef *)RTMemAlloc(cbTmpSize);
1874
1875 if (!compressedBuffer)
1876 {
1877 rc = VERR_NO_MEMORY;
1878 break;
1879 }
1880
1881
1882 decompressedBuffer = (Bytef *)RTMemAlloc(cbTmpSize*10);
1883
1884 if (!decompressedBuffer)
1885 {
1886 rc = VERR_NO_MEMORY;
1887 break;
1888 }
1889
1890 gzipStream.zalloc = Z_NULL;
1891 gzipStream.zfree = Z_NULL;
1892 gzipStream.opaque = Z_NULL;
1893 gzipStream.next_in = compressedBuffer;
1894 gzipStream.avail_in = 0;
1895 gzipStream.next_out = decompressedBuffer;
1896 gzipStream.avail_out = cbTmpSize*10;
1897
1898 rc = inflateInit2(&gzipStream, MAX_WBITS + 16 /* autodetect gzip header */);
1899
1900 if (rc < 0)
1901 {
1902 break;
1903 }
1904
1905 size_t cbRead = 0;
1906 size_t cbDecompressed = 0;
1907 bool fFinished = true;
1908
1909 for (;;)
1910 {
1911 if (fFinished == true)
1912 {
1913 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, compressedBuffer, cbTmpSize, &cbRead);
1914 if ( RT_FAILURE(rc)
1915 || cbRead == 0)
1916 break;
1917
1918 gzipStream.avail_in = cbRead;
1919 gzipStream.avail_out = cbTmpSize*10;
1920 }
1921
1922 /* decompress the buffer */
1923 rc = RTZipGzipDecompressBuffer(gzipStream,
1924 (uint32_t *)(&cbDecompressed),
1925 &fFinished);
1926
1927 if (RT_FAILURE(rc))
1928 break;
1929
1930 rc = RTFileWrite(pFile, decompressedBuffer, cbDecompressed, &cbDecompressed);
1931
1932 if (RT_FAILURE(rc))
1933 break;
1934
1935 cbAllWritten += cbDecompressed;
1936 cbAllRead += cbRead;
1937 }
1938 } while (0);
1939
1940 pIfIo->pfnClose(pvUser, pvStorage);
1941
1942 if (rc == VERR_EOF)
1943 rc = VINF_SUCCESS;
1944
1945 rc = inflateEnd(&gzipStream);
1946
1947 rc = RTFileClose(pFile);
1948
1949 if (decompressedBuffer)
1950 RTMemFree(decompressedBuffer);
1951 if (compressedBuffer)
1952 RTMemFree(compressedBuffer);
1953
1954 return rc;
1955}
1956
1957
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette