VirtualBox

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

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

ApplianceIO: Assertion to catch non sequential accesses

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