VirtualBox

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

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

ApplianceImpl: Use the other manifest API to do verification.

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

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