VirtualBox

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

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

pr6022. cleaning up the code. RTZip interface (Runtime/common/zip/zip.cpp) is untouched. All moved to ApplianceImplIO.cpp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.8 KB
Line 
1/* $Id: ApplianceImplIO.cpp 47343 2013-07-23 14:50:00Z 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
97/******************************************************************************
98 * Defined Constants And Macros *
99 ******************************************************************************/
100
101#define STATUS_WAIT UINT32_C(0)
102#define STATUS_WRITE UINT32_C(1)
103#define STATUS_WRITING UINT32_C(2)
104#define STATUS_READ UINT32_C(3)
105#define STATUS_READING UINT32_C(4)
106#define STATUS_END UINT32_C(5)
107
108/* Enable for getting some flow history. */
109#if 0
110# define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
111#else
112# define DEBUG_PRINT_FLOW() do {} while (0)
113#endif
114
115/******************************************************************************
116 * Internal Functions *
117 ******************************************************************************/
118
119
120/******************************************************************************
121 * Internal: RTFile interface
122 ******************************************************************************/
123
124static int fileOpenCallback(void * /* pvUser */, const char *pszLocation, uint32_t fOpen,
125 PFNVDCOMPLETED pfnCompleted, void **ppInt)
126{
127 /* Validate input. */
128 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
129 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
130
131 DEBUG_PRINT_FLOW();
132
133 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL));
134 if (!pInt)
135 return VERR_NO_MEMORY;
136
137 pInt->pfnCompleted = pfnCompleted;
138
139 int rc = RTFileOpen(&pInt->file, pszLocation, fOpen);
140
141 if (RT_FAILURE(rc))
142 RTMemFree(pInt);
143 else
144 *ppInt = pInt;
145
146 return rc;
147}
148
149static int fileCloseCallback(void * /* pvUser */, void *pvStorage)
150{
151 /* Validate input. */
152 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
153
154 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
155
156 DEBUG_PRINT_FLOW();
157
158 int rc = RTFileClose(pInt->file);
159
160 /* Cleanup */
161 RTMemFree(pInt);
162
163 return rc;
164}
165
166static int fileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
167{
168 DEBUG_PRINT_FLOW();
169
170 return RTFileDelete(pcszFilename);
171}
172
173static int fileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
174{
175 DEBUG_PRINT_FLOW();
176
177 return RTFileMove(pcszSrc, pcszDst, fMove);
178}
179
180static int fileGetFreeSpaceCallback(void * /* pvUser */, const char *pcszFilename, int64_t *pcbFreeSpace)
181{
182 /* Validate input. */
183 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
184 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
185
186 DEBUG_PRINT_FLOW();
187
188 return VERR_NOT_IMPLEMENTED;
189}
190
191static int fileGetModificationTimeCallback(void * /* pvUser */, const char *pcszFilename, PRTTIMESPEC pModificationTime)
192{
193 /* Validate input. */
194 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
195 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
196
197 DEBUG_PRINT_FLOW();
198
199 return VERR_NOT_IMPLEMENTED;
200}
201
202static int fileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
203{
204 /* Validate input. */
205 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
206
207 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
208
209 DEBUG_PRINT_FLOW();
210
211 return RTFileGetSize(pInt->file, pcbSize);
212}
213
214static int fileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
215{
216 /* Validate input. */
217 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
218
219 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
220
221 DEBUG_PRINT_FLOW();
222
223 return RTFileSetSize(pInt->file, cbSize);
224}
225
226static int fileWriteSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
227 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
228{
229 /* Validate input. */
230 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
231
232 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
233
234 return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
235}
236
237static int fileReadSyncCallback(void * /* pvUser */, void *pvStorage, uint64_t uOffset,
238 void *pvBuf, size_t cbRead, size_t *pcbRead)
239{
240 /* Validate input. */
241 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
242
243// DEBUG_PRINT_FLOW();
244
245 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
246
247 return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
248}
249
250static int fileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
251{
252 /* Validate input. */
253 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
254
255 DEBUG_PRINT_FLOW();
256
257 PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
258
259 return RTFileFlush(pInt->file);
260}
261
262/******************************************************************************
263 * Internal: RTTar interface
264 ******************************************************************************/
265
266static int tarOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
267 PFNVDCOMPLETED pfnCompleted, void **ppInt)
268{
269 /* Validate input. */
270 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
271 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
272 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
273// AssertReturn(!(fOpen & RTFILE_O_READWRITE), VERR_INVALID_PARAMETER);
274
275 RTTAR tar = (RTTAR)pvUser;
276
277 DEBUG_PRINT_FLOW();
278
279 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(TARSTORAGEINTERNAL));
280 if (!pInt)
281 return VERR_NO_MEMORY;
282
283 pInt->pfnCompleted = pfnCompleted;
284
285 int rc = VINF_SUCCESS;
286
287 if (fOpen & RTFILE_O_READ
288 && !(fOpen & RTFILE_O_WRITE))
289 {
290 /* Read only is a little bit more complicated than writing, cause we
291 * need streaming functionality. First try to open the file on the
292 * current file position. If this is the file the caller requested, we
293 * are fine. If not seek to the next file in the stream and check
294 * again. This is repeated until EOF of the OVA. */
295 /*
296 *
297 *
298 * TODO: recheck this with more VDMKs (or what else) in an test OVA.
299 *
300 *
301 */
302 bool fFound = false;
303
304 for (;;)
305 {
306 char *pszFilename = 0;
307 rc = RTTarCurrentFile(tar, &pszFilename);
308 if (RT_SUCCESS(rc))
309 {
310 if (rc == VINF_TAR_DIR_PATH)
311 {
312 break;
313 }
314
315 fFound = !RTStrICmp(pszFilename, pszLocation);
316
317 RTStrFree(pszFilename);
318 if (fFound)
319 break;
320 else
321 {
322 rc = RTTarSeekNextFile(tar);
323 if (RT_FAILURE(rc))
324 {
325 break;
326 }
327 }
328 }
329 else
330 break;
331 }
332 if (fFound)
333 rc = RTTarFileOpenCurrentFile(tar, &pInt->file, 0, fOpen);
334 }
335 else
336 rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
337
338 if (RT_FAILURE(rc))
339 RTMemFree(pInt);
340 else
341 *ppInt = pInt;
342
343 return rc;
344}
345
346static int tarCloseCallback(void *pvUser, void *pvStorage)
347{
348 /* Validate input. */
349 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
350 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
351
352 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
353
354 DEBUG_PRINT_FLOW();
355
356 int rc = RTTarFileClose(pInt->file);
357
358 /* Cleanup */
359 RTMemFree(pInt);
360
361 return rc;
362}
363
364static int tarDeleteCallback(void *pvUser, const char *pcszFilename)
365{
366 /* Validate input. */
367 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
368 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
369
370 DEBUG_PRINT_FLOW();
371
372 return VERR_NOT_IMPLEMENTED;
373}
374
375static int tarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
376{
377 /* Validate input. */
378 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
379 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
380 AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
381
382 DEBUG_PRINT_FLOW();
383
384 return VERR_NOT_IMPLEMENTED;
385}
386
387static int tarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
388{
389 /* Validate input. */
390 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
391 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
392 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
393
394 DEBUG_PRINT_FLOW();
395
396 return VERR_NOT_IMPLEMENTED;
397}
398
399static int tarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
400{
401 /* Validate input. */
402 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
403 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
404 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
405
406 DEBUG_PRINT_FLOW();
407
408 return VERR_NOT_IMPLEMENTED;
409}
410
411static int tarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
412{
413 /* Validate input. */
414 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
415 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
416
417 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
418
419 DEBUG_PRINT_FLOW();
420
421 return RTTarFileGetSize(pInt->file, pcbSize);
422}
423
424static int tarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
425{
426 /* Validate input. */
427 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
428 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
429
430 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
431
432 DEBUG_PRINT_FLOW();
433
434 return RTTarFileSetSize(pInt->file, cbSize);
435}
436
437static int tarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
438 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
439{
440 /* Validate input. */
441 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
442 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
443
444 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
445
446 DEBUG_PRINT_FLOW();
447
448 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
449}
450
451static int tarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
452 void *pvBuf, size_t cbRead, size_t *pcbRead)
453{
454 /* Validate input. */
455 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
456 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
457
458 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
459
460// DEBUG_PRINT_FLOW();
461
462 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
463}
464
465static int tarFlushSyncCallback(void *pvUser, void *pvStorage)
466{
467 /* Validate input. */
468 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
469 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
470
471 DEBUG_PRINT_FLOW();
472
473 return VERR_NOT_IMPLEMENTED;
474}
475
476/******************************************************************************
477 * Internal: RTSha interface
478 ******************************************************************************/
479
480DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
481{
482 /* Validate input. */
483 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
484
485 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvUser;
486
487 PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
488 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
489
490 int rc = VINF_SUCCESS;
491 bool fLoop = true;
492 while (fLoop)
493 {
494 /* What should we do next? */
495 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
496// RTPrintf("status: %d\n", u32Status);
497 switch (u32Status)
498 {
499 case STATUS_WAIT:
500 {
501 /* Wait for new work. */
502 rc = RTSemEventWait(pInt->newStatusEvent, 100);
503 if ( RT_FAILURE(rc)
504 && rc != VERR_TIMEOUT)
505 fLoop = false;
506 break;
507 }
508 case STATUS_WRITE:
509 {
510 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WRITING, STATUS_WRITE);
511 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
512 size_t cbMemAllRead = 0;
513 /* First loop over all the free memory in the circular
514 * memory buffer (could be turn around at the end). */
515 for (;;)
516 {
517 if ( cbMemAllRead == cbAvail
518 || fLoop == false)
519 break;
520 char *pcBuf;
521 size_t cbMemToRead = cbAvail - cbMemAllRead;
522 size_t cbMemRead = 0;
523 /* Try to acquire all the used space of the circular buffer. */
524 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
525 size_t cbAllWritten = 0;
526 /* Second, write as long as used memory is there. The write
527 * method could also split the writes up into to smaller
528 * parts. */
529 for (;;)
530 {
531 if (cbAllWritten == cbMemRead)
532 break;
533 size_t cbToWrite = cbMemRead - cbAllWritten;
534 size_t cbWritten = 0;
535 rc = vdIfIoFileWriteSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten], cbToWrite, &cbWritten);
536// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
537 if (RT_FAILURE(rc))
538 {
539 fLoop = false;
540 break;
541 }
542 cbAllWritten += cbWritten;
543 pInt->cbCurFile += cbWritten;
544 }
545 /* Update the SHA1/SHA256 context with the next data block. */
546 if ( RT_SUCCESS(rc)
547 && pInt->pShaStorage->fCreateDigest)
548 {
549 if (pInt->pShaStorage->fSha256)
550 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllWritten);
551 else
552 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllWritten);
553 }
554 /* Mark the block as empty. */
555 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
556 cbMemAllRead += cbAllWritten;
557 }
558 /* Reset the thread status and signal the main thread that we
559 * are finished. Use CmpXchg, so we not overwrite other states
560 * which could be signaled in the meantime. */
561 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITING))
562 rc = RTSemEventSignal(pInt->workFinishedEvent);
563 break;
564 }
565 case STATUS_READ:
566 {
567 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
568 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
569 size_t cbMemAllWrite = 0;
570 /* First loop over all the available memory in the circular
571 * memory buffer (could be turn around at the end). */
572 for (;;)
573 {
574 if ( cbMemAllWrite == cbAvail
575 || fLoop == false)
576 break;
577 char *pcBuf;
578 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
579 size_t cbMemWrite = 0;
580 /* Try to acquire all the free space of the circular buffer. */
581 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
582 /* Second, read as long as we filled all the memory. The
583 * read method could also split the reads up into to
584 * smaller parts. */
585 size_t cbAllRead = 0;
586 for (;;)
587 {
588 if (cbAllRead == cbMemWrite)
589 break;
590 size_t cbToRead = cbMemWrite - cbAllRead;
591 size_t cbRead = 0;
592 rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
593// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
594 if (RT_FAILURE(rc))
595 {
596 fLoop = false;
597 break;
598 }
599 /* This indicates end of file. Stop reading. */
600 if (cbRead == 0)
601 {
602 fLoop = false;
603 ASMAtomicWriteBool(&pInt->fEOF, true);
604 break;
605 }
606 cbAllRead += cbRead;
607 pInt->cbCurFile += cbRead;
608 }
609 /* Update the SHA1/SHA256 context with the next data block. */
610 if ( RT_SUCCESS(rc)
611 && pInt->pShaStorage->fCreateDigest)
612 {
613 if (pInt->pShaStorage->fSha256)
614 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
615 else
616 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllRead);
617 }
618 /* Mark the block as full. */
619 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
620 cbMemAllWrite += cbAllRead;
621 }
622 /* Reset the thread status and signal the main thread that we
623 * are finished. Use CmpXchg, so we not overwrite other states
624 * which could be signaled in the meantime. */
625 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
626 rc = RTSemEventSignal(pInt->workFinishedEvent);
627 break;
628 }
629 case STATUS_END:
630 {
631 /* End signaled */
632 fLoop = false;
633 break;
634 }
635 }
636 }
637 /* Cleanup any status changes to indicate we are finished. */
638 ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
639 rc = RTSemEventSignal(pInt->workFinishedEvent);
640 return rc;
641}
642
643DECLINLINE(int) shaSignalManifestThread(PSHASTORAGEINTERNAL pInt, uint32_t uStatus)
644{
645 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
646 return RTSemEventSignal(pInt->newStatusEvent);
647}
648
649DECLINLINE(int) shaWaitForManifestThreadFinished(PSHASTORAGEINTERNAL pInt)
650{
651// RTPrintf("start\n");
652 int rc = VINF_SUCCESS;
653 for (;;)
654 {
655// RTPrintf(" wait\n");
656 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
657 if (!( u32Status == STATUS_WRITE
658 || u32Status == STATUS_WRITING
659 || u32Status == STATUS_READ
660 || u32Status == STATUS_READING))
661 break;
662 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
663 }
664 if (rc == VERR_TIMEOUT)
665 rc = VINF_SUCCESS;
666 return rc;
667}
668
669DECLINLINE(int) shaFlushCurBuf(PSHASTORAGEINTERNAL pInt)
670{
671 int rc = VINF_SUCCESS;
672 if (pInt->fOpenMode & RTFILE_O_WRITE)
673 {
674 /* Let the write worker thread start immediately. */
675 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
676 if (RT_FAILURE(rc))
677 return rc;
678
679 /* Wait until the write worker thread has finished. */
680 rc = shaWaitForManifestThreadFinished(pInt);
681 }
682
683 return rc;
684}
685
686static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
687 PFNVDCOMPLETED pfnCompleted, void **ppInt)
688{
689 /* Validate input. */
690 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
691 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
692 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
693 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
694 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
695
696 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
697 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
698 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
699
700 DEBUG_PRINT_FLOW();
701
702 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL));
703 if (!pInt)
704 return VERR_NO_MEMORY;
705
706 int rc = VINF_SUCCESS;
707 do
708 {
709 pInt->pfnCompleted = pfnCompleted;
710 pInt->pShaStorage = pShaStorage;
711 pInt->fEOF = false;
712 pInt->fOpenMode = fOpen;
713 pInt->u32Status = STATUS_WAIT;
714
715 /* Circular buffer in the read case. */
716 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
717 if (RT_FAILURE(rc))
718 break;
719
720 if (fOpen & RTFILE_O_WRITE)
721 {
722 /* The zero buffer is used for appending empty parts at the end of the
723 * file (or our buffer) in setSize or when uOffset in writeSync is
724 * increased in steps bigger than a byte. */
725 pInt->cbZeroBuf = _1K;
726 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
727 if (!pInt->pvZeroBuf)
728 {
729 rc = VERR_NO_MEMORY;
730 break;
731 }
732 }
733
734 /* Create an event semaphore to indicate a state change for the worker
735 * thread. */
736 rc = RTSemEventCreate(&pInt->newStatusEvent);
737 if (RT_FAILURE(rc))
738 break;
739 /* Create an event semaphore to indicate a finished calculation of the
740 worker thread. */
741 rc = RTSemEventCreate(&pInt->workFinishedEvent);
742 if (RT_FAILURE(rc))
743 break;
744 /* Create the worker thread. */
745 rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA-Worker");
746 if (RT_FAILURE(rc))
747 break;
748
749 if (pShaStorage->fCreateDigest)
750 {
751 /* Create a SHA1/SHA256 context the worker thread will work with. */
752 if (pShaStorage->fSha256)
753 RTSha256Init(&pInt->ctx.Sha256);
754 else
755 RTSha1Init(&pInt->ctx.Sha1);
756 }
757
758 /* Open the file. */
759 rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
760 &pInt->pvStorage);
761 if (RT_FAILURE(rc))
762 break;
763
764 if (fOpen & RTFILE_O_READ)
765 {
766 /* Immediately let the worker thread start the reading. */
767 rc = shaSignalManifestThread(pInt, STATUS_READ);
768 }
769 }
770 while (0);
771
772 if (RT_FAILURE(rc))
773 {
774 if (pInt->pWorkerThread)
775 {
776 shaSignalManifestThread(pInt, STATUS_END);
777 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
778 }
779 if (pInt->workFinishedEvent)
780 RTSemEventDestroy(pInt->workFinishedEvent);
781 if (pInt->newStatusEvent)
782 RTSemEventDestroy(pInt->newStatusEvent);
783 if (pInt->pCircBuf)
784 RTCircBufDestroy(pInt->pCircBuf);
785 if (pInt->pvZeroBuf)
786 RTMemFree(pInt->pvZeroBuf);
787 RTMemFree(pInt);
788 }
789 else
790 *ppInt = pInt;
791
792 return rc;
793}
794
795static int shaCloseCallback(void *pvUser, void *pvStorage)
796{
797 /* Validate input. */
798 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
799 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
800
801 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
802 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
803 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
804
805 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
806
807 DEBUG_PRINT_FLOW();
808
809 int rc = VINF_SUCCESS;
810
811 /* Make sure all pending writes are flushed */
812 rc = shaFlushCurBuf(pInt);
813
814 if (pInt->pWorkerThread)
815 {
816 /* Signal the worker thread to end himself */
817 rc = shaSignalManifestThread(pInt, STATUS_END);
818 /* Worker thread stopped? */
819 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
820 }
821
822 if ( RT_SUCCESS(rc)
823 && pShaStorage->fCreateDigest)
824 {
825 /* Finally calculate & format the SHA1/SHA256 sum */
826 unsigned char auchDig[RTSHA256_HASH_SIZE];
827 char *pszDigest;
828 size_t cbDigest;
829 if (pShaStorage->fSha256)
830 {
831 RTSha256Final(&pInt->ctx.Sha256, auchDig);
832 cbDigest = RTSHA256_DIGEST_LEN;
833 }
834 else
835 {
836 RTSha1Final(&pInt->ctx.Sha1, auchDig);
837 cbDigest = RTSHA1_DIGEST_LEN;
838 }
839 rc = RTStrAllocEx(&pszDigest, cbDigest + 1);
840 if (RT_SUCCESS(rc))
841 {
842 if (pShaStorage->fSha256)
843 rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1);
844 else
845 rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1);
846 if (RT_SUCCESS(rc))
847 pShaStorage->strDigest = pszDigest;
848 RTStrFree(pszDigest);
849 }
850 }
851
852 /* Close the file */
853 rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
854
855// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
856
857 /* Cleanup */
858 if (pInt->workFinishedEvent)
859 RTSemEventDestroy(pInt->workFinishedEvent);
860 if (pInt->newStatusEvent)
861 RTSemEventDestroy(pInt->newStatusEvent);
862 if (pInt->pCircBuf)
863 RTCircBufDestroy(pInt->pCircBuf);
864 if (pInt->pvZeroBuf)
865 RTMemFree(pInt->pvZeroBuf);
866 RTMemFree(pInt);
867
868 return rc;
869}
870
871static int shaDeleteCallback(void *pvUser, const char *pcszFilename)
872{
873 /* Validate input. */
874 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
875
876 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
877 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
878 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
879
880 DEBUG_PRINT_FLOW();
881
882 return vdIfIoFileDelete(pIfIo, pcszFilename);
883}
884
885static int shaMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
886{
887 /* Validate input. */
888 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
889
890 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
891 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
892 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
893
894
895 DEBUG_PRINT_FLOW();
896
897 return vdIfIoFileMove(pIfIo, pcszSrc, pcszDst, fMove);
898}
899
900static int shaGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
901{
902 /* Validate input. */
903 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
904
905 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
906 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
907 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
908
909 DEBUG_PRINT_FLOW();
910
911 return vdIfIoFileGetFreeSpace(pIfIo, pcszFilename, pcbFreeSpace);
912}
913
914static int shaGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
915{
916 /* Validate input. */
917 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
918
919 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
920 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
921 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
922
923 DEBUG_PRINT_FLOW();
924
925 return vdIfIoFileGetModificationTime(pIfIo, pcszFilename, pModificationTime);
926}
927
928
929static int shaGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
930{
931 /* Validate input. */
932 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
933 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
934
935 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
936 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
937 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
938
939 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
940
941 DEBUG_PRINT_FLOW();
942
943 uint64_t cbSize;
944 int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
945 if (RT_FAILURE(rc))
946 return rc;
947
948 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
949
950 return VINF_SUCCESS;
951}
952
953static int shaSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
954{
955 /* Validate input. */
956 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
957 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
958
959 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
960 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
961 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
962
963 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
964
965 DEBUG_PRINT_FLOW();
966
967 return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
968}
969
970static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
971 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
972{
973 /* Validate input. */
974 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
975 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
976
977 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
978 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
979 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
980
981 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
982
983 DEBUG_PRINT_FLOW();
984
985 /* Check that the write is linear */
986 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
987
988 int rc = VINF_SUCCESS;
989
990 /* Check if we have to add some free space at the end, before we start the
991 * real write. */
992 if (pInt->cbCurAll < uOffset)
993 {
994 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
995 size_t cbAllWritten = 0;
996 for (;;)
997 {
998 /* Finished? */
999 if (cbAllWritten == cbSize)
1000 break;
1001 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
1002 size_t cbWritten = 0;
1003 rc = shaWriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
1004 pInt->pvZeroBuf, cbToWrite, &cbWritten);
1005 if (RT_FAILURE(rc))
1006 break;
1007 cbAllWritten += cbWritten;
1008 }
1009 if (RT_FAILURE(rc))
1010 return rc;
1011 }
1012// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
1013
1014 size_t cbAllWritten = 0;
1015 for (;;)
1016 {
1017 /* Finished? */
1018 if (cbAllWritten == cbWrite)
1019 break;
1020 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1021 if ( cbAvail == 0
1022 && pInt->fEOF)
1023 return VERR_EOF;
1024 /* If there isn't enough free space make sure the worker thread is
1025 * writing some data. */
1026 if ((cbWrite - cbAllWritten) > cbAvail)
1027 {
1028 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1029 if (RT_FAILURE(rc))
1030 break;
1031 /* If there is _no_ free space available, we have to wait until it is. */
1032 if (cbAvail == 0)
1033 {
1034 rc = shaWaitForManifestThreadFinished(pInt);
1035 if (RT_FAILURE(rc))
1036 break;
1037 cbAvail = RTCircBufFree(pInt->pCircBuf);
1038// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1039// pInt->waits++;
1040 }
1041 }
1042 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1043 char *pcBuf;
1044 size_t cbMemWritten = 0;
1045 /* Acquire a block for writing from our circular buffer. */
1046 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1047 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1048 /* Mark the block full. */
1049 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1050 cbAllWritten += cbMemWritten;
1051 pInt->cbCurAll += cbMemWritten;
1052 }
1053
1054 if (pcbWritten)
1055 *pcbWritten = cbAllWritten;
1056
1057 /* Signal the thread to write more data in the mean time. */
1058 if ( RT_SUCCESS(rc)
1059 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1060 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1061
1062 return rc;
1063}
1064
1065static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1066 void *pvBuf, size_t cbRead, size_t *pcbRead)
1067{
1068 /* Validate input. */
1069 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1070 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1071
1072 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1073 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1074 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1075
1076// DEBUG_PRINT_FLOW();
1077
1078 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1079
1080 int rc = VINF_SUCCESS;
1081
1082// pInt->calls++;
1083// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1084
1085 /* Check if we jump forward in the file. If so we have to read the
1086 * remaining stuff in the gap anyway (SHA1/SHA256; streaming). */
1087 if (pInt->cbCurAll < uOffset)
1088 {
1089 rc = shaReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1090 (size_t)(uOffset - pInt->cbCurAll), 0);
1091 if (RT_FAILURE(rc))
1092 return rc;
1093// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1094 }
1095 else if (uOffset < pInt->cbCurAll)
1096 AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
1097
1098 size_t cbAllRead = 0;
1099 for (;;)
1100 {
1101 /* Finished? */
1102 if (cbAllRead == cbRead)
1103 break;
1104 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1105 if ( cbAvail == 0
1106 && pInt->fEOF
1107 && !RTCircBufIsWriting(pInt->pCircBuf))
1108 {
1109 break;
1110 }
1111 /* If there isn't enough data make sure the worker thread is fetching
1112 * more. */
1113 if ((cbRead - cbAllRead) > cbAvail)
1114 {
1115 rc = shaSignalManifestThread(pInt, STATUS_READ);
1116 if (RT_FAILURE(rc))
1117 break;
1118 /* If there is _no_ data available, we have to wait until it is. */
1119 if (cbAvail == 0)
1120 {
1121 rc = shaWaitForManifestThreadFinished(pInt);
1122 if (RT_FAILURE(rc))
1123 break;
1124 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1125// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1126// pInt->waits++;
1127 }
1128 }
1129 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1130 char *pcBuf;
1131 size_t cbMemRead = 0;
1132 /* Acquire a block for reading from our circular buffer. */
1133 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1134 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1135 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1136 /* Mark the block as empty again. */
1137 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1138 cbAllRead += cbMemRead;
1139
1140 pInt->cbCurAll += cbMemRead;
1141 }
1142
1143 if (pcbRead)
1144 *pcbRead = cbAllRead;
1145
1146 if (rc == VERR_EOF)
1147 rc = VINF_SUCCESS;
1148
1149 /* Signal the thread to read more data in the mean time. */
1150 if ( RT_SUCCESS(rc)
1151 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1152 rc = shaSignalManifestThread(pInt, STATUS_READ);
1153
1154 return rc;
1155}
1156
1157static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1158{
1159 /* Validate input. */
1160 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1161 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1162
1163 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1164 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1165 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1166
1167 DEBUG_PRINT_FLOW();
1168
1169 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1170
1171 /* Check if there is still something in the buffer. If yes, flush it. */
1172 int rc = shaFlushCurBuf(pInt);
1173 if (RT_FAILURE(rc))
1174 return rc;
1175
1176 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1177}
1178
1179PVDINTERFACEIO ShaCreateInterface()
1180{
1181 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1182 if (!pCallbacks)
1183 return NULL;
1184
1185 pCallbacks->pfnOpen = shaOpenCallback;
1186 pCallbacks->pfnClose = shaCloseCallback;
1187 pCallbacks->pfnDelete = shaDeleteCallback;
1188 pCallbacks->pfnMove = shaMoveCallback;
1189 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1190 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1191 pCallbacks->pfnGetSize = shaGetSizeCallback;
1192 pCallbacks->pfnSetSize = shaSetSizeCallback;
1193 pCallbacks->pfnReadSync = shaReadSyncCallback;
1194 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1195 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1196
1197 return pCallbacks;
1198}
1199
1200PVDINTERFACEIO FileCreateInterface()
1201{
1202 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1203 if (!pCallbacks)
1204 return NULL;
1205
1206 pCallbacks->pfnOpen = fileOpenCallback;
1207 pCallbacks->pfnClose = fileCloseCallback;
1208 pCallbacks->pfnDelete = fileDeleteCallback;
1209 pCallbacks->pfnMove = fileMoveCallback;
1210 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1211 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1212 pCallbacks->pfnGetSize = fileGetSizeCallback;
1213 pCallbacks->pfnSetSize = fileSetSizeCallback;
1214 pCallbacks->pfnReadSync = fileReadSyncCallback;
1215 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1216 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1217
1218 return pCallbacks;
1219}
1220
1221PVDINTERFACEIO TarCreateInterface()
1222{
1223 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1224 if (!pCallbacks)
1225 return NULL;
1226
1227 pCallbacks->pfnOpen = tarOpenCallback;
1228 pCallbacks->pfnClose = tarCloseCallback;
1229 pCallbacks->pfnDelete = tarDeleteCallback;
1230 pCallbacks->pfnMove = tarMoveCallback;
1231 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1232 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1233 pCallbacks->pfnGetSize = tarGetSizeCallback;
1234 pCallbacks->pfnSetSize = tarSetSizeCallback;
1235 pCallbacks->pfnReadSync = tarReadSyncCallback;
1236 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1237 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1238
1239 return pCallbacks;
1240}
1241
1242int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1243{
1244 /* Validate input. */
1245 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1246 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1247 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1248
1249 void *pvStorage;
1250 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1251 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1252 &pvStorage);
1253 if (RT_FAILURE(rc))
1254 return rc;
1255
1256 void *pvTmpBuf = 0;
1257 void *pvBuf = 0;
1258 uint64_t cbTmpSize = _1M;
1259 size_t cbAllRead = 0;
1260 do
1261 {
1262 pvTmpBuf = RTMemAlloc(cbTmpSize);
1263 if (!pvTmpBuf)
1264 {
1265 rc = VERR_NO_MEMORY;
1266 break;
1267 }
1268
1269 for (;;)
1270 {
1271 size_t cbRead = 0;
1272 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1273 if ( RT_FAILURE(rc)
1274 || cbRead == 0)
1275 break;
1276 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1277 if (!pvBuf)
1278 {
1279 rc = VERR_NO_MEMORY;
1280 break;
1281 }
1282 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1283 cbAllRead += cbRead;
1284 }
1285 } while (0);
1286
1287 pIfIo->pfnClose(pvUser, pvStorage);
1288
1289 if (rc == VERR_EOF)
1290 rc = VINF_SUCCESS;
1291
1292 if (pvTmpBuf)
1293 RTMemFree(pvTmpBuf);
1294
1295 if (RT_SUCCESS(rc))
1296 {
1297 *ppvBuf = pvBuf;
1298 *pcbSize = cbAllRead;
1299 }
1300 else
1301 {
1302 if (pvBuf)
1303 RTMemFree(pvBuf);
1304 }
1305
1306 return rc;
1307}
1308
1309int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1310{
1311 /* Validate input. */
1312 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1313 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1314 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1315
1316 void *pvStorage;
1317 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1318 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1319 &pvStorage);
1320 if (RT_FAILURE(rc))
1321 return rc;
1322
1323 size_t cbAllWritten = 0;
1324 for (;;)
1325 {
1326 if (cbAllWritten >= cbSize)
1327 break;
1328 size_t cbToWrite = cbSize - cbAllWritten;
1329 size_t cbWritten = 0;
1330 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1331 if (RT_FAILURE(rc))
1332 break;
1333 cbAllWritten += cbWritten;
1334 }
1335
1336 rc = pIfIo->pfnClose(pvUser, pvStorage);
1337
1338 return rc;
1339}
1340
1341static int zipDecompressBuffer(z_stream streamIn,
1342 uint32_t *cbDecompressed,
1343 bool *finished)
1344{
1345 int rc;
1346 int sh = streamIn.avail_out;
1347
1348 *cbDecompressed = 0;
1349
1350 do
1351 {
1352 rc = inflate(&streamIn, Z_NO_FLUSH);
1353
1354 if (rc < 0)
1355 {
1356 switch (rc)
1357 {
1358 case Z_STREAM_ERROR:
1359 rc = VERR_ZIP_CORRUPTED;
1360 break;
1361 case Z_DATA_ERROR:
1362 rc = VERR_ZIP_CORRUPTED;
1363 break;
1364 case Z_MEM_ERROR:
1365 rc = VERR_ZIP_NO_MEMORY;
1366 break;
1367 case Z_BUF_ERROR:
1368 rc = VERR_ZIP_ERROR;
1369 break;
1370 case Z_VERSION_ERROR:
1371 rc = VERR_ZIP_UNSUPPORTED_VERSION;
1372 break;
1373 case Z_ERRNO: /* We shouldn't see this status! */
1374 default:
1375 AssertMsgFailed(("%d\n", rc));
1376 if (rc >= 0)
1377 rc = VINF_SUCCESS;
1378 rc = VERR_ZIP_ERROR;
1379 }
1380
1381 break;
1382 }
1383
1384 *cbDecompressed += (sh - streamIn.avail_out);
1385 sh = streamIn.avail_out;
1386 }
1387 while (streamIn.avail_out > 0 && streamIn.avail_in > 0 );
1388
1389 if (RT_SUCCESS(rc))
1390 {
1391 if (streamIn.avail_in == 0)
1392 *finished = true;
1393 else
1394 {
1395 if (streamIn.avail_out == 0)
1396 *finished = false;
1397 }
1398 }
1399
1400 return rc;
1401}
1402
1403int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
1404{
1405 /* Validate input. */
1406 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1407
1408 void *pvStorage;
1409 int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
1410 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1411 &pvStorage);
1412 if (RT_FAILURE(rc))
1413 return rc;
1414
1415 Bytef *decompressedBuffer = 0;
1416 Bytef *compressedBuffer = 0;
1417 uint64_t cbTmpSize = _1M;
1418 size_t cbAllRead = 0;
1419 size_t cbAllWritten = 0;
1420 RTFILE pFile = NULL;
1421 z_stream gzipStream;
1422
1423 Utf8Str pathOut(pcszFullFilenameOut);
1424 pathOut = pathOut.stripFilename();
1425
1426 Utf8Str fileIn(pcszFullFilenameIn);
1427 fileIn = fileIn.stripPath();
1428
1429 do
1430 {
1431 if (RTFileExists(pcszFullFilenameOut) == false)
1432 {
1433 /* ensure the directory exists */
1434 rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true);
1435 if (FAILED(rc))
1436 {
1437 rc = VBOX_E_FILE_ERROR;
1438 break;
1439 }
1440
1441 rc = RTFileOpen(&pFile, pcszFullFilenameOut, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1442 }
1443 else
1444 {
1445 rc = RTFileOpen(&pFile, pcszFullFilenameOut, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1446 }
1447
1448 if (FAILED(rc) || pFile == NULL)
1449 {
1450 rc = VBOX_E_FILE_ERROR;
1451 break;
1452 }
1453
1454 compressedBuffer = (Bytef *)RTMemAlloc(cbTmpSize);
1455
1456 if (!compressedBuffer)
1457 {
1458 rc = VERR_NO_MEMORY;
1459 break;
1460 }
1461
1462
1463 decompressedBuffer = (Bytef *)RTMemAlloc(cbTmpSize*10);
1464
1465 if (!decompressedBuffer)
1466 {
1467 rc = VERR_NO_MEMORY;
1468 break;
1469 }
1470
1471 gzipStream.zalloc = Z_NULL;
1472 gzipStream.zfree = Z_NULL;
1473 gzipStream.opaque = Z_NULL;
1474 gzipStream.next_in = compressedBuffer;
1475 gzipStream.avail_in = 0;
1476 gzipStream.next_out = decompressedBuffer;
1477 gzipStream.avail_out = cbTmpSize*10;
1478
1479 rc = inflateInit2(&gzipStream, MAX_WBITS + 16 /* autodetect gzip header */);
1480
1481 if (rc < 0)
1482 {
1483 break;
1484 }
1485
1486 size_t cbRead = 0;
1487 size_t cbDecompressed = 0;
1488 bool fFinished = true;
1489
1490 for (;;)
1491 {
1492 if (fFinished == true)
1493 {
1494 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, compressedBuffer, cbTmpSize, &cbRead);
1495 if ( RT_FAILURE(rc)
1496 || cbRead == 0)
1497 break;
1498
1499 gzipStream.avail_in = cbRead;
1500 gzipStream.avail_out = cbTmpSize*10;
1501 }
1502
1503 /* decompress the buffer */
1504 rc = zipDecompressBuffer(gzipStream,
1505 (uint32_t *)(&cbDecompressed),
1506 &fFinished);
1507
1508 if (RT_FAILURE(rc))
1509 break;
1510
1511 rc = RTFileWrite(pFile, decompressedBuffer, cbDecompressed, &cbDecompressed);
1512
1513 if (RT_FAILURE(rc))
1514 break;
1515
1516 cbAllWritten += cbDecompressed;
1517 cbAllRead += cbRead;
1518 }
1519 } while (0);
1520
1521 pIfIo->pfnClose(pvUser, pvStorage);
1522
1523 if (rc == VERR_EOF)
1524 rc = VINF_SUCCESS;
1525
1526 rc = inflateEnd(&gzipStream);
1527
1528 rc = RTFileClose(pFile);
1529
1530 if (decompressedBuffer)
1531 RTMemFree(decompressedBuffer);
1532 if (compressedBuffer)
1533 RTMemFree(compressedBuffer);
1534
1535 return rc;
1536}
1537
1538
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