VirtualBox

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

Last change on this file since 47500 was 47500, checked in by vboxsync, 12 years ago

pr6022. Second variant of support GZIP files for OVA appliance.

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