VirtualBox

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

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

ApplianceImplImport.cpp,ApplianceImplIO.cpp: Logging, tiny memory leaks, readability.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.1 KB
Line 
1/* $Id: ApplianceImplIO.cpp 50193 2014-01-23 17:50:07Z 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.215389.xyz. 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;
308 rc = RTTarCurrentFile(tar, &pszFilename);
309 if (RT_SUCCESS(rc))
310 {
311 if (rc == VINF_TAR_DIR_PATH)
312 {
313 RTStrFree(pszFilename);
314 break;
315 }
316
317 fFound = !RTStrICmp(pszFilename, pszLocation);
318
319 RTStrFree(pszFilename);
320 if (fFound)
321 break;
322 rc = RTTarSeekNextFile(tar);
323 if (RT_FAILURE(rc))
324 break;
325 }
326 else
327 break;
328 }
329 if (fFound)
330 rc = RTTarFileOpenCurrentFile(tar, &pInt->file, 0, fOpen);
331 }
332 else
333 rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
334
335 if (RT_FAILURE(rc))
336 RTMemFree(pInt);
337 else
338 *ppInt = pInt;
339
340 return rc;
341}
342
343static int tarCloseCallback(void *pvUser, void *pvStorage)
344{
345 /* Validate input. */
346 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
347 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
348
349 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
350
351 DEBUG_PRINT_FLOW();
352
353 int rc = RTTarFileClose(pInt->file);
354
355 /* Cleanup */
356 RTMemFree(pInt);
357
358 return rc;
359}
360
361static int tarDeleteCallback(void *pvUser, const char *pcszFilename)
362{
363 /* Validate input. */
364 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
365 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
366
367 DEBUG_PRINT_FLOW();
368
369 return VERR_NOT_IMPLEMENTED;
370}
371
372static int tarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
373{
374 /* Validate input. */
375 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
376 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
377 AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
378
379 DEBUG_PRINT_FLOW();
380
381 return VERR_NOT_IMPLEMENTED;
382}
383
384static int tarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
385{
386 /* Validate input. */
387 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
388 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
389 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
390
391 DEBUG_PRINT_FLOW();
392
393 return VERR_NOT_IMPLEMENTED;
394}
395
396static int tarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
397{
398 /* Validate input. */
399 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
400 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
401 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
402
403 DEBUG_PRINT_FLOW();
404
405 return VERR_NOT_IMPLEMENTED;
406}
407
408static int tarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
409{
410 /* Validate input. */
411 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
412 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
413
414 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
415
416 DEBUG_PRINT_FLOW();
417
418 return RTTarFileGetSize(pInt->file, pcbSize);
419}
420
421static int tarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
422{
423 /* Validate input. */
424 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
425 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
426
427 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
428
429 DEBUG_PRINT_FLOW();
430
431 return RTTarFileSetSize(pInt->file, cbSize);
432}
433
434static int tarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
435 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
436{
437 /* Validate input. */
438 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
439 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
440
441 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
442
443 DEBUG_PRINT_FLOW();
444
445 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
446}
447
448static int tarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
449 void *pvBuf, size_t cbRead, size_t *pcbRead)
450{
451 /* Validate input. */
452 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
453 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
454
455 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
456
457// DEBUG_PRINT_FLOW();
458
459 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
460}
461
462static int tarFlushSyncCallback(void *pvUser, void *pvStorage)
463{
464 /* Validate input. */
465 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
466 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
467
468 DEBUG_PRINT_FLOW();
469
470 return VERR_NOT_IMPLEMENTED;
471}
472
473/******************************************************************************
474 * Internal: RTSha interface
475 ******************************************************************************/
476
477DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
478{
479 /* Validate input. */
480 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
481
482 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvUser;
483
484 PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
485 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
486
487 int rc = VINF_SUCCESS;
488 bool fLoop = true;
489 while (fLoop)
490 {
491 /* What should we do next? */
492 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
493// RTPrintf("status: %d\n", u32Status);
494 switch (u32Status)
495 {
496 case STATUS_WAIT:
497 {
498 /* Wait for new work. */
499 rc = RTSemEventWait(pInt->newStatusEvent, 100);
500 if ( RT_FAILURE(rc)
501 && rc != VERR_TIMEOUT)
502 fLoop = false;
503 break;
504 }
505 case STATUS_WRITE:
506 {
507 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WRITING, STATUS_WRITE);
508 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
509 size_t cbMemAllRead = 0;
510 /* First loop over all the free memory in the circular
511 * memory buffer (could be turn around at the end). */
512 for (;;)
513 {
514 if ( cbMemAllRead == cbAvail
515 || fLoop == false)
516 break;
517 char *pcBuf;
518 size_t cbMemToRead = cbAvail - cbMemAllRead;
519 size_t cbMemRead = 0;
520 /* Try to acquire all the used space of the circular buffer. */
521 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
522 size_t cbAllWritten = 0;
523 /* Second, write as long as used memory is there. The write
524 * method could also split the writes up into to smaller
525 * parts. */
526 for (;;)
527 {
528 if (cbAllWritten == cbMemRead)
529 break;
530 size_t cbToWrite = cbMemRead - cbAllWritten;
531 size_t cbWritten = 0;
532 rc = vdIfIoFileWriteSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten], cbToWrite, &cbWritten);
533// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
534 if (RT_FAILURE(rc))
535 {
536 fLoop = false;
537 break;
538 }
539 cbAllWritten += cbWritten;
540 pInt->cbCurFile += cbWritten;
541 }
542 /* Update the SHA1/SHA256 context with the next data block. */
543 if ( RT_SUCCESS(rc)
544 && pInt->pShaStorage->fCreateDigest)
545 {
546 if (pInt->pShaStorage->fSha256)
547 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllWritten);
548 else
549 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllWritten);
550 }
551 /* Mark the block as empty. */
552 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
553 cbMemAllRead += cbAllWritten;
554 }
555 /* Reset the thread status and signal the main thread that we
556 * are finished. Use CmpXchg, so we not overwrite other states
557 * which could be signaled in the meantime. */
558 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITING))
559 rc = RTSemEventSignal(pInt->workFinishedEvent);
560 break;
561 }
562 case STATUS_READ:
563 {
564 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
565 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
566 size_t cbMemAllWrite = 0;
567 /* First loop over all the available memory in the circular
568 * memory buffer (could be turn around at the end). */
569 for (;;)
570 {
571 if ( cbMemAllWrite == cbAvail
572 || fLoop == false)
573 break;
574 char *pcBuf;
575 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
576 size_t cbMemWrite = 0;
577 /* Try to acquire all the free space of the circular buffer. */
578 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
579 /* Second, read as long as we filled all the memory. The
580 * read method could also split the reads up into to
581 * smaller parts. */
582 size_t cbAllRead = 0;
583 for (;;)
584 {
585 if (cbAllRead == cbMemWrite)
586 break;
587 size_t cbToRead = cbMemWrite - cbAllRead;
588 size_t cbRead = 0;
589 rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
590// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
591 if (RT_FAILURE(rc))
592 {
593 fLoop = false;
594 break;
595 }
596 /* This indicates end of file. Stop reading. */
597 if (cbRead == 0)
598 {
599 fLoop = false;
600 ASMAtomicWriteBool(&pInt->fEOF, true);
601 break;
602 }
603 cbAllRead += cbRead;
604 pInt->cbCurFile += cbRead;
605 }
606 /* Update the SHA1/SHA256 context with the next data block. */
607 if ( RT_SUCCESS(rc)
608 && pInt->pShaStorage->fCreateDigest)
609 {
610 if (pInt->pShaStorage->fSha256)
611 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
612 else
613 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllRead);
614 }
615 /* Mark the block as full. */
616 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
617 cbMemAllWrite += cbAllRead;
618 }
619 /* Reset the thread status and signal the main thread that we
620 * are finished. Use CmpXchg, so we not overwrite other states
621 * which could be signaled in the meantime. */
622 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
623 rc = RTSemEventSignal(pInt->workFinishedEvent);
624 break;
625 }
626 case STATUS_END:
627 {
628 /* End signaled */
629 fLoop = false;
630 break;
631 }
632 }
633 }
634 /* Cleanup any status changes to indicate we are finished. */
635 ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
636 rc = RTSemEventSignal(pInt->workFinishedEvent);
637 return rc;
638}
639
640DECLINLINE(int) shaSignalManifestThread(PSHASTORAGEINTERNAL pInt, uint32_t uStatus)
641{
642 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
643 return RTSemEventSignal(pInt->newStatusEvent);
644}
645
646DECLINLINE(int) shaWaitForManifestThreadFinished(PSHASTORAGEINTERNAL pInt)
647{
648// RTPrintf("start\n");
649 int rc = VINF_SUCCESS;
650 for (;;)
651 {
652// RTPrintf(" wait\n");
653 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
654 if (!( u32Status == STATUS_WRITE
655 || u32Status == STATUS_WRITING
656 || u32Status == STATUS_READ
657 || u32Status == STATUS_READING))
658 break;
659 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
660 }
661 if (rc == VERR_TIMEOUT)
662 rc = VINF_SUCCESS;
663 return rc;
664}
665
666DECLINLINE(int) shaFlushCurBuf(PSHASTORAGEINTERNAL pInt)
667{
668 int rc = VINF_SUCCESS;
669 if (pInt->fOpenMode & RTFILE_O_WRITE)
670 {
671 /* Let the write worker thread start immediately. */
672 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
673 if (RT_FAILURE(rc))
674 return rc;
675
676 /* Wait until the write worker thread has finished. */
677 rc = shaWaitForManifestThreadFinished(pInt);
678 }
679
680 return rc;
681}
682
683static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
684 PFNVDCOMPLETED pfnCompleted, void **ppInt)
685{
686 /* Validate input. */
687 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
688 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
689 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
690 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
691 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
692
693 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
694 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
695 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
696
697 DEBUG_PRINT_FLOW();
698
699 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL));
700 if (!pInt)
701 return VERR_NO_MEMORY;
702
703 int rc = VINF_SUCCESS;
704 do
705 {
706 pInt->pfnCompleted = pfnCompleted;
707 pInt->pShaStorage = pShaStorage;
708 pInt->fEOF = false;
709 pInt->fOpenMode = fOpen;
710 pInt->u32Status = STATUS_WAIT;
711
712 /* Circular buffer in the read case. */
713 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
714 if (RT_FAILURE(rc))
715 break;
716
717 if (fOpen & RTFILE_O_WRITE)
718 {
719 /* The zero buffer is used for appending empty parts at the end of the
720 * file (or our buffer) in setSize or when uOffset in writeSync is
721 * increased in steps bigger than a byte. */
722 pInt->cbZeroBuf = _1K;
723 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
724 if (!pInt->pvZeroBuf)
725 {
726 rc = VERR_NO_MEMORY;
727 break;
728 }
729 }
730
731 /* Create an event semaphore to indicate a state change for the worker
732 * thread. */
733 rc = RTSemEventCreate(&pInt->newStatusEvent);
734 if (RT_FAILURE(rc))
735 break;
736 /* Create an event semaphore to indicate a finished calculation of the
737 worker thread. */
738 rc = RTSemEventCreate(&pInt->workFinishedEvent);
739 if (RT_FAILURE(rc))
740 break;
741 /* Create the worker thread. */
742 rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA-Worker");
743 if (RT_FAILURE(rc))
744 break;
745
746 if (pShaStorage->fCreateDigest)
747 {
748 /* Create a SHA1/SHA256 context the worker thread will work with. */
749 if (pShaStorage->fSha256)
750 RTSha256Init(&pInt->ctx.Sha256);
751 else
752 RTSha1Init(&pInt->ctx.Sha1);
753 }
754
755 /* Open the file. */
756 rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
757 &pInt->pvStorage);
758 if (RT_FAILURE(rc))
759 break;
760
761 if (fOpen & RTFILE_O_READ)
762 {
763 /* Immediately let the worker thread start the reading. */
764 rc = shaSignalManifestThread(pInt, STATUS_READ);
765 }
766 }
767 while (0);
768
769 if (RT_FAILURE(rc))
770 {
771 if (pInt->pWorkerThread)
772 {
773 shaSignalManifestThread(pInt, STATUS_END);
774 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
775 }
776 if (pInt->workFinishedEvent)
777 RTSemEventDestroy(pInt->workFinishedEvent);
778 if (pInt->newStatusEvent)
779 RTSemEventDestroy(pInt->newStatusEvent);
780 if (pInt->pCircBuf)
781 RTCircBufDestroy(pInt->pCircBuf);
782 if (pInt->pvZeroBuf)
783 RTMemFree(pInt->pvZeroBuf);
784 RTMemFree(pInt);
785 }
786 else
787 *ppInt = pInt;
788
789 return rc;
790}
791
792static int shaCloseCallback(void *pvUser, void *pvStorage)
793{
794 /* Validate input. */
795 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
796 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
797
798 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
799 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
800 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
801
802 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
803
804 DEBUG_PRINT_FLOW();
805
806 int rc = VINF_SUCCESS;
807
808 /* Make sure all pending writes are flushed */
809 rc = shaFlushCurBuf(pInt);
810
811 if (pInt->pWorkerThread)
812 {
813 /* Signal the worker thread to end himself */
814 rc = shaSignalManifestThread(pInt, STATUS_END);
815 /* Worker thread stopped? */
816 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
817 }
818
819 if ( RT_SUCCESS(rc)
820 && pShaStorage->fCreateDigest)
821 {
822 /* Finally calculate & format the SHA1/SHA256 sum */
823 unsigned char auchDig[RTSHA256_HASH_SIZE];
824 char *pszDigest;
825 size_t cbDigest;
826 if (pShaStorage->fSha256)
827 {
828 RTSha256Final(&pInt->ctx.Sha256, auchDig);
829 cbDigest = RTSHA256_DIGEST_LEN;
830 }
831 else
832 {
833 RTSha1Final(&pInt->ctx.Sha1, auchDig);
834 cbDigest = RTSHA1_DIGEST_LEN;
835 }
836 rc = RTStrAllocEx(&pszDigest, cbDigest + 1);
837 if (RT_SUCCESS(rc))
838 {
839 if (pShaStorage->fSha256)
840 rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1);
841 else
842 rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1);
843 if (RT_SUCCESS(rc))
844 pShaStorage->strDigest = pszDigest;
845 RTStrFree(pszDigest);
846 }
847 }
848
849 /* Close the file */
850 rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
851
852// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
853
854 /* Cleanup */
855 if (pInt->workFinishedEvent)
856 RTSemEventDestroy(pInt->workFinishedEvent);
857 if (pInt->newStatusEvent)
858 RTSemEventDestroy(pInt->newStatusEvent);
859 if (pInt->pCircBuf)
860 RTCircBufDestroy(pInt->pCircBuf);
861 if (pInt->pvZeroBuf)
862 RTMemFree(pInt->pvZeroBuf);
863 RTMemFree(pInt);
864
865 return rc;
866}
867
868static int shaDeleteCallback(void *pvUser, const char *pcszFilename)
869{
870 /* Validate input. */
871 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
872
873 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
874 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
875 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
876
877 DEBUG_PRINT_FLOW();
878
879 return vdIfIoFileDelete(pIfIo, pcszFilename);
880}
881
882static int shaMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
883{
884 /* Validate input. */
885 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
886
887 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
888 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
889 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
890
891
892 DEBUG_PRINT_FLOW();
893
894 return vdIfIoFileMove(pIfIo, pcszSrc, pcszDst, fMove);
895}
896
897static int shaGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
898{
899 /* Validate input. */
900 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
901
902 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
903 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
904 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
905
906 DEBUG_PRINT_FLOW();
907
908 return vdIfIoFileGetFreeSpace(pIfIo, pcszFilename, pcbFreeSpace);
909}
910
911static int shaGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
912{
913 /* Validate input. */
914 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
915
916 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
917 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
918 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
919
920 DEBUG_PRINT_FLOW();
921
922 return vdIfIoFileGetModificationTime(pIfIo, pcszFilename, pModificationTime);
923}
924
925
926static int shaGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
927{
928 /* Validate input. */
929 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
930 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
931
932 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
933 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
934 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
935
936 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
937
938 DEBUG_PRINT_FLOW();
939
940 uint64_t cbSize;
941 int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
942 if (RT_FAILURE(rc))
943 return rc;
944
945 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
946
947 return VINF_SUCCESS;
948}
949
950static int shaSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
951{
952 /* Validate input. */
953 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
954 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
955
956 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
957 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
958 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
959
960 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
961
962 DEBUG_PRINT_FLOW();
963
964 return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
965}
966
967static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
968 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
969{
970 /* Validate input. */
971 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
972 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
973
974 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
975 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
976 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
977
978 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
979
980 DEBUG_PRINT_FLOW();
981
982 /* Check that the write is linear */
983 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
984
985 int rc = VINF_SUCCESS;
986
987 /* Check if we have to add some free space at the end, before we start the
988 * real write. */
989 if (pInt->cbCurAll < uOffset)
990 {
991 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
992 size_t cbAllWritten = 0;
993 for (;;)
994 {
995 /* Finished? */
996 if (cbAllWritten == cbSize)
997 break;
998 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
999 size_t cbWritten = 0;
1000 rc = shaWriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
1001 pInt->pvZeroBuf, cbToWrite, &cbWritten);
1002 if (RT_FAILURE(rc))
1003 break;
1004 cbAllWritten += cbWritten;
1005 }
1006 if (RT_FAILURE(rc))
1007 return rc;
1008 }
1009// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
1010
1011 size_t cbAllWritten = 0;
1012 for (;;)
1013 {
1014 /* Finished? */
1015 if (cbAllWritten == cbWrite)
1016 break;
1017 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1018 if ( cbAvail == 0
1019 && pInt->fEOF)
1020 return VERR_EOF;
1021 /* If there isn't enough free space make sure the worker thread is
1022 * writing some data. */
1023 if ((cbWrite - cbAllWritten) > cbAvail)
1024 {
1025 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1026 if (RT_FAILURE(rc))
1027 break;
1028 /* If there is _no_ free space available, we have to wait until it is. */
1029 if (cbAvail == 0)
1030 {
1031 rc = shaWaitForManifestThreadFinished(pInt);
1032 if (RT_FAILURE(rc))
1033 break;
1034 cbAvail = RTCircBufFree(pInt->pCircBuf);
1035// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1036// pInt->waits++;
1037 }
1038 }
1039 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1040 char *pcBuf;
1041 size_t cbMemWritten = 0;
1042 /* Acquire a block for writing from our circular buffer. */
1043 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1044 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1045 /* Mark the block full. */
1046 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1047 cbAllWritten += cbMemWritten;
1048 pInt->cbCurAll += cbMemWritten;
1049 }
1050
1051 if (pcbWritten)
1052 *pcbWritten = cbAllWritten;
1053
1054 /* Signal the thread to write more data in the mean time. */
1055 if ( RT_SUCCESS(rc)
1056 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1057 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1058
1059 return rc;
1060}
1061
1062static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1063 void *pvBuf, size_t cbRead, size_t *pcbRead)
1064{
1065 /* Validate input. */
1066 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1067 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1068
1069 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1070 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1071 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1072
1073// DEBUG_PRINT_FLOW();
1074
1075 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1076
1077 int rc = VINF_SUCCESS;
1078
1079// pInt->calls++;
1080// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1081
1082 /* Check if we jump forward in the file. If so we have to read the
1083 * remaining stuff in the gap anyway (SHA1/SHA256; streaming). */
1084 if (pInt->cbCurAll < uOffset)
1085 {
1086 rc = shaReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1087 (size_t)(uOffset - pInt->cbCurAll), 0);
1088 if (RT_FAILURE(rc))
1089 return rc;
1090// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1091 }
1092 else if (uOffset < pInt->cbCurAll)
1093 AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
1094
1095 size_t cbAllRead = 0;
1096 size_t cbAvail = 0;
1097 for (;;)
1098 {
1099 /* Finished? */
1100 if (cbAllRead == cbRead)
1101 break;
1102
1103 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1104
1105 if ( cbAvail == 0
1106 && pInt->fEOF
1107 && !RTCircBufIsWriting(pInt->pCircBuf))
1108 {
1109 rc = VINF_EOF;
1110 break;
1111 }
1112
1113 /* If there isn't enough data make sure the worker thread is fetching
1114 * more. */
1115 if ((cbRead - cbAllRead) > cbAvail)
1116 {
1117 rc = shaSignalManifestThread(pInt, STATUS_READ);
1118 if (RT_FAILURE(rc))
1119 break;
1120 /* If there is _no_ data available, we have to wait until it is. */
1121 if (cbAvail == 0)
1122 {
1123 rc = shaWaitForManifestThreadFinished(pInt);
1124 if (RT_FAILURE(rc))
1125 break;
1126 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1127// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1128// pInt->waits++;
1129 }
1130 }
1131 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1132 char *pcBuf;
1133 size_t cbMemRead = 0;
1134 /* Acquire a block for reading from our circular buffer. */
1135 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1136 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1137 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1138 /* Mark the block as empty again. */
1139 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1140 cbAllRead += cbMemRead;
1141
1142 pInt->cbCurAll += cbMemRead;
1143 }
1144
1145 if (pcbRead)
1146 *pcbRead = cbAllRead;
1147
1148 if (rc == VERR_EOF)
1149 rc = VINF_SUCCESS;
1150
1151 /* Signal the thread to read more data in the mean time. */
1152 if ( RT_SUCCESS(rc)
1153 && rc != VINF_EOF
1154 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1155 rc = shaSignalManifestThread(pInt, STATUS_READ);
1156
1157 return rc;
1158}
1159
1160static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1161{
1162 /* Validate input. */
1163 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1164 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1165
1166 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1167 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1168 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1169
1170 DEBUG_PRINT_FLOW();
1171
1172 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1173
1174 /* Check if there is still something in the buffer. If yes, flush it. */
1175 int rc = shaFlushCurBuf(pInt);
1176 if (RT_FAILURE(rc))
1177 return rc;
1178
1179 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1180}
1181
1182PVDINTERFACEIO ShaCreateInterface()
1183{
1184 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1185 if (!pCallbacks)
1186 return NULL;
1187
1188 pCallbacks->pfnOpen = shaOpenCallback;
1189 pCallbacks->pfnClose = shaCloseCallback;
1190 pCallbacks->pfnDelete = shaDeleteCallback;
1191 pCallbacks->pfnMove = shaMoveCallback;
1192 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1193 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1194 pCallbacks->pfnGetSize = shaGetSizeCallback;
1195 pCallbacks->pfnSetSize = shaSetSizeCallback;
1196 pCallbacks->pfnReadSync = shaReadSyncCallback;
1197 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1198 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1199
1200 return pCallbacks;
1201}
1202
1203PVDINTERFACEIO FileCreateInterface()
1204{
1205 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1206 if (!pCallbacks)
1207 return NULL;
1208
1209 pCallbacks->pfnOpen = fileOpenCallback;
1210 pCallbacks->pfnClose = fileCloseCallback;
1211 pCallbacks->pfnDelete = fileDeleteCallback;
1212 pCallbacks->pfnMove = fileMoveCallback;
1213 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1214 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1215 pCallbacks->pfnGetSize = fileGetSizeCallback;
1216 pCallbacks->pfnSetSize = fileSetSizeCallback;
1217 pCallbacks->pfnReadSync = fileReadSyncCallback;
1218 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1219 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1220
1221 return pCallbacks;
1222}
1223
1224PVDINTERFACEIO TarCreateInterface()
1225{
1226 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1227 if (!pCallbacks)
1228 return NULL;
1229
1230 pCallbacks->pfnOpen = tarOpenCallback;
1231 pCallbacks->pfnClose = tarCloseCallback;
1232 pCallbacks->pfnDelete = tarDeleteCallback;
1233 pCallbacks->pfnMove = tarMoveCallback;
1234 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1235 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1236 pCallbacks->pfnGetSize = tarGetSizeCallback;
1237 pCallbacks->pfnSetSize = tarSetSizeCallback;
1238 pCallbacks->pfnReadSync = tarReadSyncCallback;
1239 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1240 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1241
1242 return pCallbacks;
1243}
1244
1245int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1246{
1247 /* Validate input. */
1248 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1249 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1250 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1251
1252 void *pvStorage;
1253 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1254 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1255 &pvStorage);
1256 if (RT_FAILURE(rc))
1257 return rc;
1258
1259 void *pvTmpBuf = 0;
1260 void *pvBuf = 0;
1261 uint64_t cbTmpSize = _1M;
1262 size_t cbAllRead = 0;
1263 do
1264 {
1265 pvTmpBuf = RTMemAlloc(cbTmpSize);
1266 if (!pvTmpBuf)
1267 {
1268 rc = VERR_NO_MEMORY;
1269 break;
1270 }
1271
1272 for (;;)
1273 {
1274 size_t cbRead = 0;
1275 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1276 if ( RT_FAILURE(rc)
1277 || cbRead == 0)
1278 break;
1279 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1280 if (!pvBuf)
1281 {
1282 rc = VERR_NO_MEMORY;
1283 break;
1284 }
1285 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1286 cbAllRead += cbRead;
1287 }
1288 } while (0);
1289
1290 pIfIo->pfnClose(pvUser, pvStorage);
1291
1292 if (rc == VERR_EOF)
1293 rc = VINF_SUCCESS;
1294
1295 if (pvTmpBuf)
1296 RTMemFree(pvTmpBuf);
1297
1298 if (RT_SUCCESS(rc))
1299 {
1300 *ppvBuf = pvBuf;
1301 *pcbSize = cbAllRead;
1302 }
1303 else
1304 {
1305 if (pvBuf)
1306 RTMemFree(pvBuf);
1307 }
1308
1309 return rc;
1310}
1311
1312int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1313{
1314 /* Validate input. */
1315 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1316 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1317 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1318
1319 void *pvStorage;
1320 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1321 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1322 &pvStorage);
1323 if (RT_FAILURE(rc))
1324 return rc;
1325
1326 size_t cbAllWritten = 0;
1327 for (;;)
1328 {
1329 if (cbAllWritten >= cbSize)
1330 break;
1331 size_t cbToWrite = cbSize - cbAllWritten;
1332 size_t cbWritten = 0;
1333 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1334 if (RT_FAILURE(rc))
1335 break;
1336 cbAllWritten += cbWritten;
1337 }
1338
1339 rc = pIfIo->pfnClose(pvUser, pvStorage);
1340
1341 return rc;
1342}
1343
1344int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
1345{
1346 /* Validate input. */
1347 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1348
1349 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1350 /*
1351 * Open the source file.
1352 */
1353 void *pvStorage;
1354 int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
1355 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1356 &pvStorage);
1357 if (RT_FAILURE(rc))
1358 return rc;
1359
1360 /* Turn the source file handle/whatever into a VFS stream. */
1361 RTVFSIOSTREAM hVfsIosCompressedSrc;
1362
1363 rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosCompressedSrc);
1364 if (RT_SUCCESS(rc))
1365 {
1366 /* Pass the source thru gunzip. */
1367 RTVFSIOSTREAM hVfsIosSrc;
1368 rc = RTZipGzipDecompressIoStream(hVfsIosCompressedSrc, 0, &hVfsIosSrc);
1369 if (RT_SUCCESS(rc))
1370 {
1371 /*
1372 * Create the output file, including necessary paths.
1373 * Any existing file will be overwritten.
1374 */
1375 rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true /*fCreate*/);
1376 if (RT_SUCCESS(rc))
1377 {
1378 RTVFSIOSTREAM hVfsIosDst;
1379 rc = RTVfsIoStrmOpenNormal(pcszFullFilenameOut,
1380 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
1381 &hVfsIosDst);
1382 if (RT_SUCCESS(rc))
1383 {
1384 /*
1385 * Pump the bytes thru. If we fail, delete the output file.
1386 */
1387 RTMANIFEST hFileManifest = NIL_RTMANIFEST;
1388 rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
1389 if (RT_SUCCESS(rc))
1390 {
1391 RTVFSIOSTREAM hVfsIosMfst;
1392
1393 uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
1394
1395 rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
1396 hVfsIosSrc,
1397 "ovf import",
1398 digestType,
1399 true /*read*/, &hVfsIosMfst);
1400 if (RT_SUCCESS(rc))
1401 {
1402 rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
1403 }
1404
1405 RTVfsIoStrmRelease(hVfsIosMfst);
1406 }
1407
1408 RTVfsIoStrmRelease(hVfsIosDst);
1409 }
1410 }
1411
1412 RTVfsIoStrmRelease(hVfsIosSrc);
1413 }
1414 }
1415 pIfIo->pfnClose(pvUser, pvStorage);
1416
1417 return rc;
1418}
1419
1420int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser)
1421{
1422 /* Validate input. */
1423 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1424
1425 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1426 void *pvStorage;
1427
1428 int rc = pIfIo->pfnOpen(pvUser, pcszSourceFilename,
1429 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1430 &pvStorage);
1431 if (RT_FAILURE(rc))
1432 return rc;
1433
1434 /* Turn the source file handle/whatever into a VFS stream. */
1435 RTVFSIOSTREAM hVfsIosSrc;
1436
1437 rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosSrc);
1438 if (RT_SUCCESS(rc))
1439 {
1440 /*
1441 * Create the output file, including necessary paths.
1442 * Any existing file will be overwritten.
1443 */
1444 rc = VirtualBox::ensureFilePathExists(Utf8Str(pcszTargetFilename), true /*fCreate*/);
1445 if (RT_SUCCESS(rc))
1446 {
1447 RTVFSIOSTREAM hVfsIosDst;
1448 rc = RTVfsIoStrmOpenNormal(pcszTargetFilename,
1449 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
1450 &hVfsIosDst);
1451 if (RT_SUCCESS(rc))
1452 {
1453 /*
1454 * Pump the bytes thru. If we fail, delete the output file.
1455 */
1456 RTMANIFEST hFileManifest = NIL_RTMANIFEST;
1457 rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
1458 if (RT_SUCCESS(rc))
1459 {
1460 RTVFSIOSTREAM hVfsIosMfst;
1461
1462 uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
1463
1464 rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
1465 hVfsIosSrc,
1466 "ovf import",
1467 digestType,
1468 true /*read*/, &hVfsIosMfst);
1469 if (RT_SUCCESS(rc))
1470 {
1471 rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
1472 }
1473
1474 RTVfsIoStrmRelease(hVfsIosMfst);
1475 }
1476
1477 RTVfsIoStrmRelease(hVfsIosDst);
1478 }
1479 }
1480
1481 RTVfsIoStrmRelease(hVfsIosSrc);
1482
1483 }
1484
1485 pIfIo->pfnClose(pvUser, pvStorage);
1486 return rc;
1487}
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