~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-server/ApplianceImplIO.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: ApplianceImplIO.cpp 35368 2010-12-30 13:38:23Z 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
 
 
39
typedef struct FILESTORAGEINTERNAL
 
40
{
 
41
    /** File handle. */
 
42
    RTFILE         file;
 
43
    /** Completion callback. */
 
44
    PFNVDCOMPLETED pfnCompleted;
 
45
} FILESTORAGEINTERNAL, *PFILESTORAGEINTERNAL;
 
46
 
 
47
typedef struct TARSTORAGEINTERNAL
 
48
{
 
49
    /** Tar handle. */
 
50
    RTTARFILE      file;
 
51
    /** Completion callback. */
 
52
    PFNVDCOMPLETED pfnCompleted;
 
53
} TARSTORAGEINTERNAL, *PTARSTORAGEINTERNAL;
 
54
 
 
55
typedef 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_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
 
 
115
static int fileOpenCallback(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
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)RTMemAllocZ(sizeof(FILESTORAGEINTERNAL));
 
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
 
 
140
static int fileCloseCallback(void * /* pvUser */, void *pvStorage)
 
141
{
 
142
    /* Validate input. */
 
143
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
144
 
 
145
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)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
 
 
157
static int fileDeleteCallback(void * /* pvUser */, const char *pcszFilename)
 
158
{
 
159
    DEBUG_PRINT_FLOW();
 
160
 
 
161
    return RTFileDelete(pcszFilename);
 
162
}
 
163
 
 
164
static int fileMoveCallback(void * /* pvUser */, const char *pcszSrc, const char *pcszDst, unsigned fMove)
 
165
{
 
166
    DEBUG_PRINT_FLOW();
 
167
 
 
168
    return RTFileMove(pcszSrc, pcszDst, fMove);
 
169
}
 
170
 
 
171
static int fileGetFreeSpaceCallback(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
 
 
182
static int fileGetModificationTimeCallback(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
 
 
193
static int fileGetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t *pcbSize)
 
194
{
 
195
    /* Validate input. */
 
196
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
197
 
 
198
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
 
199
 
 
200
    DEBUG_PRINT_FLOW();
 
201
 
 
202
    return RTFileGetSize(pInt->file, pcbSize);
 
203
}
 
204
 
 
205
static int fileSetSizeCallback(void * /* pvUser */, void *pvStorage, uint64_t cbSize)
 
206
{
 
207
    /* Validate input. */
 
208
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
209
 
 
210
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
 
211
 
 
212
    DEBUG_PRINT_FLOW();
 
213
 
 
214
    return RTFileSetSize(pInt->file, cbSize);
 
215
}
 
216
 
 
217
static int fileWriteSyncCallback(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
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
 
224
 
 
225
    return RTFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
 
226
}
 
227
 
 
228
static int fileReadSyncCallback(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
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
 
237
 
 
238
    return RTFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
 
239
}
 
240
 
 
241
static int fileFlushSyncCallback(void * /* pvUser */, void *pvStorage)
 
242
{
 
243
    /* Validate input. */
 
244
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
245
 
 
246
    DEBUG_PRINT_FLOW();
 
247
 
 
248
    PFILESTORAGEINTERNAL pInt = (PFILESTORAGEINTERNAL)pvStorage;
 
249
 
 
250
    return RTFileFlush(pInt->file);
 
251
}
 
252
 
 
253
/******************************************************************************
 
254
 *   Internal: RTTar interface
 
255
 ******************************************************************************/
 
256
 
 
257
static int tarOpenCallback(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
    PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)RTMemAllocZ(sizeof(TARSTORAGEINTERNAL));
 
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
 
 
327
static int tarCloseCallback(void *pvUser, void *pvStorage)
 
328
{
 
329
    /* Validate input. */
 
330
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
331
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
332
 
 
333
    PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)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
 
 
345
static int tarDeleteCallback(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
 
 
356
static int tarMoveCallback(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
 
 
368
static int tarGetFreeSpaceCallback(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
 
 
380
static int tarGetModificationTimeCallback(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
 
 
392
static int tarGetSizeCallback(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
    PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
 
399
 
 
400
    DEBUG_PRINT_FLOW();
 
401
 
 
402
    return RTTarFileGetSize(pInt->file, pcbSize);
 
403
}
 
404
 
 
405
static int tarSetSizeCallback(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
    PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
 
412
 
 
413
    DEBUG_PRINT_FLOW();
 
414
 
 
415
    return RTTarFileSetSize(pInt->file, cbSize);
 
416
}
 
417
 
 
418
static int tarWriteSyncCallback(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
    PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
 
426
 
 
427
    DEBUG_PRINT_FLOW();
 
428
 
 
429
    return RTTarFileWriteAt(pInt->file, uOffset, pvBuf, cbWrite, pcbWritten);
 
430
}
 
431
 
 
432
static int tarReadSyncCallback(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
    PTARSTORAGEINTERNAL pInt = (PTARSTORAGEINTERNAL)pvStorage;
 
440
 
 
441
//    DEBUG_PRINT_FLOW();
 
442
 
 
443
    return RTTarFileReadAt(pInt->file, uOffset, pvBuf, cbRead, pcbRead);
 
444
}
 
445
 
 
446
static int tarFlushSyncCallback(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
 
 
461
DECLCALLBACK(int) sha1CalcWorkerThread(RTTHREAD /* aThread */, void *pvUser)
 
462
{
 
463
    /* Validate input. */
 
464
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
465
 
 
466
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)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
 
 
611
DECLINLINE(int) sha1SignalManifestThread(PSHA1STORAGEINTERNAL pInt, uint32_t uStatus)
 
612
{
 
613
    ASMAtomicWriteU32(&pInt->u32Status, uStatus);
 
614
    return RTSemEventSignal(pInt->newStatusEvent);
 
615
}
 
616
 
 
617
DECLINLINE(int) sha1WaitForManifestThreadFinished(PSHA1STORAGEINTERNAL 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
 
 
634
DECLINLINE(int) sha1FlushCurBuf(PSHA1STORAGEINTERNAL 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 = sha1SignalManifestThread(pInt, STATUS_WRITE);
 
641
        if (RT_FAILURE(rc))
 
642
            return rc;
 
643
 
 
644
        /* Wait until the write worker thread has finished. */
 
645
        rc = sha1WaitForManifestThreadFinished(pInt);
 
646
    }
 
647
 
 
648
    return rc;
 
649
}
 
650
 
 
651
static int sha1OpenCallback(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
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)RTMemAllocZ(sizeof(SHA1STORAGEINTERNAL));
 
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, sha1CalcWorkerThread, 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 = sha1SignalManifestThread(pInt, STATUS_READ);
 
730
        }
 
731
    }
 
732
    while(0);
 
733
 
 
734
    if (RT_FAILURE(rc))
 
735
    {
 
736
        if (pInt->pWorkerThread)
 
737
        {
 
738
            sha1SignalManifestThread(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
 
 
757
static int sha1CloseCallback(void *pvUser, void *pvStorage)
 
758
{
 
759
    /* Validate input. */
 
760
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
761
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
762
 
 
763
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
 
770
 
 
771
    DEBUG_PRINT_FLOW();
 
772
 
 
773
    int rc = VINF_SUCCESS;
 
774
 
 
775
    /* Make sure all pending writes are flushed */
 
776
    rc = sha1FlushCurBuf(pInt);
 
777
 
 
778
    if (pInt->pWorkerThread)
 
779
    {
 
780
        /* Signal the worker thread to end himself */
 
781
        rc = sha1SignalManifestThread(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
 
 
822
static int sha1DeleteCallback(void *pvUser, const char *pcszFilename)
 
823
{
 
824
    /* Validate input. */
 
825
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
826
 
 
827
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
 
 
838
static int sha1MoveCallback(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
 
839
{
 
840
    /* Validate input. */
 
841
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
842
 
 
843
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
 
 
854
static int sha1GetFreeSpaceCallback(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
 
855
{
 
856
    /* Validate input. */
 
857
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
858
 
 
859
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
 
 
870
static int sha1GetModificationTimeCallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
 
871
{
 
872
    /* Validate input. */
 
873
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
874
 
 
875
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
 
 
887
static int sha1GetSizeCallback(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
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)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
 
 
913
static int sha1SetSizeCallback(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
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
 
926
 
 
927
    DEBUG_PRINT_FLOW();
 
928
 
 
929
    return pCallbacks->pfnSetSize(pIO->pvUser, pInt->pvStorage, cbSize);
 
930
}
 
931
 
 
932
static int sha1WriteSyncCallback(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
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)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 = (size_t)(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 = sha1WriteSyncCallback(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 = sha1SignalManifestThread(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 = sha1WaitForManifestThreadFinished(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 = sha1SignalManifestThread(pInt, STATUS_WRITE);
 
1025
 
 
1026
    return rc;
 
1027
}
 
1028
 
 
1029
static int sha1ReadSyncCallback(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
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)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
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)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 = sha1ReadSyncCallback(pvUser, pvStorage, pInt->cbCurAll, 0,
 
1056
                                    (size_t)(uOffset - pInt->cbCurAll), 0);
 
1057
        if (RT_FAILURE(rc))
 
1058
            return rc;
 
1059
    }
 
1060
 
 
1061
    size_t cbAllRead = 0;
 
1062
    for(;;)
 
1063
    {
 
1064
        /* Finished? */
 
1065
        if (cbAllRead == cbRead)
 
1066
            break;
 
1067
        size_t cbAvail = RTCircBufUsed(pInt->pCircBuf);
 
1068
        if (   cbAvail == 0
 
1069
            && pInt->fEOF)
 
1070
        {
 
1071
            break;
 
1072
        }
 
1073
        /* If there isn't enough data make sure the worker thread is fetching
 
1074
         * more. */
 
1075
        if ((cbRead - cbAllRead) > cbAvail)
 
1076
        {
 
1077
            rc = sha1SignalManifestThread(pInt, STATUS_READ);
 
1078
            if(RT_FAILURE(rc))
 
1079
                break;
 
1080
            /* If there is _no_ data available, we have to wait until it is. */
 
1081
            if (cbAvail == 0)
 
1082
            {
 
1083
                rc = sha1WaitForManifestThreadFinished(pInt);
 
1084
                if (RT_FAILURE(rc))
 
1085
                    break;
 
1086
                cbAvail = RTCircBufUsed(pInt->pCircBuf);
 
1087
//                RTPrintf("############## wait %lu %lu %lu \n", cbRead, cbAllRead, cbAvail);
 
1088
//                pInt->waits++;
 
1089
            }
 
1090
        }
 
1091
        size_t cbToRead = RT_MIN(cbRead - cbAllRead, cbAvail);
 
1092
        char *pcBuf;
 
1093
        size_t cbMemRead = 0;
 
1094
        /* Acquire a block for reading from our circular buffer. */
 
1095
        RTCircBufAcquireReadBlock(pInt->pCircBuf, cbToRead, (void**)&pcBuf, &cbMemRead);
 
1096
        if (pvBuf) /* Make it possible to blind read data (for skipping) */
 
1097
            memcpy(&((char*)pvBuf)[cbAllRead], pcBuf, cbMemRead);
 
1098
        /* Mark the block as empty again. */
 
1099
        RTCircBufReleaseReadBlock(pInt->pCircBuf, cbMemRead);
 
1100
        cbAllRead += cbMemRead;
 
1101
 
 
1102
        pInt->cbCurAll += cbMemRead;
 
1103
    }
 
1104
 
 
1105
    if (pcbRead)
 
1106
        *pcbRead = cbAllRead;
 
1107
 
 
1108
    if (rc == VERR_EOF)
 
1109
        rc = VINF_SUCCESS;
 
1110
 
 
1111
    /* Signal the thread to read more data in the mean time. */
 
1112
    if (   RT_SUCCESS(rc)
 
1113
        && RTCircBufFree(pInt->pCircBuf) >= (RTCircBufSize(pInt->pCircBuf) / 2))
 
1114
        rc = sha1SignalManifestThread(pInt, STATUS_READ);
 
1115
 
 
1116
    return rc;
 
1117
}
 
1118
 
 
1119
static int sha1FlushSyncCallback(void *pvUser, void *pvStorage)
 
1120
{
 
1121
    /* Validate input. */
 
1122
    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
 
1123
    AssertPtrReturn(pvStorage, VERR_INVALID_POINTER);
 
1124
 
 
1125
    PSHA1STORAGE pSha1Storage = (PSHA1STORAGE)pvUser;
 
1126
    PVDINTERFACE pIO = VDInterfaceGet(pSha1Storage->pVDImageIfaces, VDINTERFACETYPE_IO);
 
1127
    AssertPtrReturn(pIO, VERR_INVALID_PARAMETER);
 
1128
    PVDINTERFACEIO pCallbacks = VDGetInterfaceIO(pIO);
 
1129
    AssertPtrReturn(pCallbacks, VERR_INVALID_PARAMETER);
 
1130
 
 
1131
    DEBUG_PRINT_FLOW();
 
1132
 
 
1133
    PSHA1STORAGEINTERNAL pInt = (PSHA1STORAGEINTERNAL)pvStorage;
 
1134
 
 
1135
    /* Check if there is still something in the buffer. If yes, flush it. */
 
1136
    int rc = sha1FlushCurBuf(pInt);
 
1137
    if (RT_FAILURE(rc))
 
1138
        return rc;
 
1139
 
 
1140
    return pCallbacks->pfnFlushSync(pIO->pvUser, pInt->pvStorage);
 
1141
}
 
1142
 
 
1143
/******************************************************************************
 
1144
 *   Public Functions                                                         *
 
1145
 ******************************************************************************/
 
1146
 
 
1147
PVDINTERFACEIO Sha1CreateInterface()
 
1148
{
 
1149
    PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
 
1150
    if (!pCallbacks)
 
1151
        return NULL;
 
1152
 
 
1153
    pCallbacks->cbSize                 = sizeof(VDINTERFACEIO);
 
1154
    pCallbacks->enmInterface           = VDINTERFACETYPE_IO;
 
1155
    pCallbacks->pfnOpen                = sha1OpenCallback;
 
1156
    pCallbacks->pfnClose               = sha1CloseCallback;
 
1157
    pCallbacks->pfnDelete              = sha1DeleteCallback;
 
1158
    pCallbacks->pfnMove                = sha1MoveCallback;
 
1159
    pCallbacks->pfnGetFreeSpace        = sha1GetFreeSpaceCallback;
 
1160
    pCallbacks->pfnGetModificationTime = sha1GetModificationTimeCallback;
 
1161
    pCallbacks->pfnGetSize             = sha1GetSizeCallback;
 
1162
    pCallbacks->pfnSetSize             = sha1SetSizeCallback;
 
1163
    pCallbacks->pfnReadSync            = sha1ReadSyncCallback;
 
1164
    pCallbacks->pfnWriteSync           = sha1WriteSyncCallback;
 
1165
    pCallbacks->pfnFlushSync           = sha1FlushSyncCallback;
 
1166
 
 
1167
    return pCallbacks;
 
1168
}
 
1169
 
 
1170
PVDINTERFACEIO FileCreateInterface()
 
1171
{
 
1172
    PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
 
1173
    if (!pCallbacks)
 
1174
        return NULL;
 
1175
 
 
1176
    pCallbacks->cbSize                 = sizeof(VDINTERFACEIO);
 
1177
    pCallbacks->enmInterface           = VDINTERFACETYPE_IO;
 
1178
    pCallbacks->pfnOpen                = fileOpenCallback;
 
1179
    pCallbacks->pfnClose               = fileCloseCallback;
 
1180
    pCallbacks->pfnDelete              = fileDeleteCallback;
 
1181
    pCallbacks->pfnMove                = fileMoveCallback;
 
1182
    pCallbacks->pfnGetFreeSpace        = fileGetFreeSpaceCallback;
 
1183
    pCallbacks->pfnGetModificationTime = fileGetModificationTimeCallback;
 
1184
    pCallbacks->pfnGetSize             = fileGetSizeCallback;
 
1185
    pCallbacks->pfnSetSize             = fileSetSizeCallback;
 
1186
    pCallbacks->pfnReadSync            = fileReadSyncCallback;
 
1187
    pCallbacks->pfnWriteSync           = fileWriteSyncCallback;
 
1188
    pCallbacks->pfnFlushSync           = fileFlushSyncCallback;
 
1189
 
 
1190
    return pCallbacks;
 
1191
}
 
1192
 
 
1193
PVDINTERFACEIO TarCreateInterface()
 
1194
{
 
1195
    PVDINTERFACEIO pCallbacks = (PVDINTERFACEIO)RTMemAllocZ(sizeof(VDINTERFACEIO));
 
1196
    if (!pCallbacks)
 
1197
        return NULL;
 
1198
 
 
1199
    pCallbacks->cbSize                 = sizeof(VDINTERFACEIO);
 
1200
    pCallbacks->enmInterface           = VDINTERFACETYPE_IO;
 
1201
    pCallbacks->pfnOpen                = tarOpenCallback;
 
1202
    pCallbacks->pfnClose               = tarCloseCallback;
 
1203
    pCallbacks->pfnDelete              = tarDeleteCallback;
 
1204
    pCallbacks->pfnMove                = tarMoveCallback;
 
1205
    pCallbacks->pfnGetFreeSpace        = tarGetFreeSpaceCallback;
 
1206
    pCallbacks->pfnGetModificationTime = tarGetModificationTimeCallback;
 
1207
    pCallbacks->pfnGetSize             = tarGetSizeCallback;
 
1208
    pCallbacks->pfnSetSize             = tarSetSizeCallback;
 
1209
    pCallbacks->pfnReadSync            = tarReadSyncCallback;
 
1210
    pCallbacks->pfnWriteSync           = tarWriteSyncCallback;
 
1211
    pCallbacks->pfnFlushSync           = tarFlushSyncCallback;
 
1212
 
 
1213
    return pCallbacks;
 
1214
}
 
1215
 
 
1216
int Sha1ReadBuf(const char *pcszFilename, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
 
1217
{
 
1218
    /* Validate input. */
 
1219
    AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
 
1220
    AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
 
1221
    AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
 
1222
 
 
1223
    void *pvStorage;
 
1224
    int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
 
1225
                                 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, 0,
 
1226
                                 &pvStorage);
 
1227
    if (RT_FAILURE(rc))
 
1228
        return rc;
 
1229
 
 
1230
    void *pvTmpBuf = 0;
 
1231
    void *pvBuf = 0;
 
1232
    uint64_t cbTmpSize = _1M;
 
1233
    size_t cbAllRead = 0;
 
1234
    do
 
1235
    {
 
1236
        pvTmpBuf = RTMemAlloc(cbTmpSize);
 
1237
        if (!pvTmpBuf)
 
1238
        {
 
1239
            rc = VERR_NO_MEMORY;
 
1240
            break;
 
1241
        }
 
1242
 
 
1243
        for(;;)
 
1244
        {
 
1245
            size_t cbRead = 0;
 
1246
            rc = pCallbacks->pfnReadSync(pvUser, pvStorage, cbAllRead, pvTmpBuf, cbTmpSize, &cbRead);
 
1247
            if (   RT_FAILURE(rc)
 
1248
                || cbRead == 0)
 
1249
                break;
 
1250
            pvBuf = RTMemRealloc(pvBuf, cbAllRead + cbRead);
 
1251
            if (!pvBuf)
 
1252
            {
 
1253
                rc = VERR_NO_MEMORY;
 
1254
                break;
 
1255
            }
 
1256
            memcpy(&((char*)pvBuf)[cbAllRead], pvTmpBuf, cbRead);
 
1257
            cbAllRead += cbRead;
 
1258
        }
 
1259
    }while(0);
 
1260
 
 
1261
    pCallbacks->pfnClose(pvUser, pvStorage);
 
1262
 
 
1263
    if (rc == VERR_EOF)
 
1264
        rc = VINF_SUCCESS;
 
1265
 
 
1266
    if (pvTmpBuf)
 
1267
        RTMemFree(pvTmpBuf);
 
1268
 
 
1269
    if (RT_SUCCESS(rc))
 
1270
    {
 
1271
        *ppvBuf = pvBuf;
 
1272
        *pcbSize = cbAllRead;
 
1273
    }else
 
1274
    {
 
1275
        if (pvBuf)
 
1276
            RTMemFree(pvBuf);
 
1277
    }
 
1278
 
 
1279
    return rc;
 
1280
}
 
1281
 
 
1282
int Sha1WriteBuf(const char *pcszFilename, void *pvBuf, size_t cbSize, PVDINTERFACEIO pCallbacks, void *pvUser)
 
1283
{
 
1284
    /* Validate input. */
 
1285
    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
 
1286
    AssertReturn(cbSize, VERR_INVALID_PARAMETER);
 
1287
    AssertPtrReturn(pCallbacks, VERR_INVALID_POINTER);
 
1288
 
 
1289
    void *pvStorage;
 
1290
    int rc = pCallbacks->pfnOpen(pvUser, pcszFilename,
 
1291
                                 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL, 0,
 
1292
                                 &pvStorage);
 
1293
    if (RT_FAILURE(rc))
 
1294
        return rc;
 
1295
 
 
1296
    size_t cbAllWritten = 0;
 
1297
    for(;;)
 
1298
    {
 
1299
        if (cbAllWritten >= cbSize)
 
1300
            break;
 
1301
        size_t cbToWrite = cbSize - cbAllWritten;
 
1302
        size_t cbWritten = 0;
 
1303
        rc = pCallbacks->pfnWriteSync(pvUser, pvStorage, cbAllWritten, &((char*)pvBuf)[cbAllWritten], cbToWrite, &cbWritten);
 
1304
        if (RT_FAILURE(rc))
 
1305
            break;
 
1306
        cbAllWritten += cbWritten;
 
1307
    }
 
1308
 
 
1309
    pCallbacks->pfnClose(pvUser, pvStorage);
 
1310
 
 
1311
    return rc;
 
1312
}
 
1313