VirtualBox

Ignore:
Timestamp:
Jan 9, 2008 10:57:05 AM (17 years ago)
Author:
vboxsync
Message:

Big virtual disk changeset containing several modifications

  • remove the always buggy translation setting and replace it with two sets of geometries, physical and logical
  • complete vmdk creation (fixed/dynamic variants, both split in 2G chunks and single file)
  • implemented VBoxHDD-new generic snapshot support, i.e. diff image creation and image merging (completely untested, I'm pretty sure there are bugs)
  • assorted changes which generalize the VBoxHDD-new interfaces (both externally and internally)
File:
1 edited

Legend:

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

    r5999 r6291  
    3636*   Constants And Macros, Structures and Typedefs                              *
    3737*******************************************************************************/
     38
     39/** VMDK descriptor DDB entry for PCHS cylinders. */
     40#define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
     41
     42/** VMDK descriptor DDB entry for PCHS heads. */
     43#define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
     44
     45/** VMDK descriptor DDB entry for PCHS sectors. */
     46#define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
     47
     48/** VMDK descriptor DDB entry for LCHS cylinders. */
     49#define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
     50
     51/** VMDK descriptor DDB entry for LCHS heads. */
     52#define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
     53
     54/** VMDK descriptor DDB entry for LCHS sectors. */
     55#define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
    3856
    3957/**
     
    6785#pragma pack()
    6886
     87/** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
     88 * divisible by the default grain size (64K) */
     89#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
     90
    6991
    7092#ifdef VBOX_WITH_VMDK_ESX
     
    89111    uint32_t    freeSector;
    90112    /* The spec incompletely documents quite a few further fields, but states
    91      * that they are not used by the current format. Replace them by padding. */
     113     * that they are unused by the current format. Replace them by padding. */
    92114    char        reserved1[1604];
    93115    uint32_t    savedGeneration;
     
    274296typedef struct VMDKIMAGE
    275297{
     298    /** Pointer to the image extents. */
    276299    PVMDKEXTENT     pExtents;
     300    /** Number of image extents. */
    277301    unsigned        cExtents;
    278302
     
    295319    /** Total size of the image. */
    296320    uint64_t        cbSize;
    297     /** BIOS translation mode. */
    298     PDMBIOSTRANSLATION enmTranslation;
    299     /** Physical geometry of this image, cylinders. */
    300     uint32_t        cCylinders;
    301     /** Physical geometry of this image, heads. */
    302     uint32_t        cHeads;
    303     /** Physical geometry of this image, sectors. */
    304     uint32_t        cSectors;
     321    /** Physical geometry of this image. */
     322    PDMMEDIAGEOMETRY   PCHSGeometry;
     323    /** Logical geometry of this image. */
     324    PDMMEDIAGEOMETRY   LCHSGeometry;
    305325    /** Image UUID. */
    306326    RTUUID          ImageUuid;
     
    310330    RTUUID          ParentUuid;
    311331
    312     /** Pointer to the grain table cache, if this image contains sparse extents. */
     332    /** Pointer to grain table cache, if this image contains sparse extents. */
    313333    PVMDKGTCACHE    pGTCache;
    314334    /** Pointer to the descriptor (NULL if no separate descriptor file). */
     
    342362static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
    343363
    344 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData);
    345 static int vmdkClose(void *pBackendData, bool fDelete);
    346 
    347364
    348365DECLINLINE(int) vmdkError(PVMDKIMAGE pImage, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
     
    350367    va_list va;
    351368    va_start(va, pszFormat);
    352     pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
     369    if (pImage->pfnError)
     370        pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
    353371    va_end(va);
    354372    return rc;
     
    439457        }
    440458
    441         for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD; i < pExtent->cGDEntries; i++, pGDTmp++, pRGDTmp++)
     459        for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD;
     460             i < pExtent->cGDEntries;
     461             i++, pGDTmp++, pRGDTmp++)
    442462        {
    443463            /* If no grain table is allocated skip the entry. */
     
    491511}
    492512
    493 static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector, bool fPreAlloc)
     513static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector,
     514                                    bool fPreAlloc)
    494515{
    495516    int rc = VINF_SUCCESS;
     
    539560            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    540561            /* Write the redundant grain directory entry to disk. */
    541             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     562            rc = RTFileWriteAt(pExtent->File,
     563                               VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
     564                               &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    542565            if (VBOX_FAILURE(rc))
    543566                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
     
    551574            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    552575            /* Write the grain directory entry to disk. */
    553             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     576            rc = RTFileWriteAt(pExtent->File,
     577                               VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
     578                               &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    554579            if (VBOX_FAILURE(rc))
    555580                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
     
    579604}
    580605
    581 static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr, char **ppszUnquoted, char **ppszNext)
     606static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr,
     607                             char **ppszUnquoted, char **ppszNext)
    582608{
    583609    char *pszQ;
     
    632658        if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
    633659        {
    634             /* Key matches, check if there is a '=' (preceded by whitespace). */
     660            /* Key matches, check for a '=' (preceded by whitespace). */
    635661            pszValue = pDescriptor->aLines[uStart] + cbKey;
    636662            while (*pszValue == ' ' || *pszValue == '\t')
     
    659685        if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
    660686        {
    661             /* Key matches, check if there is a '=' (preceded by whitespace). */
     687            /* Key matches, check for a '=' (preceded by whitespace). */
    662688            pszTmp = pDescriptor->aLines[uStart] + cbKey;
    663689            while (*pszTmp == ' ' || *pszTmp == '\t')
     
    715741    else
    716742    {
    717         /* Key doesn't exist, append it after the last entry in this category. */
     743        /* Key doesn't exist, append after the last entry in this category. */
    718744        if (!pszValue)
    719745        {
     
    765791    const char *pszValue;
    766792
    767     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue))
     793    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
     794                        &pszValue))
    768795        return VERR_VDI_VALUE_NOT_FOUND;
    769796    return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
     
    776803    char *pszValueUnquoted;
    777804
    778     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue))
     805    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
     806                        &pszValue))
    779807        return VERR_VDI_VALUE_NOT_FOUND;
    780808    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    793821    if (VBOX_FAILURE(rc))
    794822        return rc;
    795     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey, pszValueQuoted);
     823    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey,
     824                        pszValueQuoted);
    796825    RTStrFree(pszValueQuoted);
    797826    return rc;
    798827}
    799828
    800 static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor)
     829static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
     830                                   PVMDKDESCRIPTOR pDescriptor)
    801831{
    802832    unsigned uEntry = pDescriptor->uFirstExtent;
     
    807837
    808838    cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
    809     /* Move everything including the \0 in the entry marking the end of buffer. */
     839    /* Move everything including \0 in the entry marking the end of buffer. */
    810840    memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
    811841            pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
     
    902932    char *pszValueUnquoted;
    903933
    904     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
     934    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
     935                        &pszValue))
    905936        return VERR_VDI_VALUE_NOT_FOUND;
    906937    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    917948    char *pszValueUnquoted;
    918949
    919     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
     950    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
     951                        &pszValue))
    920952        return VERR_VDI_VALUE_NOT_FOUND;
    921953    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    933965    char *pszValueUnquoted;
    934966
    935     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
     967    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
     968                        &pszValue))
    936969        return VERR_VDI_VALUE_NOT_FOUND;
    937970    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    943976}
    944977
    945 static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, const char *pszVal)
     978static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     979                             const char *pszKey, const char *pszVal)
    946980{
    947981    int rc;
     
    956990    else
    957991        pszValQuoted = NULL;
    958     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValQuoted);
     992    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
     993                        pszValQuoted);
    959994    if (pszValQuoted)
    960995        RTStrFree(pszValQuoted);
     
    962997}
    963998
    964 static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, PCRTUUID pUuid)
     999static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     1000                              const char *pszKey, PCRTUUID pUuid)
    9651001{
    9661002    char *pszUuid;
     
    9691005    if (VBOX_FAILURE(rc))
    9701006        return rc;
    971     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszUuid);
     1007    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
     1008                        pszUuid);
    9721009    RTStrFree(pszUuid);
    9731010    return rc;
    9741011}
    9751012
    976 int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, uint32_t uValue)
     1013int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     1014                      const char *pszKey, uint32_t uValue)
    9771015{
    9781016    char *pszValue;
     
    9811019    if (VBOX_FAILURE(rc))
    9821020        return rc;
    983     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValue);
     1021    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
     1022                        pszValue);
    9841023    RTStrFree(pszValue);
    9851024    return rc;
    9861025}
    9871026
    988 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     1027static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
     1028                                    size_t cbDescData,
     1029                                    PVMDKDESCRIPTOR pDescriptor)
    9891030{
    9901031    int rc = VINF_SUCCESS;
     
    11011142}
    11021143
    1103 static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     1144static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
     1145                                   PCPDMMEDIAGEOMETRY pPCHSGeometry)
     1146{
     1147    int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1148                           VMDK_DDB_GEO_PCHS_CYLINDERS,
     1149                           pPCHSGeometry->cCylinders);
     1150    if (VBOX_FAILURE(rc))
     1151        return rc;
     1152    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1153                           VMDK_DDB_GEO_PCHS_HEADS,
     1154                           pPCHSGeometry->cHeads);
     1155    if (VBOX_FAILURE(rc))
     1156        return rc;
     1157    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1158                           VMDK_DDB_GEO_PCHS_SECTORS,
     1159                           pPCHSGeometry->cSectors);
     1160    return rc;
     1161}
     1162
     1163static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
     1164                                   PCPDMMEDIAGEOMETRY pLCHSGeometry)
     1165{
     1166    int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1167                           VMDK_DDB_GEO_LCHS_CYLINDERS,
     1168                           pLCHSGeometry->cCylinders);
     1169    if (VBOX_FAILURE(rc))
     1170        return rc;
     1171    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1172                           VMDK_DDB_GEO_LCHS_HEADS,
     1173                           pLCHSGeometry->cHeads);
     1174    if (VBOX_FAILURE(rc))
     1175        return rc;
     1176    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1177                           VMDK_DDB_GEO_LCHS_SECTORS,
     1178                           pLCHSGeometry->cSectors);
     1179    return rc;
     1180}
     1181
     1182static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
     1183                                size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
    11041184{
    11051185    int rc;
     
    11531233    char szBuf[9];
    11541234    RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
    1155     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "CID", szBuf);
    1156     if (VBOX_FAILURE(rc))
    1157         goto out;
    1158     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "parentCID", "ffffffff");
     1235    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
     1236                        "CID", szBuf);
     1237    if (VBOX_FAILURE(rc))
     1238        goto out;
     1239    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
     1240                        "parentCID", "ffffffff");
    11591241    if (VBOX_FAILURE(rc))
    11601242        goto out;
     
    11681250}
    11691251
    1170 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
     1252static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData,
     1253                               size_t cbDescData)
    11711254{
    11721255    int rc;
     
    11741257    unsigned uLine;
    11751258
    1176     rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData, &pImage->Descriptor);
     1259    rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
     1260                                  &pImage->Descriptor);
    11771261    if (VBOX_FAILURE(rc))
    11781262        return rc;
     
    13181402    }
    13191403
     1404    /* Determine PCHS geometry (autogenerate if necessary). */
    13201405    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1321                            "ddb.geometry.cylinders", &pImage->cCylinders);
    1322     if (VBOX_FAILURE(rc))
    1323         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
     1406                           VMDK_DDB_GEO_PCHS_CYLINDERS,
     1407                           &pImage->PCHSGeometry.cCylinders);
     1408    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1409        pImage->PCHSGeometry.cCylinders = 0;
     1410    else if (VBOX_FAILURE(rc))
     1411        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    13241412    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1325                            "ddb.geometry.heads", &pImage->cHeads);
    1326     if (VBOX_FAILURE(rc))
    1327         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
     1413                           VMDK_DDB_GEO_PCHS_HEADS,
     1414                           &pImage->PCHSGeometry.cHeads);
     1415    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1416        pImage->PCHSGeometry.cHeads = 0;
     1417    else if (VBOX_FAILURE(rc))
     1418        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    13281419    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1329                            "ddb.geometry.sectors", &pImage->cSectors);
    1330     if (VBOX_FAILURE(rc))
    1331         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
    1332     if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
    1333         pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
    1334     else
    1335         pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
     1420                           VMDK_DDB_GEO_PCHS_SECTORS,
     1421                           &pImage->PCHSGeometry.cSectors);
     1422    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1423        pImage->PCHSGeometry.cSectors = 0;
     1424    else if (VBOX_FAILURE(rc))
     1425        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1426    if (    pImage->PCHSGeometry.cCylinders == 0
     1427        ||  pImage->PCHSGeometry.cHeads == 0
     1428        ||  pImage->PCHSGeometry.cHeads > 16
     1429        ||  pImage->PCHSGeometry.cSectors == 0
     1430        ||  pImage->PCHSGeometry.cSectors > 63)
     1431    {
     1432        /* Mark PCHS geometry as not yet valid (can't do the calculation here
     1433         * as the total image size isn't known yet). */
     1434        pImage->PCHSGeometry.cCylinders = 0;
     1435        pImage->PCHSGeometry.cHeads = 16;
     1436        pImage->PCHSGeometry.cSectors = 63;
     1437    }
     1438
     1439    /* Determine LCHS geometry (set to 0 if not specified). */
     1440    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     1441                           VMDK_DDB_GEO_LCHS_CYLINDERS,
     1442                           &pImage->LCHSGeometry.cCylinders);
     1443    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1444        pImage->LCHSGeometry.cCylinders = 0;
     1445    else if (VBOX_FAILURE(rc))
     1446        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1447    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     1448                           VMDK_DDB_GEO_LCHS_HEADS,
     1449                           &pImage->LCHSGeometry.cHeads);
     1450    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1451        pImage->LCHSGeometry.cHeads = 0;
     1452    else if (VBOX_FAILURE(rc))
     1453        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1454    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     1455                           VMDK_DDB_GEO_LCHS_SECTORS,
     1456                           &pImage->LCHSGeometry.cSectors);
     1457    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1458        pImage->LCHSGeometry.cSectors = 0;
     1459    else if (VBOX_FAILURE(rc))
     1460        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1461    if (    pImage->LCHSGeometry.cCylinders == 0
     1462        ||  pImage->LCHSGeometry.cHeads == 0
     1463        ||  pImage->LCHSGeometry.cSectors == 0)
     1464    {
     1465        pImage->LCHSGeometry.cCylinders = 0;
     1466        pImage->LCHSGeometry.cHeads = 0;
     1467        pImage->LCHSGeometry.cSectors = 0;
     1468    }
    13361469
    13371470    /* Get image UUID. */
     
    13601493
    13611494    /* Get image modification UUID. */
    1362     rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, "ddb.uuid.modification",
     1495    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
     1496                            "ddb.uuid.modification",
    13631497                            &pImage->ModificationUuid);
    13641498    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     
    13751509                return rc;
    13761510            rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    1377                                     "ddb.uuid.modification", &pImage->ModificationUuid);
     1511                                    "ddb.uuid.modification",
     1512                                    &pImage->ModificationUuid);
    13781513            if (VBOX_FAILURE(rc))
    13791514                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
     
    17501885}
    17511886
    1752 static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, unsigned uOpenFlags)
     1887static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename,
     1888                         unsigned uOpenFlags)
    17531889{
    17541890    int rc = VINF_SUCCESS;
     
    18601996        }
    18611997
    1862         rc = vmdkParseDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc);
     1998        rc = vmdkParseDescriptor(pImage, pImage->pDescData,
     1999                                 pImage->cbDescAlloc);
    18632000        if (VBOX_FAILURE(rc))
    18642001            goto out;
     
    19242061                        goto out;
    19252062
    1926                     /* Mark the extent as unclean if opened in read-write mode. */
     2063                    /* Mark extent as unclean if opened in read-write mode. */
    19272064                    if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
    19282065                    {
     
    19562093    AssertRC(rc);
    19572094
     2095    /* Determine PCHS geometry if not set. */
     2096    if (pImage->PCHSGeometry.cCylinders == 0)
     2097    {
     2098        uint64_t cCylinders =   VMDK_BYTE2SECTOR(pImage->cbSize)
     2099                              / pImage->PCHSGeometry.cHeads
     2100                              / pImage->PCHSGeometry.cSectors;
     2101        pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
     2102        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     2103        {
     2104            rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
     2105            AssertRC(rc);
     2106        }
     2107    }
     2108
    19582109    /* Update the image metadata now in case has changed. */
    19592110    rc = vmdkFlushImage(pImage);
     
    20022153}
    20032154
    2004 static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
    2005 {
    2006     int rc;
    2007     uint64_t cSectorsPerGDE, cSectorsPerGD;
     2155static int vmdkCreateRawImage(PVMDKIMAGE pImage, const char *pszFilename,
     2156                              const PVBOXHDDRAW pRaw, uint64_t cbSize)
     2157{
     2158    int rc = VINF_SUCCESS;
    20082159    PVMDKEXTENT pExtent;
    20092160
    2010     pImage->uImageFlags = uImageFlags;
    2011     rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc, &pImage->Descriptor);
    2012     if (VBOX_FAILURE(rc))
    2013     {
    2014         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename);
    2015         goto out;
    2016     }
    2017 
    2018     if (    enmType == VD_IMAGE_TYPE_FIXED
    2019         ||  (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
    2020         ||  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
    2021     {
    2022         /* Fixed images and split images in general have a separate descriptor
    2023          * file. This is the more complicated case, as it requires setting up
    2024          * potentially more than one extent, including filename generation. */
    2025 
    2026         if (    enmType == VD_IMAGE_TYPE_FIXED
    2027             &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
    2028         {
    2029             PVBOXHDDRAW pRaw = (PVBOXHDDRAW)(void *)pszComment;
    2030             /* As the comment is misused, zap it so that no garbage comment
    2031              * is set below. */
    2032             pszComment = NULL;
    2033             if (pRaw->fRawDisk)
     2161    if (pRaw->fRawDisk)
     2162    {
     2163        /* Full raw disk access. This requires setting up a descriptor
     2164         * file and open the (flat) raw disk. */
     2165        rc = vmdkCreateExtents(pImage, 1);
     2166        if (VBOX_FAILURE(rc))
     2167            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     2168        pExtent = &pImage->pExtents[0];
     2169        rc = RTFileOpen(&pImage->File, pszFilename,
     2170                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     2171        if (VBOX_FAILURE(rc))
     2172            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
     2173
     2174        /* Set up basename for extent description. Cannot use StrDup. */
     2175        size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
     2176        char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
     2177        if (!pszBasename)
     2178            return VERR_NO_MEMORY;
     2179        memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
     2180        pExtent->pszBasename = pszBasename;
     2181        /* For raw disks the full name is identical to the base name. */
     2182        pExtent->pszFullname = RTStrDup(pszBasename);
     2183        if (!pExtent->pszFullname)
     2184            return VERR_NO_MEMORY;
     2185        pExtent->enmType = VMDKETYPE_FLAT;
     2186        pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     2187        pExtent->uSectorOffset = 0;
     2188        pExtent->enmAccess = VMDKACCESS_READWRITE;
     2189        pExtent->fMetaDirty = false;
     2190
     2191        /* Open flat image, the raw disk. */
     2192        rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2193                        RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2194        if (VBOX_FAILURE(rc))
     2195            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
     2196    }
     2197    else
     2198    {
     2199        /* Raw partition access. This requires setting up a descriptor
     2200         * file, write the partition information to a flat extent and
     2201         * open all the (flat) raw disk partitions. */
     2202
     2203        /* First pass over the partitions to determine how many
     2204         * extents we need. One partition can require up to 4 extents.
     2205         * One to skip over unpartitioned space, one for the
     2206         * partitioning data, one to skip over unpartitioned space
     2207         * and one for the partition data. */
     2208        unsigned cExtents = 0;
     2209        uint64_t uStart = 0;
     2210        for (unsigned i = 0; i < pRaw->cPartitions; i++)
     2211        {
     2212            PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
     2213            if (pPart->cbPartitionData)
    20342214            {
    2035                 /* Full raw disk access. This requires setting up a descriptor
    2036                  * file and open the (flat) raw disk. */
    2037                 rc = vmdkCreateExtents(pImage, 1);
    2038                 if (VBOX_FAILURE(rc))
    2039                 {
    2040                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
    2041                     goto out;
    2042                 }
    2043                 pExtent = &pImage->pExtents[0];
    2044                 rc = RTFileOpen(&pImage->File, pszFilename,
    2045                                 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    2046                 if (VBOX_FAILURE(rc))
    2047                 {
    2048                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
    2049                     goto out;
    2050                 }
    2051 
    2052                 /* Set up basename for extent description. Cannot use StrDup. */
    2053                 size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
    2054                 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2055                 if (!pszBasename)
    2056                 {
    2057                     rc = VERR_NO_MEMORY;
    2058                     goto out;
    2059                 }
    2060                 memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
    2061                 pExtent->pszBasename = pszBasename;
    2062                 /* For raw disks the full name is identical to the base name. */
    2063                 pExtent->pszFullname = RTStrDup(pszBasename);
    2064                 if (!pExtent->pszFullname)
    2065                 {
    2066                     rc = VERR_NO_MEMORY;
    2067                     goto out;
    2068                 }
    2069                 pExtent->enmType = VMDKETYPE_FLAT;
    2070                 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
    2071                 pExtent->uSectorOffset = 0;
    2072                 pExtent->enmAccess = VMDKACCESS_READWRITE;
    2073                 pExtent->fMetaDirty = false;
    2074 
    2075                 pImage->enmImageType = enmType;
    2076                 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "fullDevice");
    2077                 if (VBOX_FAILURE(rc))
    2078                 {
    2079                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
    2080                     goto out;
    2081                 }
    2082 
    2083                 /* Open flat image, the raw disk. */
    2084                 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2085                                 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2086                 if (VBOX_FAILURE(rc))
    2087                 {
    2088                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
    2089                     goto out;
    2090                 }
     2215                if (uStart > pPart->uPartitionDataStart)
     2216                    return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pszFilename);
     2217                else if (uStart != pPart->uPartitionDataStart)
     2218                    cExtents++;
     2219                uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
     2220                cExtents++;
    20912221            }
    2092             else
     2222            if (pPart->cbPartition)
    20932223            {
    2094                 /* Raw partition access. This requires setting up a descriptor
    2095                  * file, write the partition information to a flat extent and
    2096                  * open all the (flat) raw disk partitions. */
    2097 
    2098                 /* First pass over the partitions to determine how many
    2099                  * extents we need. One partition can require up to 4 extents.
    2100                  * One to skip over unpartitioned space, one for the
    2101                  * partitioning data, one to skip over unpartitioned space
    2102                  * and one for the partition data. */
    2103                 unsigned cExtents = 0;
    2104                 uint64_t uStart = 0;
    2105                 for (unsigned i = 0; i < pRaw->cPartitions; i++)
    2106                 {
    2107                     PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
    2108                     if (pPart->cbPartitionData)
    2109                     {
    2110                         if (uStart > pPart->uPartitionDataStart)
    2111                         {
    2112                             rc = vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pszFilename);
    2113                             goto out;
    2114                         } else if (uStart != pPart->uPartitionDataStart)
    2115                             cExtents++;
    2116                         uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
    2117                         cExtents++;
    2118                     }
    2119                     if (pPart->cbPartition)
    2120                     {
    2121                         if (uStart > pPart->uPartitionStart)
    2122                         {
    2123                             rc = vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pszFilename);
    2124                             goto out;
    2125                         } else if (uStart != pPart->uPartitionStart)
    2126                             cExtents++;
    2127                         uStart = pPart->uPartitionStart + pPart->cbPartition;
    2128                         cExtents++;
    2129                     }
    2130                 }
    2131                 /* Another extent for filling up the rest of the image. */
    2132                 if (uStart != cbSize)
     2224                if (uStart > pPart->uPartitionStart)
     2225                    return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pszFilename);
     2226                else if (uStart != pPart->uPartitionStart)
    21332227                    cExtents++;
    2134 
    2135                 rc = vmdkCreateExtents(pImage, cExtents);
    2136                 if (VBOX_FAILURE(rc))
    2137                 {
    2138                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
    2139                     goto out;
    2140                 }
    2141 
    2142                 rc = RTFileOpen(&pImage->File, pszFilename,
    2143                                 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    2144                 if (VBOX_FAILURE(rc))
    2145                 {
    2146                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
    2147                     goto out;
    2148                 }
    2149 
    2150                 /* Create base filename for the partition table extent. */
    2151                 /** @todo remove fixed buffer. */
    2152                 char pszPartition[1024];
    2153                 const char *pszBase = RTPathFilename(pszFilename);
    2154                 const char *pszExt = RTPathExt(pszBase);
    2155                 if (pszExt == NULL)
    2156                 {
    2157                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pszFilename);
    2158                     goto out;
    2159                 }
    2160                 memcpy(pszPartition, pszBase, pszExt - pszBase);
    2161                 memcpy(pszPartition + (pszExt - pszBase), "-pt", 3);
    2162                 memcpy(pszPartition + (pszExt - pszBase) + 3, pszExt, strlen(pszExt) + 1);
    2163 
    2164                 /* Second pass over the partitions, now define all extents. */
    2165                 uint64_t uPartOffset = 0;
    2166                 cExtents = 0;
    2167                 uStart = 0;
    2168                 for (unsigned i = 0; i < pRaw->cPartitions; i++)
    2169                 {
    2170                     PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
    2171                     if (pPart->cbPartitionData)
    2172                     {
    2173                         if (uStart != pPart->uPartitionDataStart)
    2174                         {
    2175                             pExtent = &pImage->pExtents[cExtents++];
    2176                             pExtent->pszBasename = NULL;
    2177                             pExtent->pszFullname = NULL;
    2178                             pExtent->enmType = VMDKETYPE_ZERO;
    2179                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart);
    2180                             pExtent->uSectorOffset = 0;
    2181                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2182                             pExtent->fMetaDirty = false;
    2183                         }
    2184                         uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
    2185                         pExtent = &pImage->pExtents[cExtents++];
    2186                         /* Set up basename for extent description. Cannot use StrDup. */
    2187                         size_t cbBasename = strlen(pszPartition) + 1;
    2188                         char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2189                         if (!pszBasename)
    2190                         {
    2191                             rc = VERR_NO_MEMORY;
    2192                             goto out;
    2193                         }
    2194                         memcpy(pszBasename, pszPartition, cbBasename);
    2195                         pExtent->pszBasename = pszBasename;
    2196 
    2197                         /* Set up full name for partition extent. */
    2198                         size_t cbDirname;
    2199                         char *pszDirname = RTStrDup(pImage->pszFilename);
    2200                         if (!pszDirname)
    2201                         {
    2202                             rc = VERR_NO_MEMORY;
    2203                             goto out;
    2204                         }
    2205                         RTPathStripFilename(pszDirname);
    2206                         cbDirname = strlen(pszDirname);
    2207                         char *pszFullname;
    2208                         rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
    2209                                           RTPATH_SLASH, pExtent->pszBasename);
    2210                         RTStrFree(pszDirname);
    2211                         if (VBOX_FAILURE(rc))
    2212                             goto out;
    2213                         pExtent->pszFullname = pszFullname;
    2214                         pExtent->enmType = VMDKETYPE_FLAT;
    2215                         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData);
    2216                         pExtent->uSectorOffset = uPartOffset;
    2217                         pExtent->enmAccess = VMDKACCESS_READWRITE;
    2218                         pExtent->fMetaDirty = false;
    2219 
    2220                         rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2221                                         RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    2222                         if (VBOX_FAILURE(rc))
    2223                         {
    2224                             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
    2225                             goto out;
    2226                         }
    2227                         rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uPartOffset), pPart->pvPartitionData, pPart->cbPartitionData, NULL);
    2228                         if (VBOX_FAILURE(rc))
    2229                         {
    2230                             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
    2231                             goto out;
    2232                         }
    2233                         uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData);
    2234                     }
    2235                     if (pPart->cbPartition)
    2236                     {
    2237                         if (uStart != pPart->uPartitionStart)
    2238                         {
    2239                             pExtent = &pImage->pExtents[cExtents++];
    2240                             pExtent->pszBasename = NULL;
    2241                             pExtent->pszFullname = NULL;
    2242                             pExtent->enmType = VMDKETYPE_ZERO;
    2243                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart);
    2244                             pExtent->uSectorOffset = 0;
    2245                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2246                             pExtent->fMetaDirty = false;
    2247                         }
    2248                         uStart = pPart->uPartitionStart + pPart->cbPartition;
    2249                         pExtent = &pImage->pExtents[cExtents++];
    2250                         if (pPart->pszRawDevice)
    2251                         {
    2252                             /* Set up basename for extent description. Cannot use StrDup. */
    2253                             size_t cbBasename = strlen(pPart->pszRawDevice) + 1;
    2254                             char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2255                             if (!pszBasename)
    2256                             {
    2257                                 rc = VERR_NO_MEMORY;
    2258                                 goto out;
    2259                             }
    2260                             memcpy(pszBasename, pPart->pszRawDevice, cbBasename);
    2261                             pExtent->pszBasename = pszBasename;
    2262                             /* For raw disks the full name is identical to the base name. */
    2263                             pExtent->pszFullname = RTStrDup(pszBasename);
    2264                             if (!pExtent->pszFullname)
    2265                             {
    2266                                 rc = VERR_NO_MEMORY;
    2267                                 goto out;
    2268                             }
    2269                             pExtent->enmType = VMDKETYPE_FLAT;
    2270                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
    2271                             pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset);
    2272                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2273                             pExtent->fMetaDirty = false;
    2274 
    2275                             rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2276                                             RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2277                             if (VBOX_FAILURE(rc))
    2278                             {
    2279                                 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
    2280                                 goto out;
    2281                             }
    2282                         }
    2283                         else
    2284                         {
    2285                             pExtent->pszBasename = NULL;
    2286                             pExtent->pszFullname = NULL;
    2287                             pExtent->enmType = VMDKETYPE_ZERO;
    2288                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
    2289                             pExtent->uSectorOffset = 0;
    2290                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2291                             pExtent->fMetaDirty = false;
    2292                         }
    2293                     }
    2294                 }
    2295                 /* Another extent for filling up the rest of the image. */
    2296                 if (uStart != cbSize)
     2228                uStart = pPart->uPartitionStart + pPart->cbPartition;
     2229                cExtents++;
     2230            }
     2231        }
     2232        /* Another extent for filling up the rest of the image. */
     2233        if (uStart != cbSize)
     2234            cExtents++;
     2235
     2236        rc = vmdkCreateExtents(pImage, cExtents);
     2237        if (VBOX_FAILURE(rc))
     2238            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     2239
     2240        rc = RTFileOpen(&pImage->File, pszFilename,
     2241                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     2242        if (VBOX_FAILURE(rc))
     2243            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
     2244
     2245        /* Create base filename for the partition table extent. */
     2246        /** @todo remove fixed buffer without creating memory leaks. */
     2247        char pszPartition[1024];
     2248        const char *pszBase = RTPathFilename(pszFilename);
     2249        const char *pszExt = RTPathExt(pszBase);
     2250        if (pszExt == NULL)
     2251            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pszFilename);
     2252        char *pszBaseBase = RTStrDup(pszBase);
     2253        if (!pszBaseBase)
     2254            return VERR_NO_MEMORY;
     2255        RTPathStripExt(pszBaseBase);
     2256        RTStrPrintf(pszPartition, sizeof(pszPartition), "%s-pt%s",
     2257                    pszBaseBase, pszExt);
     2258        RTStrFree(pszBaseBase);
     2259
     2260        /* Second pass over the partitions, now define all extents. */
     2261        uint64_t uPartOffset = 0;
     2262        cExtents = 0;
     2263        uStart = 0;
     2264        for (unsigned i = 0; i < pRaw->cPartitions; i++)
     2265        {
     2266            PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
     2267            if (pPart->cbPartitionData)
     2268            {
     2269                if (uStart != pPart->uPartitionDataStart)
    22972270                {
    22982271                    pExtent = &pImage->pExtents[cExtents++];
     
    23002273                    pExtent->pszFullname = NULL;
    23012274                    pExtent->enmType = VMDKETYPE_ZERO;
    2302                     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart);
     2275                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart);
    23032276                    pExtent->uSectorOffset = 0;
    23042277                    pExtent->enmAccess = VMDKACCESS_READWRITE;
    23052278                    pExtent->fMetaDirty = false;
    23062279                }
    2307 
    2308                 pImage->enmImageType = enmType;
    2309                 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "partitionedDevice");
     2280                uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
     2281                pExtent = &pImage->pExtents[cExtents++];
     2282                /* Set up basename for extent description. Can't use StrDup. */
     2283                size_t cbBasename = strlen(pszPartition) + 1;
     2284                char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
     2285                if (!pszBasename)
     2286                    return VERR_NO_MEMORY;
     2287                memcpy(pszBasename, pszPartition, cbBasename);
     2288                pExtent->pszBasename = pszBasename;
     2289
     2290                /* Set up full name for partition extent. */
     2291                size_t cbDirname;
     2292                char *pszDirname = RTStrDup(pImage->pszFilename);
     2293                if (!pszDirname)
     2294                    return VERR_NO_MEMORY;
     2295                RTPathStripFilename(pszDirname);
     2296                cbDirname = strlen(pszDirname);
     2297                char *pszFullname;
     2298                rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
     2299                                  RTPATH_SLASH, pExtent->pszBasename);
     2300                RTStrFree(pszDirname);
    23102301                if (VBOX_FAILURE(rc))
     2302                    return rc;
     2303                pExtent->pszFullname = pszFullname;
     2304                pExtent->enmType = VMDKETYPE_FLAT;
     2305                pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData);
     2306                pExtent->uSectorOffset = uPartOffset;
     2307                pExtent->enmAccess = VMDKACCESS_READWRITE;
     2308                pExtent->fMetaDirty = false;
     2309
     2310                rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2311                                RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
     2312                if (VBOX_FAILURE(rc))
     2313                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
     2314                rc = RTFileWriteAt(pExtent->File,
     2315                                   VMDK_SECTOR2BYTE(uPartOffset),
     2316                                   pPart->pvPartitionData,
     2317                                   pPart->cbPartitionData, NULL);
     2318                if (VBOX_FAILURE(rc))
     2319                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
     2320                uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData);
     2321            }
     2322            if (pPart->cbPartition)
     2323            {
     2324                if (uStart != pPart->uPartitionStart)
    23112325                {
    2312                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
    2313                     goto out;
     2326                    pExtent = &pImage->pExtents[cExtents++];
     2327                    pExtent->pszBasename = NULL;
     2328                    pExtent->pszFullname = NULL;
     2329                    pExtent->enmType = VMDKETYPE_ZERO;
     2330                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart);
     2331                    pExtent->uSectorOffset = 0;
     2332                    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2333                    pExtent->fMetaDirty = false;
     2334                }
     2335                uStart = pPart->uPartitionStart + pPart->cbPartition;
     2336                pExtent = &pImage->pExtents[cExtents++];
     2337                if (pPart->pszRawDevice)
     2338                {
     2339                    /* Set up basename for extent descr. Can't use StrDup. */
     2340                    size_t cbBasename = strlen(pPart->pszRawDevice) + 1;
     2341                    char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
     2342                    if (!pszBasename)
     2343                        return VERR_NO_MEMORY;
     2344                    memcpy(pszBasename, pPart->pszRawDevice, cbBasename);
     2345                    pExtent->pszBasename = pszBasename;
     2346                    /* For raw disks full name is identical to base name. */
     2347                    pExtent->pszFullname = RTStrDup(pszBasename);
     2348                    if (!pExtent->pszFullname)
     2349                        return VERR_NO_MEMORY;
     2350                    pExtent->enmType = VMDKETYPE_FLAT;
     2351                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
     2352                    pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset);
     2353                    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2354                    pExtent->fMetaDirty = false;
     2355
     2356                    rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2357                                    RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2358                    if (VBOX_FAILURE(rc))
     2359                        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
     2360                }
     2361                else
     2362                {
     2363                    pExtent->pszBasename = NULL;
     2364                    pExtent->pszFullname = NULL;
     2365                    pExtent->enmType = VMDKETYPE_ZERO;
     2366                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
     2367                    pExtent->uSectorOffset = 0;
     2368                    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2369                    pExtent->fMetaDirty = false;
    23142370                }
    23152371            }
    23162372        }
    2317         else
    2318         {
    2319             rc = VERR_NOT_IMPLEMENTED;
    2320             goto out;
    2321         }
    2322     }
    2323     else
    2324     {
    2325         /* Normal (growing) image which is not split into pieces. */
    2326         rc = vmdkCreateExtents(pImage, 1);
    2327         if (VBOX_FAILURE(rc))
    2328         {
    2329             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
    2330             goto out;
    2331         }
    2332         pExtent = &pImage->pExtents[0];
    2333         pImage->File = NIL_RTFILE;
    2334         rc = RTFileOpen(&pExtent->File, pszFilename,
     2373        /* Another extent for filling up the rest of the image. */
     2374        if (uStart != cbSize)
     2375        {
     2376            pExtent = &pImage->pExtents[cExtents++];
     2377            pExtent->pszBasename = NULL;
     2378            pExtent->pszFullname = NULL;
     2379            pExtent->enmType = VMDKETYPE_ZERO;
     2380            pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart);
     2381            pExtent->uSectorOffset = 0;
     2382            pExtent->enmAccess = VMDKACCESS_READWRITE;
     2383            pExtent->fMetaDirty = false;
     2384        }
     2385    }
     2386
     2387    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
     2388                            pRaw->fRawDisk ?
     2389                            "fullDevice" : "partitionedDevice");
     2390    if (VBOX_FAILURE(rc))
     2391        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
     2392    return rc;
     2393}
     2394
     2395static int vmdkCreateRegularImage(PVMDKIMAGE pImage, const char *pszFilename,
     2396                                  VDIMAGETYPE enmType, uint64_t cbSize,
     2397                                  unsigned uImageFlags,
     2398                                  PFNVMPROGRESS pfnProgress, void *pvUser,
     2399                                  unsigned uPercentStart,
     2400                                  unsigned uPercentSpan)
     2401{
     2402    int rc = VINF_SUCCESS;
     2403    unsigned cExtents = 1;
     2404    uint64_t cbOffset = 0;
     2405    uint64_t cbRemaining = cbSize;
     2406
     2407    if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
     2408    {
     2409        cExtents = cbSize / VMDK_2G_SPLIT_SIZE;
     2410        /* Do proper extent computation: need one smaller extent if the total
     2411         * size isn't evenly divisible by the split size. */
     2412        if (cbSize % VMDK_2G_SPLIT_SIZE)
     2413            cExtents++;
     2414    }
     2415    rc = vmdkCreateExtents(pImage, cExtents);
     2416    if (VBOX_FAILURE(rc))
     2417        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     2418
     2419    /* Basename strings needed for constructing the extent names. */
     2420    char *pszBasenameSubstr = RTPathFilename(pszFilename);
     2421    Assert(pszBasenameSubstr);
     2422    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     2423
     2424    /* Create searate descriptor file if necessary. */
     2425    if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED)
     2426    {
     2427        rc = RTFileOpen(&pImage->File, pszFilename,
    23352428                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    23362429        if (VBOX_FAILURE(rc))
    2337         {
    2338             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
    2339             goto out;
    2340         }
    2341 
    2342         /* Set up basename for extent description. Cannot use StrDup, as it is
    2343          * not guaranteed that the memory can be freed with RTMemTmpFree, which
    2344          * must be used as in other code paths StrDup is not usable. */
    2345         char *pszBasenameSubstr = RTPathFilename(pszFilename);
    2346         Assert(pszBasenameSubstr);
    2347         size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    2348         char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
    2349         if (!pszBasename)
    2350         {
    2351             rc = VERR_NO_MEMORY;
    2352             goto out;
    2353         }
    2354         memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    2355         pExtent->pszBasename = pszBasename;
    2356         pExtent->pszFullname = RTStrDup(pszFilename);
    2357         if (!pExtent->pszFullname)
    2358         {
    2359             rc = VERR_NO_MEMORY;
    2360             goto out;
    2361         }
    2362         pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
    2363         pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, 65536));
    2364         pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
    2365         pExtent->uDescriptorSector = 1;
    2366         pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
    2367         pExtent->cGTEntries = 512;
    2368         cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    2369         pExtent->cSectorsPerGDE = cSectorsPerGDE;
    2370         pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    2371         cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     2430            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pszFilename);
     2431        pImage->pszFilename = RTStrDup(pszFilename);
     2432    }
     2433    else
     2434        pImage->File = NIL_RTFILE;
     2435
     2436    /* Set up all extents. */
     2437    for (unsigned i = 0; i < cExtents; i++)
     2438    {
     2439        PVMDKEXTENT pExtent = &pImage->pExtents[i];
     2440        uint64_t cbExtent = cbRemaining;
     2441
     2442        /* Set up fullname/basename for extent description. Cannot use StrDup
     2443         * for basename, as it is not guaranteed that the memory can be freed
     2444         * with RTMemTmpFree, which must be used as in other code paths
     2445         * StrDup is not usable. */
     2446        if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED)
     2447        {
     2448            char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
     2449            if (!pszBasename)
     2450                return VERR_NO_MEMORY;
     2451            memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
     2452            pExtent->pszBasename = pszBasename;
     2453        }
     2454        else
     2455        {
     2456            char *pszBasenameExt = RTPathExt(pszBasenameSubstr);
     2457            char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
     2458            RTPathStripExt(pszBasenameBase);
     2459            char *pszTmp;
     2460            size_t cbTmp;
     2461            if (enmType == VD_IMAGE_TYPE_FIXED)
     2462            {
     2463                if (cExtents == 1)
     2464                    rc = RTStrAPrintf(&pszTmp, "%s-flat%s", pszBasenameBase,
     2465                                      pszBasenameExt);
     2466                else
     2467                    rc = RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
     2468                                      i+1, pszBasenameExt);
     2469            }
     2470            else
     2471                rc = RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, i+1,
     2472                                  pszBasenameExt);
     2473            RTStrFree(pszBasenameBase);
     2474            if (VBOX_FAILURE(rc))
     2475                return rc;
     2476            cbTmp = strlen(pszTmp) + 1;
     2477            char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
     2478            if (!pszBasename)
     2479                return VERR_NO_MEMORY;
     2480            memcpy(pszBasename, pszTmp, cbTmp);
     2481            RTStrFree(pszTmp);
     2482            pExtent->pszBasename = pszBasename;
     2483            cbExtent = RT_MIN(cbRemaining, VMDK_2G_SPLIT_SIZE);
     2484        }
     2485        char *pszBasedirectory = RTStrDup(pszFilename);
     2486        RTPathStripFilename(pszBasedirectory);
     2487        char *pszFN;
     2488        rc = RTStrAPrintf(&pszFN, "%s%c%s", pszBasedirectory, RTPATH_SLASH,
     2489                          pExtent->pszBasename);
     2490        RTStrFree(pszBasedirectory);
     2491        if (VBOX_FAILURE(rc))
     2492            return rc;
     2493        pExtent->pszFullname = pszFN;
     2494
     2495        /* Create file for extent. */
     2496        rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2497                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     2498        if (VBOX_FAILURE(rc))
     2499            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
     2500        if (enmType == VD_IMAGE_TYPE_FIXED)
     2501        {
     2502            rc = RTFileSetSize(pExtent->File, cbExtent);
     2503            if (VBOX_FAILURE(rc))
     2504                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
     2505        }
     2506
     2507        /* Place descriptor file information (where integrated). */
     2508        if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED)
     2509        {
     2510            pExtent->uDescriptorSector = 1;
     2511            pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
     2512            /* The descriptor is part of the (only) extent. */
     2513            pExtent->pDescData = pImage->pDescData;
     2514            pImage->pDescData = NULL;
     2515        }
     2516
     2517        if (enmType == VD_IMAGE_TYPE_NORMAL)
     2518        {
     2519            uint64_t cSectorsPerGDE, cSectorsPerGD;
     2520            pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     2521            pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbExtent, 65536));
     2522            pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
     2523            pExtent->cGTEntries = 512;
     2524            cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     2525            pExtent->cSectorsPerGDE = cSectorsPerGDE;
     2526            pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     2527            cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     2528        }
     2529        else
     2530            pExtent->enmType = VMDKETYPE_FLAT;
     2531
    23722532        pExtent->enmAccess = VMDKACCESS_READWRITE;
    23732533        pExtent->fUncleanShutdown = true;
    2374         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
    2375         pExtent->uSectorOffset = 0;
     2534        pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbExtent);
     2535        pExtent->uSectorOffset = VMDK_BYTE2SECTOR(cbOffset);
    23762536        pExtent->fMetaDirty = true;
    23772537
    2378         rc = vmdkCreateGrainDirectory(pExtent, pExtent->uDescriptorSector + pExtent->cDescriptorSectors, true);
    2379         if (VBOX_FAILURE(rc))
    2380         {
    2381             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pszFilename);
    2382             goto out;
    2383         }
    2384 
    2385         pImage->enmImageType = enmType;
    2386         rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "monolithicSparse");
    2387         if (VBOX_FAILURE(rc))
    2388         {
    2389             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
    2390             goto out;
    2391         }
    2392 
    2393         /* The descriptor is part of the extent, move info to extent. */
    2394         pExtent->pDescData = pImage->pDescData;
    2395         pImage->pDescData = NULL;
    2396     }
    2397 
     2538        if (enmType == VD_IMAGE_TYPE_NORMAL)
     2539        {
     2540            rc = vmdkCreateGrainDirectory(pExtent,
     2541                                            pExtent->uDescriptorSector
     2542                                          + pExtent->cDescriptorSectors,
     2543                                          true);
     2544            if (VBOX_FAILURE(rc))
     2545                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
     2546        }
     2547
     2548        if (VBOX_SUCCESS(rc) && pfnProgress)
     2549            pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2550                        i * uPercentSpan / cExtents + uPercentStart,
     2551                        pvUser);
     2552
     2553        cbRemaining -= cbExtent;
     2554        cbOffset += cbExtent;
     2555    }
     2556
     2557    const char *pszDescType = NULL;
     2558    if (enmType == VD_IMAGE_TYPE_FIXED)
     2559    {
     2560        pszDescType =   (cExtents == 1)
     2561                      ? "monolithicFlat" : "twoGbMaxExtentFlat";
     2562    }
     2563    else if (enmType == VD_IMAGE_TYPE_NORMAL)
     2564    {
     2565        pszDescType =   (cExtents == 1)
     2566                      ? "monolithicSparse" : "twoGbMaxExtentSparse";
     2567    }
     2568    else
     2569        AssertMsgFailed(("invalid image type %d\n", enmType));
     2570    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
     2571                            pszDescType);
     2572    if (VBOX_FAILURE(rc))
     2573        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
     2574    return rc;
     2575}
     2576
     2577static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename,
     2578                           VDIMAGETYPE enmType, uint64_t cbSize,
     2579                           unsigned uImageFlags, const char *pszComment,
     2580                           PCPDMMEDIAGEOMETRY pPCHSGeometry,
     2581                           PCPDMMEDIAGEOMETRY pLCHSGeometry,
     2582                           PFNVMPROGRESS pfnProgress, void *pvUser,
     2583                           unsigned uPercentStart, unsigned uPercentSpan)
     2584{
     2585    int rc;
     2586
     2587    pImage->uImageFlags = uImageFlags;
     2588    rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
     2589                              &pImage->Descriptor);
     2590    if (VBOX_FAILURE(rc))
     2591    {
     2592        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename);
     2593        goto out;
     2594    }
     2595
     2596    if (    enmType == VD_IMAGE_TYPE_FIXED
     2597        &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
     2598    {
     2599        /* Raw disk image (includes raw partition). */
     2600        const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
     2601        /* As the comment is misused, zap it so that no garbage comment
     2602         * is set below. */
     2603        pszComment = NULL;
     2604        rc = vmdkCreateRawImage(pImage, pszFilename, pRaw, cbSize);
     2605    }
     2606    else if (   enmType == VD_IMAGE_TYPE_FIXED
     2607             || enmType == VD_IMAGE_TYPE_NORMAL)
     2608    {
     2609        /* Regular fixed or sparse image (monolithic or split). */
     2610        rc = vmdkCreateRegularImage(pImage, pszFilename, enmType, cbSize,
     2611                                    uImageFlags, pfnProgress, pvUser,
     2612                                    uPercentStart, uPercentSpan * 95 / 100);
     2613    }
     2614    else
     2615    {
     2616        /* Unknown/invalid image type. */
     2617        rc = VERR_NOT_IMPLEMENTED;
     2618    }
     2619
     2620    if (VBOX_FAILURE(rc))
     2621        goto out;
     2622
     2623    if (VBOX_SUCCESS(rc) && pfnProgress)
     2624        pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2625                    uPercentStart + uPercentSpan * 98 / 100, pvUser);
     2626
     2627    pImage->enmImageType = enmType;
    23982628    pImage->cbSize = cbSize;
    2399     if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
    2400         pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
    2401     else
    2402         pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
    24032629
    24042630    for (unsigned i = 0; i < pImage->cExtents; i++)
    24052631    {
    2406         pExtent = &pImage->pExtents[i];
     2632        PVMDKEXTENT pExtent = &pImage->pExtents[i];
    24072633
    24082634        rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
     
    24172643    vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
    24182644
    2419     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    2420                            "ddb.geometry.cylinders", cCylinders);
    2421     if (VBOX_FAILURE(rc))
    2422         goto out;
    2423     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    2424                            "ddb.geometry.heads", cHeads);
    2425     if (VBOX_FAILURE(rc))
    2426         goto out;
    2427     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    2428                            "ddb.geometry.sectors", cSectors);
    2429     if (VBOX_FAILURE(rc))
    2430         goto out;
    2431 
    2432     pImage->cCylinders = cCylinders;
    2433     pImage->cHeads = cHeads;
    2434     pImage->cSectors = cSectors;
     2645    if (    pPCHSGeometry->cCylinders == 0
     2646        ||  pPCHSGeometry->cHeads == 0
     2647        ||  pPCHSGeometry->cSectors == 0)
     2648    {
     2649        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
     2650        if (VBOX_FAILURE(rc))
     2651            goto out;
     2652    }
     2653    if (    pLCHSGeometry->cCylinders == 0
     2654        ||  pLCHSGeometry->cHeads == 0
     2655        ||  pLCHSGeometry->cSectors == 0)
     2656    {
     2657        rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
     2658        if (VBOX_FAILURE(rc))
     2659            goto out;
     2660    }
     2661
     2662    pImage->LCHSGeometry = *pLCHSGeometry;
     2663    pImage->PCHSGeometry = *pPCHSGeometry;
    24352664
    24362665    rc = RTUuidCreate(&pImage->ImageUuid);
     
    24542683    RTUuidClear(&pImage->ModificationUuid);
    24552684    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    2456                             "ddb.uuid.modification", &pImage->ModificationUuid);
     2685                            "ddb.uuid.modification",
     2686                            &pImage->ModificationUuid);
    24572687    if (VBOX_FAILURE(rc))
    24582688    {
     
    24722702    }
    24732703
     2704    if (VBOX_SUCCESS(rc) && pfnProgress)
     2705        pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2706                    uPercentStart + uPercentSpan * 99 / 100, pvUser);
     2707
    24742708    rc = vmdkFlushImage(pImage);
    24752709
    24762710out:
     2711    if (VBOX_SUCCESS(rc) && pfnProgress)
     2712        pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2713                    uPercentStart + uPercentSpan, pvUser);
     2714
    24772715    if (VBOX_FAILURE(rc))
    24782716        vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
     
    25872825            case VMDKETYPE_FLAT:
    25882826                /** @todo implement proper path absolute check. */
    2589                 if (pExtent->File != NIL_RTFILE && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) && !(pExtent->pszBasename[0] == RTPATH_SLASH))
     2827                if (   pExtent->File != NIL_RTFILE
     2828                    && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     2829                    && !(pExtent->pszBasename[0] == RTPATH_SLASH))
    25902830                    rc = RTFileFlush(pExtent->File);
    25912831                break;
     
    26032843}
    26042844
    2605 static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector, PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
     2845static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector,
     2846                          PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
    26062847{
    26072848    PVMDKEXTENT pExtent = NULL;
     
    26272868}
    26282869
    2629 static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector, unsigned uExtent)
     2870static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector,
     2871                                unsigned uExtent)
    26302872{
    26312873    /** @todo this hash function is quite simple, maybe use a better one which
     
    26882930 */
    26892931static int vmdkAllocGrain(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
    2690                           uint64_t uSector, const void *pvBuf, uint64_t cbWrite)
     2932                          uint64_t uSector, const void *pvBuf,
     2933                          uint64_t cbWrite)
    26912934{
    26922935    uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
     
    27222965         * should be acceptable. */
    27232966        memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
    2724         for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++)
    2725         {
    2726             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
     2967        for (unsigned i = 0;
     2968             i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
     2969             i++)
     2970        {
     2971            rc = RTFileWriteAt(pExtent->File,
     2972                               VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
     2973                               aGTDataTmp, sizeof(aGTDataTmp), NULL);
    27272974            if (VBOX_FAILURE(rc))
    27282975                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
     
    27392986             * bit slower. But as this is a pretty infrequently occurring case
    27402987             * it should be acceptable. */
    2741             for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++)
     2988            for (unsigned i = 0;
     2989                 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
     2990                 i++)
    27422991            {
    2743                 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
     2992                rc = RTFileWriteAt(pExtent->File,
     2993                                   VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
     2994                                   aGTDataTmp, sizeof(aGTDataTmp), NULL);
    27442995                if (VBOX_FAILURE(rc))
    27452996                    return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
     
    27523003         * some unused sectors in the extent. */
    27533004        uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
    2754         rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     3005        rc = RTFileWriteAt(pExtent->File,
     3006                           VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
     3007                           &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    27553008        if (VBOX_FAILURE(rc))
    27563009            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
     
    27583011        {
    27593012            uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
    2760             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
     3013            rc = RTFileWriteAt(pExtent->File,
     3014                               VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
     3015                               &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
    27613016            if (VBOX_FAILURE(rc))
    27623017                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
     
    28323087}
    28333088
    2834 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData)
     3089
     3090static int vmdkCheckIfValid(const char *pszFilename)
     3091{
     3092    int rc = VINF_SUCCESS;
     3093    PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     3094    if (!pImage)
     3095    {
     3096        rc = VERR_NO_MEMORY;
     3097        goto out;
     3098    }
     3099    pImage->pszFilename = pszFilename;
     3100    pImage->File = NIL_RTFILE;
     3101    pImage->pExtents = NULL;
     3102    pImage->pGTCache = NULL;
     3103    pImage->pDescData = NULL;
     3104    pImage->pfnError = NULL;
     3105    pImage->pvErrorUser = NULL;
     3106    /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
     3107     * much as possible in vmdkOpenImage. */
     3108    rc = vmdkOpenImage(pImage, pszFilename,
     3109                       VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
     3110    vmdkFreeImage(pImage, false);
     3111
     3112out:
     3113    return rc;
     3114}
     3115
     3116static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
     3117                    PFNVDERROR pfnError, void *pvErrorUser,
     3118                    void **ppvBackendData)
    28353119{
    28363120    int rc;
     
    28713155static int vmdkCreate(const char *pszFilename, VDIMAGETYPE enmType,
    28723156                      uint64_t cbSize, unsigned uImageFlags,
    2873                       const char *pszComment, uint32_t cCylinders,
    2874                       uint32_t cHeads, uint32_t cSectors, unsigned uOpenFlags,
    2875                       PFNVMPROGRESS pfnProgress, void *pvUser,
    2876                       PFNVDERROR pfnError, void *pvErrorUser,
    2877                       void **ppvBackendData)
     3157                      const char *pszComment,
     3158                      PCPDMMEDIAGEOMETRY pPCHSGeometry,
     3159                      PCPDMMEDIAGEOMETRY pLCHSGeometry,
     3160                      unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     3161                      void *pvUser, unsigned uPercentStart,
     3162                      unsigned uPercentSpan, PFNVDERROR pfnError,
     3163                      void *pvErrorUser, void **ppvBackendData)
    28783164{
    28793165    int rc;
     
    29113197
    29123198    rc = vmdkCreateImage(pImage, pszFilename, enmType, cbSize, uImageFlags,
    2913                          pszComment, cCylinders, cHeads, cSectors);
     3199                         pszComment, pPCHSGeometry, pLCHSGeometry,
     3200                         pfnProgress, pvUser, uPercentStart, uPercentSpan);
    29143201    if (VBOX_SUCCESS(rc))
    29153202    {
     
    29273214
    29283215out:
    2929     /** @todo implement meaningful progress stuff (especially for fixed images). */
    2930     if (    VBOX_SUCCESS(rc)
    2931         &&  pfnProgress)
    2932         pfnProgress(NULL /* WARNING! pVM=NULL  */, 100, pvUser);
    2933 
    29343216    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
    29353217    return rc;
     3218}
     3219
     3220static int vmdkRename(void *pBackendData, const char *pszFilename)
     3221{
     3222    return VERR_NOT_IMPLEMENTED;
    29363223}
    29373224
     
    29503237}
    29513238
    2952 static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf, size_t cbRead, size_t *pcbActuallyRead)
     3239static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
     3240                    size_t cbRead, size_t *pcbActuallyRead)
    29533241{
    29543242    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    30043292            break;
    30053293        case VMDKETYPE_FLAT:
    3006             rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel),
     3294            rc = RTFileReadAt(pExtent->File,
     3295                              VMDK_SECTOR2BYTE(uSectorExtentRel),
    30073296                              pvBuf, cbRead, NULL);
    30083297            break;
     
    30173306}
    30183307
    3019 static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, size_t cbWrite, size_t *pcbWriteProcess, size_t *pcbPreRead, size_t *pcbPostRead)
     3308static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
     3309                     size_t cbWrite, size_t *pcbWriteProcess,
     3310                     size_t *pcbPreRead, size_t *pcbPostRead)
    30203311{
    30213312    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    31003391            /* Clip write range to remain in this extent. */
    31013392            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    3102             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel), pvBuf, cbWrite, NULL);
     3393            rc = RTFileWriteAt(pExtent->File,
     3394                               VMDK_SECTOR2BYTE(uSectorExtentRel),
     3395                               pvBuf, cbWrite, NULL);
    31033396            break;
    31043397        case VMDKETYPE_ZERO:
     
    31233416}
    31243417
     3418static unsigned vmdkGetVersion(void *pBackendData)
     3419{
     3420    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3421
     3422    Assert(pImage);
     3423
     3424    if (pImage)
     3425        return VMDK_IMAGE_VERSION;
     3426    else
     3427        return 0;
     3428}
     3429
    31253430static int vmdkGetImageType(void *pBackendData, PVDIMAGETYPE penmImageType)
    31263431{
     
    31513456}
    31523457
    3153 static int vmdkGetGeometry(void *pBackendData, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors)
     3458static uint64_t vmdkGetFileSize(void *pBackendData)
     3459{
     3460    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3461
     3462    Assert(pImage);
     3463
     3464    if (pImage)
     3465    {
     3466        int rc;
     3467        uint64_t cbFile, cb = 0;
     3468        if (pImage->File != NIL_RTFILE)
     3469        {
     3470            rc = RTFileGetSize(pImage->File, &cbFile);
     3471            if (VBOX_SUCCESS(rc))
     3472                cb += cbFile;
     3473            for (unsigned i = 0; i <= pImage->cExtents; i++)
     3474            {
     3475                rc = RTFileGetSize(pImage->File, &cbFile);
     3476                if (VBOX_SUCCESS(rc))
     3477                    cb += cbFile;
     3478            }
     3479        }
     3480        return cb;
     3481    }
     3482    else
     3483        return 0;
     3484}
     3485
     3486static int vmdkGetPCHSGeometry(void *pBackendData,
     3487                               PPDMMEDIAGEOMETRY pPCHSGeometry)
    31543488{
    31553489    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    31603494    if (pImage)
    31613495    {
    3162         if (pImage->cCylinders)
    3163         {
    3164             *pcCylinders = pImage->cCylinders;
    3165             *pcHeads = pImage->cHeads;
    3166             *pcSectors = pImage->cSectors;
     3496        if (pImage->PCHSGeometry.cCylinders)
     3497        {
     3498            *pPCHSGeometry = pImage->PCHSGeometry;
    31673499            rc = VINF_SUCCESS;
    31683500        }
     
    31733505        rc = VERR_VDI_NOT_OPENED;
    31743506    LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc,
    3175              pImage->cCylinders, pImage->cHeads, pImage->cSectors));
    3176     return rc;
    3177 }
    3178 
    3179 static int vmdkSetGeometry(void *pBackendData, unsigned cCylinders, unsigned cHeads, unsigned cSectors)
     3507             pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors));
     3508    return rc;
     3509}
     3510
     3511static int vmdkSetPCHSGeometry(void *pBackendData,
     3512                               PCPDMMEDIAGEOMETRY pPCHSGeometry)
    31803513{
    31813514    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    31913524            goto out;
    31923525        }
    3193         rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    3194                                "ddb.geometry.cylinders", cCylinders);
     3526        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    31953527        if (VBOX_FAILURE(rc))
    31963528            goto out;
    3197         rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    3198                                "ddb.geometry.heads", cHeads);
     3529
     3530        pImage->PCHSGeometry = *pPCHSGeometry;
     3531        rc = VINF_SUCCESS;
     3532    }
     3533    else
     3534        rc = VERR_VDI_NOT_OPENED;
     3535
     3536out:
     3537    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     3538    return rc;
     3539}
     3540
     3541static int vmdkGetLCHSGeometry(void *pBackendData,
     3542                               PPDMMEDIAGEOMETRY pLCHSGeometry)
     3543{
     3544    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3545    int rc;
     3546
     3547    Assert(pImage);
     3548
     3549    if (pImage)
     3550    {
     3551        if (pImage->LCHSGeometry.cCylinders)
     3552        {
     3553            *pLCHSGeometry = pImage->LCHSGeometry;
     3554            rc = VINF_SUCCESS;
     3555        }
     3556        else
     3557            rc = VERR_VDI_GEOMETRY_NOT_SET;
     3558    }
     3559    else
     3560        rc = VERR_VDI_NOT_OPENED;
     3561    LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc,
     3562             pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors));
     3563    return rc;
     3564}
     3565
     3566static int vmdkSetLCHSGeometry(void *pBackendData,
     3567                               PCPDMMEDIAGEOMETRY pLCHSGeometry)
     3568{
     3569    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3570    int rc;
     3571
     3572    Assert(pImage);
     3573
     3574    if (pImage)
     3575    {
     3576        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3577        {
     3578            rc = VERR_VDI_IMAGE_READ_ONLY;
     3579            goto out;
     3580        }
     3581        rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    31993582        if (VBOX_FAILURE(rc))
    32003583            goto out;
    3201         rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    3202                                "ddb.geometry.sectors", cSectors);
    3203         if (VBOX_FAILURE(rc))
    3204             goto out;
    3205 
    3206         pImage->cCylinders = cCylinders;
    3207         pImage->cHeads = cHeads;
    3208         pImage->cSectors = cSectors;
     3584
     3585        pImage->LCHSGeometry = *pLCHSGeometry;
    32093586        rc = VINF_SUCCESS;
    32103587    }
     
    32173594}
    32183595
    3219 static int vmdkGetTranslation(void *pBackendData, PPDMBIOSTRANSLATION penmTranslation)
     3596static unsigned vmdkGetImageFlags(void *pBackendData)
    32203597{
    32213598    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3222     int rc;
     3599    unsigned uImageFlags;
    32233600
    32243601    Assert(pImage);
    32253602
    32263603    if (pImage)
    3227     {
    3228         if (pImage->enmTranslation)
    3229         {
    3230             *penmTranslation = pImage->enmTranslation;
    3231             rc = VINF_SUCCESS;
    3232         }
    3233         else
    3234             rc = VERR_VDI_GEOMETRY_NOT_SET;
    3235     }
     3604        uImageFlags = pImage->uImageFlags;
    32363605    else
    3237         rc = VERR_VDI_NOT_OPENED;
    3238     LogFlow(("%s: returned %Vrc (%d)\n", __FUNCTION__, rc,
    3239              pImage->enmTranslation));
    3240     return rc;
    3241 }
    3242 
    3243 static int vmdkSetTranslation(void *pBackendData, PDMBIOSTRANSLATION enmTranslation)
    3244 {
    3245     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3246     int rc;
    3247 
    3248     Assert(pImage);
    3249 
    3250     if (pImage)
    3251     {
    3252         /** @todo maybe store this in the image descriptor */
    3253         pImage->enmTranslation = enmTranslation;
    3254         rc = VINF_SUCCESS;
    3255     }
    3256     else
    3257         rc = VERR_VDI_NOT_OPENED;
    3258     LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
    3259     return rc;
     3606        uImageFlags = 0;
     3607
     3608    LogFlow(("%s: returned %#x\n", __FUNCTION__, uImageFlags));
     3609    return uImageFlags;
    32603610}
    32613611
     
    33003650}
    33013651
    3302 static int vmdkGetComment(void *pBackendData, char *pszComment, size_t cbComment)
     3652static int vmdkGetComment(void *pBackendData, char *pszComment,
     3653                          size_t cbComment)
    33033654{
    33043655    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    34773828}
    34783829
     3830static void vmdkDump(void *pBackendData)
     3831{
     3832    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3833
     3834    Assert(pImage);
     3835    if (pImage)
     3836    {
     3837        RTLogPrintf("Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
     3838                    pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
     3839                    pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
     3840                    VMDK_BYTE2SECTOR(pImage->cbSize));
     3841        RTLogPrintf("Header: uuidCreation={%Vuuid}\n", pImage->ImageUuid);
     3842        RTLogPrintf("Header: uuidModification={%Vuuid}\n", pImage->ModificationUuid);
     3843        RTLogPrintf("Header: uuidParent={%Vuuid}\n", pImage->ParentUuid);
     3844    }
     3845}
     3846
    34793847
    34803848VBOXHDDBACKEND g_VmdkBackend =
    34813849{
     3850    /* pszBackendName */
     3851    "VMDK",
    34823852    /* cbSize */
    34833853    sizeof(VBOXHDDBACKEND),
    34843854    /* pfnCheckIfValid */
    3485     NULL,
     3855    vmdkCheckIfValid,
    34863856    /* pfnOpen */
    34873857    vmdkOpen,
    34883858    /* pfnCreate */
    34893859    vmdkCreate,
     3860    /* pfnRename */
     3861    vmdkRename,
    34903862    /* pfnClose */
    34913863    vmdkClose,
     
    34963868    /* pfnFlush */
    34973869    vmdkFlush,
     3870    /* pfnGetVersion */
     3871    vmdkGetVersion,
    34983872    /* pfnGetImageType */
    34993873    vmdkGetImageType,
    35003874    /* pfnGetSize */
    35013875    vmdkGetSize,
    3502     /* pfnGetGeometry */
    3503     vmdkGetGeometry,
    3504     /* pfnSetGeometry */
    3505     vmdkSetGeometry,
    3506     /* pfnGetTranslation */
    3507     vmdkGetTranslation,
    3508     /* pfnSetTranslation */
    3509     vmdkSetTranslation,
     3876    /* pfnGetFileSize */
     3877    vmdkGetFileSize,
     3878    /* pfnGetPCHSGeometry */
     3879    vmdkGetPCHSGeometry,
     3880    /* pfnSetPCHSGeometry */
     3881    vmdkSetPCHSGeometry,
     3882    /* pfnGetLCHSGeometry */
     3883    vmdkGetLCHSGeometry,
     3884    /* pfnSetLCHSGeometry */
     3885    vmdkSetLCHSGeometry,
     3886    /* pfnGetImageFlags */
     3887    vmdkGetImageFlags,
    35103888    /* pfnGetOpenFlags */
    35113889    vmdkGetOpenFlags,
     
    35273905    vmdkGetParentUuid,
    35283906    /* pfnSetParentUuid */
    3529     vmdkSetParentUuid
     3907    vmdkSetParentUuid,
     3908    /* pfnDump */
     3909    vmdkDump
    35303910};
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