VirtualBox

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

Last change on this file since 38636 was 38469, checked in by vboxsync, 13 years ago

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

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