VirtualBox

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

Last change on this file since 57415 was 57372, checked in by vboxsync, 9 years ago

scm: fixes in previous cleanup run.

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