VirtualBox

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

Last change on this file since 36986 was 36043, checked in by vboxsync, 14 years ago

sha1WaitForManifestThreadFinished: Read once instead of 4x.

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