VirtualBox

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

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

enabled shared clipboard support for Linux hosts (guest=>host only)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.6 KB
Line 
1/* $Id: ApplianceImplIO.cpp 42261 2012-07-20 13:27:47Z 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
1084 size_t cbAllRead = 0;
1085 for (;;)
1086 {
1087 /* Finished? */
1088 if (cbAllRead == cbRead)
1089 break;
1090 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1091 if ( cbAvail == 0
1092 && pInt->fEOF
1093 && !RTCircBufIsWriting(pInt->pCircBuf))
1094 {
1095 break;
1096 }
1097 /* If there isn't enough data make sure the worker thread is fetching
1098 * more. */
1099 if ((cbRead - cbAllRead) > cbAvail)
1100 {
1101 rc = shaSignalManifestThread(pInt, STATUS_READ);
1102 if(RT_FAILURE(rc))
1103 break;
1104 /* If there is _no_ data available, we have to wait until it is. */
1105 if (cbAvail == 0)
1106 {
1107 rc = shaWaitForManifestThreadFinished(pInt);
1108 if (RT_FAILURE(rc))
1109 break;
1110 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1111// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1112// pInt->waits++;
1113 }
1114 }
1115 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1116 char *pcBuf;
1117 size_t cbMemRead = 0;
1118 /* Acquire a block for reading from our circular buffer. */
1119 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1120 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1121 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1122 /* Mark the block as empty again. */
1123 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1124 cbAllRead += cbMemRead;
1125
1126 pInt->cbCurAll += cbMemRead;
1127 }
1128
1129 if (pcbRead)
1130 *pcbRead = cbAllRead;
1131
1132 if (rc == VERR_EOF)
1133 rc = VINF_SUCCESS;
1134
1135 /* Signal the thread to read more data in the mean time. */
1136 if ( RT_SUCCESS(rc)
1137 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1138 rc = shaSignalManifestThread(pInt, STATUS_READ);
1139
1140 return rc;
1141}
1142
1143static int shaFlushSyncCallback(void *pvUser, void *pvStorage)
1144{
1145 /* Validate input. */
1146 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1147 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1148
1149 PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser;
1150 PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces);
1151 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1152
1153 DEBUG_PRINT_FLOW();
1154
1155 PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage;
1156
1157 /* Check if there is still something in the buffer. If yes, flush it. */
1158 int rc = shaFlushCurBuf(pInt);
1159 if (RT_FAILURE(rc))
1160 return rc;
1161
1162 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1163}
1164
1165/******************************************************************************
1166 * Public Functions *
1167 ******************************************************************************/
1168
1169PVDINTERFACEIO ShaCreateInterface()
1170{
1171 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1172 if (!pCallbacks)
1173 return NULL;
1174
1175 pCallbacks->pfnOpen = shaOpenCallback;
1176 pCallbacks->pfnClose = shaCloseCallback;
1177 pCallbacks->pfnDelete = shaDeleteCallback;
1178 pCallbacks->pfnMove = shaMoveCallback;
1179 pCallbacks->pfnGetFreeSpace = shaGetFreeSpaceCallback;
1180 pCallbacks->pfnGetModificationTime = shaGetModificationTimeCallback;
1181 pCallbacks->pfnGetSize = shaGetSizeCallback;
1182 pCallbacks->pfnSetSize = shaSetSizeCallback;
1183 pCallbacks->pfnReadSync = shaReadSyncCallback;
1184 pCallbacks->pfnWriteSync = shaWriteSyncCallback;
1185 pCallbacks->pfnFlushSync = shaFlushSyncCallback;
1186
1187 return pCallbacks;
1188}
1189
1190PVDINTERFACEIO FileCreateInterface()
1191{
1192 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1193 if (!pCallbacks)
1194 return NULL;
1195
1196 pCallbacks->pfnOpen = fileOpenCallback;
1197 pCallbacks->pfnClose = fileCloseCallback;
1198 pCallbacks->pfnDelete = fileDeleteCallback;
1199 pCallbacks->pfnMove = fileMoveCallback;
1200 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1201 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1202 pCallbacks->pfnGetSize = fileGetSizeCallback;
1203 pCallbacks->pfnSetSize = fileSetSizeCallback;
1204 pCallbacks->pfnReadSync = fileReadSyncCallback;
1205 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1206 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1207
1208 return pCallbacks;
1209}
1210
1211PVDINTERFACEIO TarCreateInterface()
1212{
1213 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1214 if (!pCallbacks)
1215 return NULL;
1216
1217 pCallbacks->pfnOpen = tarOpenCallback;
1218 pCallbacks->pfnClose = tarCloseCallback;
1219 pCallbacks->pfnDelete = tarDeleteCallback;
1220 pCallbacks->pfnMove = tarMoveCallback;
1221 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1222 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1223 pCallbacks->pfnGetSize = tarGetSizeCallback;
1224 pCallbacks->pfnSetSize = tarSetSizeCallback;
1225 pCallbacks->pfnReadSync = tarReadSyncCallback;
1226 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1227 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1228
1229 return pCallbacks;
1230}
1231
1232int ShaReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1233{
1234 /* Validate input. */
1235 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1236 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1237 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1238
1239 void *pvStorage;
1240 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1241 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1242 &pvStorage);
1243 if (RT_FAILURE(rc))
1244 return rc;
1245
1246 void *pvTmpBuf = 0;
1247 void *pvBuf = 0;
1248 uint64_t cbTmpSize = _1M;
1249 size_t cbAllRead = 0;
1250 do
1251 {
1252 pvTmpBuf = RTMemAlloc(cbTmpSize);
1253 if (!pvTmpBuf)
1254 {
1255 rc = VERR_NO_MEMORY;
1256 break;
1257 }
1258
1259 for (;;)
1260 {
1261 size_t cbRead = 0;
1262 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1263 if ( RT_FAILURE(rc)
1264 || cbRead == 0)
1265 break;
1266 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1267 if (!pvBuf)
1268 {
1269 rc = VERR_NO_MEMORY;
1270 break;
1271 }
1272 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1273 cbAllRead += cbRead;
1274 }
1275 }while(0);
1276
1277 pIfIo->pfnClose(pvUser, pvStorage);
1278
1279 if (rc == VERR_EOF)
1280 rc = VINF_SUCCESS;
1281
1282 if (pvTmpBuf)
1283 RTMemFree(pvTmpBuf);
1284
1285 if (RT_SUCCESS(rc))
1286 {
1287 *ppvBuf = pvBuf;
1288 *pcbSize = cbAllRead;
1289 }
1290 else
1291 {
1292 if (pvBuf)
1293 RTMemFree(pvBuf);
1294 }
1295
1296 return rc;
1297}
1298
1299int ShaWriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1300{
1301 /* Validate input. */
1302 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1303 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1304 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1305
1306 void *pvStorage;
1307 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1308 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1309 &pvStorage);
1310 if (RT_FAILURE(rc))
1311 return rc;
1312
1313 size_t cbAllWritten = 0;
1314 for (;;)
1315 {
1316 if (cbAllWritten >= cbSize)
1317 break;
1318 size_t cbToWrite = cbSize - cbAllWritten;
1319 size_t cbWritten = 0;
1320 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1321 if (RT_FAILURE(rc))
1322 break;
1323 cbAllWritten += cbWritten;
1324 }
1325
1326 pIfIo->pfnClose(pvUser, pvStorage);
1327
1328 return rc;
1329}
1330
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