VirtualBox

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

Last change on this file since 48935 was 47963, checked in by vboxsync, 11 years ago

pr6022. Additional checks during OVA/OVF import. Deleting temporary files. Using small memory buffer for copying ISO images with simultaneously calculating SHA digest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.2 KB
Line 
1/* $Id: ApplianceImplIO.cpp 47963 2013-08-21 10:59:34Z 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 size_t cbAvail = 0;
1101 for (;;)
1102 {
1103 /* Finished? */
1104 if (cbAllRead == cbRead)
1105 break;
1106
1107 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1108
1109 if ( cbAvail == 0
1110 && pInt->fEOF
1111 && !RTCircBufIsWriting(pInt->pCircBuf))
1112 {
1113 rc = VINF_EOF;
1114 break;
1115 }
1116
1117 /* If there isn't enough data make sure the worker thread is fetching
1118 * more. */
1119 if ((cbRead - cbAllRead) > cbAvail)
1120 {
1121 rc = shaSignalManifestThread(pInt, STATUS_READ);
1122 if (RT_FAILURE(rc))
1123 break;
1124 /* If there is _no_ data available, we have to wait until it is. */
1125 if (cbAvail == 0)
1126 {
1127 rc = shaWaitForManifestThreadFinished(pInt);
1128 if (RT_FAILURE(rc))
1129 break;
1130 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1131// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1132// pInt->waits++;
1133 }
1134 }
1135 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1136 char *pcBuf;
1137 size_t cbMemRead = 0;
1138 /* Acquire a block for reading from our circular buffer. */
1139 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1140 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1141 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1142 /* Mark the block as empty again. */
1143 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1144 cbAllRead += cbMemRead;
1145
1146 pInt->cbCurAll += cbMemRead;
1147 }
1148
1149 if (pcbRead)
1150 *pcbRead = cbAllRead;
1151
1152 if (rc == VERR_EOF)
1153 rc = VINF_SUCCESS;
1154
1155 /* Signal the thread to read more data in the mean time. */
1156 if ( RT_SUCCESS(rc)
1157 && rc != VINF_EOF
1158 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1159 rc = shaSignalManifestThread(pInt, STATUS_READ);
1160
1161 return rc;
1162}
1163
1164static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1165{
1166 /* Validate input. */
1167 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1168 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1169
1170 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1171 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1172 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1173
1174 DEBUG_PRINT_FLOW();
1175
1176 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1177
1178 /* Check if there is still something in the buffer. If yes, flush it. */
1179 int rc = shaFlushCurBuf(pInt);
1180 if (RT_FAILURE(rc))
1181 return rc;
1182
1183 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1184}
1185
1186PVDINTERFACEIO ShaCreateInterface()
1187{
1188 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1189 if (!pCallbacks)
1190 return NULL;
1191
1192 pCallbacks->pfnOpen = shaOpenCallback;
1193 pCallbacks->pfnClose = shaCloseCallback;
1194 pCallbacks->pfnDelete = shaDeleteCallback;
1195 pCallbacks->pfnMove = shaMoveCallback;
1196 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1197 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1198 pCallbacks->pfnGetSize = shaGetSizeCallback;
1199 pCallbacks->pfnSetSize = shaSetSizeCallback;
1200 pCallbacks->pfnReadSync = shaReadSyncCallback;
1201 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1202 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1203
1204 return pCallbacks;
1205}
1206
1207PVDINTERFACEIO FileCreateInterface()
1208{
1209 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1210 if (!pCallbacks)
1211 return NULL;
1212
1213 pCallbacks->pfnOpen = fileOpenCallback;
1214 pCallbacks->pfnClose = fileCloseCallback;
1215 pCallbacks->pfnDelete = fileDeleteCallback;
1216 pCallbacks->pfnMove = fileMoveCallback;
1217 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1218 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1219 pCallbacks->pfnGetSize = fileGetSizeCallback;
1220 pCallbacks->pfnSetSize = fileSetSizeCallback;
1221 pCallbacks->pfnReadSync = fileReadSyncCallback;
1222 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1223 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1224
1225 return pCallbacks;
1226}
1227
1228PVDINTERFACEIO TarCreateInterface()
1229{
1230 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1231 if (!pCallbacks)
1232 return NULL;
1233
1234 pCallbacks->pfnOpen = tarOpenCallback;
1235 pCallbacks->pfnClose = tarCloseCallback;
1236 pCallbacks->pfnDelete = tarDeleteCallback;
1237 pCallbacks->pfnMove = tarMoveCallback;
1238 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1239 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1240 pCallbacks->pfnGetSize = tarGetSizeCallback;
1241 pCallbacks->pfnSetSize = tarSetSizeCallback;
1242 pCallbacks->pfnReadSync = tarReadSyncCallback;
1243 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1244 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1245
1246 return pCallbacks;
1247}
1248
1249int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1250{
1251 /* Validate input. */
1252 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1253 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1254 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1255
1256 void *pvStorage;
1257 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1258 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1259 &pvStorage);
1260 if (RT_FAILURE(rc))
1261 return rc;
1262
1263 void *pvTmpBuf = 0;
1264 void *pvBuf = 0;
1265 uint64_t cbTmpSize = _1M;
1266 size_t cbAllRead = 0;
1267 do
1268 {
1269 pvTmpBuf = RTMemAlloc(cbTmpSize);
1270 if (!pvTmpBuf)
1271 {
1272 rc = VERR_NO_MEMORY;
1273 break;
1274 }
1275
1276 for (;;)
1277 {
1278 size_t cbRead = 0;
1279 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1280 if ( RT_FAILURE(rc)
1281 || cbRead == 0)
1282 break;
1283 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1284 if (!pvBuf)
1285 {
1286 rc = VERR_NO_MEMORY;
1287 break;
1288 }
1289 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1290 cbAllRead += cbRead;
1291 }
1292 } while (0);
1293
1294 pIfIo->pfnClose(pvUser, pvStorage);
1295
1296 if (rc == VERR_EOF)
1297 rc = VINF_SUCCESS;
1298
1299 if (pvTmpBuf)
1300 RTMemFree(pvTmpBuf);
1301
1302 if (RT_SUCCESS(rc))
1303 {
1304 *ppvBuf = pvBuf;
1305 *pcbSize = cbAllRead;
1306 }
1307 else
1308 {
1309 if (pvBuf)
1310 RTMemFree(pvBuf);
1311 }
1312
1313 return rc;
1314}
1315
1316int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1317{
1318 /* Validate input. */
1319 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1320 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1321 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1322
1323 void *pvStorage;
1324 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1325 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1326 &pvStorage);
1327 if (RT_FAILURE(rc))
1328 return rc;
1329
1330 size_t cbAllWritten = 0;
1331 for (;;)
1332 {
1333 if (cbAllWritten >= cbSize)
1334 break;
1335 size_t cbToWrite = cbSize - cbAllWritten;
1336 size_t cbWritten = 0;
1337 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1338 if (RT_FAILURE(rc))
1339 break;
1340 cbAllWritten += cbWritten;
1341 }
1342
1343 rc = pIfIo->pfnClose(pvUser, pvStorage);
1344
1345 return rc;
1346}
1347
1348int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
1349{
1350 /* Validate input. */
1351 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1352
1353 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1354 /*
1355 * Open the source file.
1356 */
1357 void *pvStorage;
1358 int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
1359 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1360 &pvStorage);
1361 if (RT_FAILURE(rc))
1362 return rc;
1363
1364 /* Turn the source file handle/whatever into a VFS stream. */
1365 RTVFSIOSTREAM hVfsIosCompressedSrc;
1366
1367 rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosCompressedSrc);
1368 if (RT_SUCCESS(rc))
1369 {
1370 /* Pass the source thru gunzip. */
1371 RTVFSIOSTREAM hVfsIosSrc;
1372 rc = RTZipGzipDecompressIoStream(hVfsIosCompressedSrc, 0, &hVfsIosSrc);
1373 if (RT_SUCCESS(rc))
1374 {
1375 /*
1376 * Create the output file, including necessary paths.
1377 * Any existing file will be overwritten.
1378 */
1379 rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true /*fCreate*/);
1380 if (RT_SUCCESS(rc))
1381 {
1382 RTVFSIOSTREAM hVfsIosDst;
1383 rc = RTVfsIoStrmOpenNormal(pcszFullFilenameOut,
1384 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
1385 &hVfsIosDst);
1386 if (RT_SUCCESS(rc))
1387 {
1388 /*
1389 * Pump the bytes thru. If we fail, delete the output file.
1390 */
1391 RTMANIFEST hFileManifest = NIL_RTMANIFEST;
1392 rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
1393 if (RT_SUCCESS(rc))
1394 {
1395 RTVFSIOSTREAM hVfsIosMfst;
1396
1397 uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
1398
1399 rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
1400 hVfsIosSrc,
1401 "ovf import",
1402 digestType,
1403 true /*read*/, &hVfsIosMfst);
1404 if (RT_SUCCESS(rc))
1405 {
1406 rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
1407 }
1408
1409 RTVfsIoStrmRelease(hVfsIosMfst);
1410 }
1411
1412 RTVfsIoStrmRelease(hVfsIosDst);
1413 }
1414 }
1415
1416 RTVfsIoStrmRelease(hVfsIosSrc);
1417 }
1418 }
1419 pIfIo->pfnClose(pvUser, pvStorage);
1420
1421 return rc;
1422}
1423
1424int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser)
1425{
1426 /* Validate input. */
1427 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1428
1429 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1430 void *pvStorage;
1431
1432 int rc = pIfIo->pfnOpen(pvUser, pcszSourceFilename,
1433 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1434 &pvStorage);
1435 if (RT_FAILURE(rc))
1436 return rc;
1437
1438 /* Turn the source file handle/whatever into a VFS stream. */
1439 RTVFSIOSTREAM hVfsIosSrc;
1440
1441 rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosSrc);
1442 if (RT_SUCCESS(rc))
1443 {
1444 /*
1445 * Create the output file, including necessary paths.
1446 * Any existing file will be overwritten.
1447 */
1448 rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszTargetFilename), true /*fCreate*/);
1449 if (RT_SUCCESS(rc))
1450 {
1451 RTVFSIOSTREAM hVfsIosDst;
1452 rc = RTVfsIoStrmOpenNormal(pcszTargetFilename,
1453 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
1454 &hVfsIosDst);
1455 if (RT_SUCCESS(rc))
1456 {
1457 /*
1458 * Pump the bytes thru. If we fail, delete the output file.
1459 */
1460 RTMANIFEST hFileManifest = NIL_RTMANIFEST;
1461 rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
1462 if (RT_SUCCESS(rc))
1463 {
1464 RTVFSIOSTREAM hVfsIosMfst;
1465
1466 uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
1467
1468 rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
1469 hVfsIosSrc,
1470 "ovf import",
1471 digestType,
1472 true /*read*/, &hVfsIosMfst);
1473 if (RT_SUCCESS(rc))
1474 {
1475 rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
1476 }
1477
1478 RTVfsIoStrmRelease(hVfsIosMfst);
1479 }
1480
1481 RTVfsIoStrmRelease(hVfsIosDst);
1482 }
1483 }
1484
1485 RTVfsIoStrmRelease(hVfsIosSrc);
1486
1487 }
1488
1489 pIfIo->pfnClose(pvUser, pvStorage);
1490 return rc;
1491}
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