VirtualBox

Ignore:
Timestamp:
Mar 12, 2009 6:41:34 PM (16 years ago)
Author:
vboxsync
Message:

Storage/VMDK: implement creating/writing (slightly relaxed append only) of streamOptimized VMDK files.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r16873 r17775  
    294294    /** Pointer to the redundant grain directory. */
    295295    uint32_t    *pRGD;
    296     /** VMDK version of this extent. 1=1.0, 3=1.1 */
     296    /** VMDK version of this extent. 1=1.0/1.1 */
    297297    uint32_t    uVersion;
    298298    /** Type of this extent. */
     
    306306    /** Compression type for this extent. */
    307307    uint16_t    uCompression;
     308    /** Last grain which has been written to. Only for streamOptimized extents. */
     309    uint32_t    uLastGrainWritten;
     310    /** Sector number of last grain which has been written to. Only for
     311     * streamOptimized extents. */
     312    uint32_t    uLastGrainSector;
     313    /** Data size of last grain which has been written to. Only for
     314     * streamOptimized extents. */
     315    uint32_t    cbLastGrainWritten;
    308316    /** Starting sector of the decompressed grain buffer. */
    309     uint64_t    uGrainSector;
     317    uint32_t    uGrainSector;
    310318    /** Decompressed grain buffer for streamOptimized extents. */
    311319    void        *pvGrain;
     
    405413    const char      *pszFilename;
    406414    /** Descriptor file if applicable. */
    407     PVMDKFILE        pFile;
     415    PVMDKFILE       pFile;
    408416
    409417    /** Pointer to the per-disk VD interface list. */
    410     PVDINTERFACE     pVDIfsDisk;
     418    PVDINTERFACE    pVDIfsDisk;
    411419
    412420    /** Error interface. */
    413     PVDINTERFACE      pInterfaceError;
     421    PVDINTERFACE    pInterfaceError;
    414422    /** Error interface callbacks. */
    415423    PVDINTERFACEERROR pInterfaceErrorCallbacks;
    416424
    417425    /** Async I/O interface. */
    418     PVDINTERFACE        pInterfaceAsyncIO;
     426    PVDINTERFACE    pInterfaceAsyncIO;
    419427    /** Async I/O interface callbacks. */
    420428    PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks;
     
    425433     * is too expensive.
    426434     */
    427     void               **apTask;
     435    void            **apTask;
    428436    /** Entries available in the task handle array. */
    429     unsigned             cTask;
     437    unsigned        cTask;
    430438
    431439    /** Open flags passed by VBoxHD layer. */
     
    474482} VMDKINFLATESTATE;
    475483
     484/** State for the output callout of the deflate writer. */
     485typedef struct VMDKDEFLATESTATE
     486{
     487    /* File where the data is to be stored. */
     488    RTFILE File;
     489    /* Offset in the file to write at. */
     490    uint64_t uFileOffset;
     491    /* Current write position. */
     492    ssize_t iOffset;
     493} VMDKDEFLATESTATE;
     494
    476495/*******************************************************************************
    477496 *   Static Variables                                                           *
     
    748767                                  uint64_t uOffset, void *pvBuf,
    749768                                  size_t cbToRead, unsigned uMarker,
    750                                   uint64_t *puLBA)
     769                                  uint64_t *puLBA, uint32_t *pcbMarkerData)
    751770{
    752771    if (pVmdkFile->fAsyncIO)
     
    780799            if (puLBA)
    781800                *puLBA = Marker.uSector;
     801            if (pcbMarkerData)
     802                *pcbMarkerData = cbComp + 12;
    782803        }
    783804        else
     
    795816                uCompOffset = uOffset + 512;
    796817                cbComp = VMDK_SECTOR2BYTE(Marker.uSector);
     818                if (pcbMarkerData)
     819                    *pcbMarkerData = cbComp + 512;
    797820            }
    798821            else
     
    820843        if (cbActuallyRead != cbToRead)
    821844            rc = VERR_VD_VMDK_INVALID_FORMAT;
     845        return rc;
     846    }
     847}
     848
     849static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf)
     850{
     851    VMDKDEFLATESTATE *pDeflateState = (VMDKDEFLATESTATE *)pvUser;
     852
     853    Assert(cbBuf);
     854    if (pDeflateState->iOffset < 0)
     855    {
     856        pvBuf = (const uint8_t *)pvBuf + 1;
     857        cbBuf--;
     858        pDeflateState->iOffset = 0;
     859    }
     860    if (!cbBuf)
     861        return VINF_SUCCESS;
     862    int rc = RTFileWriteAt(pDeflateState->File, pDeflateState->uFileOffset, pvBuf, cbBuf, NULL);
     863    if (RT_FAILURE(rc))
     864        return rc;
     865    pDeflateState->uFileOffset += cbBuf;
     866    pDeflateState->iOffset += cbBuf;
     867    return VINF_SUCCESS;
     868}
     869
     870/**
     871 * Internal: deflate the uncompressed data and write to a file,
     872 * distinguishing between async and normal operation
     873 */
     874DECLINLINE(int) vmdkFileDeflateAt(PVMDKFILE pVmdkFile,
     875                                  uint64_t uOffset, const void *pvBuf,
     876                                  size_t cbToWrite, unsigned uMarker,
     877                                  uint64_t uLBA, uint32_t *pcbMarkerData)
     878{
     879    if (pVmdkFile->fAsyncIO)
     880    {
     881        AssertMsgFailed(("TODO\n"));
     882        return VERR_NOT_SUPPORTED;
     883    }
     884    else
     885    {
     886        int rc;
     887        PRTZIPCOMP pZip = NULL;
     888        VMDKMARKER Marker;
     889        uint64_t uCompOffset, cbDecomp;
     890        VMDKDEFLATESTATE DeflateState;
     891
     892        Marker.uSector = RT_H2LE_U64(uLBA);
     893        Marker.cbSize = RT_H2LE_U32(cbToWrite);
     894        if (uMarker == VMDK_MARKER_IGNORE)
     895        {
     896            /* Compressed grain marker. Data follows immediately. */
     897            uCompOffset = uOffset + 12;
     898            cbDecomp = cbToWrite;
     899            rc = RTFileWriteAt(pVmdkFile->File, uOffset, &Marker, 12, NULL);
     900            if (RT_FAILURE(rc))
     901                return rc;
     902        }
     903        else
     904        {
     905            /** @todo implement creating the other marker types */
     906            return VERR_NOT_IMPLEMENTED;
     907        }
     908        DeflateState.File = pVmdkFile->File;
     909        DeflateState.uFileOffset = uCompOffset;
     910        DeflateState.iOffset = -1;
     911
     912        rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper, RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
     913        if (RT_FAILURE(rc))
     914            return rc;
     915        rc = RTZipCompress(pZip, pvBuf, cbDecomp);
     916        if (RT_SUCCESS(rc))
     917            rc = RTZipCompFinish(pZip);
     918        RTZipCompDestroy(pZip);
     919        if (RT_SUCCESS(rc))
     920        {
     921            if (pcbMarkerData)
     922                *pcbMarkerData = 12 + DeflateState.iOffset;
     923            /* Set the file size to remove old garbage in case the block is
     924             * rewritten. Cannot cause data loss as the code calling this
     925             * guarantees that data gets only appended. */
     926            rc = RTFileSetSize(pVmdkFile->File, DeflateState.uFileOffset);
     927        }
    822928        return rc;
    823929    }
     
    10011107
    10021108        /* Check grain table and redundant grain table for consistency. */
    1003         size_t cbGT = pExtent->cGTEntries;
     1109        size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
    10041110        uint32_t *pTmpGT1 = (uint32_t *)RTMemTmpAlloc(cbGT);
    10051111        if (!pTmpGT1)
     
    10701176    }
    10711177
     1178    if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     1179    {
     1180        uint32_t uLastGrainWritten = 0;
     1181        uint32_t uLastGrainSector = 0;
     1182        size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
     1183        uint32_t *pTmpGT = (uint32_t *)RTMemTmpAlloc(cbGT);
     1184        if (!pTmpGT)
     1185        {
     1186            rc = VERR_NO_MEMORY;
     1187            goto out;
     1188        }
     1189        for (i = 0, pGDTmp = pGD; i < pExtent->cGDEntries; i++, pGDTmp++)
     1190        {
     1191            /* If no grain table is allocated skip the entry. */
     1192            if (*pGDTmp == 0)
     1193                continue;
     1194
     1195            /* The VMDK 1.1 spec talks about compressed grain tables, but real
     1196             * life files don't have them. The spec is wrong in creative ways. */
     1197            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp),
     1198                                pTmpGT, cbGT, NULL);
     1199            if (RT_FAILURE(rc))
     1200            {
     1201                rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
     1202                RTMemTmpFree(pTmpGT);
     1203                goto out;
     1204            }
     1205            uint32_t j;
     1206            uint32_t *pGTTmp;
     1207            for (j = 0, pGTTmp = pTmpGT; j < pExtent->cGTEntries; j++, pGTTmp++)
     1208            {
     1209                uint32_t uGTTmp = RT_LE2H_U32(*pGTTmp);
     1210
     1211                /* If no grain is allocated skip the entry. */
     1212                if (uGTTmp == 0)
     1213                    continue;
     1214
     1215                if (uLastGrainSector && uLastGrainSector >= uGTTmp)
     1216                {
     1217                    rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: grain table in '%s' contains a violation of the ordering assumptions"), pExtent->pszFullname);
     1218                    RTMemTmpFree(pTmpGT);
     1219                    goto out;
     1220                }
     1221                uLastGrainSector = uGTTmp;
     1222                uLastGrainWritten = i * pExtent->cGTEntries + j;
     1223            }
     1224        }
     1225        RTMemTmpFree(pTmpGT);
     1226
     1227        if (uLastGrainSector)
     1228        {
     1229            uint64_t uLBA = 0;
     1230            uint32_t cbMarker = 0;
     1231            rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uLastGrainSector),
     1232                                   pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA, &cbMarker);
     1233            if (RT_FAILURE(rc))
     1234                goto out;
     1235
     1236            Assert(uLBA == uLastGrainWritten * pExtent->cSectorsPerGrain);
     1237            pExtent->uGrainSector = uLastGrainSector;
     1238            pExtent->cbLastGrainWritten = RT_ALIGN(cbMarker, 512);
     1239        }
     1240        pExtent->uLastGrainWritten = uLastGrainWritten;
     1241        pExtent->uLastGrainSector = uLastGrainSector;
     1242    }
     1243
    10721244out:
    10731245    if (RT_FAILURE(rc))
     
    11081280
    11091281    cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
    1110     rc = vmdkFileSetSize(pExtent->pFile, cbOverhead);
     1282    /* For streamOptimized extents put the end-of-stream marker at the end. */
     1283    if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     1284        rc = vmdkFileSetSize(pExtent->pFile, cbOverhead + 512);
     1285    else
     1286        rc = vmdkFileSetSize(pExtent->pFile, cbOverhead);
    11111287    if (RT_FAILURE(rc))
    11121288        goto out;
     
    21372313        return rc;
    21382314
    2139     /* Stream optimized images are always readonly. Nevertheless we opened the
    2140      * file as read/write to allow us to sneak in the UUID info. */
    2141     if (pImage->uImageFlags == VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    2142         pImage->uOpenFlags |= VD_OPEN_FLAGS_READONLY;
    2143 
    21442315    return VINF_SUCCESS;
    21452316}
     
    22682439        }
    22692440        cbSize = RT_ALIGN_64(cbSize, 512);
    2270         rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL);
     2441        rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL, NULL);
    22712442        AssertRC(rc);
    22722443        if (RT_FAILURE(rc))
     
    23312502
    23322503    /* streamOptimized extents need a grain decryption buffer. */
    2333     if (pExtent->uVersion == 3)
     2504    if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    23342505    {
    23352506        pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     
    23392510            goto out;
    23402511        }
    2341         pExtent->uGrainSector = 0xffffffffffffffffULL;
     2512        pExtent->uGrainSector = 0;
    23422513    }
    23432514
     
    26032774            pExtents[i].pRGD = NULL;
    26042775            pExtents[i].pDescData = NULL;
     2776            pExtents[i].uCompression = VMDK_COMPRESSION_NONE;
    26052777            pExtents[i].uExtent = i;
    26062778            pExtents[i].pImage = pImage;
     
    33313503                if (pfnProgress)
    33323504                {
    3333                     rc = pfnProgress(NULL /* WARNING! pVM=NULL  */,
     3505                    rc = pfnProgress(NULL /* WARNING! pVM=NULL */,
    33343506                                     uPercentStart + uOff * uPercentSpan / cbExtent,
    33353507                                     pvUser);
     
    33653537            pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    33663538            cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     3539            if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     3540                pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
    33673541        }
    33683542        else
     
    33873561
    33883562        if (RT_SUCCESS(rc) && pfnProgress)
    3389             pfnProgress(NULL /* WARNING! pVM=NULL  */,
     3563            pfnProgress(NULL /* WARNING! pVM=NULL */,
    33903564                        uPercentStart + i * uPercentSpan / cExtents,
    33913565                        pvUser);
     
    34033577    else if (enmType == VD_IMAGE_TYPE_NORMAL)
    34043578    {
    3405         pszDescType =   (cExtents == 1)
    3406                       ? "monolithicSparse" : "twoGbMaxExtentSparse";
     3579        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     3580            pszDescType = "streamOptimized";
     3581        else
     3582        {
     3583            pszDescType =   (cExtents == 1)
     3584                          ? "monolithicSparse" : "twoGbMaxExtentSparse";
     3585        }
    34073586    }
    34083587    else
     
    34773656
    34783657    if (RT_SUCCESS(rc) && pfnProgress)
    3479         pfnProgress(NULL /* WARNING! pVM=NULL  */,
     3658        pfnProgress(NULL /* WARNING! pVM=NULL */,
    34803659                    uPercentStart + uPercentSpan * 98 / 100, pvUser);
    34813660
     
    35653744
    35663745    if (RT_SUCCESS(rc) && pfnProgress)
    3567         pfnProgress(NULL /* WARNING! pVM=NULL  */,
     3746        pfnProgress(NULL /* WARNING! pVM=NULL */,
    35683747                    uPercentStart + uPercentSpan * 99 / 100, pvUser);
    35693748
     
    35723751out:
    35733752    if (RT_SUCCESS(rc) && pfnProgress)
    3574         pfnProgress(NULL /* WARNING! pVM=NULL  */,
     3753        pfnProgress(NULL /* WARNING! pVM=NULL */,
    35753754                    uPercentStart + uPercentSpan, pvUser);
    35763755
     
    38063985    }
    38073986    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
    3808     uint64_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
     3987    uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
    38093988    if (uGrainSector)
    38103989        *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
     
    38504029        cbExtentSize = RT_ALIGN_64(cbExtentSize, 512);
    38514030        uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     4031        /* For writable streamOptimized extents the final sector is the
     4032         * end-of-stream marker. Will be re-added after the grain table. */
     4033        if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4034        {
     4035            uGTSector--;
     4036            pExtent->uLastGrainSector = 0;
     4037            uint8_t aEOS[512];
     4038            memset(aEOS, '\0', sizeof(aEOS));
     4039            rc = vmdkFileWriteAt(pExtent->pFile,
     4040                                 VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t),
     4041                                 aEOS, sizeof(aEOS), NULL);
     4042            if (RT_FAILURE(rc))
     4043                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after grain table in '%s'"), pExtent->pszFullname);
     4044        }
    38524045        /* Normally the grain table is preallocated for hosted sparse extents
    38534046         * that support more than 32 bit sector numbers. So this shouldn't
     
    38784071            Assert(!(cbExtentSize % 512));
    38794072            uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     4073            /* For writable streamOptimized extents the final sector is the
     4074             * end-of-stream marker. Will be re-added after the grain table. */
     4075            if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4076            {
     4077                uRGTSector--;
     4078                pExtent->uLastGrainSector = 0;
     4079                uint8_t aEOS[512];
     4080                memset(aEOS, '\0', sizeof(aEOS));
     4081                rc = vmdkFileWriteAt(pExtent->pFile,
     4082                                     VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t),
     4083                                     aEOS, sizeof(aEOS), NULL);
     4084                if (RT_FAILURE(rc))
     4085                    return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after redundant grain table in '%s'"), pExtent->pszFullname);
     4086            }
    38804087            /* Normally the redundant grain table is preallocated for hosted
    38814088             * sparse extents that support more than 32 bit sector numbers. So
     
    39304137    Assert(!(cbExtentSize % 512));
    39314138
    3932     /* Write the data. */
    3933     rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL);
    3934     if (RT_FAILURE(rc))
    3935         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
     4139    /* Write the data. Always a full grain, or we're in big trouble. */
     4140    if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4141    {
     4142        /* For streamOptimized extents this is a little more difficult, as the
     4143         * cached data also needs to be updated, to handle updating the last
     4144         * written block properly. Also we're trying to avoid unnecessary gaps.
     4145         * Additionally the end-of-stream marker needs to be written. */
     4146        if (!pExtent->uLastGrainSector)
     4147            cbExtentSize -= 512;
     4148        else
     4149            cbExtentSize = VMDK_SECTOR2BYTE(pExtent->uLastGrainSector) + pExtent->cbLastGrainWritten;
     4150        Assert(cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     4151        uint32_t cbGrain = 0;
     4152        rc = vmdkFileDeflateAt(pExtent->pFile, cbExtentSize,
     4153                               pvBuf, cbWrite, VMDK_MARKER_IGNORE, uSector, &cbGrain);
     4154        if (RT_FAILURE(rc))
     4155        {
     4156            pExtent->uGrainSector = 0;
     4157            pExtent->uLastGrainSector = 0;
     4158            AssertRC(rc);
     4159            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname);
     4160        }
     4161        cbGrain = RT_ALIGN(cbGrain, 512);
     4162        pExtent->uLastGrainSector = VMDK_BYTE2SECTOR(cbExtentSize);
     4163        pExtent->uLastGrainWritten = uSector / pExtent->cSectorsPerGrain;
     4164        pExtent->cbLastGrainWritten = cbGrain;
     4165        memcpy(pExtent->pvGrain, pvBuf, cbWrite);
     4166        pExtent->uGrainSector = uSector;
     4167
     4168        uint8_t aEOS[512];
     4169        memset(aEOS, '\0', sizeof(aEOS));
     4170        rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize + RT_ALIGN(cbGrain, 512),
     4171                             aEOS, sizeof(aEOS), NULL);
     4172        if (RT_FAILURE(rc))
     4173            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after allocated data block in '%s'"), pExtent->pszFullname);
     4174    }
     4175    else
     4176    {
     4177        rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL);
     4178        if (RT_FAILURE(rc))
     4179            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
     4180    }
    39364181
    39374182    /* Update the grain table (and the cache). */
     
    41214366        || (enmType != VD_IMAGE_TYPE_NORMAL && enmType != VD_IMAGE_TYPE_FIXED)
    41224367        || !VALID_PTR(pPCHSGeometry)
    4123         || !VALID_PTR(pLCHSGeometry))
     4368        || !VALID_PTR(pLCHSGeometry)
     4369        || (   (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4370            && (   (uImageFlags & ~VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4371                || (enmType != VD_IMAGE_TYPE_NORMAL))))
    41244372    {
    41254373        rc = VERR_INVALID_PARAMETER;
     
    42264474    unsigned i, line;
    42274475    VMDKDESCRIPTOR DescriptorCopy;
    4228     VMDKEXTENT     ExtentCopy;
     4476    VMDKEXTENT ExtentCopy;
    42294477
    42304478    memset(&DescriptorCopy, 0, sizeof(DescriptorCopy));
     
    42454493     * with zeros. We actually save stuff when and if we change it.
    42464494     */
    4247     apszOldName  = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
    4248     apszNewName  = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
     4495    apszOldName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
     4496    apszNewName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
    42494497    apszNewLines = (char **)RTMemTmpAllocZ((cExtents) * sizeof(char*));
    42504498    if (!apszOldName || !apszNewName || !apszNewLines)
     
    42634511    {
    42644512        /* Embedded descriptor file. */
    4265         ExtentCopy  = pImage->pExtents[0];
     4513        ExtentCopy = pImage->pExtents[0];
    42664514        fEmbeddedDesc = true;
    42674515    }
     
    43894637        if (fEmbeddedDesc)
    43904638        {
    4391             ExtentCopy.pFile   = pFile;
     4639            ExtentCopy.pFile = pFile;
    43924640            pImage->pExtents = &ExtentCopy;
    43934641        }
     
    45344782                    {
    45354783                        rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uSectorExtentAbs),
    4536                                                pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA);
     4784                                               pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA, NULL);
    45374785                        if (RT_FAILURE(rc))
    45384786                        {
    4539                             pExtent->uGrainSector = 0xffffffffffffffffULL;
     4787                            pExtent->uGrainSector = 0;
    45404788                            AssertRC(rc);
    45414789                            goto out;
     
    46314879            /* Clip write range to at most the rest of the grain. */
    46324880            cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
     4881            if (    pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
     4882                &&  uSectorExtentRel < (uint64_t)pExtent->uLastGrainWritten * pExtent->cSectorsPerGrain)
     4883            {
     4884                rc = VERR_VD_VMDK_INVALID_WRITE;
     4885                goto out;
     4886            }
    46334887            if (uSectorExtentAbs == 0)
    46344888            {
     
    46364890                {
    46374891                    /* Full block write to a previously unallocated block.
    4638                      * Check if the caller wants to avoid this. */
     4892                     * Check if the caller wants to avoid the automatic alloc. */
    46394893                    if (!(fWrite & VD_WRITE_NO_ALLOC))
    46404894                    {
     
    46584912            }
    46594913            else
    4660                 rc = vmdkFileWriteAt(pExtent->pFile,
    4661                                      VMDK_SECTOR2BYTE(uSectorExtentAbs),
    4662                                      pvBuf, cbToWrite, NULL);
     4914            {
     4915                if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4916                {
     4917                    uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
     4918                    uSectorExtentAbs -= uSectorInGrain;
     4919                    uint64_t uLBA;
     4920                    if (    pExtent->uGrainSector != uSectorExtentAbs
     4921                        ||  pExtent->uGrainSector != pExtent->uLastGrainSector)
     4922                    {
     4923                        rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4924                                               pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA, NULL);
     4925                        if (RT_FAILURE(rc))
     4926                        {
     4927                            pExtent->uGrainSector = 0;
     4928                            pExtent->uLastGrainSector = 0;
     4929                            AssertRC(rc);
     4930                            goto out;
     4931                        }
     4932                        pExtent->uGrainSector = uSectorExtentAbs;
     4933                        pExtent->uLastGrainSector = uSectorExtentAbs;
     4934                        Assert(uLBA == uSectorExtentRel);
     4935                    }
     4936                    memcpy((uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), pvBuf, cbToWrite);
     4937                    uint32_t cbGrain = 0;
     4938                    rc = vmdkFileDeflateAt(pExtent->pFile,
     4939                                           VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4940                                           pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
     4941                                           VMDK_MARKER_IGNORE, uLBA, &cbGrain);
     4942                    if (RT_FAILURE(rc))
     4943                    {
     4944                        pExtent->uGrainSector = 0;
     4945                        pExtent->uLastGrainSector = 0;
     4946                        AssertRC(rc);
     4947                        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
     4948                    }
     4949                    cbGrain = RT_ALIGN(cbGrain, 512);
     4950                    pExtent->uLastGrainSector = uSectorExtentAbs;
     4951                    pExtent->uLastGrainWritten = uSectorExtentRel / pExtent->cSectorsPerGrain;
     4952                    pExtent->cbLastGrainWritten = cbGrain;
     4953
     4954                    uint8_t aEOS[512];
     4955                    memset(aEOS, '\0', sizeof(aEOS));
     4956                    rc = vmdkFileWriteAt(pExtent->pFile,
     4957                                         VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512),
     4958                                         aEOS, sizeof(aEOS), NULL);
     4959                    if (RT_FAILURE(rc))
     4960                        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after data block in '%s'"), pExtent->pszFullname);
     4961                }
     4962                else
     4963                {
     4964                    rc = vmdkFileWriteAt(pExtent->pFile,
     4965                                         VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4966                                         pvBuf, cbToWrite, NULL);
     4967                }
     4968            }
    46634969            break;
    46644970        case VMDKETYPE_FLAT:
     
    53095615    unsigned cTasksToSubmit = 0;
    53105616    PPDMDATASEG paSegCurrent = paSeg;
    5311     unsigned  cbLeftInCurrentSegment = paSegCurrent->cbSeg;
    5312     unsigned  uOffsetInCurrentSegment = 0;
     5617    unsigned cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     5618    unsigned uOffsetInCurrentSegment = 0;
    53135619
    53145620    AssertPtr(pImage);
     
    54015707        }
    54025708
    5403         cbRead  -= cbToRead;
     5709        cbRead -= cbToRead;
    54045710        uOffset += cbToRead;
    54055711        cbLeftInCurrentSegment -= cbToRead;
     
    54455751    unsigned cTasksToSubmit = 0;
    54465752    PPDMDATASEG paSegCurrent = paSeg;
    5447     unsigned  cbLeftInCurrentSegment = paSegCurrent->cbSeg;
    5448     unsigned  uOffsetInCurrentSegment = 0;
     5753    unsigned cbLeftInCurrentSegment = paSegCurrent->cbSeg;
     5754    unsigned uOffsetInCurrentSegment = 0;
    54495755
    54505756    AssertPtr(pImage);
     
    55375843        }
    55385844
    5539         cbWrite  -= cbToWrite;
    5540         uOffset  += cbToWrite;
     5845        cbWrite -= cbToWrite;
     5846        uOffset += cbToWrite;
    55415847        cbLeftInCurrentSegment -= cbToWrite;
    55425848        uOffsetInCurrentSegment += cbToWrite;
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