VirtualBox

Changeset 33088 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
Oct 13, 2010 7:49:04 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66617
Message:

Storage/VMDK: merge the sequential streamOptimized image writing code into the normal backend

Location:
trunk/src/VBox/Devices/Storage
Files:
2 edited

Legend:

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

    r33082 r33088  
    433433extern VBOXHDDBACKEND g_RawBackend;
    434434extern VBOXHDDBACKEND g_VmdkBackend;
    435 extern VBOXHDDBACKEND g_VmdkStreamBackend;
    436435extern VBOXHDDBACKEND g_VDIBackend;
    437436extern VBOXHDDBACKEND g_VhdBackend;
     
    450449    &g_RawBackend,
    451450    &g_VmdkBackend,
    452     &g_VmdkStreamBackend,
    453451    &g_VDIBackend,
    454452    &g_VhdBackend,
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r32892 r33088  
    304304    /** Compression type for this extent. */
    305305    uint16_t    uCompression;
     306    /** Append position for writing new grain. Only for sparse extents. */
     307    uint64_t    uAppendPosition;
    306308    /** Last grain which has been written to. Only for streamOptimized extents. */
    307309    uint32_t    uLastGrainWritten;
     
    309311     * streamOptimized extents. */
    310312    uint32_t    uLastGrainSector;
    311     /** Data size of last grain which has been written to. Only for
    312      * streamOptimized extents. */
    313     uint32_t    cbLastGrainWritten;
    314313    /** Starting sector of the decompressed grain buffer. */
    315314    uint32_t    uGrainSector;
     
    473472
    474473
    475 /** State for the input callout of the inflate reader. */
    476 typedef struct VMDKINFLATESTATE
     474/** State for the input/output callout of the inflate reader/deflate writer. */
     475typedef struct VMDKCOMPRESSIO
    477476{
    478477    /* Image this operation relates to. */
     
    484483    /* Pointer to the compressed grain buffer. */
    485484    void *pvCompGrain;
    486 } VMDKINFLATESTATE;
    487 
    488 /** State for the output callout of the deflate writer. */
    489 typedef struct VMDKDEFLATESTATE
    490 {
    491     /* Image this operation relates to. */
    492     PVMDKIMAGE pImage;
    493     /* Current write position. */
    494     ssize_t iOffset;
    495     /* Size of the compressed grain buffer. */
    496     size_t cbCompGrain;
    497     /* Pointer to the compressed grain buffer. */
    498     void *pvCompGrain;
    499 } VMDKDEFLATESTATE;
     485} VMDKCOMPRESSIO;
     486
    500487
    501488/** Tracks async grain allocation. */
    502489typedef struct VMDKGRAINALLOCASYNC
    503490{
    504     /** Old size of the extent. Used for rollback after an error. */
    505     uint64_t    cbExtentOld;
    506491    /** Flag whether the allocation failed. */
    507492    bool        fIoErr;
     
    515500    /** Extent the allocation happens. */
    516501    PVMDKEXTENT pExtent;
    517     /** New size of the extent, required for the grain table update. */
    518     uint64_t    cbExtentSize;
     502    /** Position of the new grain, required for the grain table update. */
     503    uint64_t    uGrainOffset;
    519504    /** Grain table sector. */
    520505    uint64_t    uGTSector;
     
    850835static DECLCALLBACK(int) vmdkFileInflateHelper(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
    851836{
    852     VMDKINFLATESTATE *pInflateState = (VMDKINFLATESTATE *)pvUser;
     837    VMDKCOMPRESSIO *pInflateState = (VMDKCOMPRESSIO *)pvUser;
    853838    size_t cbInjected = 0;
    854839
     
    932917                                      512);
    933918
    934         VMDKINFLATESTATE InflateState;
     919        VMDKCOMPRESSIO InflateState;
    935920        InflateState.pImage = pImage;
    936921        InflateState.iOffset = -1;
     
    953938static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf)
    954939{
    955     VMDKDEFLATESTATE *pDeflateState = (VMDKDEFLATESTATE *)pvUser;
     940    VMDKCOMPRESSIO *pDeflateState = (VMDKCOMPRESSIO *)pvUser;
    956941
    957942    Assert(cbBuf);
     
    990975        int rc;
    991976        PRTZIPCOMP pZip = NULL;
    992         VMDKDEFLATESTATE DeflateState;
     977        VMDKCOMPRESSIO DeflateState;
    993978
    994979        DeflateState.pImage = pImage;
     
    10321017            if (RT_FAILURE(rc))
    10331018                return rc;
    1034 
    1035 /** @todo remove this code */
    1036             /* Set the file size to remove old garbage in case the block is
    1037              * rewritten. Cannot cause data loss as the code calling this
    1038              * guarantees that data gets only appended. Change the file size
    1039              * only if the size really changed, because this is very expensive
    1040              * on some filesystems such as XFS. */
    1041             uint64_t cbOld;
    1042             rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbOld);
    1043             if (RT_FAILURE(rc))
    1044                 return rc;
    1045 
    1046             if (cbOld != uOffset + uSize)
    1047                 rc = vmdkFileSetSize(pImage, pExtent->pFile, uOffset + uSize);
    10481019        }
    10491020        return rc;
    10501021    }
    10511022}
     1023
    10521024
    10531025/**
     
    11811153        RTMemFree(pExtent->pRGD);
    11821154        pExtent->pRGD = NULL;
    1183     }
    1184     if (pExtent->pvCompGrain)
    1185     {
    1186         RTMemFree(pExtent->pvCompGrain);
    1187         pExtent->pvCompGrain = NULL;
    1188     }
    1189     if (pExtent->pvGrain)
    1190     {
    1191         RTMemFree(pExtent->pvGrain);
    1192         pExtent->pvGrain = NULL;
    11931155    }
    11941156}
     
    13681330    }
    13691331
    1370     if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    1371     {
    1372         uint32_t uLastGrainWritten = 0;
    1373         uint32_t uLastGrainSector = 0;
    1374         size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
    1375         uint32_t *pTmpGT = (uint32_t *)RTMemTmpAlloc(cbGT);
    1376         if (!pTmpGT)
    1377         {
    1378             rc = VERR_NO_MEMORY;
    1379             goto out;
    1380         }
    1381         for (i = 0, pGDTmp = pExtent->pGD; i < pExtent->cGDEntries; i++, pGDTmp++)
    1382         {
    1383             /* If no grain table is allocated skip the entry. */
    1384             if (*pGDTmp == 0)
    1385                 continue;
    1386 
    1387             /* The VMDK 1.1 spec seems to talk about compressed grain tables,
    1388              * but in reality they are not compressed. */
    1389             rc = vmdkFileReadSync(pImage, pExtent->pFile,
    1390                                   VMDK_SECTOR2BYTE(*pGDTmp),
    1391                                   pTmpGT, cbGT, NULL);
    1392             if (RT_FAILURE(rc))
    1393             {
    1394                 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
    1395                 RTMemTmpFree(pTmpGT);
    1396                 goto out;
    1397             }
    1398             uint32_t j;
    1399             uint32_t *pGTTmp;
    1400             for (j = 0, pGTTmp = pTmpGT; j < pExtent->cGTEntries; j++, pGTTmp++)
    1401             {
    1402                 uint32_t uGTTmp = RT_LE2H_U32(*pGTTmp);
    1403 
    1404                 /* If no grain is allocated skip the entry. */
    1405                 if (uGTTmp == 0)
    1406                     continue;
    1407 
    1408                 if (uLastGrainSector && uLastGrainSector >= uGTTmp)
    1409                 {
    1410                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: grain table in '%s' contains a violation of the ordering assumptions"), pExtent->pszFullname);
    1411                     RTMemTmpFree(pTmpGT);
    1412                     goto out;
    1413                 }
    1414                 uLastGrainSector = uGTTmp;
    1415                 uLastGrainWritten = i * pExtent->cGTEntries + j;
    1416             }
    1417         }
    1418         RTMemTmpFree(pTmpGT);
    1419 
    1420         if (uLastGrainSector)
    1421         {
    1422             uint64_t uLBA = 0;
    1423             uint32_t cbMarker = 0;
    1424             rc = vmdkFileInflateSync(pImage, pExtent,
    1425                                      VMDK_SECTOR2BYTE(uLastGrainSector),
    1426                                      pExtent->pvGrain,
    1427                                      VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
    1428                                      &uLBA, &cbMarker);
    1429             if (RT_FAILURE(rc))
    1430                 goto out;
    1431 
    1432             Assert(uLBA == uLastGrainWritten * pExtent->cSectorsPerGrain);
    1433             pExtent->uGrainSector = uLastGrainSector;
    1434             pExtent->cbLastGrainWritten = cbMarker;
    1435         }
    1436         pExtent->uLastGrainWritten = uLastGrainWritten;
    1437         pExtent->uLastGrainSector = uLastGrainSector;
    1438     }
    1439 
    14401332out:
    14411333    if (RT_FAILURE(rc))
     
    14551347
    14561348    if (fPreAlloc)
     1349    {
    14571350        cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
     1351        cbOverhead =   VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded
     1352                     + cbGTRounded;
     1353    }
    14581354    else
     1355    {
     1356        /* Use a dummy start sector for layout computation. */
     1357        if (uStartSector == VMDK_GD_AT_END)
     1358            uStartSector = 1;
    14591359        cbGTRounded = 0;
    1460 
    1461     if (uStartSector != VMDK_GD_AT_END)
    1462     {
    1463         cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded + cbGTRounded;
    1464         /* For streamOptimized extents there is only one grain directory,
    1465          * and for all others take redundant grain directory into account. */
    1466         if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    1467         {
    1468             cbOverhead = RT_ALIGN_64(cbOverhead,
    1469                                      VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
    1470             if (!pExtent->fFooter)
    1471                 rc = vmdkFileSetSize(pImage, pExtent->pFile, cbOverhead + 512);
    1472         }
    1473         else
    1474         {
    1475             cbOverhead += cbGDRounded + cbGTRounded;
    1476             cbOverhead = RT_ALIGN_64(cbOverhead,
    1477                                      VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
    1478             rc = vmdkFileSetSize(pImage, pExtent->pFile, cbOverhead);
    1479         }
    1480         if (RT_FAILURE(rc))
    1481             goto out;
    1482         if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    1483         {
    1484             pExtent->uSectorRGD = 0;
    1485             pExtent->uSectorGD = uStartSector;
    1486         }
    1487         else
    1488         {
    1489             pExtent->uSectorRGD = uStartSector;
    1490             pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
    1491         }
     1360        cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded;
     1361    }
     1362
     1363    /* For streamOptimized extents there is only one grain directory,
     1364     * and for all others take redundant grain directory into account. */
     1365    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     1366    {
     1367        cbOverhead = RT_ALIGN_64(cbOverhead,
     1368                                 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
    14921369    }
    14931370    else
    14941371    {
    1495         cbOverhead = 512 + pImage->cbDescAlloc;
     1372        cbOverhead += cbGDRounded + cbGTRounded;
     1373        cbOverhead = RT_ALIGN_64(cbOverhead,
     1374                                 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     1375        rc = vmdkFileSetSize(pImage, pExtent->pFile, cbOverhead);
     1376    }
     1377    if (RT_FAILURE(rc))
     1378        goto out;
     1379    pExtent->uAppendPosition = cbOverhead;
     1380    pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
     1381
     1382    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     1383    {
     1384        pExtent->uSectorRGD = 0;
    14961385        pExtent->uSectorGD = uStartSector;
     1386    }
     1387    else
     1388    {
     1389        pExtent->uSectorRGD = uStartSector;
     1390        pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
    14971391    }
    14981392
     
    15431437        }
    15441438    }
    1545     pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
    15461439
    15471440out:
     
    27982691    if (RT_FAILURE(rc))
    27992692        goto out;
     2693
     2694    rc = vmdkFileGetSize(pImage, pExtent->pFile, &pExtent->uAppendPosition);
     2695    AssertRC(rc);
     2696    if (RT_FAILURE(rc))
     2697    {
     2698        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
     2699        goto out;
     2700    }
     2701    pExtent->uAppendPosition = RT_ALIGN_64(pExtent->uAppendPosition, 512);
     2702
    28002703    if (    RT_LE2H_U32(Header.flags & RT_BIT(17))
    28012704        &&  RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
    28022705    {
    28032706        /* Read the footer, which comes before the end-of-stream marker. */
    2804         uint64_t cbSize;
    2805         rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbSize);
    2806         AssertRC(rc);
    2807         if (RT_FAILURE(rc))
    2808         {
    2809             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
    2810             goto out;
    2811         }
    2812         cbSize = RT_ALIGN_64(cbSize, 512);
    2813         rc = vmdkFileReadSync(pImage, pExtent->pFile, cbSize - 2*512, &Header, sizeof(Header), NULL);
     2707        rc = vmdkFileReadSync(pImage, pExtent->pFile,
     2708                              pExtent->uAppendPosition - 2*512, &Header,
     2709                              sizeof(Header), NULL);
    28142710        AssertRC(rc);
    28152711        if (RT_FAILURE(rc))
     
    28222718            goto out;
    28232719        pExtent->fFooter = true;
     2720        /* Prohibit any writes to this extent. */
     2721        pExtent->uAppendPosition = 0;
    28242722    }
    28252723    pExtent->uVersion = RT_LE2H_U32(Header.version);
     
    29282826        goto out;
    29292827    }
     2828
     2829    /* Prohibit any writes to this streamOptimized extent. */
     2830    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     2831        pExtent->uAppendPosition = 0;
    29302832
    29312833    rc = vmdkReadGrainDirectory(pImage, pExtent);
     
    31623064        pExtent->pszFullname = NULL;
    31633065    }
     3066    if (pExtent->pvCompGrain)
     3067    {
     3068        RTMemFree(pExtent->pvCompGrain);
     3069        pExtent->pvCompGrain = NULL;
     3070    }
    31643071    if (pExtent->pvGrain)
    31653072    {
     
    33513258
    33523259        /* Mark the extent as unclean if opened in read-write mode. */
    3353         if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
     3260        if (   !(uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3261            && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
    33543262        {
    33553263            pExtent->fUncleanShutdown = true;
     
    33613269        /* Allocate at least 10K, and make sure that there is 5K free space
    33623270         * in case new entries need to be added to the descriptor. Never
    3363          * alocate more than 128K, because that's no valid descriptor file
     3271         * allocate more than 128K, because that's no valid descriptor file
    33643272         * and will result in the correct "truncated read" error handling. */
    33653273        uint64_t cbFileSize;
     
    35383446                              / pImage->PCHSGeometry.cSectors;
    35393447        pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
    3540         if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     3448        if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3449            && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
    35413450        {
    35423451            rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
     
    40813990
    40823991/**
     3992 * Internal: Create a real stream optimized VMDK using only linear writes.
     3993 */
     3994static int vmdkCreateStreamImage(PVMDKIMAGE pImage, uint64_t cbSize,
     3995                                 unsigned uImageFlags,
     3996                                 PFNVDPROGRESS pfnProgress, void *pvUser,
     3997                                 unsigned uPercentStart, unsigned uPercentSpan)
     3998{
     3999    int rc;
     4000
     4001    rc = vmdkCreateExtents(pImage, 1);
     4002    if (RT_FAILURE(rc))
     4003        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
     4004
     4005    /* Basename strings needed for constructing the extent names. */
     4006    const char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
     4007    AssertPtr(pszBasenameSubstr);
     4008    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     4009
     4010    /* No separate descriptor file. */
     4011    pImage->pFile = NULL;
     4012
     4013    /* Set up all extents. */
     4014    PVMDKEXTENT pExtent = &pImage->pExtents[0];
     4015
     4016    /* Set up fullname/basename for extent description. Cannot use StrDup
     4017     * for basename, as it is not guaranteed that the memory can be freed
     4018     * with RTMemTmpFree, which must be used as in other code paths
     4019     * StrDup is not usable. */
     4020    char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
     4021    if (!pszBasename)
     4022        return VERR_NO_MEMORY;
     4023    memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
     4024    pExtent->pszBasename = pszBasename;
     4025
     4026    char *pszBasedirectory = RTStrDup(pImage->pszFilename);
     4027    RTPathStripFilename(pszBasedirectory);
     4028    char *pszFullname;
     4029    rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszBasedirectory,
     4030                      RTPATH_SLASH, pExtent->pszBasename);
     4031    RTStrFree(pszBasedirectory);
     4032    if (RT_FAILURE(rc))
     4033        return rc;
     4034    pExtent->pszFullname = pszFullname;
     4035
     4036    /* Create file for extent. */
     4037    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     4038                      VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
     4039                                                 true /* fCreate */),
     4040                      false /* fAsyncIO */);
     4041    if (RT_FAILURE(rc))
     4042        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
     4043
     4044    /* Place descriptor file information. */
     4045    pExtent->uDescriptorSector = 1;
     4046    pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
     4047    /* The descriptor is part of the (only) extent. */
     4048    pExtent->pDescData = pImage->pDescData;
     4049    pImage->pDescData = NULL;
     4050
     4051    uint64_t cSectorsPerGDE, cSectorsPerGD;
     4052    pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     4053    pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K));
     4054    pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
     4055    pExtent->cGTEntries = 512;
     4056    cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     4057    pExtent->cSectorsPerGDE = cSectorsPerGDE;
     4058    pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     4059    cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     4060
     4061    /* The spec says version is 1 for all VMDKs, but the vast
     4062     * majority of streamOptimized VMDKs actually contain
     4063     * version 3 - so go with the majority. Both are acepted. */
     4064    pExtent->uVersion = 3;
     4065    pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
     4066    pExtent->fFooter = true;
     4067
     4068    pExtent->enmAccess = VMDKACCESS_READONLY;
     4069    pExtent->fUncleanShutdown = false;
     4070    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     4071    pExtent->uSectorOffset = 0;
     4072    pExtent->fMetaDirty = true;
     4073
     4074    /* Create grain directory, without preallocating it straight away. It will
     4075     * be constructed on the fly when writing out the data and written when
     4076     * closing the image. The end effect is that the full grain directory is
     4077     * allocated, which is a requirement of the VMDK specs. */
     4078    rc = vmdkCreateGrainDirectory(pImage, pExtent, VMDK_GD_AT_END,
     4079                                  false /* fPreAlloc */);
     4080    if (RT_FAILURE(rc))
     4081        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
     4082
     4083    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
     4084                            "streamOptimized");
     4085    if (RT_FAILURE(rc))
     4086        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
     4087
     4088    return rc;
     4089}
     4090
     4091/**
     4092 * Internal: The actual code for creating any VMDK variant currently in
     4093 * existence on hosted environments.
     4094 */
     4095static int vmdkCreateImage(PVMDKIMAGE pImage, uint64_t cbSize,
     4096                           unsigned uImageFlags, const char *pszComment,
     4097                           PCVDGEOMETRY pPCHSGeometry,
     4098                           PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
     4099                           PFNVDPROGRESS pfnProgress, void *pvUser,
     4100                           unsigned uPercentStart, unsigned uPercentSpan)
     4101{
     4102    int rc;
     4103
     4104    pImage->uImageFlags = uImageFlags;
     4105
     4106    /* Try to get error interface. */
     4107    pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
     4108    if (pImage->pInterfaceError)
     4109        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
     4110
     4111    /* Get I/O interface. */
     4112    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
     4113    AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
     4114    pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
     4115    AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
     4116
     4117    rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
     4118                              &pImage->Descriptor);
     4119    if (RT_FAILURE(rc))
     4120    {
     4121        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
     4122        goto out;
     4123    }
     4124
     4125    if (    (uImageFlags & VD_IMAGE_FLAGS_FIXED)
     4126        &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
     4127    {
     4128        /* Raw disk image (includes raw partition). */
     4129        const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
     4130        /* As the comment is misused, zap it so that no garbage comment
     4131         * is set below. */
     4132        pszComment = NULL;
     4133        rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
     4134    }
     4135    else
     4136    {
     4137        if (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4138        {
     4139            /* Stream optimized sparse image (monolithic). */
     4140            rc = vmdkCreateStreamImage(pImage, cbSize, uImageFlags,
     4141                                       pfnProgress, pvUser, uPercentStart,
     4142                                       uPercentSpan * 95 / 100);
     4143        }
     4144        else
     4145        {
     4146            /* Regular fixed or sparse image (monolithic or split). */
     4147            rc = vmdkCreateRegularImage(pImage, cbSize, uImageFlags,
     4148                                        pfnProgress, pvUser, uPercentStart,
     4149                                        uPercentSpan * 95 / 100);
     4150        }
     4151    }
     4152
     4153    if (RT_FAILURE(rc))
     4154        goto out;
     4155
     4156    if (RT_SUCCESS(rc) && pfnProgress)
     4157        pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
     4158
     4159    pImage->cbSize = cbSize;
     4160
     4161    for (unsigned i = 0; i < pImage->cExtents; i++)
     4162    {
     4163        PVMDKEXTENT pExtent = &pImage->pExtents[i];
     4164
     4165        rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
     4166                               pExtent->cNominalSectors, pExtent->enmType,
     4167                               pExtent->pszBasename, pExtent->uSectorOffset);
     4168        if (RT_FAILURE(rc))
     4169        {
     4170            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
     4171            goto out;
     4172        }
     4173    }
     4174    vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
     4175
     4176    if (    pPCHSGeometry->cCylinders != 0
     4177        &&  pPCHSGeometry->cHeads != 0
     4178        &&  pPCHSGeometry->cSectors != 0)
     4179    {
     4180        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
     4181        if (RT_FAILURE(rc))
     4182            goto out;
     4183    }
     4184    if (    pLCHSGeometry->cCylinders != 0
     4185        &&  pLCHSGeometry->cHeads != 0
     4186        &&  pLCHSGeometry->cSectors != 0)
     4187    {
     4188        rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
     4189        if (RT_FAILURE(rc))
     4190            goto out;
     4191    }
     4192
     4193    pImage->LCHSGeometry = *pLCHSGeometry;
     4194    pImage->PCHSGeometry = *pPCHSGeometry;
     4195
     4196    pImage->ImageUuid = *pUuid;
     4197    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4198                            VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
     4199    if (RT_FAILURE(rc))
     4200    {
     4201        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
     4202        goto out;
     4203    }
     4204    RTUuidClear(&pImage->ParentUuid);
     4205    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4206                            VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
     4207    if (RT_FAILURE(rc))
     4208    {
     4209        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
     4210        goto out;
     4211    }
     4212    RTUuidClear(&pImage->ModificationUuid);
     4213    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4214                            VMDK_DDB_MODIFICATION_UUID,
     4215                            &pImage->ModificationUuid);
     4216    if (RT_FAILURE(rc))
     4217    {
     4218        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
     4219        goto out;
     4220    }
     4221    RTUuidClear(&pImage->ParentModificationUuid);
     4222    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4223                            VMDK_DDB_PARENT_MODIFICATION_UUID,
     4224                            &pImage->ParentModificationUuid);
     4225    if (RT_FAILURE(rc))
     4226    {
     4227        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
     4228        goto out;
     4229    }
     4230
     4231    rc = vmdkAllocateGrainTableCache(pImage);
     4232    if (RT_FAILURE(rc))
     4233        goto out;
     4234
     4235    rc = vmdkSetImageComment(pImage, pszComment);
     4236    if (RT_FAILURE(rc))
     4237    {
     4238        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
     4239        goto out;
     4240    }
     4241
     4242    if (RT_SUCCESS(rc) && pfnProgress)
     4243        pfnProgress(pvUser, uPercentStart + uPercentSpan * 99 / 100);
     4244
     4245    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4246    {
     4247        /* streamOptimized is a bit special, we cannot trigger the flush
     4248         * until all data has been written. So we write the necessary
     4249         * information explicitly. */
     4250        pImage->pExtents[0].cDescriptorSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(  pImage->Descriptor.aLines[pImage->Descriptor.cLines]
     4251                                                                              - pImage->Descriptor.aLines[0], 512));
     4252        rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0);
     4253        if (RT_FAILURE(rc))
     4254        {
     4255            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK header in '%s'"), pImage->pszFilename);
     4256            goto out;
     4257        }
     4258
     4259        rc = vmdkWriteDescriptor(pImage);
     4260        if (RT_FAILURE(rc))
     4261        {
     4262            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK descriptor in '%s'"), pImage->pszFilename);
     4263            goto out;
     4264        }
     4265    }
     4266    else
     4267        rc = vmdkFlushImage(pImage);
     4268
     4269out:
     4270    if (RT_SUCCESS(rc) && pfnProgress)
     4271        pfnProgress(pvUser, uPercentStart + uPercentSpan);
     4272
     4273    if (RT_FAILURE(rc))
     4274        vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
     4275    return rc;
     4276}
     4277
     4278/**
     4279 * Internal: Update image comment.
     4280 */
     4281static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment)
     4282{
     4283    char *pszCommentEncoded;
     4284    if (pszComment)
     4285    {
     4286        pszCommentEncoded = vmdkEncodeString(pszComment);
     4287        if (!pszCommentEncoded)
     4288            return VERR_NO_MEMORY;
     4289    }
     4290    else
     4291        pszCommentEncoded = NULL;
     4292    int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
     4293                               "ddb.comment", pszCommentEncoded);
     4294    if (pszComment)
     4295        RTStrFree(pszCommentEncoded);
     4296    if (RT_FAILURE(rc))
     4297        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image comment in descriptor in '%s'"), pImage->pszFilename);
     4298    return VINF_SUCCESS;
     4299}
     4300
     4301/**
    40834302 * Internal. Clear the grain table buffer for real stream optimized writing.
    40844303 */
    4085 static void vmdksClearGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
     4304static void vmdkStreamClearGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
    40864305{
    40874306    uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
     
    40944313 * Internal. Flush the grain table buffer for real stream optimized writing.
    40954314 */
    4096 static int vmdksFlushGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
    4097                         uint32_t uGDEntry)
     4315static int vmdkStreamFlushGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     4316                             uint32_t uGDEntry)
    40984317{
    40994318    int rc = VINF_SUCCESS;
     
    41224341        return VINF_SUCCESS;
    41234342
    4124     uint64_t uFileOffset;
    4125     rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
    4126     AssertRC(rc);
     4343    uint64_t uFileOffset = pExtent->uAppendPosition;
     4344    if (!uFileOffset)
     4345        return VERR_INTERNAL_ERROR;
    41274346    /* Align to sector, as the previous write could have been any size. */
    41284347    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     
    41614380    }
    41624381    Assert(!(uFileOffset % 512));
     4382    pExtent->uAppendPosition = RT_ALIGN_64(uFileOffset, 512);
    41634383    return rc;
    4164 }
    4165 
    4166 /**
    4167  * Internal. Free all allocated space for representing a real stream optimized
    4168  * image, and optionally delete the image from disk.
    4169  */
    4170 static int vmdksFreeImage(PVMDKIMAGE pImage, bool fDelete)
    4171 {
    4172     int rc = VINF_SUCCESS;
    4173 
    4174     /* Freeing a never allocated image (e.g. because the open failed) is
    4175      * not signalled as an error. After all nothing bad happens. */
    4176     if (pImage)
    4177     {
    4178         if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    4179         {
    4180             /* Check if all extents are clean. */
    4181             for (unsigned i = 0; i < pImage->cExtents; i++)
    4182             {
    4183                 Assert(!pImage->pExtents[i].fUncleanShutdown);
    4184             }
    4185         }
    4186 
    4187         /* No need to write any pending data if the file will be deleted or if
    4188          * the new file wasn't successfully created. */
    4189         if (!fDelete && pImage->pExtents && pImage->pExtents[0].cGTEntries)
    4190         {
    4191             PVMDKEXTENT pExtent = &pImage->pExtents[0];
    4192             uint32_t uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
    4193             if (uLastGDEntry != pExtent->cGDEntries - 1)
    4194             {
    4195                 rc = vmdksFlushGT(pImage, pExtent, uLastGDEntry);
    4196                 AssertRC(rc);
    4197                 vmdksClearGT(pImage, pExtent);
    4198                 for (uint32_t i = uLastGDEntry + 1; i < pExtent->cGDEntries; i++)
    4199                 {
    4200                     rc = vmdksFlushGT(pImage, pExtent, i);
    4201                     AssertRC(rc);
    4202                 }
    4203             }
    4204 
    4205             uint64_t uFileOffset;
    4206             rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
    4207             AssertRC(rc);
    4208             uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    4209 
    4210             /* Grain directory marker. */
    4211             uint8_t aMarker[512];
    4212             PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
    4213             memset(pMarker, '\0', sizeof(aMarker));
    4214             pMarker->uSector = VMDK_BYTE2SECTOR(RT_ALIGN_64(RT_H2LE_U64(pExtent->cGDEntries * sizeof(uint32_t)), 512));
    4215             pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD);
    4216             rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
    4217                                    aMarker, sizeof(aMarker), NULL);
    4218             AssertRC(rc);
    4219             uFileOffset += 512;
    4220 
    4221             /* Write grain directory in little endian style. The array will
    4222              * not be used after this, so convert in place. */
    4223             uint32_t *pGDTmp = pExtent->pGD;
    4224             for (uint32_t i = 0; i < pExtent->cGDEntries; i++, pGDTmp++)
    4225                 *pGDTmp = RT_H2LE_U32(*pGDTmp);
    4226             rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
    4227                                    pExtent->pGD,
    4228                                    pExtent->cGDEntries * sizeof(uint32_t),
    4229                                    NULL);
    4230             AssertRC(rc);
    4231 
    4232             pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
    4233             pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
    4234             uFileOffset = RT_ALIGN_64(uFileOffset + pExtent->cGDEntries * sizeof(uint32_t), 512);
    4235 
    4236             /* Footer marker. */
    4237             memset(pMarker, '\0', sizeof(aMarker));
    4238             pMarker->uSector = VMDK_BYTE2SECTOR(512);
    4239             pMarker->uType = RT_H2LE_U32(VMDK_MARKER_FOOTER);
    4240             rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
    4241                                    aMarker, sizeof(aMarker), NULL);
    4242             AssertRC(rc);
    4243 
    4244             uFileOffset += 512;
    4245             rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
    4246             AssertRC(rc);
    4247 
    4248             uFileOffset += 512;
    4249             /* End-of-stream marker. */
    4250             memset(pMarker, '\0', sizeof(aMarker));
    4251             rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
    4252                                    aMarker, sizeof(aMarker), NULL);
    4253             AssertRC(rc);
    4254         }
    4255 
    4256         if (pImage->pExtents != NULL)
    4257         {
    4258             for (unsigned i = 0 ; i < pImage->cExtents; i++)
    4259                 vmdkFreeExtentData(pImage, &pImage->pExtents[i], fDelete);
    4260             RTMemFree(pImage->pExtents);
    4261             pImage->pExtents = NULL;
    4262         }
    4263         pImage->cExtents = 0;
    4264         if (pImage->pFile != NULL)
    4265             vmdkFileClose(pImage, &pImage->pFile, fDelete);
    4266         vmdkFileCheckAllClose(pImage);
    4267 
    4268         if (pImage->pGTCache)
    4269         {
    4270             RTMemFree(pImage->pGTCache);
    4271             pImage->pGTCache = NULL;
    4272         }
    4273         if (pImage->pDescData)
    4274         {
    4275             RTMemFree(pImage->pDescData);
    4276             pImage->pDescData = NULL;
    4277         }
    4278     }
    4279 
    4280     LogFlowFunc(("returns %Rrc\n", rc));
    4281     return rc;
    4282 }
    4283 
    4284 /**
    4285  * Internal: Create a real stream optimized VMDK using only linear writes.
    4286  */
    4287 static int vmdksCreateImage(PVMDKIMAGE pImage, uint64_t cbSize,
    4288                             unsigned uImageFlags, const char *pszComment,
    4289                             PCVDGEOMETRY pPCHSGeometry,
    4290                             PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
    4291                             PFNVDPROGRESS pfnProgress, void *pvUser,
    4292                             unsigned uPercentStart, unsigned uPercentSpan)
    4293 {
    4294     int rc;
    4295 
    4296     pImage->uImageFlags = uImageFlags;
    4297 
    4298     /* Try to get error interface. */
    4299     pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
    4300     if (pImage->pInterfaceError)
    4301         pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
    4302 
    4303     /* Get I/O interface. */
    4304     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
    4305     AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
    4306     pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
    4307     AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
    4308 
    4309     PVMDKEXTENT pExtent;
    4310     char *pszBasenameSubstr, *pszBasedirectory, *pszBasename;
    4311     size_t cbBasenameSubstr;
    4312 
    4313     rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
    4314                               &pImage->Descriptor);
    4315     if (RT_FAILURE(rc))
    4316     {
    4317         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
    4318         goto out;
    4319     }
    4320 
    4321     rc = vmdkCreateExtents(pImage, 1);
    4322     if (RT_FAILURE(rc))
    4323     {
    4324         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    4325         goto out;
    4326     }
    4327 
    4328     /* Basename strings needed for constructing the extent names. */
    4329     pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    4330     AssertPtr(pszBasenameSubstr);
    4331     cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    4332 
    4333     /* No separate descriptor file. */
    4334     pImage->pFile = NULL;
    4335 
    4336     /* Set up all extents. */
    4337     pExtent = &pImage->pExtents[0];
    4338 
    4339     /* Set up fullname/basename for extent description. Cannot use StrDup
    4340      * for basename, as it is not guaranteed that the memory can be freed
    4341      * with RTMemTmpFree, which must be used as in other code paths
    4342      * StrDup is not usable. */
    4343     pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
    4344     if (!pszBasename)
    4345     {
    4346         rc = VERR_NO_MEMORY;
    4347         goto out;
    4348     }
    4349     memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    4350     pExtent->pszBasename = pszBasename;
    4351 
    4352     pszBasedirectory = RTStrDup(pImage->pszFilename);
    4353     RTPathStripFilename(pszBasedirectory);
    4354     char *pszFullname;
    4355     rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszBasedirectory,
    4356                       RTPATH_SLASH, pExtent->pszBasename);
    4357     RTStrFree(pszBasedirectory);
    4358     if (RT_FAILURE(rc))
    4359         goto out;
    4360     pExtent->pszFullname = pszFullname;
    4361 
    4362     /* Create file for extent. */
    4363     rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
    4364                       VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
    4365                                                  true /* fCreate */),
    4366                       false /* fAsyncIO */);
    4367     if (RT_FAILURE(rc))
    4368     {
    4369         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
    4370         goto out;
    4371     }
    4372 
    4373     /* Place descriptor file information. */
    4374     pExtent->uDescriptorSector = 1;
    4375     pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
    4376     /* The descriptor is part of the (only) extent. */
    4377     pExtent->pDescData = pImage->pDescData;
    4378     pImage->pDescData = NULL;
    4379 
    4380     uint64_t cSectorsPerGDE, cSectorsPerGD;
    4381     pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
    4382     pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K));
    4383     pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
    4384     pExtent->cGTEntries = 512;
    4385     cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    4386     pExtent->cSectorsPerGDE = cSectorsPerGDE;
    4387     pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    4388     cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
    4389 
    4390     /* The spec says version is 1 for all VMDKs, but the vast
    4391      * majority of streamOptimized VMDKs actually contain
    4392      * version 3 - so go with the majority. Both are acepted. */
    4393     pExtent->uVersion = 3;
    4394     pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
    4395     pExtent->fFooter = true;
    4396 
    4397     pExtent->enmAccess = VMDKACCESS_READONLY;
    4398     pExtent->fUncleanShutdown = false;
    4399     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
    4400     pExtent->uSectorOffset = 0;
    4401     pExtent->fMetaDirty = true;
    4402 
    4403     /* Create grain directory, without preallocating it straight away. It will
    4404      * be constructed on the fly when writing out the data and written when
    4405      * closing the image. The end effect is that the full grain directory is
    4406      * allocated, which is a requirement of the VMDK specs. */
    4407     rc = vmdkCreateGrainDirectory(pImage, pExtent,
    4408                                   RT_MAX(  pExtent->uDescriptorSector
    4409                                          + pExtent->cDescriptorSectors,
    4410                                          1),
    4411                                   false /* fPreAlloc */);
    4412     if (RT_FAILURE(rc))
    4413     {
    4414         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
    4415         goto out;
    4416     }
    4417 
    4418     rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    4419                             "streamOptimized");
    4420     if (RT_FAILURE(rc))
    4421     {
    4422         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
    4423         goto out;
    4424     }
    4425 
    4426     if (pfnProgress)
    4427         pfnProgress(pvUser, uPercentStart + uPercentSpan * 20 / 100);
    4428 
    4429     pImage->cbSize = cbSize;
    4430 
    4431     Assert(pImage->cExtents == 1);
    4432 
    4433     rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
    4434                            pExtent->cNominalSectors, pExtent->enmType,
    4435                            pExtent->pszBasename, pExtent->uSectorOffset);
    4436     if (RT_FAILURE(rc))
    4437     {
    4438         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
    4439         goto out;
    4440     }
    4441     vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
    4442 
    4443     if (    pPCHSGeometry->cCylinders != 0
    4444         &&  pPCHSGeometry->cHeads != 0
    4445         &&  pPCHSGeometry->cSectors != 0)
    4446     {
    4447         rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    4448         if (RT_FAILURE(rc))
    4449             goto out;
    4450     }
    4451     if (    pLCHSGeometry->cCylinders != 0
    4452         &&  pLCHSGeometry->cHeads != 0
    4453         &&  pLCHSGeometry->cSectors != 0)
    4454     {
    4455         rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    4456         if (RT_FAILURE(rc))
    4457             goto out;
    4458     }
    4459 
    4460     pImage->LCHSGeometry = *pLCHSGeometry;
    4461     pImage->PCHSGeometry = *pPCHSGeometry;
    4462 
    4463     pImage->ImageUuid = *pUuid;
    4464     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4465                             VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
    4466     if (RT_FAILURE(rc))
    4467     {
    4468         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
    4469         goto out;
    4470     }
    4471     RTUuidClear(&pImage->ParentUuid);
    4472     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4473                             VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
    4474     if (RT_FAILURE(rc))
    4475     {
    4476         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
    4477         goto out;
    4478     }
    4479     RTUuidClear(&pImage->ModificationUuid);
    4480     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4481                             VMDK_DDB_MODIFICATION_UUID,
    4482                             &pImage->ModificationUuid);
    4483     if (RT_FAILURE(rc))
    4484     {
    4485         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
    4486         goto out;
    4487     }
    4488     RTUuidClear(&pImage->ParentModificationUuid);
    4489     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4490                             VMDK_DDB_PARENT_MODIFICATION_UUID,
    4491                             &pImage->ParentModificationUuid);
    4492     if (RT_FAILURE(rc))
    4493     {
    4494         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
    4495         goto out;
    4496     }
    4497 
    4498     rc = vmdkAllocateGrainTableCache(pImage);
    4499     if (RT_FAILURE(rc))
    4500         goto out;
    4501 
    4502     rc = vmdkSetImageComment(pImage, pszComment);
    4503     if (RT_FAILURE(rc))
    4504     {
    4505         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
    4506         goto out;
    4507     }
    4508 
    4509     if (pfnProgress)
    4510         pfnProgress(pvUser, uPercentStart + uPercentSpan * 50 / 100);
    4511 
    4512     /* Now that all descriptor entries are complete, shrink it to the minimum
    4513      * size. It will never be changed afterwards anyway. */
    4514     pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(  pImage->Descriptor.aLines[pImage->Descriptor.cLines]
    4515                                                                - pImage->Descriptor.aLines[0], 512));
    4516     rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0);
    4517     if (RT_FAILURE(rc))
    4518     {
    4519         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK header in '%s'"), pImage->pszFilename);
    4520         goto out;
    4521     }
    4522 
    4523     if (pfnProgress)
    4524         pfnProgress(pvUser, uPercentStart + uPercentSpan * 70 / 100);
    4525 
    4526     rc = vmdkWriteDescriptor(pImage);
    4527     if (RT_FAILURE(rc))
    4528     {
    4529         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK descriptor in '%s'"), pImage->pszFilename);
    4530         goto out;
    4531     }
    4532 
    4533     /* Skip over the overhead area. */
    4534     rc = vmdkFileSetSize(pImage, pExtent->pFile,
    4535                          VMDK_SECTOR2BYTE(pExtent->cOverheadSectors));
    4536 
    4537 out:
    4538     if (RT_SUCCESS(rc) && pfnProgress)
    4539         pfnProgress(pvUser, uPercentStart + uPercentSpan);
    4540 
    4541     if (RT_FAILURE(rc))
    4542         vmdksFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
    4543     return rc;
    4544 }
    4545 
    4546 /**
    4547  * Internal: The actual code for creating any VMDK variant currently in
    4548  * existence on hosted environments.
    4549  */
    4550 static int vmdkCreateImage(PVMDKIMAGE pImage, uint64_t cbSize,
    4551                            unsigned uImageFlags, const char *pszComment,
    4552                            PCVDGEOMETRY pPCHSGeometry,
    4553                            PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
    4554                            PFNVDPROGRESS pfnProgress, void *pvUser,
    4555                            unsigned uPercentStart, unsigned uPercentSpan)
    4556 {
    4557     int rc;
    4558 
    4559     pImage->uImageFlags = uImageFlags;
    4560 
    4561     /* Try to get error interface. */
    4562     pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
    4563     if (pImage->pInterfaceError)
    4564         pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
    4565 
    4566     /* Get I/O interface. */
    4567     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
    4568     AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
    4569     pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
    4570     AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
    4571 
    4572     rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
    4573                               &pImage->Descriptor);
    4574     if (RT_FAILURE(rc))
    4575     {
    4576         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
    4577         goto out;
    4578     }
    4579 
    4580     if (    (uImageFlags & VD_IMAGE_FLAGS_FIXED)
    4581         &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
    4582     {
    4583         /* Raw disk image (includes raw partition). */
    4584         const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
    4585         /* As the comment is misused, zap it so that no garbage comment
    4586          * is set below. */
    4587         pszComment = NULL;
    4588         rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
    4589     }
    4590     else
    4591     {
    4592         /* Regular fixed or sparse image (monolithic or split). */
    4593         rc = vmdkCreateRegularImage(pImage, cbSize, uImageFlags,
    4594                                     pfnProgress, pvUser, uPercentStart,
    4595                                     uPercentSpan * 95 / 100);
    4596     }
    4597 
    4598     if (RT_FAILURE(rc))
    4599         goto out;
    4600 
    4601     if (RT_SUCCESS(rc) && pfnProgress)
    4602         pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
    4603 
    4604     pImage->cbSize = cbSize;
    4605 
    4606     for (unsigned i = 0; i < pImage->cExtents; i++)
    4607     {
    4608         PVMDKEXTENT pExtent = &pImage->pExtents[i];
    4609 
    4610         rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
    4611                                pExtent->cNominalSectors, pExtent->enmType,
    4612                                pExtent->pszBasename, pExtent->uSectorOffset);
    4613         if (RT_FAILURE(rc))
    4614         {
    4615             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
    4616             goto out;
    4617         }
    4618     }
    4619     vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
    4620 
    4621     if (    pPCHSGeometry->cCylinders != 0
    4622         &&  pPCHSGeometry->cHeads != 0
    4623         &&  pPCHSGeometry->cSectors != 0)
    4624     {
    4625         rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    4626         if (RT_FAILURE(rc))
    4627             goto out;
    4628     }
    4629     if (    pLCHSGeometry->cCylinders != 0
    4630         &&  pLCHSGeometry->cHeads != 0
    4631         &&  pLCHSGeometry->cSectors != 0)
    4632     {
    4633         rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    4634         if (RT_FAILURE(rc))
    4635             goto out;
    4636     }
    4637 
    4638     pImage->LCHSGeometry = *pLCHSGeometry;
    4639     pImage->PCHSGeometry = *pPCHSGeometry;
    4640 
    4641     pImage->ImageUuid = *pUuid;
    4642     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4643                             VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
    4644     if (RT_FAILURE(rc))
    4645     {
    4646         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
    4647         goto out;
    4648     }
    4649     RTUuidClear(&pImage->ParentUuid);
    4650     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4651                             VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
    4652     if (RT_FAILURE(rc))
    4653     {
    4654         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
    4655         goto out;
    4656     }
    4657     RTUuidClear(&pImage->ModificationUuid);
    4658     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4659                             VMDK_DDB_MODIFICATION_UUID,
    4660                             &pImage->ModificationUuid);
    4661     if (RT_FAILURE(rc))
    4662     {
    4663         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
    4664         goto out;
    4665     }
    4666     RTUuidClear(&pImage->ParentModificationUuid);
    4667     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4668                             VMDK_DDB_PARENT_MODIFICATION_UUID,
    4669                             &pImage->ParentModificationUuid);
    4670     if (RT_FAILURE(rc))
    4671     {
    4672         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
    4673         goto out;
    4674     }
    4675 
    4676     rc = vmdkAllocateGrainTableCache(pImage);
    4677     if (RT_FAILURE(rc))
    4678         goto out;
    4679 
    4680     rc = vmdkSetImageComment(pImage, pszComment);
    4681     if (RT_FAILURE(rc))
    4682     {
    4683         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
    4684         goto out;
    4685     }
    4686 
    4687     if (RT_SUCCESS(rc) && pfnProgress)
    4688         pfnProgress(pvUser, uPercentStart + uPercentSpan * 99 / 100);
    4689 
    4690     rc = vmdkFlushImage(pImage);
    4691 
    4692 out:
    4693     if (RT_SUCCESS(rc) && pfnProgress)
    4694         pfnProgress(pvUser, uPercentStart + uPercentSpan);
    4695 
    4696     if (RT_FAILURE(rc))
    4697         vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
    4698     return rc;
    4699 }
    4700 
    4701 /**
    4702  * Internal: Update image comment.
    4703  */
    4704 static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment)
    4705 {
    4706     char *pszCommentEncoded;
    4707     if (pszComment)
    4708     {
    4709         pszCommentEncoded = vmdkEncodeString(pszComment);
    4710         if (!pszCommentEncoded)
    4711             return VERR_NO_MEMORY;
    4712     }
    4713     else
    4714         pszCommentEncoded = NULL;
    4715     int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
    4716                                "ddb.comment", pszCommentEncoded);
    4717     if (pszComment)
    4718         RTStrFree(pszCommentEncoded);
    4719     if (RT_FAILURE(rc))
    4720         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image comment in descriptor in '%s'"), pImage->pszFilename);
    4721     return VINF_SUCCESS;
    47224384}
    47234385
     
    47364398        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    47374399        {
    4738             /* Mark all extents as clean. */
    4739             for (unsigned i = 0; i < pImage->cExtents; i++)
     4400            if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    47404401            {
    4741                 if (   (   pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
    4742 #ifdef VBOX_WITH_VMDK_ESX
    4743                         || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
    4744 #endif /* VBOX_WITH_VMDK_ESX */
    4745                        )
    4746                     && pImage->pExtents[i].fUncleanShutdown)
     4402                /* Check if all extents are clean. */
     4403                for (unsigned i = 0; i < pImage->cExtents; i++)
    47474404                {
    4748                     pImage->pExtents[i].fUncleanShutdown = false;
    4749                     pImage->pExtents[i].fMetaDirty = true;
     4405                    Assert(!pImage->pExtents[i].fUncleanShutdown);
    47504406                }
    47514407            }
    4752         }
    4753         vmdkFlushImage(pImage);
     4408            else
     4409            {
     4410                /* Mark all extents as clean. */
     4411                for (unsigned i = 0; i < pImage->cExtents; i++)
     4412                {
     4413                    if (   (   pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
     4414#ifdef VBOX_WITH_VMDK_ESX
     4415                            || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
     4416#endif /* VBOX_WITH_VMDK_ESX */
     4417                           )
     4418                        && pImage->pExtents[i].fUncleanShutdown)
     4419                    {
     4420                        pImage->pExtents[i].fUncleanShutdown = false;
     4421                        pImage->pExtents[i].fMetaDirty = true;
     4422                    }
     4423
     4424                    /* From now on it's not safe to append any more data. */
     4425                    pImage->pExtents[i].uAppendPosition = 0;
     4426                }
     4427            }
     4428        }
     4429
     4430        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4431        {
     4432            /* No need to write any pending data if the file will be deleted
     4433             * or if the new file wasn't successfully created. */
     4434            if (!fDelete && pImage->pExtents && pImage->pExtents[0].cGTEntries)
     4435            {
     4436                PVMDKEXTENT pExtent = &pImage->pExtents[0];
     4437                uint32_t uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
     4438                if (uLastGDEntry != pExtent->cGDEntries - 1)
     4439                {
     4440                    rc = vmdkStreamFlushGT(pImage, pExtent, uLastGDEntry);
     4441                    AssertRC(rc);
     4442                    vmdkStreamClearGT(pImage, pExtent);
     4443                    for (uint32_t i = uLastGDEntry + 1; i < pExtent->cGDEntries; i++)
     4444                    {
     4445                        rc = vmdkStreamFlushGT(pImage, pExtent, i);
     4446                        AssertRC(rc);
     4447                    }
     4448                }
     4449
     4450                uint64_t uFileOffset = pExtent->uAppendPosition;
     4451                if (!uFileOffset)
     4452                    return VERR_INTERNAL_ERROR;
     4453                uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     4454
     4455                /* From now on it's not safe to append any more data. */
     4456                pExtent->uAppendPosition = 0;
     4457
     4458                /* Grain directory marker. */
     4459                uint8_t aMarker[512];
     4460                PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
     4461                memset(pMarker, '\0', sizeof(aMarker));
     4462                pMarker->uSector = VMDK_BYTE2SECTOR(RT_ALIGN_64(RT_H2LE_U64(pExtent->cGDEntries * sizeof(uint32_t)), 512));
     4463                pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD);
     4464                rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4465                                       aMarker, sizeof(aMarker), NULL);
     4466                AssertRC(rc);
     4467                uFileOffset += 512;
     4468
     4469                /* Write grain directory in little endian style. The array will
     4470                 * not be used after this, so convert in place. */
     4471                uint32_t *pGDTmp = pExtent->pGD;
     4472                for (uint32_t i = 0; i < pExtent->cGDEntries; i++, pGDTmp++)
     4473                    *pGDTmp = RT_H2LE_U32(*pGDTmp);
     4474                rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4475                                       pExtent->pGD,
     4476                                       pExtent->cGDEntries * sizeof(uint32_t),
     4477                                       NULL);
     4478                AssertRC(rc);
     4479
     4480                pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
     4481                pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
     4482                uFileOffset = RT_ALIGN_64(  uFileOffset
     4483                                          + pExtent->cGDEntries * sizeof(uint32_t),
     4484                                          512);
     4485
     4486                /* Footer marker. */
     4487                memset(pMarker, '\0', sizeof(aMarker));
     4488                pMarker->uSector = VMDK_BYTE2SECTOR(512);
     4489                pMarker->uType = RT_H2LE_U32(VMDK_MARKER_FOOTER);
     4490                rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4491                                       aMarker, sizeof(aMarker), NULL);
     4492                AssertRC(rc);
     4493
     4494                uFileOffset += 512;
     4495                rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
     4496                AssertRC(rc);
     4497
     4498                uFileOffset += 512;
     4499                /* End-of-stream marker. */
     4500                memset(pMarker, '\0', sizeof(aMarker));
     4501                rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4502                                       aMarker, sizeof(aMarker), NULL);
     4503                AssertRC(rc);
     4504            }
     4505        }
     4506        else
     4507            vmdkFlushImage(pImage);
    47544508
    47554509        if (pImage->pExtents != NULL)
     
    48054559            {
    48064560                case VMDKETYPE_HOSTED_SPARSE:
    4807                     rc = vmdkWriteMetaSparseExtent(pImage, pExtent, 0);
    4808                     if (RT_FAILURE(rc))
    4809                         goto out;
    4810                     if (pExtent->fFooter)
     4561                    if (!pExtent->fFooter)
    48114562                    {
    4812                         uint64_t cbSize;
    4813                         rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbSize);
     4563                        rc = vmdkWriteMetaSparseExtent(pImage, pExtent, 0);
    48144564                        if (RT_FAILURE(rc))
    48154565                            goto out;
    4816                         cbSize = RT_ALIGN_64(cbSize, 512);
    4817                         rc = vmdkWriteMetaSparseExtent(pImage, pExtent, cbSize - 2*512);
     4566                    }
     4567                    else
     4568                    {
     4569                        uint64_t uFileOffset = pExtent->uAppendPosition;
     4570                        /* Simply skip writing anything if the streamOptimized
     4571                         * image hasn't been just created. */
     4572                        if (!uFileOffset)
     4573                            break;
     4574                        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     4575                        rc = vmdkWriteMetaSparseExtent(pImage, pExtent,
     4576                                                       uFileOffset);
    48184577                        if (RT_FAILURE(rc))
    48194578                            goto out;
     
    49864745    int rc;
    49874746
     4747    /* For newly created streamOptimized images this must be a no-op. */
     4748    if (   pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
     4749        && pExtent->uAppendPosition)
     4750    {
     4751        *puExtentSector = 0;
     4752        return VINF_SUCCESS;
     4753    }
     4754
    49884755    uGDIndex = uSector / pExtent->cSectorsPerGDE;
    49894756    if (uGDIndex >= pExtent->cGDEntries)
     
    50924859    PVMDKGTCACHE pCache = pImage->pGTCache;
    50934860    uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
    5094     uint64_t cbExtentSize;
     4861    uint64_t uFileOffset;
    50954862    uint32_t uGTHash, uGTBlockIndex;
    50964863    PVMDKGTCACHEENTRY pGTCacheEntry;
     
    51114878         * entry. So there is absolutely no data in this area. Allocate
    51124879         * a new grain table and put the reference to it in the GDs. */
    5113         rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
    5114         if (RT_FAILURE(rc))
    5115             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    5116         Assert(!(cbExtentSize % 512));
    5117         cbExtentSize = RT_ALIGN_64(cbExtentSize, 512);
    5118         uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    5119         /* For writable streamOptimized extents the final sector is the
    5120          * end-of-stream marker. Will be re-added after the grain table.
    5121          * If the file has a footer it also will be re-added before EOS. */
    5122         if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    5123         {
    5124             uint64_t uEOSOff = 0;
    5125             uGTSector--;
    5126             if (pExtent->fFooter)
    5127             {
    5128                 uGTSector--;
    5129                 uEOSOff = 512;
    5130                 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t));
    5131                 if (RT_FAILURE(rc))
    5132                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after grain table in '%s'"), pExtent->pszFullname);
    5133             }
    5134             pExtent->uLastGrainSector = 0;
    5135             uint8_t aEOS[512];
    5136             memset(aEOS, '\0', sizeof(aEOS));
    5137             rc = vmdkFileWriteSync(pImage, pExtent->pFile,
    5138                                    VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t) + uEOSOff,
    5139                                    aEOS, sizeof(aEOS), NULL);
    5140             if (RT_FAILURE(rc))
    5141                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after grain table in '%s'"), pExtent->pszFullname);
    5142         }
     4880        uFileOffset = pExtent->uAppendPosition;
     4881        if (!uFileOffset)
     4882            return VERR_INTERNAL_ERROR;
     4883        Assert(!(uFileOffset % 512));
     4884        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     4885        uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
     4886
     4887        pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
     4888
    51434889        /* Normally the grain table is preallocated for hosted sparse extents
    51444890         * that support more than 32 bit sector numbers. So this shouldn't
     
    51464892        if (uGTSector > UINT32_MAX)
    51474893            return VERR_VD_VMDK_INVALID_HEADER;
     4894
    51484895        /* Write grain table by writing the required number of grain table
    51494896         * cache chunks. Avoids dynamic memory allocation, but is a bit
     
    51614908                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
    51624909        }
     4910        pExtent->uAppendPosition = RT_ALIGN_64(  pExtent->uAppendPosition
     4911                                               + pExtent->cGTEntries * sizeof(uint32_t),
     4912                                               512);
     4913
    51634914        if (pExtent->pRGD)
    51644915        {
    51654916            AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
    5166             rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
    5167             if (RT_FAILURE(rc))
    5168                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    5169             Assert(!(cbExtentSize % 512));
    5170             uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    5171             /* For writable streamOptimized extents the final sector is the
    5172              * end-of-stream marker. Will be re-added after the grain table.
    5173              * If the file has a footer it also will be re-added before EOS. */
    5174             if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    5175             {
    5176                 uint64_t uEOSOff = 0;
    5177                 uRGTSector--;
    5178                 if (pExtent->fFooter)
    5179                 {
    5180                     uRGTSector--;
    5181                     uEOSOff = 512;
    5182                     rc = vmdkWriteMetaSparseExtent(pImage, pExtent, VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t));
    5183                     if (RT_FAILURE(rc))
    5184                         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after redundant grain table in '%s'"), pExtent->pszFullname);
    5185                 }
    5186                 pExtent->uLastGrainSector = 0;
    5187                 uint8_t aEOS[512];
    5188                 memset(aEOS, '\0', sizeof(aEOS));
    5189                 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
    5190                                        VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t) + uEOSOff,
    5191                                        aEOS, sizeof(aEOS), NULL);
    5192                 if (RT_FAILURE(rc))
    5193                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after redundant grain table in '%s'"), pExtent->pszFullname);
    5194             }
     4917            uFileOffset = pExtent->uAppendPosition;
     4918            if (!uFileOffset)
     4919                return VERR_INTERNAL_ERROR;
     4920            Assert(!(uFileOffset % 512));
     4921            uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
     4922
     4923            pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
     4924
    51954925            /* Normally the redundant grain table is preallocated for hosted
    51964926             * sparse extents that support more than 32 bit sector numbers. So
     
    51984928            if (uRGTSector > UINT32_MAX)
    51994929                return VERR_VD_VMDK_INVALID_HEADER;
     4930
    52004931            /* Write backup grain table by writing the required number of grain
    52014932             * table cache chunks. Avoids dynamic memory allocation, but is a
     
    52124943                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
    52134944            }
     4945
     4946            pExtent->uAppendPosition =   pExtent->uAppendPosition
     4947                                       + pExtent->cGTEntries * sizeof(uint32_t);
    52144948        }
    52154949
     
    52404974    }
    52414975
    5242     rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
    5243     if (RT_FAILURE(rc))
    5244         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    5245     Assert(!(cbExtentSize % 512));
     4976    uFileOffset = pExtent->uAppendPosition;
     4977    if (!uFileOffset)
     4978        return VERR_INTERNAL_ERROR;
     4979    Assert(!(uFileOffset % 512));
    52464980
    52474981    /* Write the data. Always a full grain, or we're in big trouble. */
    52484982    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    52494983    {
    5250         /* For streamOptimized extents this is a little more difficult, as the
    5251          * cached data also needs to be updated, to handle updating the last
    5252          * written block properly. Also we're trying to avoid unnecessary gaps.
    5253          * Additionally the end-of-stream marker needs to be written. */
    5254         if (!pExtent->uLastGrainSector)
    5255         {
    5256             cbExtentSize -= 512;
    5257             if (pExtent->fFooter)
    5258                 cbExtentSize -= 512;
    5259         }
    5260         else
    5261             cbExtentSize = VMDK_SECTOR2BYTE(pExtent->uLastGrainSector) + pExtent->cbLastGrainWritten;
    5262         Assert(cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     4984        if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     4985            return vmdkError(pImage, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
     4986
     4987        /* Invalidate cache, just in case some code incorrectly allows mixing
     4988         * of reads and writes. Normally shouldn't be needed. */
     4989        pExtent->uGrainSector = 0;
     4990        pExtent->uLastGrainSector = 0;
     4991
     4992        /* Write compressed data block and the markers. */
    52634993        uint32_t cbGrain = 0;
    5264         rc = vmdkFileDeflateSync(pImage, pExtent, cbExtentSize,
     4994        rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
    52654995                                 pvBuf, cbWrite, uSector, &cbGrain);
    52664996        if (RT_FAILURE(rc))
    52674997        {
    5268             pExtent->uGrainSector = 0;
    5269             pExtent->uLastGrainSector = 0;
    52704998            AssertRC(rc);
    52714999            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname);
    52725000        }
    5273         pExtent->uLastGrainSector = VMDK_BYTE2SECTOR(cbExtentSize);
    52745001        pExtent->uLastGrainWritten = uSector / pExtent->cSectorsPerGrain;
    5275         pExtent->cbLastGrainWritten = cbGrain;
    5276         memcpy(pExtent->pvGrain, pvBuf, cbWrite);
    5277         pExtent->uGrainSector = uSector;
    5278 
    5279         uint64_t uEOSOff = 0;
    5280         if (pExtent->fFooter)
    5281         {
    5282             uEOSOff = 512;
    5283             rc = vmdkWriteMetaSparseExtent(pImage, pExtent, cbExtentSize + RT_ALIGN(cbGrain, 512));
    5284             if (RT_FAILURE(rc))
    5285                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after allocated data block in '%s'"), pExtent->pszFullname);
    5286         }
    5287         uint8_t aEOS[512];
    5288         memset(aEOS, '\0', sizeof(aEOS));
    5289         rc = vmdkFileWriteSync(pImage, pExtent->pFile,
    5290                                cbExtentSize + RT_ALIGN(cbGrain, 512) + uEOSOff,
    5291                                aEOS, sizeof(aEOS), NULL);
    5292         if (RT_FAILURE(rc))
    5293             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after allocated data block in '%s'"), pExtent->pszFullname);
     5002        pExtent->uAppendPosition += cbGrain;
    52945003    }
    52955004    else
    52965005    {
    5297         rc = vmdkFileWriteSync(pImage, pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL);
     5006        rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     5007                               pvBuf, cbWrite, NULL);
    52985008        if (RT_FAILURE(rc))
    52995009            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
     5010        pExtent->uAppendPosition += cbWrite;
    53005011    }
    53015012
     
    53265037    }
    53275038    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
    5328     aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(cbExtentSize));
    5329     pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(cbExtentSize);
     5039    aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(uFileOffset));
     5040    pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(uFileOffset);
    53305041    /* Update grain table on disk. */
    53315042    rc = vmdkFileWriteSync(pImage, pExtent->pFile,
     
    53505061    }
    53515062#endif /* VBOX_WITH_VMDK_ESX */
     5063    return rc;
     5064}
     5065
     5066/**
     5067 * Internal. Writes the grain and also if necessary the grain tables.
     5068 * Uses the grain table cache as a true grain table.
     5069 */
     5070static int vmdkStreamAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     5071                                uint64_t uSector, const void *pvBuf,
     5072                                uint64_t cbWrite)
     5073{
     5074    uint32_t uGrain;
     5075    uint32_t uGDEntry, uLastGDEntry;
     5076    uint32_t cbGrain = 0;
     5077    uint32_t uCacheLine, uCacheEntry;
     5078    const void *pData = pvBuf;
     5079    int rc;
     5080
     5081    /* Very strict requirements: always write at least one full grain, with
     5082     * proper alignment. Everything else would require reading of already
     5083     * written data, which we don't support for obvious reasons. The only
     5084     * exception is the last grain, and only if the image size specifies
     5085     * that only some portion holds data. In any case the write must be
     5086     * within the image limits, no "overshoot" allowed. */
     5087    if (   cbWrite == 0
     5088        || (   cbWrite < VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
     5089            && pExtent->cNominalSectors - uSector >= pExtent->cSectorsPerGrain)
     5090        || uSector % pExtent->cSectorsPerGrain
     5091        || uSector + VMDK_BYTE2SECTOR(cbWrite) > pExtent->cNominalSectors)
     5092        return VERR_INVALID_PARAMETER;
     5093
     5094    /* Clip write range to at most the rest of the grain. */
     5095    cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
     5096
     5097    /* Do not allow to go back. */
     5098    uGrain = uSector / pExtent->cSectorsPerGrain;
     5099    uCacheLine = uGrain % pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
     5100    uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE;
     5101    uGDEntry = uGrain / pExtent->cGTEntries;
     5102    uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
     5103    if (uGrain < pExtent->uLastGrainWritten)
     5104        return VERR_VD_VMDK_INVALID_WRITE;
     5105
     5106    /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
     5107     * to allocate something, we also need to detect the situation ourself. */
     5108    if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
     5109        && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbWrite * 8) == -1)
     5110        return VINF_SUCCESS;
     5111
     5112    if (uGDEntry != uLastGDEntry)
     5113    {
     5114        rc = vmdkStreamFlushGT(pImage, pExtent, uLastGDEntry);
     5115        if (RT_FAILURE(rc))
     5116            return rc;
     5117        vmdkStreamClearGT(pImage, pExtent);
     5118        for (uint32_t i = uLastGDEntry + 1; i < uGDEntry; i++)
     5119        {
     5120            rc = vmdkStreamFlushGT(pImage, pExtent, i);
     5121            if (RT_FAILURE(rc))
     5122                return rc;
     5123        }
     5124    }
     5125
     5126    uint64_t uFileOffset;
     5127    uFileOffset = pExtent->uAppendPosition;
     5128    if (!uFileOffset)
     5129        return VERR_INTERNAL_ERROR;
     5130    /* Align to sector, as the previous write could have been any size. */
     5131    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     5132
     5133    /* Paranoia check: extent type, grain table buffer presence and
     5134     * grain table buffer space. Also grain table entry must be clear. */
     5135    if (   pExtent->enmType != VMDKETYPE_HOSTED_SPARSE
     5136        || !pImage->pGTCache
     5137        || pExtent->cGTEntries > VMDK_GT_CACHE_SIZE * VMDK_GT_CACHELINE_SIZE
     5138        || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
     5139        return VERR_INTERNAL_ERROR;
     5140
     5141    /* Update grain table entry. */
     5142    pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
     5143
     5144    if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     5145    {
     5146        memcpy(pExtent->pvGrain, pvBuf, cbWrite);
     5147        memset((char *)pExtent->pvGrain + cbWrite, '\0',
     5148               VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite);
     5149        pData = pExtent->pvGrain;
     5150    }
     5151    rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset, pData,
     5152                             VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
     5153                             uSector, &cbGrain);
     5154    if (RT_FAILURE(rc))
     5155    {
     5156        pExtent->uGrainSector = 0;
     5157        pExtent->uLastGrainSector = 0;
     5158        AssertRC(rc);
     5159        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
     5160    }
     5161    pExtent->uLastGrainSector = VMDK_BYTE2SECTOR(uFileOffset);
     5162    pExtent->uLastGrainWritten = uGrain;
     5163    pExtent->uAppendPosition += cbGrain;
     5164
    53525165    return rc;
    53535166}
     
    54145227    pGrainAlloc->fGTUpdateNeeded = false;
    54155228    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
    5416     aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(pGrainAlloc->cbExtentSize));
    5417     pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(pGrainAlloc->cbExtentSize);
     5229    aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(pGrainAlloc->uGrainOffset));
     5230    pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(pGrainAlloc->uGrainOffset);
    54185231    /* Update grain table on disk. */
    54195232    rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
     
    54875300    PVMDKGTCACHE pCache = pImage->pGTCache;
    54885301    uint64_t uGDIndex, uGTSector, uRGTSector;
    5489     uint64_t cbExtentSize;
     5302    uint64_t uFileOffset;
    54905303    PVMDKGRAINALLOCASYNC pGrainAlloc = NULL;
    54915304    int rc;
     
    55185331         * entry. So there is absolutely no data in this area. Allocate
    55195332         * a new grain table and put the reference to it in the GDs. */
    5520         rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
    5521         if (RT_FAILURE(rc))
    5522             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    5523         Assert(!(cbExtentSize % 512));
    5524 
    5525         pGrainAlloc->cbExtentOld = cbExtentSize;
    5526 
    5527         cbExtentSize = RT_ALIGN_64(cbExtentSize, 512);
    5528         uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     5333        uFileOffset = pExtent->uAppendPosition;
     5334        if (!uFileOffset)
     5335            return VERR_INTERNAL_ERROR;
     5336        Assert(!(uFileOffset % 512));
     5337
     5338        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     5339        uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
    55295340
    55305341        /* Normally the grain table is preallocated for hosted sparse extents
     
    55365347        /* Write grain table by writing the required number of grain table
    55375348         * cache chunks. Allocate memory dynamically here or we flood the
    5538          * metadata cache with very small entries.
    5539          */
    5540         size_t cbGTDataTmp = (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE) * VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t);
     5349         * metadata cache with very small entries. */
     5350        size_t cbGTDataTmp = pExtent->cGTEntries * sizeof(uint32_t);
    55415351        uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp);
    55425352
     
    55565366            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
    55575367        }
     5368        pExtent->uAppendPosition = RT_ALIGN_64(  pExtent->uAppendPosition
     5369                                               + cbGTDataTmp, 512);
    55585370
    55595371        if (pExtent->pRGD)
    55605372        {
    55615373            AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
    5562             rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
    5563             if (RT_FAILURE(rc))
    5564                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    5565             Assert(!(cbExtentSize % 512));
    5566             uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     5374            uFileOffset = pExtent->uAppendPosition;
     5375            if (!uFileOffset)
     5376                return VERR_INTERNAL_ERROR;
     5377            Assert(!(uFileOffset % 512));
     5378            uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
    55675379
    55685380            /* Normally the redundant grain table is preallocated for hosted
     
    55745386                return VERR_VD_VMDK_INVALID_HEADER;
    55755387            }
    5576             /* Write backup grain table by writing the required number of grain
    5577              * table cache chunks. */
     5388
     5389            /* Write grain table by writing the required number of grain table
     5390             * cache chunks. Allocate memory dynamically here or we flood the
     5391             * metadata cache with very small entries. */
    55785392            rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
    55795393                                        VMDK_SECTOR2BYTE(uRGTSector),
     
    55875401                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
    55885402            }
     5403
     5404            pExtent->uAppendPosition = pExtent->uAppendPosition + cbGTDataTmp;
    55895405        }
    55905406
     
    56275443    pGrainAlloc->uRGTSector = uRGTSector;
    56285444
    5629     rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
    5630     if (RT_FAILURE(rc))
    5631         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    5632     Assert(!(cbExtentSize % 512));
    5633 
    5634     if (!pGrainAlloc->cbExtentOld)
    5635         pGrainAlloc->cbExtentOld = cbExtentSize;
    5636 
    5637     pGrainAlloc->cbExtentSize = cbExtentSize;
     5445    uFileOffset = pExtent->uAppendPosition;
     5446    if (!uFileOffset)
     5447        return VERR_INTERNAL_ERROR;
     5448    Assert(!(uFileOffset % 512));
     5449
     5450    pGrainAlloc->uGrainOffset = uFileOffset;
    56385451
    56395452    /* Write the data. Always a full grain, or we're in big trouble. */
    56405453    rc = vmdkFileWriteUserAsync(pImage, pExtent->pFile,
    5641                                 cbExtentSize, pIoCtx, cbWrite,
     5454                                uFileOffset, pIoCtx, cbWrite,
    56425455                                vmdkAllocGrainAsyncComplete, pGrainAlloc);
    56435456    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     
    56885501    }
    56895502    return pszNewStr;
    5690 }
    5691 
    5692 
    5693 /** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
    5694 static int vmdksCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
    5695                              PVDINTERFACE pVDIfsImage)
    5696 {
    5697     LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
    5698     int rc = VINF_SUCCESS;
    5699 
    5700     if (   !VALID_PTR(pszFilename)
    5701         || !*pszFilename
    5702         || strchr(pszFilename, '"'))
    5703     {
    5704         rc = VERR_INVALID_PARAMETER;
    5705         goto out;
    5706     }
    5707 
    5708     /* Always return failure, to avoid opening other VMDK files via this
    5709      * special VMDK streamOptimized format backend. */
    5710     rc = VERR_VD_VMDK_INVALID_HEADER;
    5711 
    5712 out:
    5713     LogFlowFunc(("returns %Rrc\n", rc));
    5714     return rc;
    5715 }
    5716 
    5717 
    5718 /** @copydoc VBOXHDDBACKEND::pfnOpen */
    5719 static int vmdksOpen(const char *pszFilename, unsigned uOpenFlags,
    5720                      PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
    5721                      void **ppBackendData)
    5722 {
    5723     LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
    5724     int rc;
    5725 
    5726     rc = VERR_NOT_SUPPORTED;
    5727     LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    5728     return rc;
    5729 }
    5730 
    5731 /** @copydoc VBOXHDDBACKEND::pfnCreate */
    5732 static int vmdksCreate(const char *pszFilename, uint64_t cbSize,
    5733                        unsigned uImageFlags, const char *pszComment,
    5734                        PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
    5735                        PCRTUUID pUuid, unsigned uOpenFlags,
    5736                        unsigned uPercentStart, unsigned uPercentSpan,
    5737                        PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
    5738                        PVDINTERFACE pVDIfsOperation, void **ppBackendData)
    5739 {
    5740     LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
    5741     int rc;
    5742     PVMDKIMAGE pImage;
    5743 
    5744     PFNVDPROGRESS pfnProgress = NULL;
    5745     void *pvUser = NULL;
    5746     PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
    5747                                               VDINTERFACETYPE_PROGRESS);
    5748     PVDINTERFACEPROGRESS pCbProgress = NULL;
    5749     if (pIfProgress)
    5750     {
    5751         pCbProgress = VDGetInterfaceProgress(pIfProgress);
    5752         pfnProgress = pCbProgress->pfnProgress;
    5753         pvUser = pIfProgress->pvUser;
    5754     }
    5755 
    5756     /* Check open flags. No flags are supported. */
    5757     if (uOpenFlags != VD_OPEN_FLAGS_NORMAL)
    5758     {
    5759         rc = VERR_INVALID_PARAMETER;
    5760         goto out;
    5761     }
    5762 
    5763     /* Check image flags. No flags are supported. */
    5764     if (uImageFlags != VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    5765     {
    5766         rc = VERR_INVALID_PARAMETER;
    5767         goto out;
    5768     }
    5769 
    5770     /* Check size. Maximum 2TB-64K. */
    5771     if (   !cbSize
    5772         || cbSize >= _1T * 2 - _64K)
    5773     {
    5774         rc = VERR_VD_INVALID_SIZE;
    5775         goto out;
    5776     }
    5777 
    5778     /* Check remaining arguments. */
    5779     if (   !VALID_PTR(pszFilename)
    5780         || !*pszFilename
    5781         || strchr(pszFilename, '"')
    5782         || !VALID_PTR(pPCHSGeometry)
    5783         || !VALID_PTR(pLCHSGeometry))
    5784     {
    5785         rc = VERR_INVALID_PARAMETER;
    5786         goto out;
    5787     }
    5788 
    5789     pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
    5790     if (!pImage)
    5791     {
    5792         rc = VERR_NO_MEMORY;
    5793         goto out;
    5794     }
    5795     pImage->pszFilename = pszFilename;
    5796     pImage->pFile = NULL;
    5797     pImage->pExtents = NULL;
    5798     pImage->pFiles = NULL;
    5799     pImage->pGTCache = NULL;
    5800     pImage->pDescData = NULL;
    5801     pImage->pVDIfsDisk = pVDIfsDisk;
    5802     pImage->pVDIfsImage = pVDIfsImage;
    5803     /* Descriptors for stream optimized images are small, so don't waste
    5804      * space in the resulting image and allocate a small buffer. */
    5805     pImage->cbDescAlloc = VMDK_SECTOR2BYTE(4);
    5806     pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
    5807     if (!pImage->pDescData)
    5808     {
    5809         rc = VERR_NO_MEMORY;
    5810         goto out;
    5811     }
    5812 
    5813     rc = vmdksCreateImage(pImage, cbSize, uImageFlags, pszComment,
    5814                           pPCHSGeometry, pLCHSGeometry, pUuid,
    5815                           pfnProgress, pvUser, uPercentStart, uPercentSpan);
    5816     if (RT_SUCCESS(rc))
    5817     {
    5818         /* Image is always writable. */
    5819         *ppBackendData = pImage;
    5820     }
    5821     else
    5822     {
    5823         RTMemFree(pImage->pDescData);
    5824         RTMemFree(pImage);
    5825     }
    5826 
    5827 out:
    5828     LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    5829     return rc;
    5830 }
    5831 
    5832 /** @copydoc VBOXHDDBACKEND::pfnClose */
    5833 static int vmdksClose(void *pBackendData, bool fDelete)
    5834 {
    5835     LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
    5836     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    5837     int rc;
    5838 
    5839     rc = vmdksFreeImage(pImage, fDelete);
    5840     RTMemFree(pImage);
    5841 
    5842     LogFlowFunc(("returns %Rrc\n", rc));
    5843     return rc;
    5844 }
    5845 
    5846 /** @copydoc VBOXHDDBACKEND::pfnRead */
    5847 static int vmdksRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
    5848                      size_t cbToRead, size_t *pcbActuallyRead)
    5849 {
    5850     LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
    5851     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    5852     int rc;
    5853 
    5854     rc = VERR_NOT_SUPPORTED;
    5855     LogFlowFunc(("returns %Rrc\n", rc));
    5856     return rc;
    5857 }
    5858 
    5859 /** @copydoc VBOXHDDBACKEND::pfnWrite */
    5860 static int vmdksWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
    5861                       size_t cbToWrite, size_t *pcbWriteProcess,
    5862                       size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
    5863 {
    5864     LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
    5865     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    5866     PVMDKEXTENT pExtent;
    5867     uint64_t uSector;
    5868     uint32_t uGrain;
    5869     uint32_t uGDEntry, uLastGDEntry;
    5870     uint32_t cbGrain = 0;
    5871     uint32_t uCacheLine, uCacheEntry;
    5872     const void *pData = pvBuf;
    5873     int rc;
    5874 
    5875     AssertPtr(pImage);
    5876     Assert(uOffset % 512 == 0);
    5877     Assert(cbToWrite % 512 == 0);
    5878 
    5879     if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    5880     {
    5881         rc = VERR_VD_IMAGE_READ_ONLY;
    5882         goto out;
    5883     }
    5884 
    5885     pExtent = &pImage->pExtents[0];
    5886     uSector = VMDK_BYTE2SECTOR(uOffset);
    5887 
    5888     /* Very strict requirements: always write at least one full grain, with
    5889      * proper alignment. Everything else would require reading of already
    5890      * written data, which we don't support for obvious reasons. The only
    5891      * exception is the last grain, and only if the image size specifies
    5892      * that only some portion holds data. In any case the write must be
    5893      * within the image limits, no "overshoot" allowed. */
    5894     if (   cbToWrite == 0
    5895         || (   cbToWrite < VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
    5896             && pImage->cbSize - uOffset >= VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    5897         || uOffset % VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
    5898         || uOffset + cbToWrite > pImage->cbSize)
    5899     {
    5900         rc = VERR_INVALID_PARAMETER;
    5901         goto out;
    5902     }
    5903 
    5904     /* Clip write range to at most the rest of the grain. */
    5905     cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
    5906 
    5907     /* Do not allow to go back. */
    5908     uGrain = VMDK_BYTE2SECTOR(uOffset) / pExtent->cSectorsPerGrain;
    5909     uCacheLine = uGrain % pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
    5910     uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE;
    5911     uGDEntry = uGrain / pExtent->cGTEntries;
    5912     uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
    5913     if (uGrain < pExtent->uLastGrainWritten)
    5914     {
    5915         rc = VERR_VD_VMDK_INVALID_WRITE;
    5916         goto out;
    5917     }
    5918 
    5919     /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
    5920      * to allocate something, we also need to detect the situation ourself. */
    5921     if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
    5922         && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbToWrite * 8) == -1)
    5923     {
    5924         rc = VINF_SUCCESS;
    5925         if (pcbWriteProcess)
    5926             *pcbWriteProcess = cbToWrite;
    5927         goto out;
    5928     }
    5929 
    5930     if (uGDEntry != uLastGDEntry)
    5931     {
    5932         rc = vmdksFlushGT(pImage, pExtent, uLastGDEntry);
    5933         if (RT_FAILURE(rc))
    5934             goto out;
    5935         vmdksClearGT(pImage, pExtent);
    5936         for (uint32_t i = uLastGDEntry + 1; i < uGDEntry; i++)
    5937         {
    5938             rc = vmdksFlushGT(pImage, pExtent, i);
    5939             if (RT_FAILURE(rc))
    5940                 goto out;
    5941         }
    5942     }
    5943 
    5944     /* Check access permissions as defined in the extent descriptor.
    5945      * May sound a bit paradoxical, but we created the image with a
    5946      * readonly extent since the resulting image is kind of "write once". */
    5947     if (pExtent->enmAccess != VMDKACCESS_READONLY)
    5948     {
    5949         rc = VERR_VD_VMDK_INVALID_STATE;
    5950         goto out;
    5951     }
    5952 
    5953     uint64_t uFileOffset;
    5954     rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
    5955     if (RT_FAILURE(rc))
    5956         goto out;
    5957     /* Align to sector, as the previous write could have been any size. */
    5958     uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    5959 
    5960     /* Paranoia check: extent type, grain table buffer presence and
    5961      * grain table buffer space. Also grain table entry must be clear. */
    5962     if (   pExtent->enmType != VMDKETYPE_HOSTED_SPARSE
    5963         || !pImage->pGTCache
    5964         || pExtent->cGTEntries > VMDK_GT_CACHE_SIZE * VMDK_GT_CACHELINE_SIZE
    5965         || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
    5966     {
    5967         rc = VERR_INTERNAL_ERROR;
    5968         goto out;
    5969     }
    5970 
    5971     /* Update grain table entry. */
    5972     pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
    5973 
    5974     if (cbToWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    5975     {
    5976         memcpy(pExtent->pvGrain, pvBuf, cbToWrite);
    5977         memset((char *)pExtent->pvGrain + cbToWrite, '\0',
    5978                VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite);
    5979         pData = pExtent->pvGrain;
    5980     }
    5981     rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset, pData,
    5982                              VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
    5983                              uSector, &cbGrain);
    5984     if (RT_FAILURE(rc))
    5985     {
    5986         pExtent->uGrainSector = 0;
    5987         pExtent->uLastGrainSector = 0;
    5988         AssertRC(rc);
    5989         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
    5990     }
    5991     pExtent->uLastGrainSector = VMDK_BYTE2SECTOR(uFileOffset);
    5992     pExtent->uLastGrainWritten = uGrain;
    5993     pExtent->cbLastGrainWritten = cbGrain;
    5994 
    5995     if (pcbWriteProcess)
    5996         *pcbWriteProcess = cbToWrite;
    5997 
    5998 out:
    5999     LogFlowFunc(("returns %Rrc\n", rc));
    6000     return rc;
    6001 }
    6002 
    6003 /** @copydoc VBOXHDDBACKEND::pfnFlush */
    6004 static int vmdksFlush(void *pBackendData)
    6005 {
    6006     LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    6007     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6008     int rc;
    6009 
    6010     AssertPtr(pImage);
    6011 
    6012     /* Pure dummy operation, closing takes care of everything. */
    6013     rc = VINF_SUCCESS;
    6014     LogFlowFunc(("returns %Rrc\n", rc));
    6015     return rc;
    6016 }
    6017 
    6018 /** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
    6019 static int vmdksSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
    6020 {
    6021     LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
    6022     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6023     int rc;
    6024 
    6025     AssertPtr(pImage);
    6026 
    6027     if (pImage)
    6028     {
    6029         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6030             rc = VERR_VD_IMAGE_READ_ONLY;
    6031         else
    6032             rc = VERR_NOT_SUPPORTED;
    6033     }
    6034     else
    6035         rc = VERR_VD_NOT_OPENED;
    6036 
    6037     LogFlowFunc(("returns %Rrc\n", rc));
    6038     return rc;
    6039 }
    6040 
    6041 /** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
    6042 static int vmdksSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
    6043 {
    6044     LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    6045     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6046     int rc;
    6047 
    6048     AssertPtr(pImage);
    6049 
    6050     if (pImage)
    6051     {
    6052         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6053             rc = VERR_VD_IMAGE_READ_ONLY;
    6054         else
    6055             rc = VERR_NOT_SUPPORTED;
    6056     }
    6057     else
    6058         rc = VERR_VD_NOT_OPENED;
    6059 
    6060     LogFlowFunc(("returns %Rrc\n", rc));
    6061     return rc;
    6062 }
    6063 
    6064 /** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
    6065 static int vmdksSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
    6066 {
    6067     LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
    6068     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6069     int rc = VINF_SUCCESS;
    6070 
    6071     /* Image must be opened and the new flags must be the same as before. */
    6072     if (!pImage || pImage->uOpenFlags != uOpenFlags)
    6073     {
    6074         rc = VERR_INVALID_PARAMETER;
    6075         goto out;
    6076     }
    6077 
    6078 out:
    6079     LogFlowFunc(("returns %Rrc\n", rc));
    6080     return rc;
    6081 }
    6082 
    6083 /** @copydoc VBOXHDDBACKEND::pfnSetComment */
    6084 static int vmdksSetComment(void *pBackendData, const char *pszComment)
    6085 {
    6086     LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
    6087     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6088     int rc;
    6089 
    6090     AssertPtr(pImage);
    6091 
    6092     if (pImage)
    6093     {
    6094         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6095             rc = VERR_VD_IMAGE_READ_ONLY;
    6096         else
    6097             rc = VERR_NOT_SUPPORTED;
    6098     }
    6099     else
    6100         rc = VERR_VD_NOT_OPENED;
    6101 
    6102     LogFlowFunc(("returns %Rrc\n", rc));
    6103     return rc;
    6104 }
    6105 
    6106 /** @copydoc VBOXHDDBACKEND::pfnSetUuid */
    6107 static int vmdksSetUuid(void *pBackendData, PCRTUUID pUuid)
    6108 {
    6109     LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
    6110     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6111     int rc;
    6112 
    6113     LogFlowFunc(("%RTuuid\n", pUuid));
    6114     AssertPtr(pImage);
    6115 
    6116     if (pImage)
    6117     {
    6118         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6119             rc = VERR_VD_IMAGE_READ_ONLY;
    6120         else
    6121             rc = VERR_NOT_SUPPORTED;
    6122     }
    6123     else
    6124         rc = VERR_VD_NOT_OPENED;
    6125 
    6126     LogFlowFunc(("returns %Rrc\n", rc));
    6127     return rc;
    6128 }
    6129 
    6130 /** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
    6131 static int vmdksSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
    6132 {
    6133     LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
    6134     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6135     int rc;
    6136 
    6137     AssertPtr(pImage);
    6138 
    6139     if (pImage)
    6140     {
    6141         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6142             rc = VERR_VD_IMAGE_READ_ONLY;
    6143         else
    6144             rc = VERR_NOT_SUPPORTED;
    6145     }
    6146     else
    6147         rc = VERR_VD_NOT_OPENED;
    6148 
    6149     LogFlowFunc(("returns %Rrc\n", rc));
    6150     return rc;
    6151 }
    6152 
    6153 /** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
    6154 static int vmdksSetParentUuid(void *pBackendData, PCRTUUID pUuid)
    6155 {
    6156     LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
    6157     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6158     int rc;
    6159 
    6160     AssertPtr(pImage);
    6161 
    6162     if (pImage)
    6163     {
    6164         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6165             rc = VERR_VD_IMAGE_READ_ONLY;
    6166         else
    6167             rc = VERR_NOT_SUPPORTED;
    6168     }
    6169     else
    6170         rc = VERR_VD_NOT_OPENED;
    6171 
    6172     LogFlowFunc(("returns %Rrc\n", rc));
    6173     return rc;
    6174 }
    6175 
    6176 /** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
    6177 static int vmdksSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
    6178 {
    6179     LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
    6180     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6181     int rc;
    6182 
    6183     AssertPtr(pImage);
    6184 
    6185     if (pImage)
    6186     {
    6187         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    6188             rc = VERR_VD_IMAGE_READ_ONLY;
    6189         else
    6190             rc = VERR_NOT_SUPPORTED;
    6191     }
    6192     else
    6193         rc = VERR_VD_NOT_OPENED;
    6194 
    6195     LogFlowFunc(("returns %Rrc\n", rc));
    6196     return rc;
    61975503}
    61985504
     
    62635569        goto out;
    62645570    }
    6265 
    62665571
    62675572    pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     
    66976002        goto out;
    66986003    }
    6699 
    67006004
    67016005    /* Clip read range to remain in this extent. */
     
    68106114
    68116115    /* Check access permissions as defined in the extent descriptor. */
    6812     if (pExtent->enmAccess != VMDKACCESS_READWRITE)
     6116    if (   pExtent->enmAccess != VMDKACCESS_READWRITE
     6117        && (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     6118            && !pImage->pExtents[0].uAppendPosition
     6119            && pExtent->enmAccess != VMDKACCESS_READONLY))
    68136120    {
    68146121        rc = VERR_VD_VMDK_INVALID_STATE;
     
    68376144            if (uSectorExtentAbs == 0)
    68386145            {
    6839                 if (cbToWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     6146                if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
    68406147                {
    6841                     /* Full block write to a previously unallocated block.
    6842                      * Check if the caller wants to avoid the automatic alloc. */
    6843                     if (!(fWrite & VD_WRITE_NO_ALLOC))
     6148                    if (cbToWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    68446149                    {
    6845                         /* Allocate GT and find out where to store the grain. */
    6846                         rc = vmdkAllocGrain(pImage, pExtent, uSectorExtentRel,
    6847                                             pvBuf, cbToWrite);
     6150                        /* Full block write to a previously unallocated block.
     6151                         * Check if the caller wants feedback. */
     6152                        if (!(fWrite & VD_WRITE_NO_ALLOC))
     6153                        {
     6154                            /* Allocate GT and store the grain. */
     6155                            rc = vmdkAllocGrain(pImage, pExtent,
     6156                                                uSectorExtentRel,
     6157                                                pvBuf, cbToWrite);
     6158                        }
     6159                        else
     6160                            rc = VERR_VD_BLOCK_FREE;
     6161                        *pcbPreRead = 0;
     6162                        *pcbPostRead = 0;
    68486163                    }
    68496164                    else
     6165                    {
     6166                        /* Clip write range to remain in this extent. */
     6167                        cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     6168                        *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
     6169                        *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite - *pcbPreRead;
    68506170                        rc = VERR_VD_BLOCK_FREE;
    6851                     *pcbPreRead = 0;
    6852                     *pcbPostRead = 0;
     6171                    }
    68536172                }
    68546173                else
    68556174                {
    6856                     /* Clip write range to remain in this extent. */
    6857                     cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    6858                     *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
    6859                     *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite - *pcbPreRead;
    6860                     rc = VERR_VD_BLOCK_FREE;
     6175                    rc = vmdkStreamAllocGrain(pImage, pExtent,
     6176                                              uSectorExtentRel,
     6177                                              pvBuf, cbToWrite);
    68616178                }
    68626179            }
     
    68656182                if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    68666183                {
    6867                     uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
    6868                     uSectorExtentAbs -= uSectorInGrain;
    6869                     uint64_t uLBA = uSectorExtentRel;
    6870                     if (    pExtent->uGrainSector != uSectorExtentAbs
    6871                         ||  pExtent->uGrainSector != pExtent->uLastGrainSector)
    6872                     {
    6873                         rc = vmdkFileInflateSync(pImage, pExtent,
    6874                                                  VMDK_SECTOR2BYTE(uSectorExtentAbs),
    6875                                                  pExtent->pvGrain,
    6876                                                  VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
    6877                                                  &uLBA, NULL);
    6878                         if (RT_FAILURE(rc))
    6879                         {
    6880                             pExtent->uGrainSector = 0;
    6881                             pExtent->uLastGrainSector = 0;
    6882                             AssertRC(rc);
    6883                             goto out;
    6884                         }
    6885                         pExtent->uGrainSector = uSectorExtentAbs;
    6886                         pExtent->uLastGrainSector = uSectorExtentAbs;
    6887                         Assert(uLBA == uSectorExtentRel);
    6888                     }
    6889                     memcpy((uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), pvBuf, cbToWrite);
    6890                     uint32_t cbGrain = 0;
    6891                     rc = vmdkFileDeflateSync(pImage, pExtent,
    6892                                              VMDK_SECTOR2BYTE(uSectorExtentAbs),
    6893                                              pExtent->pvGrain,
    6894                                              VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
    6895                                              uLBA, &cbGrain);
    6896                     if (RT_FAILURE(rc))
    6897                     {
    6898                         pExtent->uGrainSector = 0;
    6899                         pExtent->uLastGrainSector = 0;
    6900                         AssertRC(rc);
    6901                         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
    6902                     }
    6903                     pExtent->uLastGrainSector = uSectorExtentAbs;
    6904                     pExtent->uLastGrainWritten = uSectorExtentRel / pExtent->cSectorsPerGrain;
    6905                     pExtent->cbLastGrainWritten = cbGrain;
    6906 
    6907                     uint64_t uEOSOff = 0;
    6908                     if (pExtent->fFooter)
    6909                     {
    6910                         uEOSOff = 512;
    6911                         rc = vmdkWriteMetaSparseExtent(pImage, pExtent, VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512));
    6912                         if (RT_FAILURE(rc))
    6913                             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after data block in '%s'"), pExtent->pszFullname);
    6914                     }
    6915                     uint8_t aEOS[512];
    6916                     memset(aEOS, '\0', sizeof(aEOS));
    6917                     rc = vmdkFileWriteSync(pImage, pExtent->pFile,
    6918                                            VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512) + uEOSOff,
    6919                                            aEOS, sizeof(aEOS), NULL);
    6920                     if (RT_FAILURE(rc))
    6921                         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after data block in '%s'"), pExtent->pszFullname);
     6184                    /* A partial write to a streamOptimized image is simply
     6185                     * invalid. It requires rewriting already compressed data
     6186                     * which is somewhere between expensive and impossible. */
     6187                    rc = VERR_VD_VMDK_INVALID_STATE;
     6188                    pExtent->uGrainSector = 0;
     6189                    pExtent->uLastGrainSector = 0;
     6190                    AssertRC(rc);
    69226191                }
    69236192                else
     
    69566225    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    69576226    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    6958     int rc;
     6227    int rc = VINF_SUCCESS;
    69596228
    69606229    AssertPtr(pImage);
    69616230
    6962     rc = vmdkFlushImage(pImage);
     6231    if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     6232        rc = vmdkFlushImage(pImage);
     6233
    69636234    LogFlowFunc(("returns %Rrc\n", rc));
    69646235    return rc;
     
    70686339            goto out;
    70696340        }
     6341        if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     6342        {
     6343            rc = VERR_NOT_SUPPORTED;
     6344            goto out;
     6345        }
    70706346        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    70716347        if (RT_FAILURE(rc))
     
    71236399        {
    71246400            rc = VERR_VD_IMAGE_READ_ONLY;
     6401            goto out;
     6402        }
     6403        if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     6404        {
     6405            rc = VERR_NOT_SUPPORTED;
    71256406            goto out;
    71266407        }
     
    71886469    {
    71896470        rc = VERR_INVALID_PARAMETER;
     6471        goto out;
     6472    }
     6473
     6474    /* StreamOptimized images need special treatment: reopen is prohibited. */
     6475    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     6476    {
     6477        if (pImage->uOpenFlags == uOpenFlags)
     6478            rc = VINF_SUCCESS;
     6479        else
     6480            rc = VERR_INVALID_PARAMETER;
    71906481        goto out;
    71916482    }
     
    72536544        goto out;
    72546545    }
     6546    if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     6547    {
     6548        rc = VERR_NOT_SUPPORTED;
     6549        goto out;
     6550    }
    72556551
    72566552    if (pImage)
     
    72996595        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    73006596        {
    7301             pImage->ImageUuid = *pUuid;
    7302             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    7303                                     VMDK_DDB_IMAGE_UUID, pUuid);
    7304             if (RT_FAILURE(rc))
    7305                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
    7306             rc = VINF_SUCCESS;
     6597            if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     6598            {
     6599                pImage->ImageUuid = *pUuid;
     6600                rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     6601                                        VMDK_DDB_IMAGE_UUID, pUuid);
     6602                if (RT_FAILURE(rc))
     6603                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
     6604                rc = VINF_SUCCESS;
     6605            }
     6606            else
     6607                rc = VERR_NOT_SUPPORTED;
    73076608        }
    73086609        else
     
    73506651        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    73516652        {
    7352             /*
    7353              * Only change the modification uuid if it changed.
    7354              * Avoids a lot of unneccessary 1-byte writes during
    7355              * vmdkFlush.
    7356              */
    7357             if (RTUuidCompare(&pImage->ModificationUuid, pUuid))
     6653            if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
    73586654            {
    7359                 pImage->ModificationUuid = *pUuid;
    7360                 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    7361                                         VMDK_DDB_MODIFICATION_UUID, pUuid);
    7362                 if (RT_FAILURE(rc))
    7363                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
     6655                /* Only touch the modification uuid if it changed. */
     6656                if (RTUuidCompare(&pImage->ModificationUuid, pUuid))
     6657                {
     6658                    pImage->ModificationUuid = *pUuid;
     6659                    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     6660                                            VMDK_DDB_MODIFICATION_UUID, pUuid);
     6661                    if (RT_FAILURE(rc))
     6662                        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
     6663                }
     6664                rc = VINF_SUCCESS;
    73646665            }
    7365             rc = VINF_SUCCESS;
     6666            else
     6667                rc = VERR_NOT_SUPPORTED;
    73666668        }
    73676669        else
     
    74096711        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    74106712        {
    7411             pImage->ParentUuid = *pUuid;
    7412             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    7413                                     VMDK_DDB_PARENT_UUID, pUuid);
    7414             if (RT_FAILURE(rc))
    7415                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
    7416             rc = VINF_SUCCESS;
     6713            if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     6714            {
     6715                pImage->ParentUuid = *pUuid;
     6716                rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     6717                                        VMDK_DDB_PARENT_UUID, pUuid);
     6718                if (RT_FAILURE(rc))
     6719                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
     6720                rc = VINF_SUCCESS;
     6721            }
     6722            else
     6723                rc = VERR_NOT_SUPPORTED;
    74176724        }
    74186725        else
     
    74606767        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    74616768        {
    7462             pImage->ParentModificationUuid = *pUuid;
    7463             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    7464                                     VMDK_DDB_PARENT_MODIFICATION_UUID, pUuid);
    7465             if (RT_FAILURE(rc))
    7466                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
    7467             rc = VINF_SUCCESS;
     6769            if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     6770            {
     6771                pImage->ParentModificationUuid = *pUuid;
     6772                rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     6773                                        VMDK_DDB_PARENT_MODIFICATION_UUID, pUuid);
     6774                if (RT_FAILURE(rc))
     6775                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
     6776                rc = VINF_SUCCESS;
     6777            }
     6778            else
     6779                rc = VERR_NOT_SUPPORTED;
    74686780        }
    74696781        else
     
    77377049                    if (pExtent->fFooter)
    77387050                    {
    7739                         uint64_t cbSize;
    7740                         rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbSize);
    7741                         if (RT_FAILURE(rc))
     7051                        uint64_t uFileOffset = pExtent->uAppendPosition;
     7052                        if (!uFileOffset)
     7053                        {
     7054                            rc = VERR_INTERNAL_ERROR;
    77427055                            goto out;
    7743                         cbSize = RT_ALIGN_64(cbSize, 512);
    7744                         rc = vmdkWriteMetaSparseExtent(pImage, pExtent, cbSize - 2*512);
     7056                        }
     7057                        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     7058                        rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
    77457059                        if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
    77467060                            goto out;
     
    77897103    return rc;
    77907104}
    7791 
    7792 
    7793 VBOXHDDBACKEND g_VmdkStreamBackend =
    7794 {
    7795     /* pszBackendName */
    7796     "VMDKstream",
    7797     /* cbSize */
    7798     sizeof(VBOXHDDBACKEND),
    7799     /* uBackendCaps */
    7800     VD_CAP_UUID | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_VFS,
    7801     /* papszFileExtensions */
    7802     s_apszVmdkFileExtensions,
    7803     /* paConfigInfo */
    7804     NULL,
    7805     /* hPlugin */
    7806     NIL_RTLDRMOD,
    7807     /* pfnCheckIfValid */
    7808     vmdksCheckIfValid,
    7809     /* pfnOpen */
    7810     vmdksOpen,
    7811     /* pfnCreate */
    7812     vmdksCreate,
    7813     /* pfnRename */
    7814     NULL,
    7815     /* pfnClose */
    7816     vmdksClose,
    7817     /* pfnRead */
    7818     vmdksRead,
    7819     /* pfnWrite */
    7820     vmdksWrite,
    7821     /* pfnFlush */
    7822     vmdksFlush,
    7823     /* pfnGetVersion */
    7824     vmdkGetVersion,
    7825     /* pfnGetSize */
    7826     vmdkGetSize,
    7827     /* pfnGetFileSize */
    7828     vmdkGetFileSize,
    7829     /* pfnGetPCHSGeometry */
    7830     vmdkGetPCHSGeometry,
    7831     /* pfnSetPCHSGeometry */
    7832     vmdksSetPCHSGeometry,
    7833     /* pfnGetLCHSGeometry */
    7834     vmdkGetLCHSGeometry,
    7835     /* pfnSetLCHSGeometry */
    7836     vmdksSetLCHSGeometry,
    7837     /* pfnGetImageFlags */
    7838     vmdkGetImageFlags,
    7839     /* pfnGetOpenFlags */
    7840     vmdkGetOpenFlags,
    7841     /* pfnSetOpenFlags */
    7842     vmdksSetOpenFlags,
    7843     /* pfnGetComment */
    7844     vmdkGetComment,
    7845     /* pfnSetComment */
    7846     vmdksSetComment,
    7847     /* pfnGetUuid */
    7848     vmdkGetUuid,
    7849     /* pfnSetUuid */
    7850     vmdksSetUuid,
    7851     /* pfnGetModificationUuid */
    7852     vmdkGetModificationUuid,
    7853     /* pfnSetModificationUuid */
    7854     vmdksSetModificationUuid,
    7855     /* pfnGetParentUuid */
    7856     vmdkGetParentUuid,
    7857     /* pfnSetParentUuid */
    7858     vmdksSetParentUuid,
    7859     /* pfnGetParentModificationUuid */
    7860     vmdkGetParentModificationUuid,
    7861     /* pfnSetParentModificationUuid */
    7862     vmdksSetParentModificationUuid,
    7863     /* pfnDump */
    7864     vmdkDump,
    7865     /* pfnGetTimeStamp */
    7866     NULL,
    7867     /* pfnGetParentTimeStamp */
    7868     NULL,
    7869     /* pfnSetParentTimeStamp */
    7870     NULL,
    7871     /* pfnGetParentFilename */
    7872     NULL,
    7873     /* pfnSetParentFilename */
    7874     NULL,
    7875     /* pfnIsAsyncIOSupported */
    7876     NULL,
    7877     /* pfnAsyncRead */
    7878     NULL,
    7879     /* pfnAsyncWrite */
    7880     NULL,
    7881     /* pfnAsyncFlush */
    7882     NULL,
    7883     /* pfnComposeLocation */
    7884     genericFileComposeLocation,
    7885     /* pfnComposeName */
    7886     genericFileComposeName,
    7887     /* pfnCompact */
    7888     NULL,
    7889     /* pfnResize */
    7890     NULL
    7891 };
    78927105
    78937106
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