VirtualBox

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

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

6813 src-client/MachineDebuggerImpl.cpp + various formatting changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.6 KB
Line 
1/* $Id: ApplianceImplIO.cpp 51092 2014-04-16 17:57:25Z 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 pThis->CoreIo.pfnOpen = fssRdOnly_Open;
664 pThis->CoreIo.pfnClose = fssRdOnly_Close;
665 pThis->CoreIo.pfnDelete = notImpl_Delete;
666 pThis->CoreIo.pfnMove = notImpl_Move;
667 pThis->CoreIo.pfnGetFreeSpace = notImpl_GetFreeSpace;
668 pThis->CoreIo.pfnGetModificationTime = notImpl_GetModificationTime;
669 pThis->CoreIo.pfnGetSize = fssRdOnly_GetSize;
670 pThis->CoreIo.pfnSetSize = notImpl_SetSize;
671 pThis->CoreIo.pfnReadSync = fssRdOnly_ReadSync;
672 pThis->CoreIo.pfnWriteSync = notImpl_WriteSync;
673 pThis->CoreIo.pfnFlushSync = notImpl_FlushSync;
674
675 pThis->hVfsFss = hVfsFss;
676 pThis->fEndOfFss = false;
677 pThis->hVfsCurObj = NIL_RTVFSOBJ;
678 pThis->pszCurName = NULL;
679 pThis->enmCurType = RTVFSOBJTYPE_INVALID;
680
681 *ppTarIo = pThis;
682 return VINF_SUCCESS;
683 }
684
685 RTVfsFsStrmRelease(hVfsFss);
686 }
687 RTVfsIoStrmRelease(hVfsIos);
688 RTVfsFileRelease(hVfsFile);
689 }
690
691 *ppTarIo = NULL;
692 return rc;
693}
694
695/**
696 * Destroys a read-only FSS interface.
697 *
698 * @param pFssIo What TarFssCreateReadOnlyInterfaceForFile
699 * returned.
700 */
701void fssRdOnlyDestroyInterface(PFSSRDONLYINTERFACEIO pFssIo)
702{
703 AssertPtr(pFssIo); AssertPtr(pFssIo->hVfsFss);
704
705 RTVfsFsStrmRelease(pFssIo->hVfsFss);
706 pFssIo->hVfsFss = NIL_RTVFSFSSTREAM;
707
708 RTVfsObjRelease(pFssIo->hVfsCurObj);
709 pFssIo->hVfsCurObj = NIL_RTVFSOBJ;
710
711 RTStrFree(pFssIo->pszCurName);
712 pFssIo->pszCurName = NULL;
713
714 RTMemFree(pFssIo);
715}
716
717
718/**
719 * Returns the read-only name of the current stream object.
720 *
721 * @returns VBox status code.
722 * @param pFssIo What TarFssCreateReadOnlyInterfaceForFile
723 * returned.
724 * @param ppszName Where to return the filename. DO NOT FREE!
725 */
726int fssRdOnlyGetCurrentName(PFSSRDONLYINTERFACEIO pFssIo, const char **ppszName)
727{
728 AssertPtr(pFssIo); AssertPtr(pFssIo->hVfsFss);
729
730 if (pFssIo->hVfsCurObj == NIL_RTVFSOBJ)
731 {
732 if (pFssIo->fEndOfFss)
733 return VERR_EOF;
734 int rc = RTVfsFsStrmNext(pFssIo->hVfsFss, &pFssIo->pszCurName, &pFssIo->enmCurType, &pFssIo->hVfsCurObj);
735 if (RT_FAILURE(rc))
736 {
737 pFssIo->fEndOfFss = rc == VERR_EOF;
738 *ppszName = NULL;
739 return rc;
740 }
741 }
742
743 *ppszName = pFssIo->pszCurName;
744 return VINF_SUCCESS;
745}
746
747
748/**
749 * Skips the current object.
750 *
751 * @returns VBox status code.
752 * @param pFssIo What TarFssCreateReadOnlyInterfaceForFile
753 * returned.
754 */
755int fssRdOnlySkipCurrent(PFSSRDONLYINTERFACEIO pFssIo)
756{
757 AssertPtr(pFssIo); AssertPtr(pFssIo->hVfsFss);
758
759 if (pFssIo->hVfsCurObj == NIL_RTVFSOBJ)
760 {
761 if (pFssIo->fEndOfFss)
762 return VERR_EOF;
763 int rc = RTVfsFsStrmNext(pFssIo->hVfsFss, &pFssIo->pszCurName, &pFssIo->enmCurType, &pFssIo->hVfsCurObj);
764 if (RT_FAILURE(rc))
765 {
766 pFssIo->fEndOfFss = rc == VERR_EOF;
767 return rc;
768 }
769 }
770
771 /* Force a RTVfsFsStrmNext call the next time around. */
772 RTVfsObjRelease(pFssIo->hVfsCurObj);
773 pFssIo->hVfsCurObj = NIL_RTVFSOBJ;
774
775 RTStrFree(pFssIo->pszCurName);
776 pFssIo->pszCurName = NULL;
777
778 return VINF_SUCCESS;
779}
780
781
782/**
783 * Checks if the current file is a directory.
784 *
785 * @returns true if directory, false if not (or error).
786 * @param pFssIo What TarFssCreateReadOnlyInterfaceForFile
787 * returned.
788 */
789bool fssRdOnlyIsCurrentDirectory(PFSSRDONLYINTERFACEIO pFssIo)
790{
791 AssertPtr(pFssIo); AssertPtr(pFssIo->hVfsFss);
792
793 if (pFssIo->hVfsCurObj == NIL_RTVFSOBJ)
794 {
795 if (pFssIo->fEndOfFss)
796 return false;
797 int rc = RTVfsFsStrmNext(pFssIo->hVfsFss, &pFssIo->pszCurName, &pFssIo->enmCurType, &pFssIo->hVfsCurObj);
798 if (RT_FAILURE(rc))
799 {
800 pFssIo->fEndOfFss = rc == VERR_EOF;
801 return false;
802 }
803 }
804
805 return pFssIo->enmCurType == RTVFSOBJTYPE_DIR;
806}
807
808
809
810/** @} */
811
812
813/******************************************************************************
814 * Internal: RTSha interface
815 ******************************************************************************/
816
817DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
818{
819 /* Validate input. */
820 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
821
822 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvUser;
823
824 PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
825 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
826
827 int rc = VINF_SUCCESS;
828 bool fLoop = true;
829 while (fLoop)
830 {
831 /* What should we do next? */
832 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
833// RTPrintf("status: %d\n", u32Status);
834 switch (u32Status)
835 {
836 case STATUS_WAIT:
837 {
838 /* Wait for new work. */
839 rc = RTSemEventWait(pInt->newStatusEvent, 100);
840 if ( RT_FAILURE(rc)
841 && rc != VERR_TIMEOUT)
842 fLoop = false;
843 break;
844 }
845 case STATUS_WRITE:
846 {
847 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WRITING, STATUS_WRITE);
848 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
849 size_t cbMemAllRead = 0;
850 /* First loop over all the free memory in the circular
851 * memory buffer (could be turn around at the end). */
852 for (;;)
853 {
854 if ( cbMemAllRead == cbAvail
855 || fLoop == false)
856 break;
857 char *pcBuf;
858 size_t cbMemToRead = cbAvail - cbMemAllRead;
859 size_t cbMemRead = 0;
860 /* Try to acquire all the used space of the circular buffer. */
861 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
862 size_t cbAllWritten = 0;
863 /* Second, write as long as used memory is there. The write
864 * method could also split the writes up into to smaller
865 * parts. */
866 for (;;)
867 {
868 if (cbAllWritten == cbMemRead)
869 break;
870 size_t cbToWrite = cbMemRead - cbAllWritten;
871 size_t cbWritten = 0;
872 rc = vdIfIoFileWriteSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten],
873 cbToWrite, &cbWritten);
874// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
875 if (RT_FAILURE(rc))
876 {
877 fLoop = false;
878 break;
879 }
880 cbAllWritten += cbWritten;
881 pInt->cbCurFile += cbWritten;
882 }
883 /* Update the SHA1/SHA256 context with the next data block. */
884 if ( RT_SUCCESS(rc)
885 && pInt->pShaStorage->fCreateDigest)
886 {
887 if (pInt->pShaStorage->fSha256)
888 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllWritten);
889 else
890 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllWritten);
891 }
892 /* Mark the block as empty. */
893 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
894 cbMemAllRead += cbAllWritten;
895 }
896 /* Reset the thread status and signal the main thread that we
897 * are finished. Use CmpXchg, so we not overwrite other states
898 * which could be signaled in the meantime. */
899 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITING))
900 rc = RTSemEventSignal(pInt->workFinishedEvent);
901 break;
902 }
903 case STATUS_READ:
904 {
905 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
906 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
907 size_t cbMemAllWrite = 0;
908 /* First loop over all the available memory in the circular
909 * memory buffer (could be turn around at the end). */
910 for (;;)
911 {
912 if ( cbMemAllWrite == cbAvail
913 || fLoop == false)
914 break;
915 char *pcBuf;
916 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
917 size_t cbMemWrite = 0;
918 /* Try to acquire all the free space of the circular buffer. */
919 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
920 /* Second, read as long as we filled all the memory. The
921 * read method could also split the reads up into to
922 * smaller parts. */
923 size_t cbAllRead = 0;
924 for (;;)
925 {
926 if (cbAllRead == cbMemWrite)
927 break;
928 size_t cbToRead = cbMemWrite - cbAllRead;
929 size_t cbRead = 0;
930 rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
931// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
932 if (RT_FAILURE(rc))
933 {
934 fLoop = false;
935 break;
936 }
937 /* This indicates end of file. Stop reading. */
938 if (cbRead == 0)
939 {
940 fLoop = false;
941 ASMAtomicWriteBool(&pInt->fEOF, true);
942 break;
943 }
944 cbAllRead += cbRead;
945 pInt->cbCurFile += cbRead;
946 }
947 /* Update the SHA1/SHA256 context with the next data block. */
948 if ( RT_SUCCESS(rc)
949 && pInt->pShaStorage->fCreateDigest)
950 {
951 if (pInt->pShaStorage->fSha256)
952 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
953 else
954 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllRead);
955 }
956 /* Mark the block as full. */
957 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
958 cbMemAllWrite += cbAllRead;
959 }
960 /* Reset the thread status and signal the main thread that we
961 * are finished. Use CmpXchg, so we not overwrite other states
962 * which could be signaled in the meantime. */
963 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
964 rc = RTSemEventSignal(pInt->workFinishedEvent);
965 break;
966 }
967 case STATUS_END:
968 {
969 /* End signaled */
970 fLoop = false;
971 break;
972 }
973 }
974 }
975 /* Cleanup any status changes to indicate we are finished. */
976 ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
977 rc = RTSemEventSignal(pInt->workFinishedEvent);
978 return rc;
979}
980
981DECLINLINE(int) shaSignalManifestThread(PSHASTORAGEINTERNAL pInt, uint32_t uStatus)
982{
983 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
984 return RTSemEventSignal(pInt->newStatusEvent);
985}
986
987DECLINLINE(int) shaWaitForManifestThreadFinished(PSHASTORAGEINTERNAL pInt)
988{
989// RTPrintf("start\n");
990 int rc = VINF_SUCCESS;
991 for (;;)
992 {
993// RTPrintf(" wait\n");
994 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
995 if (!( u32Status == STATUS_WRITE
996 || u32Status == STATUS_WRITING
997 || u32Status == STATUS_READ
998 || u32Status == STATUS_READING))
999 break;
1000 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
1001 }
1002 if (rc == VERR_TIMEOUT)
1003 rc = VINF_SUCCESS;
1004 return rc;
1005}
1006
1007DECLINLINE(int) shaFlushCurBuf(PSHASTORAGEINTERNAL pInt)
1008{
1009 int rc = VINF_SUCCESS;
1010 if (pInt->fOpenMode & RTFILE_O_WRITE)
1011 {
1012 /* Let the write worker thread start immediately. */
1013 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1014 if (RT_FAILURE(rc))
1015 return rc;
1016
1017 /* Wait until the write worker thread has finished. */
1018 rc = shaWaitForManifestThreadFinished(pInt);
1019 }
1020
1021 return rc;
1022}
1023
1024static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
1025 PFNVDCOMPLETED pfnCompleted, void **ppInt)
1026{
1027 /* Validate input. */
1028 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
1029 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
1030 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
1031 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
1032 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
1033
1034 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1035 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1036 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1037
1038 DEBUG_PRINT_FLOW();
1039
1040 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL));
1041 if (!pInt)
1042 return VERR_NO_MEMORY;
1043
1044 int rc = VINF_SUCCESS;
1045 do
1046 {
1047 pInt->pfnCompleted = pfnCompleted;
1048 pInt->pShaStorage = pShaStorage;
1049 pInt->fEOF = false;
1050 pInt->fOpenMode = fOpen;
1051 pInt->u32Status = STATUS_WAIT;
1052
1053 /* Circular buffer in the read case. */
1054 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
1055 if (RT_FAILURE(rc))
1056 break;
1057
1058 if (fOpen & RTFILE_O_WRITE)
1059 {
1060 /* The zero buffer is used for appending empty parts at the end of the
1061 * file (or our buffer) in setSize or when uOffset in writeSync is
1062 * increased in steps bigger than a byte. */
1063 pInt->cbZeroBuf = _1K;
1064 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
1065 if (!pInt->pvZeroBuf)
1066 {
1067 rc = VERR_NO_MEMORY;
1068 break;
1069 }
1070 }
1071
1072 /* Create an event semaphore to indicate a state change for the worker
1073 * thread. */
1074 rc = RTSemEventCreate(&pInt->newStatusEvent);
1075 if (RT_FAILURE(rc))
1076 break;
1077 /* Create an event semaphore to indicate a finished calculation of the
1078 worker thread. */
1079 rc = RTSemEventCreate(&pInt->workFinishedEvent);
1080 if (RT_FAILURE(rc))
1081 break;
1082 /* Create the worker thread. */
1083 rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER,
1084 RTTHREADFLAGS_WAITABLE, "SHA-Worker");
1085 if (RT_FAILURE(rc))
1086 break;
1087
1088 if (pShaStorage->fCreateDigest)
1089 {
1090 /* Create a SHA1/SHA256 context the worker thread will work with. */
1091 if (pShaStorage->fSha256)
1092 RTSha256Init(&pInt->ctx.Sha256);
1093 else
1094 RTSha1Init(&pInt->ctx.Sha1);
1095 }
1096
1097 /* Open the file. */
1098 rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
1099 &pInt->pvStorage);
1100 if (RT_FAILURE(rc))
1101 break;
1102
1103 if (fOpen & RTFILE_O_READ)
1104 {
1105 /* Immediately let the worker thread start the reading. */
1106 rc = shaSignalManifestThread(pInt, STATUS_READ);
1107 }
1108 }
1109 while (0);
1110
1111 if (RT_FAILURE(rc))
1112 {
1113 if (pInt->pWorkerThread)
1114 {
1115 shaSignalManifestThread(pInt, STATUS_END);
1116 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
1117 }
1118 if (pInt->workFinishedEvent)
1119 RTSemEventDestroy(pInt->workFinishedEvent);
1120 if (pInt->newStatusEvent)
1121 RTSemEventDestroy(pInt->newStatusEvent);
1122 if (pInt->pCircBuf)
1123 RTCircBufDestroy(pInt->pCircBuf);
1124 if (pInt->pvZeroBuf)
1125 RTMemFree(pInt->pvZeroBuf);
1126 RTMemFree(pInt);
1127 }
1128 else
1129 *ppInt = pInt;
1130
1131 return rc;
1132}
1133
1134static int shaCloseCallback(void *pvUser, void *pvStorage)
1135{
1136 /* Validate input. */
1137 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1138 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1139
1140 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1141 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1142 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1143
1144 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1145
1146 DEBUG_PRINT_FLOW();
1147
1148 int rc = VINF_SUCCESS;
1149
1150 /* Make sure all pending writes are flushed */
1151 rc = shaFlushCurBuf(pInt);
1152
1153 if (pInt->pWorkerThread)
1154 {
1155 /* Signal the worker thread to end himself */
1156 rc = shaSignalManifestThread(pInt, STATUS_END);
1157 /* Worker thread stopped? */
1158 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
1159 }
1160
1161 if ( RT_SUCCESS(rc)
1162 && pShaStorage->fCreateDigest)
1163 {
1164 /* Finally calculate & format the SHA1/SHA256 sum */
1165 unsigned char auchDig[RTSHA256_HASH_SIZE];
1166 char *pszDigest;
1167 size_t cbDigest;
1168 if (pShaStorage->fSha256)
1169 {
1170 RTSha256Final(&pInt->ctx.Sha256, auchDig);
1171 cbDigest = RTSHA256_DIGEST_LEN;
1172 }
1173 else
1174 {
1175 RTSha1Final(&pInt->ctx.Sha1, auchDig);
1176 cbDigest = RTSHA1_DIGEST_LEN;
1177 }
1178 rc = RTStrAllocEx(&pszDigest, cbDigest + 1);
1179 if (RT_SUCCESS(rc))
1180 {
1181 if (pShaStorage->fSha256)
1182 rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1);
1183 else
1184 rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1);
1185 if (RT_SUCCESS(rc))
1186 pShaStorage->strDigest = pszDigest;
1187 RTStrFree(pszDigest);
1188 }
1189 }
1190
1191 /* Close the file */
1192 rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
1193
1194// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
1195
1196 /* Cleanup */
1197 if (pInt->workFinishedEvent)
1198 RTSemEventDestroy(pInt->workFinishedEvent);
1199 if (pInt->newStatusEvent)
1200 RTSemEventDestroy(pInt->newStatusEvent);
1201 if (pInt->pCircBuf)
1202 RTCircBufDestroy(pInt->pCircBuf);
1203 if (pInt->pvZeroBuf)
1204 RTMemFree(pInt->pvZeroBuf);
1205 RTMemFree(pInt);
1206
1207 return rc;
1208}
1209
1210static int shaDeleteCallback(void *pvUser, const char *pcszFilename)
1211{
1212 /* Validate input. */
1213 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1214
1215 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1216 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1217 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1218
1219 DEBUG_PRINT_FLOW();
1220
1221 return vdIfIoFileDelete(pIfIo, pcszFilename);
1222}
1223
1224static int shaMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
1225{
1226 /* Validate input. */
1227 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1228
1229 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1230 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1231 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1232
1233
1234 DEBUG_PRINT_FLOW();
1235
1236 return vdIfIoFileMove(pIfIo, pcszSrc, pcszDst, fMove);
1237}
1238
1239static int shaGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
1240{
1241 /* Validate input. */
1242 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1243
1244 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1245 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1246 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1247
1248 DEBUG_PRINT_FLOW();
1249
1250 return vdIfIoFileGetFreeSpace(pIfIo, pcszFilename, pcbFreeSpace);
1251}
1252
1253static int shaGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
1254{
1255 /* Validate input. */
1256 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1257
1258 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1259 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1260 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1261
1262 DEBUG_PRINT_FLOW();
1263
1264 return vdIfIoFileGetModificationTime(pIfIo, pcszFilename, pModificationTime);
1265}
1266
1267
1268static int shaGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
1269{
1270 /* Validate input. */
1271 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1272 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1273
1274 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1275 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1276 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1277
1278 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1279
1280 DEBUG_PRINT_FLOW();
1281
1282 uint64_t cbSize;
1283 int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
1284 if (RT_FAILURE(rc))
1285 return rc;
1286
1287 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
1288
1289 return VINF_SUCCESS;
1290}
1291
1292static int shaSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
1293{
1294 /* Validate input. */
1295 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1296 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1297
1298 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1299 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1300 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1301
1302 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1303
1304 DEBUG_PRINT_FLOW();
1305
1306 return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
1307}
1308
1309static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1310 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
1311{
1312 /* Validate input. */
1313 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1314 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1315
1316 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1317 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1318 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1319
1320 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1321
1322 DEBUG_PRINT_FLOW();
1323
1324 /* Check that the write is linear */
1325 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!",
1326 uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
1327
1328 int rc = VINF_SUCCESS;
1329
1330 /* Check if we have to add some free space at the end, before we start the
1331 * real write. */
1332 if (pInt->cbCurAll < uOffset)
1333 {
1334 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
1335 size_t cbAllWritten = 0;
1336 for (;;)
1337 {
1338 /* Finished? */
1339 if (cbAllWritten == cbSize)
1340 break;
1341 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
1342 size_t cbWritten = 0;
1343 rc = shaWriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
1344 pInt->pvZeroBuf, cbToWrite, &cbWritten);
1345 if (RT_FAILURE(rc))
1346 break;
1347 cbAllWritten += cbWritten;
1348 }
1349 if (RT_FAILURE(rc))
1350 return rc;
1351 }
1352// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
1353
1354 size_t cbAllWritten = 0;
1355 for (;;)
1356 {
1357 /* Finished? */
1358 if (cbAllWritten == cbWrite)
1359 break;
1360 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1361 if ( cbAvail == 0
1362 && pInt->fEOF)
1363 return VERR_EOF;
1364 /* If there isn't enough free space make sure the worker thread is
1365 * writing some data. */
1366 if ((cbWrite - cbAllWritten) > cbAvail)
1367 {
1368 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1369 if (RT_FAILURE(rc))
1370 break;
1371 /* If there is _no_ free space available, we have to wait until it is. */
1372 if (cbAvail == 0)
1373 {
1374 rc = shaWaitForManifestThreadFinished(pInt);
1375 if (RT_FAILURE(rc))
1376 break;
1377 cbAvail = RTCircBufFree(pInt->pCircBuf);
1378// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1379// pInt->waits++;
1380 }
1381 }
1382 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1383 char *pcBuf;
1384 size_t cbMemWritten = 0;
1385 /* Acquire a block for writing from our circular buffer. */
1386 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1387 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1388 /* Mark the block full. */
1389 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1390 cbAllWritten += cbMemWritten;
1391 pInt->cbCurAll += cbMemWritten;
1392 }
1393
1394 if (pcbWritten)
1395 *pcbWritten = cbAllWritten;
1396
1397 /* Signal the thread to write more data in the mean time. */
1398 if ( RT_SUCCESS(rc)
1399 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1400 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1401
1402 return rc;
1403}
1404
1405static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1406 void *pvBuf, size_t cbRead, size_t *pcbRead)
1407{
1408 /* Validate input. */
1409 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1410 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1411
1412 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1413 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1414 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1415
1416// DEBUG_PRINT_FLOW();
1417
1418 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1419
1420 int rc = VINF_SUCCESS;
1421
1422// pInt->calls++;
1423// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1424
1425 /* Check if we jump forward in the file. If so we have to read the
1426 * remaining stuff in the gap anyway (SHA1/SHA256; streaming). */
1427 if (pInt->cbCurAll < uOffset)
1428 {
1429 rc = shaReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1430 (size_t)(uOffset - pInt->cbCurAll), 0);
1431 if (RT_FAILURE(rc))
1432 return rc;
1433// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1434 }
1435 else if (uOffset < pInt->cbCurAll)
1436 AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
1437
1438 size_t cbAllRead = 0;
1439 size_t cbAvail = 0;
1440 for (;;)
1441 {
1442 /* Finished? */
1443 if (cbAllRead == cbRead)
1444 break;
1445
1446 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1447
1448 if ( cbAvail == 0
1449 && pInt->fEOF
1450 && !RTCircBufIsWriting(pInt->pCircBuf))
1451 {
1452 rc = VINF_EOF;
1453 break;
1454 }
1455
1456 /* If there isn't enough data make sure the worker thread is fetching
1457 * more. */
1458 if ((cbRead - cbAllRead) > cbAvail)
1459 {
1460 rc = shaSignalManifestThread(pInt, STATUS_READ);
1461 if (RT_FAILURE(rc))
1462 break;
1463 /* If there is _no_ data available, we have to wait until it is. */
1464 if (cbAvail == 0)
1465 {
1466 rc = shaWaitForManifestThreadFinished(pInt);
1467 if (RT_FAILURE(rc))
1468 break;
1469 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1470// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1471// pInt->waits++;
1472 }
1473 }
1474 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1475 char *pcBuf;
1476 size_t cbMemRead = 0;
1477 /* Acquire a block for reading from our circular buffer. */
1478 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1479 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1480 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1481 /* Mark the block as empty again. */
1482 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1483 cbAllRead += cbMemRead;
1484
1485 pInt->cbCurAll += cbMemRead;
1486 }
1487
1488 if (pcbRead)
1489 *pcbRead = cbAllRead;
1490
1491 if (rc == VERR_EOF)
1492 rc = VINF_SUCCESS;
1493
1494 /* Signal the thread to read more data in the mean time. */
1495 if ( RT_SUCCESS(rc)
1496 && rc != VINF_EOF
1497 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1498 rc = shaSignalManifestThread(pInt, STATUS_READ);
1499
1500 return rc;
1501}
1502
1503static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1504{
1505 /* Validate input. */
1506 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1507 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1508
1509 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1510 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1511 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1512
1513 DEBUG_PRINT_FLOW();
1514
1515 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1516
1517 /* Check if there is still something in the buffer. If yes, flush it. */
1518 int rc = shaFlushCurBuf(pInt);
1519 if (RT_FAILURE(rc))
1520 return rc;
1521
1522 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1523}
1524
1525PVDINTERFACEIO ShaCreateInterface()
1526{
1527 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1528 if (!pCallbacks)
1529 return NULL;
1530
1531 pCallbacks->pfnOpen = shaOpenCallback;
1532 pCallbacks->pfnClose = shaCloseCallback;
1533 pCallbacks->pfnDelete = shaDeleteCallback;
1534 pCallbacks->pfnMove = shaMoveCallback;
1535 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1536 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1537 pCallbacks->pfnGetSize = shaGetSizeCallback;
1538 pCallbacks->pfnSetSize = shaSetSizeCallback;
1539 pCallbacks->pfnReadSync = shaReadSyncCallback;
1540 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1541 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1542
1543 return pCallbacks;
1544}
1545
1546PVDINTERFACEIO FileCreateInterface()
1547{
1548 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1549 if (!pCallbacks)
1550 return NULL;
1551
1552 pCallbacks->pfnOpen = fileOpenCallback;
1553 pCallbacks->pfnClose = fileCloseCallback;
1554 pCallbacks->pfnDelete = fileDeleteCallback;
1555 pCallbacks->pfnMove = fileMoveCallback;
1556 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1557 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1558 pCallbacks->pfnGetSize = fileGetSizeCallback;
1559 pCallbacks->pfnSetSize = fileSetSizeCallback;
1560 pCallbacks->pfnReadSync = fileReadSyncCallback;
1561 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1562 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1563
1564 return pCallbacks;
1565}
1566
1567int readFileIntoBuffer(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1568{
1569 /* Validate input. */
1570 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1571 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1572 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1573
1574 void *pvStorage;
1575 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1576 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1577 &pvStorage);
1578 if (RT_FAILURE(rc))
1579 return rc;
1580
1581 void *pvTmpBuf = 0;
1582 void *pvBuf = 0;
1583 uint64_t cbTmpSize = _1M;
1584 size_t cbAllRead = 0;
1585 do
1586 {
1587 pvTmpBuf = RTMemAlloc(cbTmpSize);
1588 if (!pvTmpBuf)
1589 {
1590 rc = VERR_NO_MEMORY;
1591 break;
1592 }
1593
1594 for (;;)
1595 {
1596 size_t cbRead = 0;
1597 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1598 if ( RT_FAILURE(rc)
1599 || cbRead == 0)
1600 break;
1601 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1602 if (!pvBuf)
1603 {
1604 rc = VERR_NO_MEMORY;
1605 break;
1606 }
1607 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1608 cbAllRead += cbRead;
1609 }
1610 } while (0);
1611
1612 pIfIo->pfnClose(pvUser, pvStorage);
1613
1614 if (rc == VERR_EOF)
1615 rc = VINF_SUCCESS;
1616
1617 if (pvTmpBuf)
1618 RTMemFree(pvTmpBuf);
1619
1620 if (RT_SUCCESS(rc))
1621 {
1622 *ppvBuf = pvBuf;
1623 *pcbSize = cbAllRead;
1624 }
1625 else
1626 {
1627 if (pvBuf)
1628 RTMemFree(pvBuf);
1629 }
1630
1631 return rc;
1632}
1633
1634int writeBufferToFile(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1635{
1636 /* Validate input. */
1637 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1638 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1639 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1640
1641 void *pvStorage;
1642 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1643 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1644 &pvStorage);
1645 if (RT_FAILURE(rc))
1646 return rc;
1647
1648 size_t cbAllWritten = 0;
1649 for (;;)
1650 {
1651 if (cbAllWritten >= cbSize)
1652 break;
1653 size_t cbToWrite = cbSize - cbAllWritten;
1654 size_t cbWritten = 0;
1655 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1656 if (RT_FAILURE(rc))
1657 break;
1658 cbAllWritten += cbWritten;
1659 }
1660
1661 rc = pIfIo->pfnClose(pvUser, pvStorage);
1662
1663 return rc;
1664}
1665
1666int decompressImageAndSave(const char *pcszFullFilenameIn, const char *pcszFullFilenameOut, PVDINTERFACEIO pIfIo, void *pvUser)
1667{
1668 /* Validate input. */
1669 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1670
1671 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1672 /*
1673 * Open the source file.
1674 */
1675 void *pvStorage;
1676 int rc = pIfIo->pfnOpen(pvUser, pcszFullFilenameIn,
1677 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1678 &pvStorage);
1679 if (RT_FAILURE(rc))
1680 return rc;
1681
1682 /* Turn the source file handle/whatever into a VFS stream. */
1683 RTVFSIOSTREAM hVfsIosCompressedSrc;
1684
1685 rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosCompressedSrc);
1686 if (RT_SUCCESS(rc))
1687 {
1688 /* Pass the source thru gunzip. */
1689 RTVFSIOSTREAM hVfsIosSrc;
1690 rc = RTZipGzipDecompressIoStream(hVfsIosCompressedSrc, 0, &hVfsIosSrc);
1691 if (RT_SUCCESS(rc))
1692 {
1693 /*
1694 * Create the output file, including necessary paths.
1695 * Any existing file will be overwritten.
1696 */
1697 rc = VirtualBox::i_ensureFilePathExists(Utf8Str(pcszFullFilenameOut), true /*fCreate*/);
1698 if (RT_SUCCESS(rc))
1699 {
1700 RTVFSIOSTREAM hVfsIosDst;
1701 rc = RTVfsIoStrmOpenNormal(pcszFullFilenameOut,
1702 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
1703 &hVfsIosDst);
1704 if (RT_SUCCESS(rc))
1705 {
1706 /*
1707 * Pump the bytes thru. If we fail, delete the output file.
1708 */
1709 RTMANIFEST hFileManifest = NIL_RTMANIFEST;
1710 rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
1711 if (RT_SUCCESS(rc))
1712 {
1713 RTVFSIOSTREAM hVfsIosMfst;
1714
1715 uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
1716
1717 rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
1718 hVfsIosSrc,
1719 "ovf import",
1720 digestType,
1721 true /*read*/, &hVfsIosMfst);
1722 if (RT_SUCCESS(rc))
1723 {
1724 rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
1725 }
1726
1727 RTVfsIoStrmRelease(hVfsIosMfst);
1728 }
1729
1730 RTVfsIoStrmRelease(hVfsIosDst);
1731 }
1732 }
1733
1734 RTVfsIoStrmRelease(hVfsIosSrc);
1735 }
1736 }
1737 pIfIo->pfnClose(pvUser, pvStorage);
1738
1739 return rc;
1740}
1741
1742int copyFileAndCalcShaDigest(const char *pcszSourceFilename, const char *pcszTargetFilename, PVDINTERFACEIO pIfIo, void *pvUser)
1743{
1744 /* Validate input. */
1745 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1746
1747 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1748 void *pvStorage;
1749
1750 int rc = pIfIo->pfnOpen(pvUser, pcszSourceFilename,
1751 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1752 &pvStorage);
1753 if (RT_FAILURE(rc))
1754 return rc;
1755
1756 /* Turn the source file handle/whatever into a VFS stream. */
1757 RTVFSIOSTREAM hVfsIosSrc;
1758
1759 rc = VDIfCreateVfsStream(pIfIo, pvStorage, RTFILE_O_READ, &hVfsIosSrc);
1760 if (RT_SUCCESS(rc))
1761 {
1762 /*
1763 * Create the output file, including necessary paths.
1764 * Any existing file will be overwritten.
1765 */
1766 rc = VirtualBox::i_ensureFilePathExists(Utf8Str(pcszTargetFilename), true /*fCreate*/);
1767 if (RT_SUCCESS(rc))
1768 {
1769 RTVFSIOSTREAM hVfsIosDst;
1770 rc = RTVfsIoStrmOpenNormal(pcszTargetFilename,
1771 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL,
1772 &hVfsIosDst);
1773 if (RT_SUCCESS(rc))
1774 {
1775 /*
1776 * Pump the bytes thru. If we fail, delete the output file.
1777 */
1778 RTMANIFEST hFileManifest = NIL_RTMANIFEST;
1779 rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
1780 if (RT_SUCCESS(rc))
1781 {
1782 RTVFSIOSTREAM hVfsIosMfst;
1783
1784 uint32_t digestType = (pShaStorage->fSha256 == true) ? RTMANIFEST_ATTR_SHA256: RTMANIFEST_ATTR_SHA1;
1785
1786 rc = RTManifestEntryAddPassthruIoStream(hFileManifest,
1787 hVfsIosSrc,
1788 "ovf import",
1789 digestType,
1790 true /*read*/, &hVfsIosMfst);
1791 if (RT_SUCCESS(rc))
1792 {
1793 rc = RTVfsUtilPumpIoStreams(hVfsIosMfst, hVfsIosDst, 0);
1794 }
1795
1796 RTVfsIoStrmRelease(hVfsIosMfst);
1797 }
1798
1799 RTVfsIoStrmRelease(hVfsIosDst);
1800 }
1801 }
1802
1803 RTVfsIoStrmRelease(hVfsIosSrc);
1804
1805 }
1806
1807 pIfIo->pfnClose(pvUser, pvStorage);
1808 return rc;
1809}
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