VirtualBox

Changeset 34407 in vbox


Ignore:
Timestamp:
Nov 26, 2010 4:45:50 PM (14 years ago)
Author:
vboxsync
Message:

vfsmemory.cpp: initial coding.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/vfslowlevel.h

    r34029 r34407  
    620620    /** The structure version (RTVFSIOSTREAMOPS_VERSION). */
    621621    uint32_t                uVersion;
    622     /** Reserved field, MBZ. */
    623     uint32_t                fReserved;
     622    /** Feature field. */
     623    uint32_t                fFeatures;
    624624
    625625    /**
     
    722722/** The RTVFSIOSTREAMOPS structure version. */
    723723#define RTVFSIOSTREAMOPS_VERSION    RT_MAKE_U32_FROM_U8(0xff,0x6f,1,0)
     724
     725/** @name RTVFSIOSTREAMOPS::fFeatures
     726 * @{ */
     727/** No scatter gather lists, thank you. */
     728#define RTVFSIOSTREAMOPS_FEAT_NO_SG         RT_BIT_32(0)
     729/** Mask of the valid I/O stream feature flags. */
     730#define RTVFSIOSTREAMOPS_FEAT_VALID_MASK    UINT32_C(0x00000001)
     731/** @}  */
    724732
    725733
     
    900908RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath);
    901909
     910/**
     911 * Dummy implementation of RTVFSIOSTREAMOPS::pfnPollOne.
     912 *
     913 * This handles the case where there is no chance any events my be raised and
     914 * all that is required is to wait according to the parameters.
     915 *
     916 * @returns IPRT status code.
     917 * @param   pvThis      The implementation specific file data.
     918 * @param   fEvents     The events to poll for (RTPOLL_EVT_XXX).
     919 * @param   cMillies    How long to wait for event to eventuate.
     920 * @param   fIntr       Whether the wait is interruptible and can return
     921 *                      VERR_INTERRUPTED (@c true) or if this condition
     922 *                      should be hidden from the caller (@c false).
     923 * @param   pfRetEvents Where to return the event mask.
     924 * @sa      RTVFSIOSTREAMOPS::pfnPollOne, RTPollSetAdd, RTPoll, RTPollNoResume.
     925 */
     926RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents);
     927
     928/**
     929 * Pumps data from one I/O stream to another.
     930 *
     931 * The data is read in chunks from @a hVfsIosSrc and written to @a hVfsIosDst
     932 * until @hVfsIosSrc indicates end of stream.
     933 *
     934 * @returns IPRT status code
     935 *
     936 * @param   hVfsIosSrc  The input stream.
     937 * @param   hVfsIosDst  The output stream.
     938 * @param   cbBufHint   Hints at a good temporary buffer size, pass 0 if
     939 *                      clueless.
     940 */
     941RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint);
     942
    902943/** @}  */
    903944
  • trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp

    r34055 r34407  
    101101        RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \
    102102        Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \
    103         Assert(!(pIoStreamOps)->fReserved); \
     103        Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \
    104104        AssertPtr((pIoStreamOps)->pfnRead); \
    105105        AssertPtr((pIoStreamOps)->pfnWrite); \
     
    15091509
    15101510
     1511RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
     1512{
     1513    int rc;
     1514    if (fIntr)
     1515        rc = RTThreadSleep(cMillies);
     1516    else
     1517    {
     1518        uint64_t uMsStart = RTTimeMilliTS();
     1519        do
     1520            rc = RTThreadSleep(cMillies);
     1521        while (   rc == VERR_INTERRUPTED
     1522               && !fIntr
     1523               && RTTimeMilliTS() - uMsStart < cMillies);
     1524        if (rc == VERR_INTERRUPTED)
     1525            rc = VERR_TIMEOUT;
     1526    }
     1527
     1528    *pfRetEvents = 0;
     1529    return rc;
     1530}
     1531
     1532
     1533RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
     1534{
     1535    /*
     1536     * Allocate a temporary buffer.
     1537     */
     1538    size_t cbBuf = cbBufHint;
     1539    if (!cbBuf)
     1540        cbBuf = _64K;
     1541    else if (cbBuf < _4K)
     1542        cbBuf = _4K;
     1543    else if (cbBuf > _1M)
     1544        cbBuf = _1M;
     1545
     1546    void *pvBuf = RTMemTmpAlloc(cbBuf);
     1547    if (!pvBuf)
     1548    {
     1549        cbBuf = _4K;
     1550        pvBuf = RTMemTmpAlloc(cbBuf);
     1551        if (!pvBuf)
     1552            return VERR_NO_TMP_MEMORY;
     1553    }
     1554
     1555    /*
     1556     * Pump loop.
     1557     */
     1558    int rc;
     1559    for (;;)
     1560    {
     1561        size_t cbRead;
     1562        rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
     1563        if (RT_FAILURE(rc))
     1564            break;
     1565        if (rc == VINF_EOF && cbRead == 0)
     1566            break;
     1567
     1568        rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
     1569        if (RT_FAILURE(rc))
     1570            break;
     1571    }
     1572
     1573    RTMemTmpFree(pvBuf);
     1574    return rc;
     1575}
     1576
     1577
    15111578
    15121579
     
    17991866    AssertReturn(pIoStreamOps->uVersion   == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
    18001867    AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
    1801     Assert(!pIoStreamOps->fReserved);
     1868    Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
    18021869    RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
    18031870    Assert(cbInstance > 0);
     
    18871954    AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
    18881955    AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
     1956    AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
    18891957
    18901958    RTSGSEG Seg = { pvBuf, cbToRead };
     
    19081976    AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
    19091977    AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
     1978    AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
    19101979
    19111980    RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
     
    19301999    AssertPtr(pSgBuf);
    19312000    AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
     2001    AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
    19322002
    19332003    RTVfsLockAcquireWrite(pThis->Base.hLock);
    1934     int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead);
     2004    int rc;
     2005    if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
     2006        rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead);
     2007    else
     2008    {
     2009        size_t cbRead = 0;
     2010        rc = VINF_SUCCESS;
     2011
     2012        for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
     2013        {
     2014            RTSGBUF SgBuf;
     2015            RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
     2016
     2017            size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
     2018            rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
     2019            if (RT_FAILURE(rc))
     2020                break;
     2021            cbRead += cbReadSeg;
     2022            if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
     2023                break;
     2024        }
     2025
     2026        if (pcbRead)
     2027            *pcbRead = cbRead;
     2028    }
    19352029    RTVfsLockReleaseWrite(pThis->Base.hLock);
    19362030    return rc;
     
    19482042    AssertPtr(pSgBuf);
    19492043    AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
     2044    AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
    19502045
    19512046    RTVfsLockAcquireWrite(pThis->Base.hLock);
    1952     int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
     2047    int rc;
     2048    if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
     2049        rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
     2050    else
     2051    {
     2052        size_t cbWritten = 0;
     2053        rc = VINF_SUCCESS;
     2054
     2055        for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
     2056        {
     2057            RTSGBUF SgBuf;
     2058            RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
     2059
     2060            size_t cbWrittenSeg = 0;
     2061            rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
     2062            if (RT_FAILURE(rc))
     2063                break;
     2064            if (pcbWritten)
     2065            {
     2066                cbWritten += cbWrittenSeg;
     2067                if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
     2068                    break;
     2069            }
     2070        }
     2071
     2072        if (pcbWritten)
     2073            *pcbWritten = cbWritten;
     2074    }
    19532075    RTVfsLockReleaseWrite(pThis->Base.hLock);
    19542076    return rc;
     
    20112133        RTVfsLockAcquireWrite(pThis->Base.hLock);
    20122134        rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
     2135        RTVfsLockReleaseWrite(pThis->Base.hLock);
     2136    }
     2137    else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
     2138    {
     2139        RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
     2140        RTFOFF             offIgnored;
     2141
     2142        RTVfsLockAcquireWrite(pThis->Base.hLock);
     2143        rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
    20132144        RTVfsLockReleaseWrite(pThis->Base.hLock);
    20142145    }
  • trunk/src/VBox/Runtime/common/vfs/vfsmemory.cpp

    r34391 r34407  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Virtual File System, Memory Files.
     3 * IPRT - Virtual File System, Memory Backed VFS.
    44 */
    55
     
    3232#include <iprt/vfs.h>
    3333
     34#include <iprt/asm.h>
    3435#include <iprt/assert.h>
    3536#include <iprt/err.h>
    3637#include <iprt/file.h>
    37 #include <iprt/handle.h>
     38#include <iprt/list.h>
     39#include <iprt/poll.h>
     40#include <iprt/string.h>
     41#include <iprt/vfslowlevel.h>
    3842
    3943
     
    4953
    5054
     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 */
     69typedef 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 */
     81typedef 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. */
     93typedef RTVFSMEMEXTENT *PRTVFSMEMEXTENT;
     94
     95/**
     96 * Memory file.
     97 */
     98typedef 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. */
     113typedef RTVFSMEMFILE *PRTVFSMEMFILE;
     114
     115
     116
     117/**
     118 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
     119 */
     120static 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 */
     144static 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 */
     165static 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 = RTListNodeGetNext(&pExtent->Entry, RTVFSMEMEXTENT, Entry);
     186        if (   RTListNodeIsLast(&pThis->ExtentHead, &pNext->Entry)
     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 */
     213DECLINLINE(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 = RTListNodeGetNext(&pExtent->Entry, 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 */
     240static 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        *pcbRead = cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
     272
     273    /*
     274     * Ok, we've got a valid stretch within the file.  Do the reading.
     275     */
     276    if (cbLeftToRead > 0)
     277    {
     278        uint8_t        *pbDst   = (uint8_t *)pSgBuf->paSegs[0].pvSeg;
     279        bool            fHit;
     280        PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
     281        for (;;)
     282        {
     283            PRTVFSMEMEXTENT pNext;
     284            size_t          cbThisRead;
     285            Assert(!pExtent || pExtent->off <= offUnsigned);
     286
     287            /*
     288             * Do we hit an extent covering the the current file surface?
     289             */
     290            if (fHit)
     291            {
     292                size_t const offExtent = (size_t)(offUnsigned - pExtent->off);
     293                cbThisRead = pExtent->cb - offExtent;
     294                if (cbThisRead >= cbLeftToRead)
     295                    cbThisRead = cbLeftToRead;
     296
     297                memcpy(pbDst, &pExtent->abData[offUnsigned - pExtent->off], cbThisRead);
     298
     299                offUnsigned  += cbThisRead;
     300                cbLeftToRead -= cbThisRead;
     301                if (!cbLeftToRead)
     302                    break;
     303                pbDst        += cbThisRead;
     304
     305                pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
     306                if (   pNext
     307                    && pNext->off == pExtent->off + pExtent->cb)
     308                {
     309                    pExtent = pNext;
     310                    continue;
     311                }
     312                fHit = false;
     313            }
     314
     315            /*
     316             * No extent of this portion (sparse file).
     317             */
     318            else if (pExtent)
     319                pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
     320            else
     321                pNext = NULL;
     322            Assert(!pNext || pNext->off > pExtent->off);
     323
     324            if (   !pNext
     325                || offUnsigned + cbLeftToRead <= pNext->off)
     326                cbThisRead = cbLeftToRead;
     327            else
     328                cbThisRead = pNext->off - offUnsigned;
     329
     330            RT_BZERO(pbDst, cbThisRead);
     331
     332            offUnsigned  += cbThisRead;
     333            cbLeftToRead -= cbThisRead;
     334            if (!cbLeftToRead)
     335                break;
     336            pbDst        += cbThisRead;
     337
     338            /* Go on and read content from the next extent. */
     339            fHit     = true;
     340            pExtent  = pNext;
     341        }
     342    }
     343
     344    pThis->offCurPos = offUnsigned;
     345    return VINF_SUCCESS;
     346}
     347
     348
     349/**
     350 * Allocates a new extent covering the ground at @a offUnsigned.
     351 *
     352 * @returns Pointer to the new extent on success, NULL if we're out of memory.
     353 * @param   pThis               The memory file.
     354 * @param   offUnsigned         The location to allocate the extent at.
     355 * @param   cbToWrite           The number of bytes we're interested in writing
     356 *                              starting at @a offUnsigned.
     357 * @param   pPrev               The extention before @a offUnsigned.  NULL if
     358 *                              none.
     359 */
     360static PRTVFSMEMEXTENT rtVfsMemFile_AllocExtent(PRTVFSMEMFILE pThis, uint64_t offUnsigned, size_t cbToWrite,
     361                                                PRTVFSMEMEXTENT pPrev)
     362{
     363    /*
     364     * Adjust the extent size if we haven't reached the max size yet.
     365     */
     366    if (pThis->cbExtent != RTVFSMEM_MAX_EXTENT_SIZE)
     367    {
     368        if (cbToWrite >= RTVFSMEM_MAX_EXTENT_SIZE)
     369            pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
     370        else if (!RTListIsEmpty(&pThis->ExtentHead))
     371        {
     372            size_t cbNextExtent = pThis->cbExtent;
     373            if (RT_IS_POWER_OF_TWO(cbNextExtent))
     374                cbNextExtent *= 2;
     375            else
     376            {
     377                /* Make it a power of two (seeRTVfsMemorizeIoStreamAsFile). */
     378                cbNextExtent = _4K;
     379                while (cbNextExtent < pThis->cbExtent)
     380                    cbNextExtent *= 2;
     381            }
     382            if (((pThis->Base.ObjInfo.cbAllocated + cbNextExtent) & (cbNextExtent - 1)) == 0)
     383                pThis->cbExtent = cbNextExtent;
     384        }
     385    }
     386
     387    /*
     388     * Figure out the size and position of the extent we're adding.
     389     */
     390    uint64_t        offExtent = offUnsigned & ~(uint64_t)(pThis->cbExtent - 1);
     391    uint32_t        cbExtent  = pThis->cbExtent;
     392
     393    uint64_t const  offPrev   = pPrev ? pPrev->off + pPrev->cb : 0;
     394    if (offExtent < offPrev)
     395        offExtent = offPrev;
     396
     397    PRTVFSMEMEXTENT pNext     = pPrev
     398                              ? RTListGetNext(&pThis->ExtentHead, pPrev, RTVFSMEMEXTENT, Entry)
     399                              : RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
     400    if (pNext)
     401    {
     402        uint64_t cbMaxExtent = pNext->off - offExtent;
     403        if (cbMaxExtent < cbExtent)
     404            cbExtent = cbMaxExtent;
     405    }
     406
     407    /*
     408     * Allocate, initialize and insert the new extent.
     409     */
     410    PRTVFSMEMEXTENT pNew = (PRTVFSMEMEXTENT)RTMemAllocZ(RT_OFFSETOF(RTVFSMEMEXTENT, abData[cbExtent]));
     411    if (pNew)
     412    {
     413        pNew->off = offExtent;
     414        pNew->cb  = cbExtent;
     415        if (pPrev)
     416            RTListNodeInsertAfter(&pPrev->Entry, &pNew->Entry);
     417        else
     418            RTListPrepend(&pThis->ExtentHead, &pNew->Entry);
     419
     420        pThis->Base.ObjInfo.cbAllocated += cbExtent;
     421    }
     422    /** @todo retry with minimum size. */
     423
     424    return pNew;
     425}
     426
     427
     428/**
     429 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
     430 */
     431static DECLCALLBACK(int) rtVfsMemFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
     432{
     433    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     434
     435    Assert(pSgBuf->cSegs == 1);
     436    Assert(off < 0);
     437    NOREF(fBlocking);
     438
     439    /*
     440     * Validate the write and set up the write loop.
     441     */
     442    size_t          cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
     443    if (!cbLeftToWrite)
     444        return VINF_SUCCESS; /* pcbWritten is already 0. */
     445    uint64_t        offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
     446    if (offUnsigned + cbLeftToWrite >= (uint64_t)RTFOFF_MAX)
     447        return VERR_OUT_OF_RANGE;
     448
     449    int             rc      = VINF_SUCCESS;
     450    uint8_t const  *pbSrc   = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
     451    bool            fHit;
     452    PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
     453    for (;;)
     454    {
     455        /*
     456         * If we didn't hit an extent, allocate one (unless it's all zeros).
     457         */
     458        if (!fHit)
     459        {
     460            Assert(!pExtent || (pExtent->off < offUnsigned && pExtent->off + pExtent->cb <= offUnsigned));
     461
     462            /* Skip leading zeros if there is a whole bunch of them. */
     463            uint8_t const *pbSrcNZ = (uint8_t const *)ASMMemIsAll8(pbSrc, cbLeftToWrite, 0);
     464            if (!pbSrcNZ)
     465            {
     466                offUnsigned  += cbLeftToWrite;
     467                cbLeftToWrite = 0;
     468                break;
     469            }
     470            size_t const cbZeros = pbSrcNZ - pbSrc;
     471            if (cbZeros >= RT_MIN(pThis->cbExtent, _64K))
     472            {
     473                offUnsigned   += cbZeros;
     474                cbLeftToWrite -= cbZeros;
     475                pbSrc          = pbSrcNZ;
     476                pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
     477                break;
     478            }
     479
     480            fHit    = true;
     481            pExtent = rtVfsMemFile_AllocExtent(pThis, offUnsigned, cbLeftToWrite, pExtent);
     482            if (!pExtent)
     483            {
     484                rc = VERR_NO_MEMORY;
     485                break;
     486            }
     487        }
     488
     489        /*
     490         * Copy the source data into the current extent.
     491         */
     492        uint32_t const  offDst      = offUnsigned - pExtent->off;
     493        uint32_t        cbThisWrite = pExtent->cb - offDst;
     494        if (cbThisWrite > cbLeftToWrite)
     495            cbThisWrite = (uint32_t)cbLeftToWrite;
     496        memcpy(&pExtent->abData[offDst], pbSrc, cbThisWrite);
     497
     498        offUnsigned   += cbLeftToWrite;
     499        cbLeftToWrite -= cbThisWrite;
     500        if (!cbLeftToWrite)
     501            break;
     502        pbSrc += cbThisWrite;
     503        Assert(offUnsigned == pExtent->off + pExtent->cb);
     504
     505        /*
     506         * Advance to the next extent.
     507         */
     508        PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
     509        Assert(!pNext || pNext->off >= offUnsigned);
     510        if (pNext && pNext->off == offUnsigned)
     511            pExtent = pNext;
     512        else
     513            fHit = false;
     514    }
     515
     516    /*
     517     * Update the state, set return value and return.
     518     * Note! There must be no alternative exit path from the loop above.
     519     */
     520    pThis->offCurPos = offUnsigned;
     521    if ((uint64_t)pThis->Base.ObjInfo.cbObject < offUnsigned)
     522        pThis->Base.ObjInfo.cbObject = offUnsigned;
     523
     524    if (pcbWritten)
     525        *pcbWritten = pSgBuf->paSegs[0].cbSeg - cbLeftToWrite;
     526    return rc;
     527}
     528
     529
     530/**
     531 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
     532 */
     533static DECLCALLBACK(int) rtVfsMemFile_Flush(void *pvThis)
     534{
     535    NOREF(pvThis);
     536    return VINF_SUCCESS;
     537}
     538
     539
     540/**
     541 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
     542 */
     543static DECLCALLBACK(int) rtVfsMemFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
     544                                              uint32_t *pfRetEvents)
     545{
     546    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     547    int           rc;
     548
     549    if (fEvents != RTPOLL_EVT_ERROR)
     550    {
     551        *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
     552        rc = VINF_SUCCESS;
     553    }
     554    else
     555        rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
     556    return rc;
     557}
     558
     559
     560/**
     561 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
     562 */
     563static DECLCALLBACK(int) rtVfsMemFile_Tell(void *pvThis, PRTFOFF poffActual)
     564{
     565    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     566    *poffActual = pThis->offCurPos;
     567    return VINF_SUCCESS;
     568}
     569
     570
     571/**
     572 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
     573 */
     574static DECLCALLBACK(int) rtVfsMemFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
     575{
     576    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     577    pThis->Base.ObjInfo.Attr.fMode = (pThis->Base.ObjInfo.Attr.fMode & ~fMask) | fMode;
     578    return VINF_SUCCESS;
     579}
     580
     581
     582/**
     583 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
     584 */
     585static DECLCALLBACK(int) rtVfsMemFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
     586                                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
     587{
     588    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     589
     590    if (pAccessTime)
     591        pThis->Base.ObjInfo.AccessTime          = *pAccessTime;
     592    if (pModificationTime)
     593        pThis->Base.ObjInfo.ModificationTime    = *pModificationTime;
     594    if (pChangeTime)
     595        pThis->Base.ObjInfo.ChangeTime          = *pChangeTime;
     596    if (pBirthTime)
     597        pThis->Base.ObjInfo.BirthTime           = *pBirthTime;
     598
     599    return VINF_SUCCESS;
     600}
     601
     602
     603/**
     604 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
     605 */
     606static DECLCALLBACK(int) rtVfsMemFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
     607{
     608    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     609
     610    if (uid != NIL_RTUID)
     611        pThis->Base.ObjInfo.Attr.u.Unix.uid = uid;
     612    if (gid != NIL_RTUID)
     613        pThis->Base.ObjInfo.Attr.u.Unix.gid = gid;
     614
     615    return VINF_SUCCESS;
     616}
     617
     618
     619/**
     620 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
     621 */
     622static DECLCALLBACK(int) rtVfsMemFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
     623{
     624    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     625
     626    /*
     627     * Seek relative to which position.
     628     */
     629    uint64_t offWrt;
     630    switch (uMethod)
     631    {
     632        case RTFILE_SEEK_BEGIN:
     633            offWrt = 0;
     634            break;
     635
     636        case RTFILE_SEEK_CURRENT:
     637            offWrt = pThis->offCurPos;
     638            break;
     639
     640        case RTFILE_SEEK_END:
     641            offWrt = pThis->Base.ObjInfo.cbObject;
     642            break;
     643
     644        default:
     645            return VERR_INTERNAL_ERROR_5;
     646    }
     647
     648    /*
     649     * Calc new position, take care to stay without bounds.
     650     */
     651    uint64_t offNew;
     652    if (offSeek == 0)
     653        offNew = offWrt;
     654    else if (offSeek > 0)
     655    {
     656        offNew = offWrt + offSeek;
     657        if (   offNew < offWrt
     658            || offNew > RTFOFF_MAX)
     659            offNew = RTFOFF_MAX;
     660    }
     661    else if ((uint64_t)-offSeek < offNew)
     662        offNew = offWrt + offSeek;
     663    else
     664        offNew = 0;
     665
     666    /*
     667     * Update the state and set return value.
     668     */
     669    if (   pThis->pCurExt
     670        && pThis->pCurExt->off - offNew >= pThis->pCurExt->cb)
     671        pThis->pCurExt = NULL;
     672    pThis->offCurPos = offNew;
     673
     674    *poffActual = offNew;
     675    return VINF_SUCCESS;
     676}
     677
     678
     679/**
     680 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
     681 */
     682static DECLCALLBACK(int) rtVfsMemFile_QuerySize(void *pvThis, uint64_t *pcbFile)
     683{
     684    PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
     685    return pThis->Base.ObjInfo.cbObject;
     686}
     687
     688
     689/**
     690 * Standard file operations.
     691 */
     692DECLHIDDEN(const RTVFSFILEOPS) g_rtVfsStdFileOps =
     693{
     694    { /* Stream */
     695        { /* Obj */
     696            RTVFSOBJOPS_VERSION,
     697            RTVFSOBJTYPE_FILE,
     698            "MemFile",
     699            rtVfsMemFile_Close,
     700            rtVfsMemFile_QueryInfo,
     701            RTVFSOBJOPS_VERSION
     702        },
     703        RTVFSIOSTREAMOPS_VERSION,
     704        RTVFSIOSTREAMOPS_FEAT_NO_SG,
     705        rtVfsMemFile_Read,
     706        rtVfsMemFile_Write,
     707        rtVfsMemFile_Flush,
     708        rtVfsMemFile_PollOne,
     709        rtVfsMemFile_Tell,
     710        NULL /*Skip*/,
     711        NULL /*ZeroFill*/,
     712        RTVFSIOSTREAMOPS_VERSION,
     713    },
     714    RTVFSFILEOPS_VERSION,
     715    /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
     716    { /* ObjSet */
     717        RTVFSOBJSETOPS_VERSION,
     718        RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
     719        rtVfsMemFile_SetMode,
     720        rtVfsMemFile_SetTimes,
     721        rtVfsMemFile_SetOwner,
     722        RTVFSOBJSETOPS_VERSION
     723    },
     724    rtVfsMemFile_Seek,
     725    rtVfsMemFile_QuerySize,
     726    RTVFSFILEOPS_VERSION
     727};
     728
     729
     730
    51731
    52732
    53733RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile)
    54734{
    55     return VERR_NOT_IMPLEMENTED;
    56 }
     735    /*
     736     * Create a memory file instance and try set the extension size to match
     737     * the length of the I/O stream.
     738     */
     739    RTFSOBJINFO ObjInfo;
     740    int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
     741    if (RT_SUCCESS(rc))
     742    {
     743        RTVFSFILE       hVfsFile;
     744        PRTVFSMEMFILE   pThis;
     745        rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(*pThis), fFlags, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
     746        if (RT_SUCCESS(rc))
     747        {
     748            pThis->Base.ObjInfo = ObjInfo;
     749            pThis->offCurPos    = 0;
     750            pThis->pCurExt      = NULL;
     751            RTListInit(&pThis->ExtentHead);
     752            if (ObjInfo.cbObject <= 0)
     753                pThis->cbExtent = _4K;
     754            else if (ObjInfo.cbObject < RTVFSMEM_MAX_EXTENT_SIZE)
     755                pThis->cbExtent = _4K;
     756            else
     757                pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
     758
     759            /*
     760             * Copy the stream.
     761             */
     762            RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile);
     763            rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent);
     764            RTVfsIoStrmRelease(hVfsIosDst);
     765            if (RT_SUCCESS(rc))
     766            {
     767                *phVfsFile = hVfsFile;
     768                return VINF_SUCCESS;
     769            }
     770            RTVfsFileRelease(hVfsFile);
     771        }
     772    }
     773    return rc;
     774}
Note: See TracChangeset for help on using the changeset viewer.

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