VirtualBox

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

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

pr6022. Support handling directories in the TAR has been added. Added several useful checks during import OVA package.

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

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