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

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/common/vfs/vfsmemory.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: vfsmemory.cpp 34560 2010-12-01 11:05:54Z vboxsync $ */
 
2
/** @file
 
3
 * IPRT - Virtual File System, Memory Backed VFS.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2010 Oracle Corporation
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 *
 
17
 * The contents of this file may alternatively be used under the terms
 
18
 * of the Common Development and Distribution License Version 1.0
 
19
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 
20
 * VirtualBox OSE distribution, in which case the provisions of the
 
21
 * CDDL are applicable instead of those of the GPL.
 
22
 *
 
23
 * You may elect to license modified versions of this file under the
 
24
 * terms and conditions of either the GPL or the CDDL or both.
 
25
 */
 
26
 
 
27
 
 
28
/*******************************************************************************
 
29
*   Header Files                                                               *
 
30
*******************************************************************************/
 
31
#include "internal/iprt.h"
 
32
#include <iprt/vfs.h>
 
33
 
 
34
#include <iprt/asm.h>
 
35
#include <iprt/assert.h>
 
36
#include <iprt/err.h>
 
37
#include <iprt/file.h>
 
38
#include <iprt/list.h>
 
39
#include <iprt/poll.h>
 
40
#include <iprt/string.h>
 
41
#include <iprt/vfslowlevel.h>
 
42
 
 
43
 
 
44
 
 
45
/*******************************************************************************
 
46
*   Header Files                                                               *
 
47
*******************************************************************************/
 
48
#include "internal/iprt.h"
 
49
#include <iprt/vfs.h>
 
50
 
 
51
#include <iprt/err.h>
 
52
#include <iprt/mem.h>
 
53
 
 
54
 
 
55
/*******************************************************************************
 
56
*   Defined Constants And Macros                                               *
 
57
*******************************************************************************/
 
58
/** The max extent size. */
 
59
#define RTVFSMEM_MAX_EXTENT_SIZE    _2M
 
60
 
 
61
 
 
62
/*******************************************************************************
 
63
*   Structures and Typedefs                                                    *
 
64
*******************************************************************************/
 
65
 
 
66
/**
 
67
 * Memory base object info.
 
68
 */
 
69
typedef struct RTVFSMEMBASE
 
70
{
 
71
    /** The basic object info. */
 
72
    RTFSOBJINFO         ObjInfo;
 
73
} RTVFSMEMBASE;
 
74
 
 
75
 
 
76
/**
 
77
 * Memory file extent.
 
78
 *
 
79
 * This stores part of the file content.
 
80
 */
 
81
typedef struct RTVFSMEMEXTENT
 
82
{
 
83
    /** Extent list entry. */
 
84
    RTLISTNODE          Entry;
 
85
    /** The offset of this extent within the file. */
 
86
    uint64_t            off;
 
87
    /** The size of the this extent. */
 
88
    uint32_t            cb;
 
89
    /** The data. */
 
90
    uint8_t             abData[1];
 
91
} RTVFSMEMEXTENT;
 
92
/** Pointer to a memory file extent. */
 
93
typedef RTVFSMEMEXTENT *PRTVFSMEMEXTENT;
 
94
 
 
95
/**
 
96
 * Memory file.
 
97
 */
 
98
typedef struct RTVFSMEMFILE
 
99
{
 
100
    /** The base info. */
 
101
    RTVFSMEMBASE        Base;
 
102
    /** The current file position. */
 
103
    uint64_t            offCurPos;
 
104
    /** Pointer to the current file extent. */
 
105
    PRTVFSMEMEXTENT     pCurExt;
 
106
    /** Linked list of file extents - RTVFSMEMEXTENT. */
 
107
    RTLISTNODE          ExtentHead;
 
108
    /** The current extent size.
 
109
     * This is slowly grown to RTVFSMEM_MAX_EXTENT_SIZE as the file grows.  */
 
110
    uint32_t            cbExtent;
 
111
} RTVFSMEMFILE;
 
112
/** Pointer to a memory file. */
 
113
typedef RTVFSMEMFILE *PRTVFSMEMFILE;
 
114
 
 
115
 
 
116
 
 
117
/**
 
118
 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
 
119
 */
 
120
static DECLCALLBACK(int) rtVfsMemFile_Close(void *pvThis)
 
121
{
 
122
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
123
 
 
124
    /*
 
125
     * Free the extent list.
 
126
     */
 
127
    PRTVFSMEMEXTENT pCur, pNext;
 
128
    RTListForEachSafe(&pThis->ExtentHead, pCur, pNext, RTVFSMEMEXTENT, Entry)
 
129
    {
 
130
        pCur->off       = RTFOFF_MAX;
 
131
        pCur->cb        = UINT32_MAX;
 
132
        RTListNodeRemove(&pCur->Entry);
 
133
        RTMemFree(pCur);
 
134
    }
 
135
    pThis->pCurExt = NULL;
 
136
 
 
137
    return VINF_SUCCESS;
 
138
}
 
139
 
 
140
 
 
141
/**
 
142
 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
 
143
 */
 
144
static DECLCALLBACK(int) rtVfsMemFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
 
145
{
 
146
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
147
    switch (enmAddAttr)
 
148
    {
 
149
        case RTFSOBJATTRADD_NOTHING:
 
150
        case RTFSOBJATTRADD_UNIX:
 
151
            *pObjInfo = pThis->Base.ObjInfo;
 
152
            return VINF_SUCCESS;
 
153
 
 
154
        default:
 
155
            return VERR_NOT_SUPPORTED;
 
156
    }
 
157
}
 
158
 
 
159
 
 
160
/**
 
161
 * The slow paths of rtVfsMemFile_LocateExtent.
 
162
 *
 
163
 * @copydoc rtVfsMemFile_LocateExtent
 
164
 */
 
165
static PRTVFSMEMEXTENT rtVfsMemFile_LocateExtentSlow(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit)
 
166
{
 
167
    /*
 
168
     * Search from the start or the previously used extent.  The heuristics
 
169
     * are very very simple, but whatever.
 
170
     */
 
171
    PRTVFSMEMEXTENT pExtent = pThis->pCurExt;
 
172
    if (!pExtent || pExtent->off < off)
 
173
    {
 
174
        pExtent = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
 
175
        if (!pExtent)
 
176
        {
 
177
            *pfHit = false;
 
178
            return NULL;
 
179
        }
 
180
    }
 
181
 
 
182
    while (off - pExtent->off >= pExtent->cb)
 
183
    {
 
184
        Assert(pExtent->off <= off);
 
185
        PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
 
186
        if (   !pNext
 
187
            || pNext->off > off)
 
188
        {
 
189
            *pfHit = false;
 
190
            return pExtent;
 
191
        }
 
192
 
 
193
        pExtent = pNext;
 
194
    }
 
195
 
 
196
    *pfHit = true;
 
197
    pThis->pCurExt = pExtent;
 
198
    return pExtent;
 
199
}
 
200
 
 
201
 
 
202
/**
 
203
 * Locates the extent covering the specified offset, or then one before it.
 
204
 *
 
205
 * @returns The closest extent.  NULL if off is 0 and there are no extent
 
206
 *          covering byte 0 yet.
 
207
 * @param   pThis               The memory file.
 
208
 * @param   off                 The offset (0-positive).
 
209
 * @param   pfHit               Where to indicate whether the extent is a
 
210
 *                              direct hit (@c true) or just a closest match
 
211
 *                              (@c false).
 
212
 */
 
213
DECLINLINE(PRTVFSMEMEXTENT) rtVfsMemFile_LocateExtent(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit)
 
214
{
 
215
    /*
 
216
     * The most likely case is that we're hitting the extent we used in the
 
217
     * previous access or the one immediately following it.
 
218
     */
 
219
    PRTVFSMEMEXTENT pExtent = pThis->pCurExt;
 
220
    if (!pExtent)
 
221
        return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit);
 
222
 
 
223
    if (off - pExtent->off >= pExtent->cb)
 
224
    {
 
225
        pExtent = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
 
226
        if (   !pExtent
 
227
            || off - pExtent->off >= pExtent->cb)
 
228
            return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit);
 
229
        pThis->pCurExt = pExtent;
 
230
    }
 
231
 
 
232
    *pfHit = true;
 
233
    return pExtent;
 
234
}
 
235
 
 
236
 
 
237
/**
 
238
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
 
239
 */
 
240
static DECLCALLBACK(int) rtVfsMemFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
 
241
{
 
242
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
243
 
 
244
    Assert(pSgBuf->cSegs == 1);
 
245
    Assert(off < 0);
 
246
    NOREF(fBlocking);
 
247
 
 
248
    /*
 
249
     * Find the current position and check if it's within the file.
 
250
     */
 
251
    uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
 
252
    if (offUnsigned >= (uint64_t)pThis->Base.ObjInfo.cbObject)
 
253
    {
 
254
        if (pcbRead)
 
255
        {
 
256
            *pcbRead = 0;
 
257
            pThis->offCurPos = offUnsigned;
 
258
            return VINF_EOF;
 
259
        }
 
260
        return VERR_EOF;
 
261
    }
 
262
 
 
263
    size_t cbLeftToRead;
 
264
    if (offUnsigned + pSgBuf->paSegs[0].cbSeg > (uint64_t)pThis->Base.ObjInfo.cbObject)
 
265
    {
 
266
        if (!pcbRead)
 
267
            return VERR_EOF;
 
268
        *pcbRead = cbLeftToRead = (size_t)((uint64_t)pThis->Base.ObjInfo.cbObject - offUnsigned);
 
269
    }
 
270
    else
 
271
    {
 
272
        cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
 
273
        if (pcbRead)
 
274
            *pcbRead = cbLeftToRead;
 
275
    }
 
276
 
 
277
    /*
 
278
     * Ok, we've got a valid stretch within the file.  Do the reading.
 
279
     */
 
280
    if (cbLeftToRead > 0)
 
281
    {
 
282
        uint8_t        *pbDst   = (uint8_t *)pSgBuf->paSegs[0].pvSeg;
 
283
        bool            fHit;
 
284
        PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
 
285
        for (;;)
 
286
        {
 
287
            PRTVFSMEMEXTENT pNext;
 
288
            size_t          cbThisRead;
 
289
            Assert(!pExtent || pExtent->off <= offUnsigned);
 
290
 
 
291
            /*
 
292
             * Do we hit an extent covering the the current file surface?
 
293
             */
 
294
            if (fHit)
 
295
            {
 
296
                size_t const offExtent = (size_t)(offUnsigned - pExtent->off);
 
297
                cbThisRead = pExtent->cb - offExtent;
 
298
                if (cbThisRead >= cbLeftToRead)
 
299
                    cbThisRead = cbLeftToRead;
 
300
 
 
301
                memcpy(pbDst, &pExtent->abData[offUnsigned - pExtent->off], cbThisRead);
 
302
 
 
303
                offUnsigned  += cbThisRead;
 
304
                cbLeftToRead -= cbThisRead;
 
305
                if (!cbLeftToRead)
 
306
                    break;
 
307
                pbDst        += cbThisRead;
 
308
 
 
309
                pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
 
310
                if (   pNext
 
311
                    && pNext->off == pExtent->off + pExtent->cb)
 
312
                {
 
313
                    pExtent = pNext;
 
314
                    continue;
 
315
                }
 
316
                fHit = false;
 
317
            }
 
318
 
 
319
            /*
 
320
             * No extent of this portion (sparse file).
 
321
             */
 
322
            else if (pExtent)
 
323
                pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
 
324
            else
 
325
                pNext = NULL;
 
326
            Assert(!pNext || pNext->off > pExtent->off);
 
327
 
 
328
            if (   !pNext
 
329
                || offUnsigned + cbLeftToRead <= pNext->off)
 
330
                cbThisRead = cbLeftToRead;
 
331
            else
 
332
                cbThisRead = (size_t)(pNext->off - offUnsigned);
 
333
 
 
334
            RT_BZERO(pbDst, cbThisRead);
 
335
 
 
336
            offUnsigned  += cbThisRead;
 
337
            cbLeftToRead -= cbThisRead;
 
338
            if (!cbLeftToRead)
 
339
                break;
 
340
            pbDst        += cbThisRead;
 
341
 
 
342
            /* Go on and read content from the next extent. */
 
343
            fHit     = true;
 
344
            pExtent  = pNext;
 
345
        }
 
346
    }
 
347
 
 
348
    pThis->offCurPos = offUnsigned;
 
349
    return VINF_SUCCESS;
 
350
}
 
351
 
 
352
 
 
353
/**
 
354
 * Allocates a new extent covering the ground at @a offUnsigned.
 
355
 *
 
356
 * @returns Pointer to the new extent on success, NULL if we're out of memory.
 
357
 * @param   pThis               The memory file.
 
358
 * @param   offUnsigned         The location to allocate the extent at.
 
359
 * @param   cbToWrite           The number of bytes we're interested in writing
 
360
 *                              starting at @a offUnsigned.
 
361
 * @param   pPrev               The extention before @a offUnsigned.  NULL if
 
362
 *                              none.
 
363
 */
 
364
static PRTVFSMEMEXTENT rtVfsMemFile_AllocExtent(PRTVFSMEMFILE pThis, uint64_t offUnsigned, size_t cbToWrite,
 
365
                                                PRTVFSMEMEXTENT pPrev)
 
366
{
 
367
    /*
 
368
     * Adjust the extent size if we haven't reached the max size yet.
 
369
     */
 
370
    if (pThis->cbExtent != RTVFSMEM_MAX_EXTENT_SIZE)
 
371
    {
 
372
        if (cbToWrite >= RTVFSMEM_MAX_EXTENT_SIZE)
 
373
            pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
 
374
        else if (!RTListIsEmpty(&pThis->ExtentHead))
 
375
        {
 
376
            uint32_t cbNextExtent = pThis->cbExtent;
 
377
            if (RT_IS_POWER_OF_TWO(cbNextExtent))
 
378
                cbNextExtent *= 2;
 
379
            else
 
380
            {
 
381
                /* Make it a power of two (seeRTVfsMemorizeIoStreamAsFile). */
 
382
                cbNextExtent = _4K;
 
383
                while (cbNextExtent < pThis->cbExtent)
 
384
                    cbNextExtent *= 2;
 
385
            }
 
386
            if (((pThis->Base.ObjInfo.cbAllocated + cbNextExtent) & (cbNextExtent - 1)) == 0)
 
387
                pThis->cbExtent = cbNextExtent;
 
388
        }
 
389
    }
 
390
 
 
391
    /*
 
392
     * Figure out the size and position of the extent we're adding.
 
393
     */
 
394
    uint64_t        offExtent = offUnsigned & ~(uint64_t)(pThis->cbExtent - 1);
 
395
    uint32_t        cbExtent  = pThis->cbExtent;
 
396
 
 
397
    uint64_t const  offPrev   = pPrev ? pPrev->off + pPrev->cb : 0;
 
398
    if (offExtent < offPrev)
 
399
        offExtent = offPrev;
 
400
 
 
401
    PRTVFSMEMEXTENT pNext     = pPrev
 
402
                              ? RTListGetNext(&pThis->ExtentHead, pPrev, RTVFSMEMEXTENT, Entry)
 
403
                              : RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
 
404
    if (pNext)
 
405
    {
 
406
        uint64_t cbMaxExtent = pNext->off - offExtent;
 
407
        if (cbMaxExtent < cbExtent)
 
408
            cbExtent = (uint32_t)cbMaxExtent;
 
409
    }
 
410
 
 
411
    /*
 
412
     * Allocate, initialize and insert the new extent.
 
413
     */
 
414
    PRTVFSMEMEXTENT pNew = (PRTVFSMEMEXTENT)RTMemAllocZ(RT_OFFSETOF(RTVFSMEMEXTENT, abData[cbExtent]));
 
415
    if (pNew)
 
416
    {
 
417
        pNew->off = offExtent;
 
418
        pNew->cb  = cbExtent;
 
419
        if (pPrev)
 
420
            RTListNodeInsertAfter(&pPrev->Entry, &pNew->Entry);
 
421
        else
 
422
            RTListPrepend(&pThis->ExtentHead, &pNew->Entry);
 
423
 
 
424
        pThis->Base.ObjInfo.cbAllocated += cbExtent;
 
425
    }
 
426
    /** @todo retry with minimum size. */
 
427
 
 
428
    return pNew;
 
429
}
 
430
 
 
431
 
 
432
/**
 
433
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
 
434
 */
 
435
static DECLCALLBACK(int) rtVfsMemFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
 
436
{
 
437
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
438
 
 
439
    Assert(pSgBuf->cSegs == 1);
 
440
    Assert(off < 0);
 
441
    NOREF(fBlocking);
 
442
 
 
443
    /*
 
444
     * Validate the write and set up the write loop.
 
445
     */
 
446
    size_t          cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
 
447
    if (!cbLeftToWrite)
 
448
        return VINF_SUCCESS; /* pcbWritten is already 0. */
 
449
    uint64_t        offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
 
450
    if (offUnsigned + cbLeftToWrite >= (uint64_t)RTFOFF_MAX)
 
451
        return VERR_OUT_OF_RANGE;
 
452
 
 
453
    int             rc      = VINF_SUCCESS;
 
454
    uint8_t const  *pbSrc   = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
 
455
    bool            fHit;
 
456
    PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
 
457
    for (;;)
 
458
    {
 
459
        /*
 
460
         * If we didn't hit an extent, allocate one (unless it's all zeros).
 
461
         */
 
462
        if (!fHit)
 
463
        {
 
464
            Assert(!pExtent || (pExtent->off < offUnsigned && pExtent->off + pExtent->cb <= offUnsigned));
 
465
 
 
466
            /* Skip leading zeros if there is a whole bunch of them. */
 
467
            uint8_t const *pbSrcNZ = (uint8_t const *)ASMMemIsAll8(pbSrc, cbLeftToWrite, 0);
 
468
            if (!pbSrcNZ)
 
469
            {
 
470
                offUnsigned  += cbLeftToWrite;
 
471
                cbLeftToWrite = 0;
 
472
                break;
 
473
            }
 
474
            size_t const cbZeros = pbSrcNZ - pbSrc;
 
475
            if (cbZeros >= RT_MIN(pThis->cbExtent, _64K))
 
476
            {
 
477
                offUnsigned   += cbZeros;
 
478
                cbLeftToWrite -= cbZeros;
 
479
                pbSrc          = pbSrcNZ;
 
480
                pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
 
481
                break;
 
482
            }
 
483
 
 
484
            fHit    = true;
 
485
            pExtent = rtVfsMemFile_AllocExtent(pThis, offUnsigned, cbLeftToWrite, pExtent);
 
486
            if (!pExtent)
 
487
            {
 
488
                rc = VERR_NO_MEMORY;
 
489
                break;
 
490
            }
 
491
        }
 
492
 
 
493
        /*
 
494
         * Copy the source data into the current extent.
 
495
         */
 
496
        uint32_t const  offDst      = (uint32_t)(offUnsigned - pExtent->off);
 
497
        uint32_t        cbThisWrite = pExtent->cb - offDst;
 
498
        if (cbThisWrite > cbLeftToWrite)
 
499
            cbThisWrite = (uint32_t)cbLeftToWrite;
 
500
        memcpy(&pExtent->abData[offDst], pbSrc, cbThisWrite);
 
501
 
 
502
        offUnsigned   += cbLeftToWrite;
 
503
        cbLeftToWrite -= cbThisWrite;
 
504
        if (!cbLeftToWrite)
 
505
            break;
 
506
        pbSrc += cbThisWrite;
 
507
        Assert(offUnsigned == pExtent->off + pExtent->cb);
 
508
 
 
509
        /*
 
510
         * Advance to the next extent.
 
511
         */
 
512
        PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
 
513
        Assert(!pNext || pNext->off >= offUnsigned);
 
514
        if (pNext && pNext->off == offUnsigned)
 
515
            pExtent = pNext;
 
516
        else
 
517
            fHit = false;
 
518
    }
 
519
 
 
520
    /*
 
521
     * Update the state, set return value and return.
 
522
     * Note! There must be no alternative exit path from the loop above.
 
523
     */
 
524
    pThis->offCurPos = offUnsigned;
 
525
    if ((uint64_t)pThis->Base.ObjInfo.cbObject < offUnsigned)
 
526
        pThis->Base.ObjInfo.cbObject = offUnsigned;
 
527
 
 
528
    if (pcbWritten)
 
529
        *pcbWritten = pSgBuf->paSegs[0].cbSeg - cbLeftToWrite;
 
530
    return rc;
 
531
}
 
532
 
 
533
 
 
534
/**
 
535
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
 
536
 */
 
537
static DECLCALLBACK(int) rtVfsMemFile_Flush(void *pvThis)
 
538
{
 
539
    NOREF(pvThis);
 
540
    return VINF_SUCCESS;
 
541
}
 
542
 
 
543
 
 
544
/**
 
545
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
 
546
 */
 
547
static DECLCALLBACK(int) rtVfsMemFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
 
548
                                              uint32_t *pfRetEvents)
 
549
{
 
550
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
551
    int           rc;
 
552
 
 
553
    if (fEvents != RTPOLL_EVT_ERROR)
 
554
    {
 
555
        *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
 
556
        rc = VINF_SUCCESS;
 
557
    }
 
558
    else
 
559
        rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
 
560
    return rc;
 
561
}
 
562
 
 
563
 
 
564
/**
 
565
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
 
566
 */
 
567
static DECLCALLBACK(int) rtVfsMemFile_Tell(void *pvThis, PRTFOFF poffActual)
 
568
{
 
569
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
570
    *poffActual = pThis->offCurPos;
 
571
    return VINF_SUCCESS;
 
572
}
 
573
 
 
574
 
 
575
/**
 
576
 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
 
577
 */
 
578
static DECLCALLBACK(int) rtVfsMemFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
 
579
{
 
580
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
581
    pThis->Base.ObjInfo.Attr.fMode = (pThis->Base.ObjInfo.Attr.fMode & ~fMask) | fMode;
 
582
    return VINF_SUCCESS;
 
583
}
 
584
 
 
585
 
 
586
/**
 
587
 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
 
588
 */
 
589
static DECLCALLBACK(int) rtVfsMemFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
 
590
                                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
 
591
{
 
592
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
593
 
 
594
    if (pAccessTime)
 
595
        pThis->Base.ObjInfo.AccessTime          = *pAccessTime;
 
596
    if (pModificationTime)
 
597
        pThis->Base.ObjInfo.ModificationTime    = *pModificationTime;
 
598
    if (pChangeTime)
 
599
        pThis->Base.ObjInfo.ChangeTime          = *pChangeTime;
 
600
    if (pBirthTime)
 
601
        pThis->Base.ObjInfo.BirthTime           = *pBirthTime;
 
602
 
 
603
    return VINF_SUCCESS;
 
604
}
 
605
 
 
606
 
 
607
/**
 
608
 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
 
609
 */
 
610
static DECLCALLBACK(int) rtVfsMemFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
 
611
{
 
612
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
613
 
 
614
    if (uid != NIL_RTUID)
 
615
        pThis->Base.ObjInfo.Attr.u.Unix.uid = uid;
 
616
    if (gid != NIL_RTUID)
 
617
        pThis->Base.ObjInfo.Attr.u.Unix.gid = gid;
 
618
 
 
619
    return VINF_SUCCESS;
 
620
}
 
621
 
 
622
 
 
623
/**
 
624
 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
 
625
 */
 
626
static DECLCALLBACK(int) rtVfsMemFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
 
627
{
 
628
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
629
 
 
630
    /*
 
631
     * Seek relative to which position.
 
632
     */
 
633
    uint64_t offWrt;
 
634
    switch (uMethod)
 
635
    {
 
636
        case RTFILE_SEEK_BEGIN:
 
637
            offWrt = 0;
 
638
            break;
 
639
 
 
640
        case RTFILE_SEEK_CURRENT:
 
641
            offWrt = pThis->offCurPos;
 
642
            break;
 
643
 
 
644
        case RTFILE_SEEK_END:
 
645
            offWrt = pThis->Base.ObjInfo.cbObject;
 
646
            break;
 
647
 
 
648
        default:
 
649
            return VERR_INTERNAL_ERROR_5;
 
650
    }
 
651
 
 
652
    /*
 
653
     * Calc new position, take care to stay without bounds.
 
654
     */
 
655
    uint64_t offNew;
 
656
    if (offSeek == 0)
 
657
        offNew = offWrt;
 
658
    else if (offSeek > 0)
 
659
    {
 
660
        offNew = offWrt + offSeek;
 
661
        if (   offNew < offWrt
 
662
            || offNew > RTFOFF_MAX)
 
663
            offNew = RTFOFF_MAX;
 
664
    }
 
665
    else if ((uint64_t)-offSeek < offWrt)
 
666
        offNew = offWrt + offSeek;
 
667
    else
 
668
        offNew = 0;
 
669
 
 
670
    /*
 
671
     * Update the state and set return value.
 
672
     */
 
673
    if (   pThis->pCurExt
 
674
        && pThis->pCurExt->off - offNew >= pThis->pCurExt->cb)
 
675
        pThis->pCurExt = NULL;
 
676
    pThis->offCurPos = offNew;
 
677
 
 
678
    *poffActual = offNew;
 
679
    return VINF_SUCCESS;
 
680
}
 
681
 
 
682
 
 
683
/**
 
684
 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
 
685
 */
 
686
static DECLCALLBACK(int) rtVfsMemFile_QuerySize(void *pvThis, uint64_t *pcbFile)
 
687
{
 
688
    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
 
689
    *pcbFile = pThis->Base.ObjInfo.cbObject;
 
690
    return VINF_SUCCESS;
 
691
}
 
692
 
 
693
 
 
694
/**
 
695
 * Standard file operations.
 
696
 */
 
697
DECLHIDDEN(const RTVFSFILEOPS) g_rtVfsStdFileOps =
 
698
{
 
699
    { /* Stream */
 
700
        { /* Obj */
 
701
            RTVFSOBJOPS_VERSION,
 
702
            RTVFSOBJTYPE_FILE,
 
703
            "MemFile",
 
704
            rtVfsMemFile_Close,
 
705
            rtVfsMemFile_QueryInfo,
 
706
            RTVFSOBJOPS_VERSION
 
707
        },
 
708
        RTVFSIOSTREAMOPS_VERSION,
 
709
        RTVFSIOSTREAMOPS_FEAT_NO_SG,
 
710
        rtVfsMemFile_Read,
 
711
        rtVfsMemFile_Write,
 
712
        rtVfsMemFile_Flush,
 
713
        rtVfsMemFile_PollOne,
 
714
        rtVfsMemFile_Tell,
 
715
        NULL /*Skip*/,
 
716
        NULL /*ZeroFill*/,
 
717
        RTVFSIOSTREAMOPS_VERSION,
 
718
    },
 
719
    RTVFSFILEOPS_VERSION,
 
720
    /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
 
721
    { /* ObjSet */
 
722
        RTVFSOBJSETOPS_VERSION,
 
723
        RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
 
724
        rtVfsMemFile_SetMode,
 
725
        rtVfsMemFile_SetTimes,
 
726
        rtVfsMemFile_SetOwner,
 
727
        RTVFSOBJSETOPS_VERSION
 
728
    },
 
729
    rtVfsMemFile_Seek,
 
730
    rtVfsMemFile_QuerySize,
 
731
    RTVFSFILEOPS_VERSION
 
732
};
 
733
 
 
734
 
 
735
 
 
736
 
 
737
 
 
738
RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile)
 
739
{
 
740
    /*
 
741
     * Create a memory file instance and try set the extension size to match
 
742
     * the length of the I/O stream.
 
743
     */
 
744
    RTFSOBJINFO ObjInfo;
 
745
    int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
 
746
    if (RT_SUCCESS(rc))
 
747
    {
 
748
        RTVFSFILE       hVfsFile;
 
749
        PRTVFSMEMFILE   pThis;
 
750
        rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(*pThis), fFlags | RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
 
751
                          &hVfsFile, (void **)&pThis);
 
752
        if (RT_SUCCESS(rc))
 
753
        {
 
754
            pThis->Base.ObjInfo = ObjInfo;
 
755
            pThis->offCurPos    = 0;
 
756
            pThis->pCurExt      = NULL;
 
757
            RTListInit(&pThis->ExtentHead);
 
758
            if (ObjInfo.cbObject <= 0)
 
759
                pThis->cbExtent = _4K;
 
760
            else if (ObjInfo.cbObject < RTVFSMEM_MAX_EXTENT_SIZE)
 
761
                pThis->cbExtent = _4K /* ObjInfo.cbObject */;
 
762
            else
 
763
                pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
 
764
 
 
765
            /*
 
766
             * Copy the stream.
 
767
             */
 
768
            RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile);
 
769
            rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent);
 
770
            RTVfsIoStrmRelease(hVfsIosDst);
 
771
            if (RT_SUCCESS(rc))
 
772
            {
 
773
                pThis->pCurExt   = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
 
774
                pThis->offCurPos = 0;
 
775
 
 
776
                if (!(fFlags & RTFILE_O_WRITE))
 
777
                {
 
778
                    /** @todo clear RTFILE_O_WRITE from the resulting. */
 
779
                }
 
780
                *phVfsFile = hVfsFile;
 
781
                return VINF_SUCCESS;
 
782
            }
 
783
            RTVfsFileRelease(hVfsFile);
 
784
        }
 
785
    }
 
786
    return rc;
 
787
}