VirtualBox

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

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

Main-OVF: fix exporting to slow medias

  • 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 36015 2011-02-17 15:10:32Z vboxsync $ */
2/** @file
3 *
4 * IO helper for IAppliance COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. 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 if (!( ASMAtomicReadU32(&pInt->u32Status) == STATUS_WRITE
632 || ASMAtomicReadU32(&pInt->u32Status) == STATUS_WRITING
633 || ASMAtomicReadU32(&pInt->u32Status) == STATUS_READ
634 || ASMAtomicReadU32(&pInt->u32Status) == STATUS_READING))
635 break;
636 rc = RTSemEventWait(pInt->workFinishedEvent, 100);
637 }
638 if (rc == VERR_TIMEOUT)
639 rc = VINF_SUCCESS;
640 return rc;
641}
642
643DECLINLINE(int) sha1FlushCurBuf(PSHA1STORAGEINTERNAL pInt)
644{
645 int rc = VINF_SUCCESS;
646 if (pInt->fOpenMode & RTFILE_O_WRITE)
647 {
648 /* Let the write worker thread start immediately. */
649 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
650 if (RT_FAILURE(rc))
651 return rc;
652
653 /* Wait until the write worker thread has finished. */
654 rc = sha1WaitForManifestThreadFinished(pInt);
655 }
656
657 return rc;
658}
659
660static int sha1OpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen,
661 PFNVDCOMPLETED pfnCompleted, void **ppInt)
662{
663 /* Validate input. */
664 AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER);
665 AssertPtrReturn(pszLocation, VERR_INVALID_POINTER);
666 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
667 AssertPtrReturn(ppInt, VERR_INVALID_POINTER);
668 AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */
669
670 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
671 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
672 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
673 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
674 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
675
676 DEBUG_PRINT_FLOW();
677
678 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)RTMemAllocZ(sizeof(SHA1STORAGEINTERNAL));
679 if (!pInt)
680 return VERR_NO_MEMORY;
681
682 int rc = VINF_SUCCESS;
683 do
684 {
685 pInt->pfnCompleted = pfnCompleted;
686 pInt->pSha1Storage = pSha1Storage;
687 pInt->fEOF = false;
688 pInt->fOpenMode = fOpen;
689 pInt->u32Status = STATUS_WAIT;
690
691 /* Circular buffer in the read case. */
692 rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2);
693 if (RT_FAILURE(rc))
694 break;
695
696 if (fOpen & RTFILE_O_WRITE)
697 {
698 /* The zero buffer is used for appending empty parts at the end of the
699 * file (or our buffer) in setSize or when uOffset in writeSync is
700 * increased in steps bigger than a byte. */
701 pInt->cbZeroBuf = _1K;
702 pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf);
703 if (!pInt->pvZeroBuf)
704 {
705 rc = VERR_NO_MEMORY;
706 break;
707 }
708 }
709
710 /* Create an event semaphore to indicate a state change for the worker
711 * thread. */
712 rc = RTSemEventCreate(&pInt->newStatusEvent);
713 if (RT_FAILURE(rc))
714 break;
715 /* Create an event semaphore to indicate a finished calculation of the
716 worker thread. */
717 rc = RTSemEventCreate(&pInt->workFinishedEvent);
718 if (RT_FAILURE(rc))
719 break;
720 /* Create the worker thread. */
721 rc = RTThreadCreate(&pInt->pWorkerThread, sha1CalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA1-Worker");
722 if (RT_FAILURE(rc))
723 break;
724
725 if (pSha1Storage->fCreateDigest)
726 /* Create a SHA1 context the worker thread will work with. */
727 RTSha1Init(&pInt->ctx);
728
729 /* Open the file. */
730 rc = pCallbacks->pfnOpen(pIO->pvUser, pszLocation,
731 fOpen, pInt->pfnCompleted,
732 &pInt->pvStorage);
733 if (RT_FAILURE(rc))
734 break;
735
736 if (fOpen & RTFILE_O_READ)
737 {
738 /* Immediately let the worker thread start the reading. */
739 rc = sha1SignalManifestThread(pInt, STATUS_READ);
740 }
741 }
742 while(0);
743
744 if (RT_FAILURE(rc))
745 {
746 if (pInt->pWorkerThread)
747 {
748 sha1SignalManifestThread(pInt, STATUS_END);
749 RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
750 }
751 if (pInt->workFinishedEvent)
752 RTSemEventDestroy(pInt->workFinishedEvent);
753 if (pInt->newStatusEvent)
754 RTSemEventDestroy(pInt->newStatusEvent);
755 if (pInt->pCircBuf)
756 RTCircBufDestroy(pInt->pCircBuf);
757 if (pInt->pvZeroBuf)
758 RTMemFree(pInt->pvZeroBuf);
759 RTMemFree(pInt);
760 }
761 else
762 *ppInt = pInt;
763
764 return rc;
765}
766
767static int sha1CloseCallback(void *pvUser, void *pvStorage)
768{
769 /* Validate input. */
770 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
771 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
772
773 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
774 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
775 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
776 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
777 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
778
779 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
780
781 DEBUG_PRINT_FLOW();
782
783 int rc = VINF_SUCCESS;
784
785 /* Make sure all pending writes are flushed */
786 rc = sha1FlushCurBuf(pInt);
787
788 if (pInt->pWorkerThread)
789 {
790 /* Signal the worker thread to end himself */
791 rc = sha1SignalManifestThread(pInt, STATUS_END);
792 /* Worker thread stopped? */
793 rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0);
794 }
795
796 if ( RT_SUCCESS(rc)
797 && pSha1Storage->fCreateDigest)
798 {
799 /* Finally calculate & format the SHA1 sum */
800 unsigned char auchDig[RTSHA1_HASH_SIZE];
801 char *pszDigest;
802 RTSha1Final(&pInt->ctx, auchDig);
803 rc = RTStrAllocEx(&pszDigest, RTSHA1_DIGEST_LEN + 1);
804 if (RT_SUCCESS(rc))
805 {
806 rc = RTSha1ToString(auchDig, pszDigest, RTSHA1_DIGEST_LEN + 1);
807 if (RT_SUCCESS(rc))
808 pSha1Storage->strDigest = pszDigest;
809 RTStrFree(pszDigest);
810 }
811 }
812
813 /* Close the file */
814 rc = pCallbacks->pfnClose(pIO->pvUser, pInt->pvStorage);
815
816// RTPrintf("%lu %lu\n", pInt->calls, pInt->waits);
817
818 /* Cleanup */
819 if (pInt->workFinishedEvent)
820 RTSemEventDestroy(pInt->workFinishedEvent);
821 if (pInt->newStatusEvent)
822 RTSemEventDestroy(pInt->newStatusEvent);
823 if (pInt->pCircBuf)
824 RTCircBufDestroy(pInt->pCircBuf);
825 if (pInt->pvZeroBuf)
826 RTMemFree(pInt->pvZeroBuf);
827 RTMemFree(pInt);
828
829 return rc;
830}
831
832static int sha1DeleteCallback(void *pvUser, const char *pcszFilename)
833{
834 /* Validate input. */
835 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
836
837 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
838 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
839 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
840 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
841 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
842
843 DEBUG_PRINT_FLOW();
844
845 return pCallbacks->pfnDelete(pIO->pvUser, pcszFilename);
846}
847
848static int sha1MoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
849{
850 /* Validate input. */
851 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
852
853 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
854 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
855 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
856 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
857 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
858
859 DEBUG_PRINT_FLOW();
860
861 return pCallbacks->pfnMove(pIO->pvUser, pcszSrc, pcszDst, fMove);
862}
863
864static int sha1GetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
865{
866 /* Validate input. */
867 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
868
869 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
870 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
871 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
872 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
873 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
874
875 DEBUG_PRINT_FLOW();
876
877 return pCallbacks->pfnGetFreeSpace(pIO->pvUser, pcszFilename, pcbFreeSpace);
878}
879
880static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
881{
882 /* Validate input. */
883 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
884
885 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
886 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
887 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
888 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
889 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
890
891 DEBUG_PRINT_FLOW();
892
893 return pCallbacks->pfnGetModificationTime(pIO->pvUser, pcszFilename, pModificationTime);
894}
895
896
897static int sha1GetSizeCallback(void *pvUser, void *pvStorage, uint64_t *pcbSize)
898{
899 /* Validate input. */
900 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
901 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
902
903 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
904 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
905 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
906 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
907 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
908
909 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
910
911 DEBUG_PRINT_FLOW();
912
913 uint64_t cbSize;
914 int rc = pCallbacks->pfnGetSize(pIO->pvUser, pInt->pvStorage, &cbSize);
915 if (RT_FAILURE(rc))
916 return rc;
917
918 *pcbSize = RT_MAX(pInt->cbCurAll, cbSize);
919
920 return VINF_SUCCESS;
921}
922
923static int sha1SetSizeCallback(void *pvUser, void *pvStorage, uint64_t cbSize)
924{
925 /* Validate input. */
926 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
927 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
928
929 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
930 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
931 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
932 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
933 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
934
935 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
936
937 DEBUG_PRINT_FLOW();
938
939 return pCallbacks->pfnSetSize(pIO->pvUser, pInt->pvStorage, cbSize);
940}
941
942static int sha1WriteSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
943 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
944{
945 /* Validate input. */
946 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
947 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
948
949 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
950 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
951 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
952 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
953 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
954
955 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
956
957 DEBUG_PRINT_FLOW();
958
959 /* Check that the write is linear */
960 AssertMsgReturn(pInt->cbCurAll <= uOffset, ("Backward seeking is not allowed (uOffset: %7lu cbCurAll: %7lu)!", uOffset, pInt->cbCurAll), VERR_INVALID_PARAMETER);
961
962 int rc = VINF_SUCCESS;
963
964 /* Check if we have to add some free space at the end, before we start the
965 * real write. */
966 if (pInt->cbCurAll < uOffset)
967 {
968 size_t cbSize = (size_t)(uOffset - pInt->cbCurAll);
969 size_t cbAllWritten = 0;
970 for(;;)
971 {
972 /* Finished? */
973 if (cbAllWritten == cbSize)
974 break;
975 size_t cbToWrite = RT_MIN(pInt->cbZeroBuf, cbSize - cbAllWritten);
976 size_t cbWritten = 0;
977 rc = sha1WriteSyncCallback(pvUser, pvStorage, pInt->cbCurAll,
978 pInt->pvZeroBuf, cbToWrite, &cbWritten);
979 if (RT_FAILURE(rc))
980 break;
981 cbAllWritten += cbWritten;
982 }
983 if (RT_FAILURE(rc))
984 return rc;
985 }
986// RTPrintf("Write uOffset: %7lu cbWrite: %7lu = %7lu\n", uOffset, cbWrite, uOffset + cbWrite);
987
988 size_t cbAllWritten = 0;
989 for(;;)
990 {
991 /* Finished? */
992 if (cbAllWritten == cbWrite)
993 break;
994 size_t cbAvail = RTCircBufFree(pInt->pCircBuf);
995 if ( cbAvail == 0
996 && pInt->fEOF)
997 return VERR_EOF;
998 /* If there isn't enough free space make sure the worker thread is
999 * writing some data. */
1000 if ((cbWrite - cbAllWritten) > cbAvail)
1001 {
1002 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
1003 if(RT_FAILURE(rc))
1004 break;
1005 /* If there is _no_ free space available, we have to wait until it is. */
1006 if (cbAvail == 0)
1007 {
1008 rc = sha1WaitForManifestThreadFinished(pInt);
1009 if (RT_FAILURE(rc))
1010 break;
1011 cbAvail = RTCircBufFree(pInt->pCircBuf);
1012// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1013// pInt->waits++;
1014 }
1015 }
1016 size_t cbToWrite = RT_MIN(cbWrite - cbAllWritten, cbAvail);
1017 char *pcBuf;
1018 size_t cbMemWritten = 0;
1019 /* Acquire a block for writing from our circular buffer. */
1020 RTCircBufAcquireWriteBlock(pInt->pCircBuf, cbToWrite, (void**)&pcBuf, &cbMemWritten);
1021 memcpy(pcBuf, &((char*)pvBuf)[cbAllWritten], cbMemWritten);
1022 /* Mark the block full. */
1023 RTCircBufReleaseWriteBlock(pInt->pCircBuf, cbMemWritten);
1024 cbAllWritten += cbMemWritten;
1025 pInt->cbCurAll += cbMemWritten;
1026 }
1027
1028 if (pcbWritten)
1029 *pcbWritten = cbAllWritten;
1030
1031 /* Signal the thread to write more data in the mean time. */
1032 if ( RT_SUCCESS(rc)
1033 && RTCircBufUsed(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1034 rc = sha1SignalManifestThread(pInt, STATUS_WRITE);
1035
1036 return rc;
1037}
1038
1039static int sha1ReadSyncCallback(void *pvUser, void *pvStorage, uint64_t uOffset,
1040 void *pvBuf, size_t cbRead, size_t *pcbRead)
1041{
1042 /* Validate input. */
1043 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1044 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1045
1046 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1047 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
1048 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
1049 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
1050 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
1051
1052// DEBUG_PRINT_FLOW();
1053
1054 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1055
1056 int rc = VINF_SUCCESS;
1057
1058// pInt->calls++;
1059// RTPrintf("Read uOffset: %7lu cbRead: %7lu = %7lu\n", uOffset, cbRead, uOffset + cbRead);
1060
1061 /* Check if we jump forward in the file. If so we have to read the
1062 * remaining stuff in the gap anyway (SHA1; streaming). */
1063 if (pInt->cbCurAll < uOffset)
1064 {
1065 rc = sha1ReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
1066 (size_t)(uOffset - pInt->cbCurAll), 0);
1067 if (RT_FAILURE(rc))
1068 return rc;
1069 }
1070
1071 size_t cbAllRead = 0;
1072 for(;;)
1073 {
1074 /* Finished? */
1075 if (cbAllRead == cbRead)
1076 break;
1077 size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
1078 if ( cbAvail == 0
1079 && pInt->fEOF)
1080 {
1081 break;
1082 }
1083 /* If there isn't enough data make sure the worker thread is fetching
1084 * more. */
1085 if ((cbRead - cbAllRead) > cbAvail)
1086 {
1087 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1088 if(RT_FAILURE(rc))
1089 break;
1090 /* If there is _no_ data available, we have to wait until it is. */
1091 if (cbAvail == 0)
1092 {
1093 rc = sha1WaitForManifestThreadFinished(pInt);
1094 if (RT_FAILURE(rc))
1095 break;
1096 cbAvail = RTCircBufUsed(pInt->pCircBuf);
1097// RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
1098// pInt->waits++;
1099 }
1100 }
1101 size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
1102 char *pcBuf;
1103 size_t cbMemRead = 0;
1104 /* Acquire a block for reading from our circular buffer. */
1105 RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
1106 if (pvBuf) /* Make it possible to blind read data (for skipping) */
1107 memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
1108 /* Mark the block as empty again. */
1109 RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
1110 cbAllRead += cbMemRead;
1111
1112 pInt->cbCurAll += cbMemRead;
1113 }
1114
1115 if (pcbRead)
1116 *pcbRead = cbAllRead;
1117
1118 if (rc == VERR_EOF)
1119 rc = VINF_SUCCESS;
1120
1121 /* Signal the thread to read more data in the mean time. */
1122 if ( RT_SUCCESS(rc)
1123 && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
1124 rc = sha1SignalManifestThread(pInt, STATUS_READ);
1125
1126 return rc;
1127}
1128
1129static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
1130{
1131 /* Validate input. */
1132 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1133 AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
1134
1135 PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
1136 PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
1137 AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
1138 PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
1139 AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
1140
1141 DEBUG_PRINT_FLOW();
1142
1143 PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
1144
1145 /* Check if there is still something in the buffer. If yes, flush it. */
1146 int rc = sha1FlushCurBuf(pInt);
1147 if (RT_FAILURE(rc))
1148 return rc;
1149
1150 return pCallbacks->pfnFlushSync(pIO->pvUser, pInt->pvStorage);
1151}
1152
1153/******************************************************************************
1154 * Public Functions *
1155 ******************************************************************************/
1156
1157PVDINTERFACEIO Sha1CreateInterface()
1158{
1159 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1160 if (!pCallbacks)
1161 return NULL;
1162
1163 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1164 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1165 pCallbacks->pfnOpen = sha1OpenCallback;
1166 pCallbacks->pfnClose = sha1CloseCallback;
1167 pCallbacks->pfnDelete = sha1DeleteCallback;
1168 pCallbacks->pfnMove = sha1MoveCallback;
1169 pCallbacks->pfnGetFreeSpace = sha1GetFreeSpaceCallback;
1170 pCallbacks->pfnGetModificationTime = sha1GetModificationTimeCallback;
1171 pCallbacks->pfnGetSize = sha1GetSizeCallback;
1172 pCallbacks->pfnSetSize = sha1SetSizeCallback;
1173 pCallbacks->pfnReadSync = sha1ReadSyncCallback;
1174 pCallbacks->pfnWriteSync = sha1WriteSyncCallback;
1175 pCallbacks->pfnFlushSync = sha1FlushSyncCallback;
1176
1177 return pCallbacks;
1178}
1179
1180PVDINTERFACEIO FileCreateInterface()
1181{
1182 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1183 if (!pCallbacks)
1184 return NULL;
1185
1186 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1187 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1188 pCallbacks->pfnOpen = fileOpenCallback;
1189 pCallbacks->pfnClose = fileCloseCallback;
1190 pCallbacks->pfnDelete = fileDeleteCallback;
1191 pCallbacks->pfnMove = fileMoveCallback;
1192 pCallbacks->pfnGetFreeSpace = fileGetFreeSpaceCallback;
1193 pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
1194 pCallbacks->pfnGetSize = fileGetSizeCallback;
1195 pCallbacks->pfnSetSize = fileSetSizeCallback;
1196 pCallbacks->pfnReadSync = fileReadSyncCallback;
1197 pCallbacks->pfnWriteSync = fileWriteSyncCallback;
1198 pCallbacks->pfnFlushSync = fileFlushSyncCallback;
1199
1200 return pCallbacks;
1201}
1202
1203PVDINTERFACEIO TarCreateInterface()
1204{
1205 PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
1206 if (!pCallbacks)
1207 return NULL;
1208
1209 pCallbacks->cbSize = sizeof(VDINTERFACEIO);
1210 pCallbacks->enmInterface = VDINTERFACETYPE_IO;
1211 pCallbacks->pfnOpen = tarOpenCallback;
1212 pCallbacks->pfnClose = tarCloseCallback;
1213 pCallbacks->pfnDelete = tarDeleteCallback;
1214 pCallbacks->pfnMove = tarMoveCallback;
1215 pCallbacks->pfnGetFreeSpace = tarGetFreeSpaceCallback;
1216 pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
1217 pCallbacks->pfnGetSize = tarGetSizeCallback;
1218 pCallbacks->pfnSetSize = tarSetSizeCallback;
1219 pCallbacks->pfnReadSync = tarReadSyncCallback;
1220 pCallbacks->pfnWriteSync = tarWriteSyncCallback;
1221 pCallbacks->pfnFlushSync = tarFlushSyncCallback;
1222
1223 return pCallbacks;
1224}
1225
1226int Sha1ReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1227{
1228 /* Validate input. */
1229 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
1230 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1231 AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1232
1233 void *pvStorage;
1234 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1235 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
1236 &pvStorage);
1237 if (RT_FAILURE(rc))
1238 return rc;
1239
1240 void *pvTmpBuf = 0;
1241 void *pvBuf = 0;
1242 uint64_t cbTmpSize = _1M;
1243 size_t cbAllRead = 0;
1244 do
1245 {
1246 pvTmpBuf = RTMemAlloc(cbTmpSize);
1247 if (!pvTmpBuf)
1248 {
1249 rc = VERR_NO_MEMORY;
1250 break;
1251 }
1252
1253 for(;;)
1254 {
1255 size_t cbRead = 0;
1256 rc = pCallbacks->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
1257 if ( RT_FAILURE(rc)
1258 || cbRead == 0)
1259 break;
1260 pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
1261 if (!pvBuf)
1262 {
1263 rc = VERR_NO_MEMORY;
1264 break;
1265 }
1266 memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
1267 cbAllRead += cbRead;
1268 }
1269 }while(0);
1270
1271 pCallbacks->pfnClose(pvUser, pvStorage);
1272
1273 if (rc == VERR_EOF)
1274 rc = VINF_SUCCESS;
1275
1276 if (pvTmpBuf)
1277 RTMemFree(pvTmpBuf);
1278
1279 if (RT_SUCCESS(rc))
1280 {
1281 *ppvBuf = pvBuf;
1282 *pcbSize = cbAllRead;
1283 }else
1284 {
1285 if (pvBuf)
1286 RTMemFree(pvBuf);
1287 }
1288
1289 return rc;
1290}
1291
1292int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
1293{
1294 /* Validate input. */
1295 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1296 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
1297 AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
1298
1299 void *pvStorage;
1300 int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
1301 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
1302 &pvStorage);
1303 if (RT_FAILURE(rc))
1304 return rc;
1305
1306 size_t cbAllWritten = 0;
1307 for(;;)
1308 {
1309 if (cbAllWritten >= cbSize)
1310 break;
1311 size_t cbToWrite = cbSize - cbAllWritten;
1312 size_t cbWritten = 0;
1313 rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
1314 if (RT_FAILURE(rc))
1315 break;
1316 cbAllWritten += cbWritten;
1317 }
1318
1319 pCallbacks->pfnClose(pvUser, pvStorage);
1320
1321 return rc;
1322}
1323
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette