VirtualBox

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

Last change on this file since 47743 was 47716, checked in by vboxsync, 11 years ago

pr6022. 3rd variant (using VFS streaming feature) of GZIP support for reading the gzipped storage images from OVA/OVF package has been added.

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

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