VirtualBox

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

最後變更 在這個檔案從50200是 50200,由 vboxsync 提交於 11 年 前

Main: Working on reducing RTTar to a write-only interface. Not there yet, though.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette