VirtualBox

Changeset 66249 in vbox


Ignore:
Timestamp:
Mar 26, 2017 9:51:14 PM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
114170
Message:

Storage/vbox-img: Add option to create sparse files

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/testcase/vbox-img.cpp

    r65812 r66249  
    2424#include <VBox/version.h>
    2525#include <iprt/initterm.h>
     26#include <iprt/asm.h>
    2627#include <iprt/buildconfig.h>
    2728#include <iprt/path.h>
     
    464465{
    465466    RTFILE file;
     467    /** Size of file. */
     468    uint64_t cb;
    466469    /** Offset in the file. */
    467470    uint64_t off;
     
    494497
    495498    pFS->file = file;
     499    pFS->cb   = 0;
    496500    pFS->off = 0;
    497501    pFS->offBuffer = UINT64_MAX;
     
    668672}
    669673
    670 static DECLCALLBACK(int) convOutOpen(void *pvUser, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
    671                                      void **ppStorage)
     674static DECLCALLBACK(int) convStdOutOpen(void *pvUser, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
     675                                        void **ppStorage)
    672676{
    673677    RT_NOREF2(pvUser, pszLocation);
     
    688692
    689693    pFS->file = file;
     694    pFS->cb   = 0;
    690695    pFS->off = 0;
    691696    pFS->offBuffer = 0;
     
    696701}
    697702
    698 static DECLCALLBACK(int) convOutClose(void *pvUser, void *pStorage)
     703static DECLCALLBACK(int) convStdOutClose(void *pvUser, void *pStorage)
    699704{
    700705    NOREF(pvUser);
     
    706711    if (pFS->cbBuffer)
    707712        rc = RTFileWrite(pFS->file, &pFS->abBuffer[0], pFS->cbBuffer, NULL);
     713    if (   RT_SUCCESS(rc)
     714        && pFS->cb > pFS->off)
     715    {
     716        /* Write zeros if the set file size is not met. */
     717        uint64_t cbLeft = pFS->cb - pFS->off;
     718        RT_ZERO(pFS->abBuffer);
     719
     720        while (cbLeft)
     721        {
     722            size_t cbThisWrite = RT_MIN(cbLeft, sizeof(pFS->abBuffer));
     723            rc = RTFileWrite(pFS->file, &pFS->abBuffer[0],
     724                             cbThisWrite, NULL);
     725            cbLeft -= cbThisWrite;
     726        }
     727    }
    708728
    709729    RTMemFree(pFS);
     
    712732}
    713733
    714 static DECLCALLBACK(int) convOutDelete(void *pvUser, const char *pcszFilename)
     734static DECLCALLBACK(int) convStdOutDelete(void *pvUser, const char *pcszFilename)
    715735{
    716736    NOREF(pvUser);
     
    719739}
    720740
    721 static DECLCALLBACK(int) convOutMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
     741static DECLCALLBACK(int) convStdOutMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
    722742{
    723743    NOREF(pvUser);
     
    728748}
    729749
    730 static DECLCALLBACK(int) convOutGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
     750static DECLCALLBACK(int) convStdOutGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
    731751{
    732752    NOREF(pvUser);
     
    737757}
    738758
    739 static DECLCALLBACK(int) convOutGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
     759static DECLCALLBACK(int) convStdOutGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
    740760{
    741761    NOREF(pvUser);
     
    745765}
    746766
    747 static DECLCALLBACK(int) convOutGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
     767static DECLCALLBACK(int) convStdOutGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
    748768{
    749769    NOREF(pvUser);
     
    753773}
    754774
    755 static DECLCALLBACK(int) convOutSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
    756 {
    757     NOREF(pvUser);
    758     NOREF(pStorage);
    759     NOREF(cbSize);
     775static DECLCALLBACK(int) convStdOutSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
     776{
     777    RT_NOREF2(pvUser, cbSize);
     778    AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
    760779    AssertFailedReturn(VERR_NOT_SUPPORTED);
    761780}
    762781
    763 static DECLCALLBACK(int) convOutRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer,
    764                                      size_t *pcbRead)
     782static DECLCALLBACK(int) convStdOutRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer,
     783                                        size_t *pcbRead)
    765784{
    766785    NOREF(pvUser);
     
    773792}
    774793
    775 static DECLCALLBACK(int) convOutWrite(void *pvUser, void *pStorage, uint64_t uOffset, const void *pvBuffer, size_t cbBuffer,
    776                                       size_t *pcbWritten)
     794static DECLCALLBACK(int) convStdOutWrite(void *pvUser, void *pStorage, uint64_t uOffset, const void *pvBuffer, size_t cbBuffer,
     795                                         size_t *pcbWritten)
    777796{
    778797    NOREF(pvUser);
     
    818837}
    819838
    820 static DECLCALLBACK(int) convOutFlush(void *pvUser, void *pStorage)
     839static DECLCALLBACK(int) convStdOutFlush(void *pvUser, void *pStorage)
     840{
     841    NOREF(pvUser);
     842    NOREF(pStorage);
     843    return VINF_SUCCESS;
     844}
     845
     846static DECLCALLBACK(int) convFileOutOpen(void *pvUser, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
     847                                         void **ppStorage)
     848{
     849    RT_NOREF1(pvUser);
     850
     851    /* Validate input. */
     852    AssertPtrReturn(ppStorage, VERR_INVALID_POINTER);
     853    AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
     854    AssertReturn((fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_WRITE, VERR_INVALID_PARAMETER);
     855    RTFILE file;
     856    int rc = RTFileOpen(&file, pszLocation, fOpen);
     857    if (RT_FAILURE(rc))
     858        return rc;
     859
     860    /* Must clear buffer, so that skipped over data is initialized properly. */
     861    PFILEIOSTATE pFS = (PFILEIOSTATE)RTMemAllocZ(sizeof(FILEIOSTATE));
     862    if (!pFS)
     863        return VERR_NO_MEMORY;
     864
     865    pFS->file      = file;
     866    pFS->cb        = 0;
     867    pFS->off       = 0;
     868    pFS->offBuffer = 0;
     869    pFS->cbBuffer  = sizeof(FILEIOSTATE);
     870
     871    *ppStorage = pFS;
     872    return VINF_SUCCESS;
     873}
     874
     875static DECLCALLBACK(int) convFileOutClose(void *pvUser, void *pStorage)
     876{
     877    NOREF(pvUser);
     878    AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
     879    PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
     880    int rc = VINF_SUCCESS;
     881
     882    /* Flush any remaining buffer contents. */
     883    if (pFS->cbBuffer)
     884        rc = RTFileWriteAt(pFS->file, pFS->offBuffer, &pFS->abBuffer[0], pFS->cbBuffer, NULL);
     885    RTFileClose(pFS->file);
     886
     887    RTMemFree(pFS);
     888
     889    return rc;
     890}
     891
     892static DECLCALLBACK(int) convFileOutDelete(void *pvUser, const char *pcszFilename)
     893{
     894    NOREF(pvUser);
     895    NOREF(pcszFilename);
     896    AssertFailedReturn(VERR_NOT_SUPPORTED);
     897}
     898
     899static DECLCALLBACK(int) convFileOutMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
     900{
     901    NOREF(pvUser);
     902    NOREF(pcszSrc);
     903    NOREF(pcszDst);
     904    NOREF(fMove);
     905    AssertFailedReturn(VERR_NOT_SUPPORTED);
     906}
     907
     908static DECLCALLBACK(int) convFileOutGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
     909{
     910    NOREF(pvUser);
     911    NOREF(pcszFilename);
     912    AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
     913    *pcbFreeSpace = INT64_MAX;
     914    return VINF_SUCCESS;
     915}
     916
     917static DECLCALLBACK(int) convFileOutGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
     918{
     919    NOREF(pvUser);
     920    NOREF(pcszFilename);
     921    AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
     922    AssertFailedReturn(VERR_NOT_SUPPORTED);
     923}
     924
     925static DECLCALLBACK(int) convFileOutGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
     926{
     927    NOREF(pvUser);
     928    NOREF(pStorage);
     929    AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
     930    AssertFailedReturn(VERR_NOT_SUPPORTED);
     931}
     932
     933static DECLCALLBACK(int) convFileOutSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
     934{
     935    NOREF(pvUser);
     936    AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
     937    PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
     938
     939    int rc = RTFileSetSize(pFS->file, cbSize);
     940    if (RT_SUCCESS(rc))
     941        pFS->cb = cbSize;
     942    return VINF_SUCCESS;
     943}
     944
     945static DECLCALLBACK(int) convFileOutRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer,
     946                                         size_t *pcbRead)
     947{
     948    NOREF(pvUser);
     949    NOREF(pStorage);
     950    NOREF(uOffset);
     951    NOREF(cbBuffer);
     952    NOREF(pcbRead);
     953    AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
     954    AssertFailedReturn(VERR_NOT_SUPPORTED);
     955}
     956
     957static DECLCALLBACK(int) convFileOutWrite(void *pvUser, void *pStorage, uint64_t uOffset, const void *pvBuffer, size_t cbBuffer,
     958                                          size_t *pcbWritten)
     959{
     960    NOREF(pvUser);
     961    AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
     962    AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
     963    PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
     964    AssertReturn(uOffset >= pFS->off, VERR_INVALID_PARAMETER);
     965    int rc;
     966
     967    /* Write the data to the buffer, flushing as required. */
     968    size_t cbTotalWritten = 0;
     969    do
     970    {
     971        /* Flush the buffer if we need a new one. */
     972        while (uOffset > pFS->offBuffer + sizeof(pFS->abBuffer) - 1)
     973        {
     974            if (!ASMMemIsZero(pFS->abBuffer, sizeof(pFS->abBuffer)))
     975                rc = RTFileWriteAt(pFS->file, pFS->offBuffer,
     976                                   &pFS->abBuffer[0],
     977                                   sizeof(pFS->abBuffer), NULL);
     978            RT_ZERO(pFS->abBuffer);
     979            pFS->offBuffer += sizeof(pFS->abBuffer);
     980            pFS->cbBuffer = 0;
     981        }
     982
     983        uint32_t cbThisWrite = (uint32_t)RT_MIN(cbBuffer,
     984                                                sizeof(pFS->abBuffer) - uOffset % sizeof(pFS->abBuffer));
     985        memcpy(&pFS->abBuffer[uOffset % sizeof(pFS->abBuffer)], pvBuffer,
     986               cbThisWrite);
     987        uOffset += cbThisWrite;
     988        pvBuffer = (uint8_t *)pvBuffer + cbThisWrite;
     989        cbBuffer -= cbThisWrite;
     990        cbTotalWritten += cbThisWrite;
     991    } while (cbBuffer > 0);
     992
     993    if (pcbWritten)
     994        *pcbWritten = cbTotalWritten;
     995
     996    pFS->cbBuffer = uOffset % sizeof(pFS->abBuffer);
     997    if (!pFS->cbBuffer)
     998        pFS->cbBuffer = sizeof(pFS->abBuffer);
     999    pFS->off = uOffset;
     1000
     1001    return VINF_SUCCESS;
     1002}
     1003
     1004static DECLCALLBACK(int) convFileOutFlush(void *pvUser, void *pStorage)
    8211005{
    8221006    NOREF(pvUser);
     
    8311015    bool fStdIn = false;
    8321016    bool fStdOut = false;
     1017    bool fCreateSparse = false;
    8331018    const char *pszSrcFormat = NULL;
    8341019    VDTYPE enmSrcType = VDTYPE_HDD;
     
    8531038        { "--srcformat", 's', RTGETOPT_REQ_STRING },
    8541039        { "--dstformat", 'd', RTGETOPT_REQ_STRING },
    855         { "--variant", 'v', RTGETOPT_REQ_STRING }
     1040        { "--variant", 'v', RTGETOPT_REQ_STRING },
     1041        { "--create-sparse", 'c', RTGETOPT_REQ_NOTHING }
    8561042    };
    8571043    int ch;
     
    8831069            case 'v':   // --variant
    8841070                pszVariant = ValueUnion.psz;
     1071                break;
     1072            case 'c':   // --create-sparse
     1073                fCreateSparse = true;
    8851074                break;
    8861075
     
    9361125    if (fStdOut)
    9371126    {
    938         IfsOutputIO.pfnOpen                   = convOutOpen;
    939         IfsOutputIO.pfnClose                  = convOutClose;
    940         IfsOutputIO.pfnDelete                 = convOutDelete;
    941         IfsOutputIO.pfnMove                   = convOutMove;
    942         IfsOutputIO.pfnGetFreeSpace           = convOutGetFreeSpace;
    943         IfsOutputIO.pfnGetModificationTime    = convOutGetModificationTime;
    944         IfsOutputIO.pfnGetSize                = convOutGetSize;
    945         IfsOutputIO.pfnSetSize                = convOutSetSize;
    946         IfsOutputIO.pfnReadSync               = convOutRead;
    947         IfsOutputIO.pfnWriteSync              = convOutWrite;
    948         IfsOutputIO.pfnFlushSync              = convOutFlush;
     1127        IfsOutputIO.pfnOpen                   = convStdOutOpen;
     1128        IfsOutputIO.pfnClose                  = convStdOutClose;
     1129        IfsOutputIO.pfnDelete                 = convStdOutDelete;
     1130        IfsOutputIO.pfnMove                   = convStdOutMove;
     1131        IfsOutputIO.pfnGetFreeSpace           = convStdOutGetFreeSpace;
     1132        IfsOutputIO.pfnGetModificationTime    = convStdOutGetModificationTime;
     1133        IfsOutputIO.pfnGetSize                = convStdOutGetSize;
     1134        IfsOutputIO.pfnSetSize                = convStdOutSetSize;
     1135        IfsOutputIO.pfnReadSync               = convStdOutRead;
     1136        IfsOutputIO.pfnWriteSync              = convStdOutWrite;
     1137        IfsOutputIO.pfnFlushSync              = convStdOutFlush;
    9491138        VDInterfaceAdd(&IfsOutputIO.Core, "stdout", VDINTERFACETYPE_IO,
     1139                       NULL, sizeof(VDINTERFACEIO), &pIfsImageOutput);
     1140    }
     1141    else if (fCreateSparse)
     1142    {
     1143        IfsOutputIO.pfnOpen                   = convFileOutOpen;
     1144        IfsOutputIO.pfnClose                  = convFileOutClose;
     1145        IfsOutputIO.pfnDelete                 = convFileOutDelete;
     1146        IfsOutputIO.pfnMove                   = convFileOutMove;
     1147        IfsOutputIO.pfnGetFreeSpace           = convFileOutGetFreeSpace;
     1148        IfsOutputIO.pfnGetModificationTime    = convFileOutGetModificationTime;
     1149        IfsOutputIO.pfnGetSize                = convFileOutGetSize;
     1150        IfsOutputIO.pfnSetSize                = convFileOutSetSize;
     1151        IfsOutputIO.pfnReadSync               = convFileOutRead;
     1152        IfsOutputIO.pfnWriteSync              = convFileOutWrite;
     1153        IfsOutputIO.pfnFlushSync              = convFileOutFlush;
     1154        VDInterfaceAdd(&IfsOutputIO.Core, "fileout", VDINTERFACETYPE_IO,
    9501155                       NULL, sizeof(VDINTERFACEIO), &pIfsImageOutput);
    9511156    }
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