VirtualBox

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

Last change on this file since 40262 was 39352, checked in by vboxsync, 13 years ago

Main: spaces

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.6 KB
Line 
1/* $Id: ApplianceImplIO.cpp 39352 2011-11-17 15:10:13Z 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// RTPrintf("Gap Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1049 }
1050
1051 size_t cbAllRead = 0;
1052 for(;;)
1053 {
1054 /* Finished? */
1055 if (cbAllRead == cbRead)
1056 break;
1057 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1058 if ( cbAvail == 0
1059 && pInt->fEOF
1060 && !RTCircBufIsWriting(pInt->pCircBuf))
1061 {
1062 break;
1063 }
1064 /* If there isn't enough data make sure the worker thread is fetching
1065 * more. */
1066 if ((cbRead - cbAllRead) > cbAvail)
1067 {
1068 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1069 if(RT_FAILURE(rc))
1070 break;
1071 /* If there is _no_ data available, we have to wait until it is. */
1072 if (cbAvail == 0)
1073 {
1074 rc = sha1WaitForManifestThreadFinished(pInt);
1075 if (RT_FAILURE(rc))
1076 break;
1077 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1078// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1079// pInt->waits++;
1080 }
1081 }
1082 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1083 char *pcBuf;
1084 size_t cbMemRead = 0;
1085 /* Acquire a block for reading from our circular buffer. */
1086 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1087 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1088 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1089 /* Mark the block as empty again. */
1090 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1091 cbAllRead += cbMemRead;
1092
1093 pInt->cbCurAll += cbMemRead;
1094 }
1095
1096 if (pcbRead)
1097 *pcbRead = cbAllRead;
1098
1099 if (rc == VERR_EOF)
1100 rc = VINF_SUCCESS;
1101
1102 /* Signal the thread to read more data in the mean time. */
1103 if ( RT_SUCCESS(rc)
1104 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1105 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1106
1107 return rc;
1108}
1109
1110static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
1111{
1112 /* Validate input. */
1113 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1114 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1115
1116 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1117 PVDINTERFACEIO pIfIo = VDIfIoGet(pSha1Storage->pVDImageIfaces);
1118 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1119
1120 DEBUG_PRINT_FLOW();
1121
1122 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1123
1124 /* Check if there is still something in the buffer. If yes, flush it. */
1125 int rc = sha1FlushCurBuf(pInt);
1126 if (RT_FAILURE(rc))
1127 return rc;
1128
1129 return vdIfIoFileFlushSync(pIfIo, pInt->pvStorage);
1130}
1131
1132/******************************************************************************
1133 * Public Functions *
1134 ******************************************************************************/
1135
1136PVDINTERFACEIO Sha1CreateInterface()
1137{
1138 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1139 if (!pCallbacks)
1140 return NULL;
1141
1142 pCallbacks->pfnOpen = sha1OpenCallback;
1143 pCallbacks->pfnClose = sha1CloseCallback;
1144 pCallbacks->pfnDelete = sha1DeleteCallback;
1145 pCallbacks->pfnMove = sha1MoveCallback;
1146 pCallbacks->pfnGetFreeSpace = sha1GetFreeSpaceCallback;
1147 pCallbacks->pfnGetModificationTime = sha1GetModificationTimeCallback;
1148 pCallbacks->pfnGetSize = sha1GetSizeCallback;
1149 pCallbacks->pfnSetSize = sha1SetSizeCallback;
1150 pCallbacks->pfnReadSync = sha1ReadSyncCallback;
1151 pCallbacks->pfnWriteSync = sha1WriteSyncCallback;
1152 pCallbacks->pfnFlushSync = sha1FlushSyncCallback;
1153
1154 return pCallbacks;
1155}
1156
1157PVDINTERFACEIO FileCreateInterface()
1158{
1159 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1160 if (!pCallbacks)
1161 return NULL;
1162
1163 pCallbacks->pfnOpen = fileOpenCallback;
1164 pCallbacks->pfnClose = fileCloseCallback;
1165 pCallbacks->pfnDelete = fileDeleteCallback;
1166 pCallbacks->pfnMove = fileMoveCallback;
1167 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1168 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1169 pCallbacks->pfnGetSize = fileGetSizeCallback;
1170 pCallbacks->pfnSetSize = fileSetSizeCallback;
1171 pCallbacks->pfnReadSync = fileReadSyncCallback;
1172 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1173 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1174
1175 return pCallbacks;
1176}
1177
1178PVDINTERFACEIO TarCreateInterface()
1179{
1180 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1181 if (!pCallbacks)
1182 return NULL;
1183
1184 pCallbacks->pfnOpen = tarOpenCallback;
1185 pCallbacks->pfnClose = tarCloseCallback;
1186 pCallbacks->pfnDelete = tarDeleteCallback;
1187 pCallbacks->pfnMove = tarMoveCallback;
1188 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1189 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1190 pCallbacks->pfnGetSize = tarGetSizeCallback;
1191 pCallbacks->pfnSetSize = tarSetSizeCallback;
1192 pCallbacks->pfnReadSync = tarReadSyncCallback;
1193 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1194 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1195
1196 return pCallbacks;
1197}
1198
1199int Sha1ReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1200{
1201 /* Validate input. */
1202 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1203 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1204 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1205
1206 void *pvStorage;
1207 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1208 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1209 &pvStorage);
1210 if (RT_FAILURE(rc))
1211 return rc;
1212
1213 void *pvTmpBuf = 0;
1214 void *pvBuf = 0;
1215 uint64_t cbTmpSize = _1M;
1216 size_t cbAllRead = 0;
1217 do
1218 {
1219 pvTmpBuf = RTMemAlloc(cbTmpSize);
1220 if (!pvTmpBuf)
1221 {
1222 rc = VERR_NO_MEMORY;
1223 break;
1224 }
1225
1226 for(;;)
1227 {
1228 size_t cbRead = 0;
1229 rc = pIfIo->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1230 if ( RT_FAILURE(rc)
1231 || cbRead == 0)
1232 break;
1233 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1234 if (!pvBuf)
1235 {
1236 rc = VERR_NO_MEMORY;
1237 break;
1238 }
1239 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1240 cbAllRead += cbRead;
1241 }
1242 }while(0);
1243
1244 pIfIo->pfnClose(pvUser, pvStorage);
1245
1246 if (rc == VERR_EOF)
1247 rc = VINF_SUCCESS;
1248
1249 if (pvTmpBuf)
1250 RTMemFree(pvTmpBuf);
1251
1252 if (RT_SUCCESS(rc))
1253 {
1254 *ppvBuf = pvBuf;
1255 *pcbSize = cbAllRead;
1256 }else
1257 {
1258 if (pvBuf)
1259 RTMemFree(pvBuf);
1260 }
1261
1262 return rc;
1263}
1264
1265int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pIfIo, void *pvUser)
1266{
1267 /* Validate input. */
1268 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1269 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1270 AssertPtrReturn(pIfIo, VERR_INVALID_POINTER);
1271
1272 void *pvStorage;
1273 int rc = pIfIo->pfnOpen(pvUser, pcszFilename,
1274 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1275 &pvStorage);
1276 if (RT_FAILURE(rc))
1277 return rc;
1278
1279 size_t cbAllWritten = 0;
1280 for(;;)
1281 {
1282 if (cbAllWritten >= cbSize)
1283 break;
1284 size_t cbToWrite = cbSize - cbAllWritten;
1285 size_t cbWritten = 0;
1286 rc = pIfIo->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1287 if (RT_FAILURE(rc))
1288 break;
1289 cbAllWritten += cbWritten;
1290 }
1291
1292 pIfIo->pfnClose(pvUser, pvStorage);
1293
1294 return rc;
1295}
1296
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