VirtualBox

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

Last change on this file since 56459 was 56307, checked in by vboxsync, 10 years ago

Main/Appliance: fixed reference counting

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