VirtualBox

source: vbox/trunk/src/VBox/Main/ApplianceImplIO.cpp@ 33659

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

Main-OVF: cleanup

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