VirtualBox

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

Last change on this file since 46860 was 46611, checked in by vboxsync, 11 years ago

ApplianceImplIO: Propagate error when closing a file

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.8 KB
Line 
1/* $Id: ApplianceImplIO.cpp 46611 2013-06-18 09:23:54Z 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 fFound = !strcmp(pszFilename, RTPathFilename(pszLocation));
307 RTStrFree(pszFilename);
308 if (fFound)
309 break;
310 else
311 {
312 rc = RTTarSeekNextFile(tar);
313 if (RT_FAILURE(rc))
314 {
315 break;
316 }
317 }
318 }
319 else
320 break;
321 }
322 if (fFound)
323 rc = RTTarFileOpenCurrentFile(tar, &pInt->file, 0, fOpen);
324 }
325 else
326 rc = RTTarFileOpen(tar, &pInt->file, RTPathFilename(pszLocation), fOpen);
327
328 if (RT_FAILURE(rc))
329 RTMemFree(pInt);
330 else
331 *ppInt = pInt;
332
333 return rc;
334}
335
336static int tarCloseCallback(void *pvUser, void *pvStorage)
337{
338 /* Validate input. */
339 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
340 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
341
342 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
343
344 DEBUG_PRINT_FLOW();
345
346 int rc = RTTarFileClose(pInt->file);
347
348 /* Cleanup */
349 RTMemFree(pInt);
350
351 return rc;
352}
353
354static int tarDeleteCallback(void *pvUser, const char *pcszFilename)
355{
356 /* Validate input. */
357 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
358 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
359
360 DEBUG_PRINT_FLOW();
361
362 return VERR_NOT_IMPLEMENTED;
363}
364
365static int tarMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned /* fMove */)
366{
367 /* Validate input. */
368 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
369 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
370 AssertPtrReturn(pcszDst, VERR_INVALID_POINTER);
371
372 DEBUG_PRINT_FLOW();
373
374 return VERR_NOT_IMPLEMENTED;
375}
376
377static int tarGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
378{
379 /* Validate input. */
380 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
381 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
382 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
383
384 DEBUG_PRINT_FLOW();
385
386 return VERR_NOT_IMPLEMENTED;
387}
388
389static int tarGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
390{
391 /* Validate input. */
392 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
393 AssertPtrReturn(pcszFilename, VERR_INVALID_POINTER);
394 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
395
396 DEBUG_PRINT_FLOW();
397
398 return VERR_NOT_IMPLEMENTED;
399}
400
401static int tarGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
402{
403 /* Validate input. */
404 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
405 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
406
407 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
408
409 DEBUG_PRINT_FLOW();
410
411 return RTTarFileGetSize(pInt->file, pcbSize);
412}
413
414static int tarSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
415{
416 /* Validate input. */
417 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
418 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
419
420 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
421
422 DEBUG_PRINT_FLOW();
423
424 return RTTarFileSetSize(pInt->file, cbSize);
425}
426
427static int tarWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
428 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
429{
430 /* Validate input. */
431 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
432 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
433
434 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
435
436 DEBUG_PRINT_FLOW();
437
438 return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
439}
440
441static int tarReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
442 void *pvBuf, size_t cbRead, size_t *pcbRead)
443{
444 /* Validate input. */
445 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
446 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
447
448 PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
449
450// DEBUG_PRINT_FLOW();
451
452 return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
453}
454
455static int tarFlushSyncCallback(void *pvUser, void *pvStorage)
456{
457 /* Validate input. */
458 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
459 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
460
461 DEBUG_PRINT_FLOW();
462
463 return VERR_NOT_IMPLEMENTED;
464}
465
466/******************************************************************************
467 * Internal: RTSha interface
468 ******************************************************************************/
469
470DECLCALLBACK(int) shaCalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
471{
472 /* Validate input. */
473 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
474
475 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvUser;
476
477 PVDINTERFACEIO pIfIo = VDIfIoGet(pInt->pShaStorage->pVDImageIfaces);
478 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
479
480 int rc = VINF_SUCCESS;
481 bool fLoop = true;
482 while (fLoop)
483 {
484 /* What should we do next? */
485 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
486// RTPrintf("status: %d\n", u32Status);
487 switch (u32Status)
488 {
489 case STATUS_WAIT:
490 {
491 /* Wait for new work. */
492 rc = RTSemEventWait(pInt->newStatusEvent, 100);
493 if ( RT_FAILURE(rc)
494 && rc != VERR_TIMEOUT)
495 fLoop = false;
496 break;
497 }
498 case STATUS_WRITE:
499 {
500 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WRITING, STATUS_WRITE);
501 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
502 size_t cbMemAllRead = 0;
503 /* First loop over all the free memory in the circular
504 * memory buffer (could be turn around at the end). */
505 for (;;)
506 {
507 if ( cbMemAllRead == cbAvail
508 || fLoop == false)
509 break;
510 char *pcBuf;
511 size_t cbMemToRead = cbAvail - cbMemAllRead;
512 size_t cbMemRead = 0;
513 /* Try to acquire all the used space of the circular buffer. */
514 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbMemToRead, (void**)&pcBuf, &cbMemRead);
515 size_t cbAllWritten = 0;
516 /* Second, write as long as used memory is there. The write
517 * method could also split the writes up into to smaller
518 * parts. */
519 for (;;)
520 {
521 if (cbAllWritten == cbMemRead)
522 break;
523 size_t cbToWrite = cbMemRead - cbAllWritten;
524 size_t cbWritten = 0;
525 rc = vdIfIoFileWriteSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllWritten], cbToWrite, &cbWritten);
526// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
527 if (RT_FAILURE(rc))
528 {
529 fLoop = false;
530 break;
531 }
532 cbAllWritten += cbWritten;
533 pInt->cbCurFile += cbWritten;
534 }
535 /* Update the SHA1/SHA256 context with the next data block. */
536 if ( RT_SUCCESS(rc)
537 && pInt->pShaStorage->fCreateDigest)
538 {
539 if (pInt->pShaStorage->fSha256)
540 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllWritten);
541 else
542 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllWritten);
543 }
544 /* Mark the block as empty. */
545 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbAllWritten);
546 cbMemAllRead += cbAllWritten;
547 }
548 /* Reset the thread status and signal the main thread that we
549 * are finished. Use CmpXchg, so we not overwrite other states
550 * which could be signaled in the meantime. */
551 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_WRITING))
552 rc = RTSemEventSignal(pInt->workFinishedEvent);
553 break;
554 }
555 case STATUS_READ:
556 {
557 ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_READING, STATUS_READ);
558 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
559 size_t cbMemAllWrite = 0;
560 /* First loop over all the available memory in the circular
561 * memory buffer (could be turn around at the end). */
562 for (;;)
563 {
564 if ( cbMemAllWrite == cbAvail
565 || fLoop == false)
566 break;
567 char *pcBuf;
568 size_t cbMemToWrite = cbAvail - cbMemAllWrite;
569 size_t cbMemWrite = 0;
570 /* Try to acquire all the free space of the circular buffer. */
571 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbMemToWrite, (void**)&pcBuf, &cbMemWrite);
572 /* Second, read as long as we filled all the memory. The
573 * read method could also split the reads up into to
574 * smaller parts. */
575 size_t cbAllRead = 0;
576 for (;;)
577 {
578 if (cbAllRead == cbMemWrite)
579 break;
580 size_t cbToRead = cbMemWrite - cbAllRead;
581 size_t cbRead = 0;
582 rc = vdIfIoFileReadSync(pIfIo, pInt->pvStorage, pInt->cbCurFile, &pcBuf[cbAllRead], cbToRead, &cbRead);
583// RTPrintf ("%lu %lu %lu %Rrc\n", pInt->cbCurFile, cbToRead, cbRead, rc);
584 if (RT_FAILURE(rc))
585 {
586 fLoop = false;
587 break;
588 }
589 /* This indicates end of file. Stop reading. */
590 if (cbRead == 0)
591 {
592 fLoop = false;
593 ASMAtomicWriteBool(&pInt->fEOF, true);
594 break;
595 }
596 cbAllRead += cbRead;
597 pInt->cbCurFile += cbRead;
598 }
599 /* Update the SHA1/SHA256 context with the next data block. */
600 if ( RT_SUCCESS(rc)
601 && pInt->pShaStorage->fCreateDigest)
602 {
603 if (pInt->pShaStorage->fSha256)
604 RTSha256Update(&pInt->ctx.Sha256, pcBuf, cbAllRead);
605 else
606 RTSha1Update(&pInt->ctx.Sha1, pcBuf, cbAllRead);
607 }
608 /* Mark the block as full. */
609 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbAllRead);
610 cbMemAllWrite += cbAllRead;
611 }
612 /* Reset the thread status and signal the main thread that we
613 * are finished. Use CmpXchg, so we not overwrite other states
614 * which could be signaled in the meantime. */
615 if (ASMAtomicCmpXchgU32(&pInt->u32Status, STATUS_WAIT, STATUS_READING))
616 rc = RTSemEventSignal(pInt->workFinishedEvent);
617 break;
618 }
619 case STATUS_END:
620 {
621 /* End signaled */
622 fLoop = false;
623 break;
624 }
625 }
626 }
627 /* Cleanup any status changes to indicate we are finished. */
628 ASMAtomicWriteU32(&pInt->u32Status, STATUS_END);
629 rc = RTSemEventSignal(pInt->workFinishedEvent);
630 return rc;
631}
632
633DECLINLINE(int) shaSignalManifestThread(PSHASTORAGEINTERNAL pInt, uint32_t uStatus)
634{
635 ASMAtomicWriteU32(&pInt->u32Status, uStatus);
636 return RTSemEventSignal(pInt->newStatusEvent);
637}
638
639DECLINLINE(int) shaWaitForManifestThreadFinished(PSHASTORAGEINTERNAL pInt)
640{
641// RTPrintf("start\n");
642 int rc = VINF_SUCCESS;
643 for (;;)
644 {
645// RTPrintf(" wait\n");
646 uint32_t u32Status = ASMAtomicReadU32(&pInt->u32Status);
647 if (!( u32Status == STATUS_WRITE
648 || u32Status == STATUS_WRITING
649 || u32Status == STATUS_READ
650 || u32Status == STATUS_READING))
651 break;
652 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
653 }
654 if (rc == VERR_TIMEOUT)
655 rc = VINF_SUCCESS;
656 return rc;
657}
658
659DECLINLINE(int) shaFlushCurBuf(PSHASTORAGEINTERNAL pInt)
660{
661 int rc = VINF_SUCCESS;
662 if (pInt->fOpenMode & RTFILE_O_WRITE)
663 {
664 /* Let the write worker thread start immediately. */
665 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
666 if (RT_FAILURE(rc))
667 return rc;
668
669 /* Wait until the write worker thread has finished. */
670 rc = shaWaitForManifestThreadFinished(pInt);
671 }
672
673 return rc;
674}
675
676static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
677 PFNVDCOMPLETED pfnCompleted, void **ppInt)
678{
679 /* Validate input. */
680 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
681 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
682 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
683 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
684 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
685
686 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
687 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
688 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
689
690 DEBUG_PRINT_FLOW();
691
692 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL));
693 if (!pInt)
694 return VERR_NO_MEMORY;
695
696 int rc = VINF_SUCCESS;
697 do
698 {
699 pInt->pfnCompleted = pfnCompleted;
700 pInt->pShaStorage = pShaStorage;
701 pInt->fEOF = false;
702 pInt->fOpenMode = fOpen;
703 pInt->u32Status = STATUS_WAIT;
704
705 /* Circular buffer in the read case. */
706 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
707 if (RT_FAILURE(rc))
708 break;
709
710 if (fOpen & RTFILE_O_WRITE)
711 {
712 /* The zero buffer is used for appending empty parts at the end of the
713 * file (or our buffer) in setSize or when uOffset in writeSync is
714 * increased in steps bigger than a byte. */
715 pInt->cbZeroBuf = _1K;
716 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
717 if (!pInt->pvZeroBuf)
718 {
719 rc = VERR_NO_MEMORY;
720 break;
721 }
722 }
723
724 /* Create an event semaphore to indicate a state change for the worker
725 * thread. */
726 rc = RTSemEventCreate(&pInt->newStatusEvent);
727 if (RT_FAILURE(rc))
728 break;
729 /* Create an event semaphore to indicate a finished calculation of the
730 worker thread. */
731 rc = RTSemEventCreate(&pInt->workFinishedEvent);
732 if (RT_FAILURE(rc))
733 break;
734 /* Create the worker thread. */
735 rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA-Worker");
736 if (RT_FAILURE(rc))
737 break;
738
739 if (pShaStorage->fCreateDigest)
740 {
741 /* Create a SHA1/SHA256 context the worker thread will work with. */
742 if (pShaStorage->fSha256)
743 RTSha256Init(&pInt->ctx.Sha256);
744 else
745 RTSha1Init(&pInt->ctx.Sha1);
746 }
747
748 /* Open the file. */
749 rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted,
750 &pInt->pvStorage);
751 if (RT_FAILURE(rc))
752 break;
753
754 if (fOpen & RTFILE_O_READ)
755 {
756 /* Immediately let the worker thread start the reading. */
757 rc = shaSignalManifestThread(pInt, STATUS_READ);
758 }
759 }
760 while (0);
761
762 if (RT_FAILURE(rc))
763 {
764 if (pInt->pWorkerThread)
765 {
766 shaSignalManifestThread(pInt, STATUS_END);
767 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
768 }
769 if (pInt->workFinishedEvent)
770 RTSemEventDestroy(pInt->workFinishedEvent);
771 if (pInt->newStatusEvent)
772 RTSemEventDestroy(pInt->newStatusEvent);
773 if (pInt->pCircBuf)
774 RTCircBufDestroy(pInt->pCircBuf);
775 if (pInt->pvZeroBuf)
776 RTMemFree(pInt->pvZeroBuf);
777 RTMemFree(pInt);
778 }
779 else
780 *ppInt = pInt;
781
782 return rc;
783}
784
785static int shaCloseCallback(void *pvUser, void *pvStorage)
786{
787 /* Validate input. */
788 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
789 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
790
791 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
792 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
793 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
794
795 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
796
797 DEBUG_PRINT_FLOW();
798
799 int rc = VINF_SUCCESS;
800
801 /* Make sure all pending writes are flushed */
802 rc = shaFlushCurBuf(pInt);
803
804 if (pInt->pWorkerThread)
805 {
806 /* Signal the worker thread to end himself */
807 rc = shaSignalManifestThread(pInt, STATUS_END);
808 /* Worker thread stopped? */
809 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
810 }
811
812 if ( RT_SUCCESS(rc)
813 && pShaStorage->fCreateDigest)
814 {
815 /* Finally calculate & format the SHA1/SHA256 sum */
816 unsigned char auchDig[RTSHA256_HASH_SIZE];
817 char *pszDigest;
818 size_t cbDigest;
819 if (pShaStorage->fSha256)
820 {
821 RTSha256Final(&pInt->ctx.Sha256, auchDig);
822 cbDigest = RTSHA256_DIGEST_LEN;
823 }
824 else
825 {
826 RTSha1Final(&pInt->ctx.Sha1, auchDig);
827 cbDigest = RTSHA1_DIGEST_LEN;
828 }
829 rc = RTStrAllocEx(&pszDigest, cbDigest + 1);
830 if (RT_SUCCESS(rc))
831 {
832 if (pShaStorage->fSha256)
833 rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1);
834 else
835 rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1);
836 if (RT_SUCCESS(rc))
837 pShaStorage->strDigest = pszDigest;
838 RTStrFree(pszDigest);
839 }
840 }
841
842 /* Close the file */
843 rc = vdIfIoFileClose(pIfIo, pInt->pvStorage);
844
845// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
846
847 /* Cleanup */
848 if (pInt->workFinishedEvent)
849 RTSemEventDestroy(pInt->workFinishedEvent);
850 if (pInt->newStatusEvent)
851 RTSemEventDestroy(pInt->newStatusEvent);
852 if (pInt->pCircBuf)
853 RTCircBufDestroy(pInt->pCircBuf);
854 if (pInt->pvZeroBuf)
855 RTMemFree(pInt->pvZeroBuf);
856 RTMemFree(pInt);
857
858 return rc;
859}
860
861static int shaDeleteCallback(void *pvUser, const char *pcszFilename)
862{
863 /* Validate input. */
864 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
865
866 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
867 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
868 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
869
870 DEBUG_PRINT_FLOW();
871
872 return vdIfIoFileDelete(pIfIo, pcszFilename);
873}
874
875static int shaMoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
876{
877 /* Validate input. */
878 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
879
880 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
881 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
882 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
883
884
885 DEBUG_PRINT_FLOW();
886
887 return vdIfIoFileMove(pIfIo, pcszSrc, pcszDst, fMove);
888}
889
890static int shaGetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
891{
892 /* Validate input. */
893 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
894
895 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
896 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
897 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
898
899 DEBUG_PRINT_FLOW();
900
901 return vdIfIoFileGetFreeSpace(pIfIo, pcszFilename, pcbFreeSpace);
902}
903
904static int shaGetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
905{
906 /* Validate input. */
907 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
908
909 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
910 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
911 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
912
913 DEBUG_PRINT_FLOW();
914
915 return vdIfIoFileGetModificationTime(pIfIo, pcszFilename, pModificationTime);
916}
917
918
919static int shaGetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
920{
921 /* Validate input. */
922 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
923 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
924
925 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
926 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
927 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
928
929 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
930
931 DEBUG_PRINT_FLOW();
932
933 uint64_t cbSize;
934 int rc = vdIfIoFileGetSize(pIfIo, pInt->pvStorage, &cbSize);
935 if (RT_FAILURE(rc))
936 return rc;
937
938 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
939
940 return VINF_SUCCESS;
941}
942
943static int shaSetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
944{
945 /* Validate input. */
946 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
947 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
948
949 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
950 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
951 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
952
953 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
954
955 DEBUG_PRINT_FLOW();
956
957 return vdIfIoFileSetSize(pIfIo, pInt->pvStorage, cbSize);
958}
959
960static int shaWriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
961 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
962{
963 /* Validate input. */
964 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
965 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
966
967 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
968 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
969 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
970
971 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
972
973 DEBUG_PRINT_FLOW();
974
975 /* Check that the write is linear */
976 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
977
978 int rc = VINF_SUCCESS;
979
980 /* Check if we have to add some free space at the end, before we start the
981 * real write. */
982 if (pInt->cbCurAll < uOffset)
983 {
984 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
985 size_t cbAllWritten = 0;
986 for (;;)
987 {
988 /* Finished? */
989 if (cbAllWritten == cbSize)
990 break;
991 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
992 size_t cbWritten = 0;
993 rc = shaWriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
994 pInt->pvZeroBuf, cbToWrite, &cbWritten);
995 if (RT_FAILURE(rc))
996 break;
997 cbAllWritten += cbWritten;
998 }
999 if (RT_FAILURE(rc))
1000 return rc;
1001 }
1002// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
1003
1004 size_t cbAllWritten = 0;
1005 for (;;)
1006 {
1007 /* Finished? */
1008 if (cbAllWritten == cbWrite)
1009 break;
1010 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
1011 if ( cbAvail == 0
1012 && pInt->fEOF)
1013 return VERR_EOF;
1014 /* If there isn't enough free space make sure the worker thread is
1015 * writing some data. */
1016 if ((cbWrite - cbAllWritten) > cbAvail)
1017 {
1018 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1019 if (RT_FAILURE(rc))
1020 break;
1021 /* If there is _no_ free space available, we have to wait until it is. */
1022 if (cbAvail == 0)
1023 {
1024 rc = shaWaitForManifestThreadFinished(pInt);
1025 if (RT_FAILURE(rc))
1026 break;
1027 cbAvail = RTCircBufFree(pInt->pCircBuf);
1028// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1029// pInt->waits++;
1030 }
1031 }
1032 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1033 char *pcBuf;
1034 size_t cbMemWritten = 0;
1035 /* Acquire a block for writing from our circular buffer. */
1036 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1037 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1038 /* Mark the block full. */
1039 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1040 cbAllWritten += cbMemWritten;
1041 pInt->cbCurAll += cbMemWritten;
1042 }
1043
1044 if (pcbWritten)
1045 *pcbWritten = cbAllWritten;
1046
1047 /* Signal the thread to write more data in the mean time. */
1048 if ( RT_SUCCESS(rc)
1049 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1050 rc = shaSignalManifestThread(pInt, STATUS_WRITE);
1051
1052 return rc;
1053}
1054
1055static int shaReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1056 void *pvBuf, size_t cbRead, size_t *pcbRead)
1057{
1058 /* Validate input. */
1059 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1060 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1061
1062 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1063 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1064 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1065
1066// DEBUG_PRINT_FLOW();
1067
1068 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1069
1070 int rc = VINF_SUCCESS;
1071
1072// pInt->calls++;
1073// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1074
1075 /* Check if we jump forward in the file. If so we have to read the
1076 * remaining stuff in the gap anyway (SHA1/SHA256; streaming). */
1077 if (pInt->cbCurAll < uOffset)
1078 {
1079 rc = shaReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1080 (size_t)(uOffset - pInt->cbCurAll), 0);
1081 if (RT_FAILURE(rc))
1082 return rc;
1083// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1084 }
1085 else if (uOffset < pInt->cbCurAll)
1086 AssertMsgFailed(("Jumping backwards is not possible, sequential access is supported only\n"));
1087
1088 size_t cbAllRead = 0;
1089 for (;;)
1090 {
1091 /* Finished? */
1092 if (cbAllRead == cbRead)
1093 break;
1094 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1095 if ( cbAvail == 0
1096 && pInt->fEOF
1097 && !RTCircBufIsWriting(pInt->pCircBuf))
1098 {
1099 break;
1100 }
1101 /* If there isn't enough data make sure the worker thread is fetching
1102 * more. */
1103 if ((cbRead - cbAllRead) > cbAvail)
1104 {
1105 rc = shaSignalManifestThread(pInt, STATUS_READ);
1106 if (RT_FAILURE(rc))
1107 break;
1108 /* If there is _no_ data available, we have to wait until it is. */
1109 if (cbAvail == 0)
1110 {
1111 rc = shaWaitForManifestThreadFinished(pInt);
1112 if (RT_FAILURE(rc))
1113 break;
1114 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1115// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1116// pInt->waits++;
1117 }
1118 }
1119 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1120 char *pcBuf;
1121 size_t cbMemRead = 0;
1122 /* Acquire a block for reading from our circular buffer. */
1123 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1124 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1125 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1126 /* Mark the block as empty again. */
1127 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1128 cbAllRead += cbMemRead;
1129
1130 pInt->cbCurAll += cbMemRead;
1131 }
1132
1133 if (pcbRead)
1134 *pcbRead = cbAllRead;
1135
1136 if (rc == VERR_EOF)
1137 rc = VINF_SUCCESS;
1138
1139 /* Signal the thread to read more data in the mean time. */
1140 if ( RT_SUCCESS(rc)
1141 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1142 rc = shaSignalManifestThread(pInt, STATUS_READ);
1143
1144 return rc;
1145}
1146
1147static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1148{
1149 /* Validate input. */
1150 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1151 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1152
1153 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1154 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1155 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1156
1157 DEBUG_PRINT_FLOW();
1158
1159 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1160
1161 /* Check if there is still something in the buffer. If yes, flush it. */
1162 int rc = shaFlushCurBuf(pInt);
1163 if (RT_FAILURE(rc))
1164 return rc;
1165
1166 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1167}
1168
1169/******************************************************************************
1170 * Public Functions *
1171 ******************************************************************************/
1172
1173PVDINTERFACEIO ShaCreateInterface()
1174{
1175 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1176 if (!pCallbacks)
1177 return NULL;
1178
1179 pCallbacks->pfnOpen = shaOpenCallback;
1180 pCallbacks->pfnClose = shaCloseCallback;
1181 pCallbacks->pfnDelete = shaDeleteCallback;
1182 pCallbacks->pfnMove = shaMoveCallback;
1183 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1184 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1185 pCallbacks->pfnGetSize = shaGetSizeCallback;
1186 pCallbacks->pfnSetSize = shaSetSizeCallback;
1187 pCallbacks->pfnReadSync = shaReadSyncCallback;
1188 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1189 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1190
1191 return pCallbacks;
1192}
1193
1194PVDINTERFACEIO FileCreateInterface()
1195{
1196 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1197 if (!pCallbacks)
1198 return NULL;
1199
1200 pCallbacks->pfnOpen = fileOpenCallback;
1201 pCallbacks->pfnClose = fileCloseCallback;
1202 pCallbacks->pfnDelete = fileDeleteCallback;
1203 pCallbacks->pfnMove = fileMoveCallback;
1204 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1205 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1206 pCallbacks->pfnGetSize = fileGetSizeCallback;
1207 pCallbacks->pfnSetSize = fileSetSizeCallback;
1208 pCallbacks->pfnReadSync = fileReadSyncCallback;
1209 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1210 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1211
1212 return pCallbacks;
1213}
1214
1215PVDINTERFACEIO TarCreateInterface()
1216{
1217 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1218 if (!pCallbacks)
1219 return NULL;
1220
1221 pCallbacks->pfnOpen = tarOpenCallback;
1222 pCallbacks->pfnClose = tarCloseCallback;
1223 pCallbacks->pfnDelete = tarDeleteCallback;
1224 pCallbacks->pfnMove = tarMoveCallback;
1225 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1226 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1227 pCallbacks->pfnGetSize = tarGetSizeCallback;
1228 pCallbacks->pfnSetSize = tarSetSizeCallback;
1229 pCallbacks->pfnReadSync = tarReadSyncCallback;
1230 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1231 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1232
1233 return pCallbacks;
1234}
1235
1236int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1237{
1238 /* Validate input. */
1239 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1240 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1241 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1242
1243 void *pvStorage;
1244 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1245 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1246 &pvStorage);
1247 if (RT_FAILURE(rc))
1248 return rc;
1249
1250 void *pvTmpBuf = 0;
1251 void *pvBuf = 0;
1252 uint64_t cbTmpSize = _1M;
1253 size_t cbAllRead = 0;
1254 do
1255 {
1256 pvTmpBuf = RTMemAlloc(cbTmpSize);
1257 if (!pvTmpBuf)
1258 {
1259 rc = VERR_NO_MEMORY;
1260 break;
1261 }
1262
1263 for (;;)
1264 {
1265 size_t cbRead = 0;
1266 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1267 if ( RT_FAILURE(rc)
1268 || cbRead == 0)
1269 break;
1270 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1271 if (!pvBuf)
1272 {
1273 rc = VERR_NO_MEMORY;
1274 break;
1275 }
1276 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1277 cbAllRead += cbRead;
1278 }
1279 } while (0);
1280
1281 pIfIo->pfnClose(pvUser, pvStorage);
1282
1283 if (rc == VERR_EOF)
1284 rc = VINF_SUCCESS;
1285
1286 if (pvTmpBuf)
1287 RTMemFree(pvTmpBuf);
1288
1289 if (RT_SUCCESS(rc))
1290 {
1291 *ppvBuf = pvBuf;
1292 *pcbSize = cbAllRead;
1293 }
1294 else
1295 {
1296 if (pvBuf)
1297 RTMemFree(pvBuf);
1298 }
1299
1300 return rc;
1301}
1302
1303int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1304{
1305 /* Validate input. */
1306 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1307 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1308 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1309
1310 void *pvStorage;
1311 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1312 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1313 &pvStorage);
1314 if (RT_FAILURE(rc))
1315 return rc;
1316
1317 size_t cbAllWritten = 0;
1318 for (;;)
1319 {
1320 if (cbAllWritten >= cbSize)
1321 break;
1322 size_t cbToWrite = cbSize - cbAllWritten;
1323 size_t cbWritten = 0;
1324 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1325 if (RT_FAILURE(rc))
1326 break;
1327 cbAllWritten += cbWritten;
1328 }
1329
1330 rc = pIfIo->pfnClose(pvUser, pvStorage);
1331
1332 return rc;
1333}
1334
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