VirtualBox

Ignore:
Timestamp:
May 15, 2007 3:59:11 PM (18 years ago)
Author:
vboxsync
Message:

Updated VD image create interface. Implemented closing/deleting of
images. First part of create implementation (currently only single-file
growing images). Cleaned up error messages a bit and fixed a number or
minor errors that didn't show up so far.

File:
1 edited

Legend:

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

    r2589 r2650  
    3434#include <iprt/path.h>
    3535#include <iprt/string.h>
     36#include <iprt/rand.h>
    3637
    3738
     
    148149    RTFILE      File;
    149150    /** Base name of the image extent. */
    150     char        *pszBasename;
     151    const char  *pszBasename;
    151152    /** Full name of the image extent. */
    152     char        *pszFullname;
     153    const char  *pszFullname;
    153154    /** Number of sectors in this extent. */
    154155    uint64_t    cSectors;
     
    164165    uint64_t    uSectorRGD;
    165166    /** Total number of metadata sectors. */
    166     uint64_t    uOverheadSectors;
     167    uint64_t    cOverheadSectors;
    167168    /** Nominal size (i.e. as described by the descriptor) of this extent. */
    168169    uint64_t    cNominalSectors;
     
    216217 * making it variable. Descriptor files are generally very short (~20 lines).
    217218 */
    218 #define VMDK_DESCRIPTOR_LINES_MAX   100
     219#define VMDK_DESCRIPTOR_LINES_MAX   100U
    219220
    220221/**
     
    234235    /** Total amount of memory available for the descriptor. */
    235236    size_t      cbDescAlloc;
    236     /** Set if descriptor has been changed and not yer written to disk. */
     237    /** Set if descriptor has been changed and not yet written to disk. */
    237238    bool        fDirty;
    238239    /** Array of pointers to the data in the descriptor. */
     
    335336static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent);
    336337#endif /* VBOX_WITH_VMDK_ESX */
    337 static void vmdkFreeExtentData(PVMDKEXTENT pExtent);
     338static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete);
    338339
    339340static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
    340341static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, unsigned uOpenFlags);
    341342static int vmdkFlushImage(PVMDKIMAGE pImage);
    342 static void vmdkFreeImage(PVMDKIMAGE pImage);
     343static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
    343344
    344345static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData);
    345 static int vmdkClose(void *pBackendData);
     346static int vmdkClose(void *pBackendData, bool fDelete);
    346347
    347348
     
    374375    if (VBOX_FAILURE(rc))
    375376    {
    376         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory for file '%s'"), pExtent->pszFullname);
     377        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s'"), pExtent->pszFullname);
    377378        goto out;
    378379    }
     
    394395        if (VBOX_FAILURE(rc))
    395396        {
    396             rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read redundant grain directory for file '%s'"), pExtent->pszFullname);
     397            rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname);
    397398            goto out;
    398399        }
     
    429430                RTMemTmpFree(pTmpGT1);
    430431                RTMemTmpFree(pTmpGT2);
    431                 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in file '%s'"), pExtent->pszFullname);
     432                rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname);
    432433                goto out;
    433434            }
     
    436437            if (VBOX_FAILURE(rc))
    437438            {
    438                 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in file '%s'"), pExtent->pszFullname);
     439                rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
    439440                RTMemTmpFree(pTmpGT1);
    440441                RTMemTmpFree(pTmpGT2);
     
    445446            if (VBOX_FAILURE(rc))
    446447            {
    447                 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading backup grain table in file '%s'"), pExtent->pszFullname);
     448                rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname);
    448449                RTMemTmpFree(pTmpGT1);
    449450                RTMemTmpFree(pTmpGT2);
     
    454455                RTMemTmpFree(pTmpGT1);
    455456                RTMemTmpFree(pTmpGT2);
    456                 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistency between grain table and backup grain table"));
     457                rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname);
    457458                goto out;
    458459            }
     
    468469}
    469470
     471static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector, bool fPreAlloc)
     472{
     473    int rc = VINF_SUCCESS;
     474    unsigned i;
     475    uint32_t *pGD = NULL, *pRGD = NULL;
     476    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
     477    size_t cbGDRounded = RT_ALIGN_64(pExtent->cGDEntries * sizeof(uint32_t), 512);
     478    size_t cbGTRounded;
     479    uint64_t cbOverhead;
     480   
     481    if (fPreAlloc)
     482        cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
     483    else
     484        cbGTRounded = 0;
     485
     486    pGD = (uint32_t *)RTMemAllocZ(cbGD);
     487    if (!pGD)
     488    {
     489        rc = VERR_NO_MEMORY;
     490        goto out;
     491    }
     492    pExtent->pGD = pGD;
     493    pRGD = (uint32_t *)RTMemAllocZ(cbGD);
     494    if (!pRGD)
     495    {
     496        rc = VERR_NO_MEMORY;
     497        goto out;
     498    }
     499    pExtent->pRGD = pRGD;
     500
     501    cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     502    rc = RTFileSetSize(pExtent->File, cbOverhead);
     503    if (VBOX_FAILURE(rc))
     504        goto out;
     505    pExtent->uSectorRGD = uStartSector;
     506    pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
     507
     508    if (fPreAlloc)
     509    {
     510        uint32_t uGTSectorLE;
     511        uint32_t uOffsetSectors;
     512
     513        uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
     514        for (i = 0; i < pExtent->cGDEntries; i++)
     515        {
     516            pRGD[i] = uOffsetSectors;
     517            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
     518            /* Write the redundant grain directory entry to disk. */
     519            rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     520            if (VBOX_FAILURE(rc))
     521                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
     522            uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
     523        }
     524
     525        uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded);
     526        for (i = 0; i < pExtent->cGDEntries; i++)
     527        {
     528            pGD[i] = uOffsetSectors;
     529            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
     530            /* Write the grain directory entry to disk. */
     531            rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     532            if (VBOX_FAILURE(rc))
     533                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
     534            uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
     535        }
     536    }
     537    pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
     538
     539out:
     540    if (VBOX_FAILURE(rc))
     541        vmdkFreeGrainDirectory(pExtent);
     542    return rc;
     543}
     544
    470545static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent)
    471546{
    472547    if (pExtent->pszBasename)
    473548    {
    474         RTMemTmpFree(pExtent->pszBasename);
     549        RTMemTmpFree((void *)pExtent->pszBasename);
    475550        pExtent->pszBasename = NULL;
    476551    }
     
    496571        pszStr++;
    497572    if (*pszStr++ != '"')
    498         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor"));
     573        return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
    499574
    500575    pszQ = (char*)strchr(pszStr, '"');
    501576    if (pszQ == NULL)
    502         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor"));
     577        return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
    503578    pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
    504579    if (!pszUnquoted)
     
    509584    if (ppszNext)
    510585        *ppszNext = pszQ + 1;
     586    return VINF_SUCCESS;
     587}
     588
     589static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     590                           const char *pszLine)
     591{
     592    char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
     593    ssize_t cbDiff = strlen(pszLine) + 1;
     594
     595    if (    pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
     596        &&  pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
     597        return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     598
     599    memcpy(pEnd, pszLine, cbDiff);
     600    pDescriptor->cLines++;
     601    pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
     602    pDescriptor->fDirty = true;
     603
    511604    return VINF_SUCCESS;
    512605}
     
    573666        if (    pDescriptor->aLines[pDescriptor->cLines]
    574667            -   pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    575             return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big"));
     668            return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    576669
    577670        memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
     
    591684            || (  pDescriptor->aLines[pDescriptor->cLines]
    592685                - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
    593             return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big"));
     686            return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    594687        for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
    595688        {
    596689            pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
    597             if (pDescriptor->aNextLines[i])
    598                 pDescriptor->aNextLines[i]++;
     690            if (pDescriptor->aNextLines[i - 1])
     691                pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
     692            else
     693                pDescriptor->aNextLines[i] = 0;
    599694        }
    600695        uStart = uLast + 1;
     
    610705        for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    611706            pDescriptor->aLines[i] += cbDiff;
     707
     708        /* Adjust starting line numbers of following descriptor sections. */
     709        if (uStart <= pDescriptor->uFirstExtent)
     710            pDescriptor->uFirstExtent++;
     711        if (uStart <= pDescriptor->uFirstDDB)
     712            pDescriptor->uFirstDDB++;
    612713    }
    613714    pDescriptor->fDirty = true;
     
    625726}
    626727
     728static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor)
     729{
     730    unsigned uEntry = pDescriptor->uFirstExtent;
     731    ssize_t cbDiff;
     732
     733    if (!uEntry)
     734        return;
     735
     736    cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
     737    /* Move everything including the \0 in the entry marking the end of buffer. */
     738    memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
     739            pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
     740    for (unsigned i = uEntry + 1; i <= pDescriptor->cLines; i++)
     741    {
     742        pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
     743        if (pDescriptor->aNextLines[i])
     744            pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
     745        else
     746            pDescriptor->aNextLines[i - 1] = 0;
     747    }
     748    pDescriptor->cLines--;
     749    if (pDescriptor->uFirstDDB)
     750        pDescriptor->uFirstDDB--;
     751
     752    return;
     753}
     754
     755static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     756                             VMDKACCESS enmAccess, uint64_t cNominalSectors,
     757                             VMDKETYPE enmType, const char *pszBasename,
     758                             uint64_t uSectorOffset)
     759{
     760    static const char *apszAccess[] = { "NOACCESS", "RDONLY", "RW" };
     761    static const char *apszType[] = { "", "SPARSE", "FLAT", "ZERO" };
     762    char *pszTmp;
     763    unsigned uStart = pDescriptor->uFirstExtent, uLast;
     764    char szExt[1024];
     765    ssize_t cbDiff;
     766
     767    /* Find last entry in extent description. */
     768    while (uStart)
     769    {
     770        if (!pDescriptor->aNextLines[uStart])
     771            uLast = uStart;
     772        uStart = pDescriptor->aNextLines[uStart];
     773    }
     774
     775    if (enmType == VMDKETYPE_ZERO)
     776    {
     777        RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s ", apszAccess[enmAccess],
     778                    cNominalSectors, apszType[enmType]);
     779    }
     780    else
     781    {
     782        if (!uSectorOffset)
     783            RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\"",
     784                        apszAccess[enmAccess], cNominalSectors,
     785                        apszType[enmType], pszBasename);
     786        else
     787            RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\" %llu",
     788                        apszAccess[enmAccess], cNominalSectors,
     789                        apszType[enmType], pszBasename, uSectorOffset);
     790    }
     791    cbDiff = strlen(szExt) + 1;
     792
     793    /* Check for buffer overflow. */
     794    if (   (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
     795        || (  pDescriptor->aLines[pDescriptor->cLines]
     796            - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
     797        return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     798
     799    for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
     800    {
     801        pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
     802        if (pDescriptor->aNextLines[i - 1])
     803            pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
     804        else
     805            pDescriptor->aNextLines[i] = 0;
     806    }
     807    uStart = uLast + 1;
     808    pDescriptor->aNextLines[uLast] = uStart;
     809    pDescriptor->aNextLines[uStart] = 0;
     810    pDescriptor->cLines++;
     811    pszTmp = pDescriptor->aLines[uStart];
     812    memmove(pszTmp + cbDiff, pszTmp,
     813            pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
     814    memcpy(pDescriptor->aLines[uStart], szExt, cbDiff);
     815    for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
     816        pDescriptor->aLines[i] += cbDiff;
     817
     818    /* Adjust starting line numbers of following descriptor sections. */
     819    if (uStart <= pDescriptor->uFirstDDB)
     820        pDescriptor->uFirstDDB++;
     821
     822    pDescriptor->fDirty = true;
     823    return VINF_SUCCESS;
     824}
     825
    627826static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    628827                             const char *pszKey, uint32_t *puValue)
     
    657856}
    658857
     858int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, const char *pszVal)
     859{
     860    char *pszValQuoted;
     861
     862    int rc = RTStrAPrintf(&pszValQuoted, "\"%s\"", pszVal);
     863    if (VBOX_FAILURE(rc))
     864        return rc;
     865    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValQuoted);
     866    RTStrFree(pszValQuoted);
     867    return rc;
     868}
     869
    659870int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, PCRTUUID pUuid)
    660871{
     
    693904        if (cLine >= VMDK_DESCRIPTOR_LINES_MAX)
    694905        {
    695             rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too long"));
     906            rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    696907            goto out;
    697908        }
     
    703914                if (*(pTmp + 1) != '\n')
    704915                {
    705                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor"));
     916                    rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor in '%s'"), pImage->pszFilename);
    706917                    goto out;
    707918                }
     
    727938    if (strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile"))
    728939    {
    729         rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected"));
     940        rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
    730941        goto out;
    731942    }
     
    747958                {
    748959                    /* Incorrect ordering of entries. */
    749                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor"));
     960                    rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
    750961                    goto out;
    751962                }
     
    762973                {
    763974                    /* Incorrect ordering of entries. */
    764                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor"));
     975                    rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
    765976                    goto out;
    766977                }
     
    777988                {
    778989                    /* Incorrect ordering of entries. */
    779                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor"));
     990                    rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
    780991                    goto out;
    781992                }
     
    7961007}
    7971008
     1009static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     1010{
     1011    int rc;
     1012
     1013    pDescriptor->uFirstDesc = 0;
     1014    pDescriptor->uFirstExtent = 0;
     1015    pDescriptor->uFirstDDB = 0;
     1016    pDescriptor->cLines = 0;
     1017    pDescriptor->cbDescAlloc = cbDescData;
     1018    pDescriptor->fDirty = false;
     1019    pDescriptor->aLines[pDescriptor->cLines] = pDescData;
     1020    memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
     1021
     1022    rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
     1023    if (VBOX_FAILURE(rc))
     1024        goto out;
     1025    rc = vmdkDescInitStr(pImage, pDescriptor, "version=1");
     1026    if (VBOX_FAILURE(rc))
     1027        goto out;
     1028    pDescriptor->uFirstDesc = pDescriptor->cLines - 1;
     1029    rc = vmdkDescInitStr(pImage, pDescriptor, "");
     1030    if (VBOX_FAILURE(rc))
     1031        goto out;
     1032    rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description");
     1033    if (VBOX_FAILURE(rc))
     1034        goto out;
     1035    rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO ");
     1036    if (VBOX_FAILURE(rc))
     1037        goto out;
     1038    pDescriptor->uFirstExtent = pDescriptor->cLines - 1;
     1039    rc = vmdkDescInitStr(pImage, pDescriptor, "");
     1040    if (VBOX_FAILURE(rc))
     1041        goto out;
     1042    /* The trailing space is created by VMware, too. */
     1043    rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base ");
     1044    if (VBOX_FAILURE(rc))
     1045        goto out;
     1046    rc = vmdkDescInitStr(pImage, pDescriptor, "# DDB");
     1047    if (VBOX_FAILURE(rc))
     1048        goto out;
     1049    rc = vmdkDescInitStr(pImage, pDescriptor, "");
     1050    if (VBOX_FAILURE(rc))
     1051        goto out;
     1052    rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\"");
     1053    if (VBOX_FAILURE(rc))
     1054        goto out;
     1055    pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
     1056
     1057    /* Now that the framework is in place, use the normal functions to insert
     1058     * the remaining keys. */
     1059    char szBuf[9];
     1060    RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
     1061    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "CID", szBuf);
     1062    if (VBOX_FAILURE(rc))
     1063        goto out;
     1064    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "parentCID", "ffffffff");
     1065    if (VBOX_FAILURE(rc))
     1066        goto out;
     1067
     1068    rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
     1069    if (VBOX_FAILURE(rc))
     1070        goto out;
     1071
     1072out:
     1073    return rc;
     1074}
     1075
    7981076static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
    7991077{
     
    8101088    rc = vmdkDescBaseGetU32(&pImage->Descriptor, "version", &uVersion);
    8111089    if (VBOX_FAILURE(rc))
    812         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error finding key 'version' in descriptor"));
     1090        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error finding key 'version' in descriptor in '%s'"), pImage->pszFilename);
    8131091    if (uVersion != 1)
    814         return vmdkError(pImage, VERR_VDI_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor"));
     1092        return vmdkError(pImage, VERR_VDI_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
    8151093
    8161094    /* Count the number of extent config entries. */
     
    8231101    {
    8241102        /* Monolithic image, must have only one extent (already opened). */
    825         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image may only have one extent"));
     1103        return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image may only have one extent in '%s'"), pImage->pszFilename);
    8261104    }
    8271105
     
    8561134        }
    8571135        else
    858             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1136            return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    8591137        if (*pszLine++ != ' ')
    860             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1138            return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    8611139
    8621140        /* Nominal size of the extent. */
     
    8641142                             &pImage->pExtents[i].cNominalSectors);
    8651143        if (VBOX_FAILURE(rc))
    866             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1144            return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    8671145        if (*pszLine++ != ' ')
    868             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1146            return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    8691147
    8701148        /* Type of the extent. */
     
    8901168        }
    8911169        else
    892             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1170            return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    8931171        if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
    8941172        {
     
    8971175                pszLine++;
    8981176            if (*pszLine != '\0')
    899                 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1177                return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    9001178            pImage->pExtents[i].pszBasename = NULL;
    9011179        }
     
    9041182            /* All other extent types have basename and optional offset. */
    9051183            if (*pszLine++ != ' ')
    906                 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1184                return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    9071185
    9081186            /* Basename of the image. Surrounded by quotes. */
    909             rc = vmdkStringUnquote(pImage, pszLine,
    910                                    &pImage->pExtents[i].pszBasename, &pszLine);
     1187            char *pszBasename;
     1188            rc = vmdkStringUnquote(pImage, pszLine, &pszBasename, &pszLine);
    9111189            if (VBOX_FAILURE(rc))
    9121190                return rc;
     1191            pImage->pExtents[i].pszBasename = pszBasename;
    9131192            if (*pszLine == ' ')
    9141193            {
     
    9201199                                         &pImage->pExtents[i].uSectorOffset);
    9211200                    if (VBOX_FAILURE(rc))
    922                         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1201                        return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    9231202                }
    9241203            }
    9251204
    9261205            if (*pszLine != '\0')
    927                 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description"));
     1206                return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    9281207        }
    9291208    }
     
    9321211                           "ddb.geometry.cylinders", &pImage->cCylinders);
    9331212    if (VBOX_FAILURE(rc))
    934         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description"));
     1213        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
    9351214    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    9361215                           "ddb.geometry.heads", &pImage->cHeads);
    9371216    if (VBOX_FAILURE(rc))
    938         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description"));
     1217        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
    9391218    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    9401219                           "ddb.geometry.sectors", &pImage->cSectors);
    9411220    if (VBOX_FAILURE(rc))
    942         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description"));
     1221        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
    9431222    if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
    9441223        pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
     
    9641243                                    "ddb.uuid.image", &pImage->ImageUuid);
    9651244            if (VBOX_FAILURE(rc))
    966                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor"));
     1245                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
    9671246        }
    9681247    }
     
    9881267                                    "ddb.uuid.modification", &pImage->ModificationUuid);
    9891268            if (VBOX_FAILURE(rc))
    990                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor"));
     1269                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
    9911270        }
    9921271    }
     
    10121291                                    "ddb.uuid.parent", &pImage->ParentUuid);
    10131292            if (VBOX_FAILURE(rc))
    1014                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent UUID in descriptor"));
     1293                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent UUID in descriptor in '%s'"), pImage->pszFilename);
    10151294        }
    10161295    }
     
    10491328
    10501329        if (cbLimit && uOffset + cb + 1 > cbLimit)
    1051             return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long"));
     1330            return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
    10521331        rc = RTFileWriteAt(DescFile, uOffset, psz, cb, NULL);
    10531332        if (VBOX_FAILURE(rc))
    1054             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor for '%s'"), pImage->pszFilename);
     1333            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    10551334        uOffset += cb;
    10561335        rc = RTFileWriteAt(DescFile, uOffset, "\n", 1, NULL);
    10571336        if (VBOX_FAILURE(rc))
    1058             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor for '%s'"), pImage->pszFilename);
     1337            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    10591338        uOffset++;
    10601339    }
     
    10661345            rc = RTFileWriteAt(DescFile, uOffset, "", 1, NULL);
    10671346            if (VBOX_FAILURE(rc))
    1068                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor for '%s'"), pImage->pszFilename);
     1347                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    10691348            uOffset++;
    10701349        }
     
    10741353        rc = RTFileSetSize(DescFile, uOffset);
    10751354        if (VBOX_FAILURE(rc))
    1076             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor file '%s'"), pImage->pszFilename);
     1355            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
    10771356    }
    10781357    pImage->Descriptor.fDirty = false;
     
    10891368    if (VBOX_FAILURE(rc))
    10901369    {
    1091         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header of file '%s'"), pExtent->pszFullname);
     1370        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
    10921371        goto out;
    10931372    }
     
    10951374        ||  RT_LE2H_U32(Header.version) != 1)
    10961375    {
    1097         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic/version in extent header of file '%s'"), pExtent->pszFullname);
     1376        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic/version in extent header in '%s'"), pExtent->pszFullname);
    10981377        goto out;
    10991378    }
     
    11031382    if (VBOX_FAILURE(rc))
    11041383    {
    1105         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size of file '%s'"), pExtent->pszFullname);
     1384        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    11061385        goto out;
    11071386    }
     
    11121391             || Header.doubleEndLineChar2 != '\n') )
    11131392    {
    1114         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: file '%s' is corrupted by CR/LF translation"), pExtent->pszFullname);
     1393        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
    11151394        goto out;
    11161395    }
     
    11231402        ||  pExtent->cSectorsPerGrain < 8)
    11241403    {
    1125         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u for file '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
     1404        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
    11261405        goto out;
    11271406    }
     
    11301409    if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
    11311410    {
    1132         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config for file '%s'"), pExtent->pszFullname);
     1411        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
    11331412        goto out;
    11341413    }
     
    11391418        ||  pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)
    11401419    {
    1141         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem for file '%s'"), pExtent->pszFullname);
     1420        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
    11421421        goto out;
    11431422    }
     
    11541433        pExtent->uSectorRGD = 0;
    11551434    }
    1156     pExtent->uOverheadSectors = RT_LE2H_U64(Header.overHead);
     1435    pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
    11571436    pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
    11581437    cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    11591438    if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
    11601439    {
    1161         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size for file '%s'"), pExtent->pszFullname);
     1440        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
    11621441        goto out;
    11631442    }
     
    11691448out:
    11701449    if (VBOX_FAILURE(rc))
    1171     {
    1172         vmdkFreeExtentData(pExtent);
    1173     }
     1450        vmdkFreeExtentData(pExtent, false);
    11741451
    11751452    return rc;
     
    12001477        Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorGD);
    12011478    }
    1202     Header.overHead = RT_H2LE_U64(pExtent->uOverheadSectors);
     1479    Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
    12031480    Header.uncleanShutdown = pExtent->fUncleanShutdown;
    12041481    Header.singleEndLineChar = '\n';
     
    12101487    AssertRC(rc);
    12111488    if (VBOX_FAILURE(rc))
    1212         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header to file '%s'"), pExtent->pszFullname);
     1489        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
    12131490    return rc;
    12141491}
     
    12471524    pExtent->uSectorGD = RT_LE2H_U32(Header.gdOffset);
    12481525    pExtent->uSectorRGD = 0;
    1249     pExtent->uOverheadSectors = 0;
     1526    pExtent->cOverheadSectors = 0;
    12501527    pExtent->cGTEntries = 4096;
    12511528    cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     
    12711548out:
    12721549    if (VBOX_FAILURE(rc))
    1273     {
    1274         vmdkFreeExtentData(pExtent);
    1275     }
     1550        vmdkFreeExtentData(pExtent, false);
    12761551
    12771552    return rc;
     
    12791554#endif /* VBOX_WITH_VMDK_ESX */
    12801555
    1281 static void vmdkFreeExtentData(PVMDKEXTENT pExtent)
     1556static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete)
    12821557{
    12831558    vmdkFreeGrainDirectory(pExtent);
     
    12871562        pExtent->pDescData = NULL;
    12881563    }
    1289     if (pExtent->pszFullname)
    1290     {
    1291         RTStrFree(pExtent->pszFullname);
    1292         pExtent->pszFullname = NULL;
    1293     }
    12941564    if (pExtent->File != NIL_RTFILE)
    12951565    {
    12961566        RTFileClose(pExtent->File);
    12971567        pExtent->File = NIL_RTFILE;
    1298     }
    1299 }
    1300 
     1568        if (fDelete && pExtent->pszFullname)
     1569            RTFileDelete(pExtent->pszFullname);
     1570    }
     1571    if (pExtent->pszFullname)
     1572    {
     1573        RTStrFree((char *)(void *)pExtent->pszFullname);
     1574        pExtent->pszFullname = NULL;
     1575    }
     1576}
     1577
     1578static int vmdkAllocateGrainTableCache(PVMDKIMAGE pImage)
     1579{
     1580    PVMDKEXTENT pExtent;
     1581
     1582    /* Allocate grain table cache if any sparse extent is present. */
     1583    for (unsigned i = 0; i < pImage->cExtents; i++)
     1584    {
     1585        pExtent = &pImage->pExtents[i];
     1586        if (    pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
     1587#ifdef VBOX_WITH_VMDK_ESX
     1588            ||  pExtent->enmType == VMDKETYPE_ESX_SPARSE
     1589#endif /* VBOX_WITH_VMDK_ESX */
     1590           )
     1591        {
     1592            /* Allocate grain table cache. */
     1593            pImage->pGTCache = (PVMDKGTCACHE)RTMemAllocZ(sizeof(VMDKGTCACHE));
     1594            if (!pImage->pGTCache)
     1595                return VERR_NO_MEMORY;
     1596            for (unsigned i = 0; i < VMDK_GT_CACHE_SIZE; i++)
     1597            {
     1598                PVMDKGTCACHEENTRY pGCE = &pImage->pGTCache->aGTCache[i];
     1599                pGCE->uExtent = UINT32_MAX;
     1600            }
     1601            pImage->pGTCache->cEntries = VMDK_GT_CACHE_SIZE;
     1602            break;
     1603        }
     1604    }
     1605
     1606    return VINF_SUCCESS;
     1607}
    13011608static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents)
    13021609{
     
    13341641    pImage->uOpenFlags = uOpenFlags;
    13351642
    1336     /** @todo check the image file name for invalid characters, especially double quotes. */
    1337 
    13381643    /** @todo check whether the same file is used somewhere else. don't open any file twice, leads to locking problems and can cause trouble with file caching. */
    13391644
     
    13551660    if (VBOX_FAILURE(rc))
    13561661    {
    1357         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading the magic number from file '%s'"), pszFilename);
     1662        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading the magic number in '%s'"), pszFilename);
    13581663        goto out;
    13591664    }
     
    13781683        if (!pExtent->uDescriptorSector || !pExtent->cDescriptorSectors)
    13791684        {
    1380             rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in file '%s'"), pszFilename);
     1685            rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in '%s'"), pszFilename);
    13811686            goto out;
    13821687        }
     
    13951700        if (VBOX_FAILURE(rc))
    13961701        {
    1397             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in file '%s'"), pExtent->pszFullname);
     1702            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pExtent->pszFullname);
    13981703            goto out;
    13991704        }
     
    14261731        if (VBOX_FAILURE(rc))
    14271732        {
    1428             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in file '%s'"), pszFilename);
     1733            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pszFilename);
    14291734            goto out;
    14301735        }
     
    14331738            /* Likely the read is truncated. Better fail a bit too early
    14341739             * (normally the descriptor is much smaller than our buffer). */
    1435             rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in file '%s'"), pszFilename);
     1740            rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in '%s'"), pszFilename);
    14361741            goto out;
    14371742        }
     
    15691874    }
    15701875
    1571     /* Allocate grain table cache if any sparse extent is present. */
     1876    rc = vmdkAllocateGrainTableCache(pImage);
     1877    if (VBOX_FAILURE(rc))
     1878        goto out;
     1879
     1880out:
     1881    if (VBOX_FAILURE(rc))
     1882        vmdkFreeImage(pImage, false);
     1883    return rc;
     1884}
     1885
     1886static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
     1887{
     1888    int rc;
     1889    uint64_t cSectorsPerGDE, cSectorsPerGD;
     1890    PVMDKEXTENT pExtent;
     1891
     1892    rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc, &pImage->Descriptor);
     1893    if (VBOX_FAILURE(rc))
     1894    {
     1895        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename);
     1896        goto out;
     1897    }
     1898
     1899    if (    enmType == VD_IMAGE_TYPE_FIXED
     1900        ||  uImageFlags == VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
     1901    {
     1902        /* Fixed images and split images in general have a separate descriptor
     1903         * file. This is the more complicated case, as it requires setting up
     1904         * potentially more than one extent, including filename generation. */
     1905        rc = VERR_NOT_IMPLEMENTED;
     1906        goto out;
     1907    }
     1908    else
     1909    {
     1910        /* Normal (growing) image which is not split into pieces. */
     1911        rc = vmdkCreateExtents(pImage, 1);
     1912        if (VBOX_FAILURE(rc))
     1913        {
     1914            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     1915            goto out;
     1916        }
     1917        pExtent = &pImage->pExtents[0];
     1918        pImage->File = NIL_RTFILE;
     1919        rc = RTFileOpen(&pExtent->File, pszFilename,
     1920                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     1921        if (VBOX_FAILURE(rc))
     1922        {
     1923            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
     1924            goto out;
     1925        }
     1926
     1927        /* Set up basename for extent description. Cannot use StrDup, as it is
     1928         * not guaranteed that the memory can be freed with RTMemTmpFree, which
     1929         * must be used as in other code paths StrDup is not usable. */
     1930        char *pszBasenameSubstr = RTPathFilename(pszFilename);
     1931        Assert(pszBasenameSubstr);
     1932        size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     1933        char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
     1934        if (!pszBasename)
     1935        {
     1936            rc = VERR_NO_MEMORY;
     1937            goto out;
     1938        }
     1939        memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
     1940        pExtent->pszBasename = pszBasename;
     1941        pExtent->pszFullname = RTStrDup(pszFilename);
     1942        if (!pExtent->pszFullname)
     1943        {
     1944            rc = VERR_NO_MEMORY;
     1945            goto out;
     1946        }
     1947        pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     1948        pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, 65536));
     1949        pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
     1950        pExtent->uDescriptorSector = 1;
     1951        pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
     1952        pExtent->cGTEntries = 512;
     1953        cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     1954        pExtent->cSectorsPerGDE = cSectorsPerGDE;
     1955        pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     1956        cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     1957        pExtent->enmAccess = VMDKACCESS_READWRITE;
     1958        pExtent->fUncleanShutdown = true;
     1959        pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     1960        pExtent->uSectorOffset = 0;
     1961        pExtent->fMetaDirty = true;
     1962
     1963        rc = vmdkCreateGrainDirectory(pExtent, pExtent->uDescriptorSector + pExtent->cDescriptorSectors, true);
     1964        if (VBOX_FAILURE(rc))
     1965        {
     1966            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pszFilename);
     1967            goto out;
     1968        }
     1969
     1970        pImage->enmImageType = enmType;
     1971        rc = vmdkDescSetStr(pImage, &pImage->Descriptor, pImage->Descriptor.uFirstDesc, "createType", "\"monolithicSparse\"");
     1972        if (VBOX_FAILURE(rc))
     1973        {
     1974            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
     1975            goto out;
     1976        }
     1977
     1978        /* The descriptor is part of the extent, move info to extent. */
     1979        pExtent->pDescData = pImage->pDescData;
     1980        pImage->pDescData = NULL;
     1981    }
     1982
     1983    pImage->cbSize = cbSize;
     1984    if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
     1985        pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
     1986    else
     1987        pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
     1988
    15721989    for (unsigned i = 0; i < pImage->cExtents; i++)
    15731990    {
    15741991        pExtent = &pImage->pExtents[i];
    1575         if (    pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
     1992
     1993        rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
     1994                               pExtent->cNominalSectors, pExtent->enmType,
     1995                               pExtent->pszBasename, pExtent->uSectorOffset);
     1996        if (VBOX_FAILURE(rc))
     1997        {
     1998            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pszFilename);
     1999            goto out;
     2000        }
     2001    }
     2002    vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
     2003
     2004    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     2005                           "ddb.geometry.cylinders", cCylinders);
     2006    if (VBOX_FAILURE(rc))
     2007        goto out;
     2008    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     2009                           "ddb.geometry.heads", cHeads);
     2010    if (VBOX_FAILURE(rc))
     2011        goto out;
     2012    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     2013                           "ddb.geometry.sectors", cSectors);
     2014    if (VBOX_FAILURE(rc))
     2015        goto out;
     2016
     2017    pImage->cCylinders = cCylinders;
     2018    pImage->cHeads = cHeads;
     2019    pImage->cSectors = cSectors;
     2020
     2021    rc = RTUuidCreate(&pImage->ImageUuid);
     2022    if (VBOX_FAILURE(rc))
     2023        goto out;
     2024    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     2025                            "ddb.uuid.image", &pImage->ImageUuid);
     2026    if (VBOX_FAILURE(rc))
     2027    {
     2028        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pszFilename);
     2029        goto out;
     2030    }
     2031    RTUuidClear(&pImage->ParentUuid);
     2032    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     2033                            "ddb.uuid.parent", &pImage->ParentUuid);
     2034    if (VBOX_FAILURE(rc))
     2035    {
     2036        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pszFilename);
     2037        goto out;
     2038    }
     2039    RTUuidClear(&pImage->ModificationUuid);
     2040    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     2041                            "ddb.uuid.modification", &pImage->ModificationUuid);
     2042    if (VBOX_FAILURE(rc))
     2043    {
     2044        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pszFilename);
     2045        goto out;
     2046    }
     2047
     2048    rc = vmdkAllocateGrainTableCache(pImage);
     2049    if (VBOX_FAILURE(rc))
     2050        goto out;
     2051
     2052    rc = vmdkFlushImage(pImage);
     2053
     2054out:
     2055    if (VBOX_FAILURE(rc))
     2056        vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
     2057    return rc;
     2058}
     2059
     2060static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete)
     2061{
     2062    if (pImage->enmImageType)
     2063    {
     2064        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     2065        {
     2066            /* Mark all extents as clean. */
     2067            for (unsigned i = 0; i < pImage->cExtents; i++)
     2068            {
     2069                if ((   pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
    15762070#ifdef VBOX_WITH_VMDK_ESX
    1577             ||  pExtent->enmType == VMDKETYPE_ESX_SPARSE
     2071                     || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
    15782072#endif /* VBOX_WITH_VMDK_ESX */
    1579            )
    1580         {
    1581             /* Allocate grain table cache. */
    1582             pImage->pGTCache = (PVMDKGTCACHE)RTMemAllocZ(sizeof(VMDKGTCACHE));
    1583             if (!pImage->pGTCache)
    1584             {
    1585                 rc = VERR_NO_MEMORY;
    1586                 goto out;
     2073                    )
     2074                    &&  pImage->pExtents[i].fUncleanShutdown)
     2075                {
     2076                    pImage->pExtents[i].fUncleanShutdown = false;
     2077                    pImage->pExtents[i].fMetaDirty = true;
     2078                }
    15872079            }
    1588             for (unsigned i = 0; i < VMDK_GT_CACHE_SIZE; i++)
    1589             {
    1590                 PVMDKGTCACHEENTRY pGCE = &pImage->pGTCache->aGTCache[i];
    1591                 pGCE->uExtent = UINT32_MAX;
    1592             }
    1593             pImage->pGTCache->cEntries = VMDK_GT_CACHE_SIZE;
    1594             break;
    1595         }
    1596     }
    1597 
    1598 out:
    1599     if (VBOX_FAILURE(rc))
    1600         vmdkFreeImage(pImage);
    1601     return rc;
    1602 }
    1603 
    1604 static void vmdkFreeImage(PVMDKIMAGE pImage)
    1605 {
    1606     if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    1607     {
    1608         /* Mark all extents as clean. */
    1609         for (unsigned i = 0; i < pImage->cExtents; i++)
    1610         {
    1611             if ((   pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
    1612 #ifdef VBOX_WITH_VMDK_ESX
    1613                  || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
    1614 #endif /* VBOX_WITH_VMDK_ESX */
    1615                 )
    1616                 &&  pImage->pExtents[i].fUncleanShutdown)
    1617             {
    1618                 pImage->pExtents[i].fUncleanShutdown = false;
    1619                 pImage->pExtents[i].fMetaDirty = true;
    1620             }
    1621         }
    1622     }
    1623     (void)vmdkFlushImage(pImage);
     2080        }
     2081        (void)vmdkFlushImage(pImage);
     2082    }
    16242083    if (pImage->pExtents != NULL)
    16252084    {
    16262085        for (unsigned i = 0 ; i < pImage->cExtents; i++)
    1627             vmdkFreeExtentData(&pImage->pExtents[i]);
     2086            vmdkFreeExtentData(&pImage->pExtents[i], fDelete);
    16282087        RTMemFree(pImage->pExtents);
    16292088        pImage->pExtents = NULL;
     
    16342093        pImage->File = NIL_RTFILE;
    16352094    }
     2095    if (fDelete && pImage->pszFilename)
     2096        RTFileDelete(pImage->pszFilename);
    16362097}
    16372098
     
    17622223                          aGTDataTmp, sizeof(aGTDataTmp), NULL);
    17632224        if (VBOX_FAILURE(rc))
    1764             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in file '%s'"), pExtent->pszFullname);
     2225            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
    17652226        pGTCacheEntry->uExtent = pExtent->uExtent;
    17662227        pGTCacheEntry->uGTBlock = uGTBlock;
     
    18052266        rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    18062267        if (VBOX_FAILURE(rc))
    1807             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size of file '%s'"), pExtent->pszFullname);
     2268            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    18082269        Assert(!(cbExtentSize % 512));
    18092270        uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     
    18222283            rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
    18232284            if (VBOX_FAILURE(rc))
    1824                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in file '%s'"), pExtent->pszFullname);
     2285                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
    18252286        }
    18262287        if (pExtent->pRGD)
     
    18282289            rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    18292290            if (VBOX_FAILURE(rc))
    1830                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size of file '%s'"), pExtent->pszFullname);
     2291                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    18312292            Assert(!(cbExtentSize % 512));
    18322293            uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     
    18392300                rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
    18402301                if (VBOX_FAILURE(rc))
    1841                     return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in file '%s'"), pExtent->pszFullname);
     2302                    return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
    18422303            }
    18432304        }
     
    18502311        rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    18512312        if (VBOX_FAILURE(rc))
    1852             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in file '%s'"), pExtent->pszFullname);
     2313            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
    18532314        if (pExtent->pRGD)
    18542315        {
     
    18562317            rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
    18572318            if (VBOX_FAILURE(rc))
    1858                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in file '%s'"), pExtent->pszFullname);
     2319                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
    18592320        }
    18602321
     
    18672328    rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    18682329    if (VBOX_FAILURE(rc))
    1869         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size of file '%s'"), pExtent->pszFullname);
     2330        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    18702331    Assert(!(cbExtentSize % 512));
    18712332
     
    18732334    rc = RTFileWriteAt(pExtent->File, cbExtentSize, pvBuf, cbWrite, NULL);
    18742335    if (VBOX_FAILURE(rc))
    1875         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in file '%s'"), pExtent->pszFullname);
     2336        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
    18762337
    18772338    /* Update the grain table (and the cache). */
     
    18872348                          aGTDataTmp, sizeof(aGTDataTmp), NULL);
    18882349        if (VBOX_FAILURE(rc))
    1889             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in file '%s'"), pExtent->pszFullname);
     2350            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
    18902351        pGTCacheEntry->uExtent = pExtent->uExtent;
    18912352        pGTCacheEntry->uGTBlock = uGTBlock;
     
    19082369                       aGTDataTmp, sizeof(aGTDataTmp), NULL);
    19092370    if (VBOX_FAILURE(rc))
    1910         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in file '%s'"), pExtent->pszFullname);
     2371        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
    19112372    if (pExtent->pRGD)
    19122373    {
     
    19162377                           aGTDataTmp, sizeof(aGTDataTmp), NULL);
    19172378        if (VBOX_FAILURE(rc))
    1918             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in file '%s'"), pExtent->pszFullname);
     2379            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
    19192380    }
    19202381#ifdef VBOX_WITH_VMDK_ESX
     
    19302391static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData)
    19312392{
    1932     int rc = VINF_SUCCESS;
     2393    int rc;
    19332394    PVMDKIMAGE pImage;
    19342395
    1935     /* Check open flags. Just readonly flag is supported. */
    1936     if (uOpenFlags & ~VD_OPEN_FLAGS_READONLY)
     2396    /** @todo check the image file name for invalid characters, especially double quotes. */
     2397
     2398    /* Check open flags. All valid flags are supported. */
     2399    if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
    19372400    {
    19382401        rc = VERR_INVALID_PARAMETER;
     
    19542417    pImage->pvErrorUser = pvErrorUser;
    19552418
     2419    rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
    19562420    if (VBOX_SUCCESS(rc))
    1957     {
    1958         rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
    1959         if (VBOX_SUCCESS(rc))
    1960             *ppvBackendData = pImage;
    1961     }
     2421        *ppvBackendData = pImage;
    19622422
    19632423out:
     
    19662426}
    19672427
    1968 static int vmdkCreate(const char *pszFilename, VDIMAGETYPE penmType,
     2428static int vmdkCreate(const char *pszFilename, VDIMAGETYPE enmType,
    19692429                      uint64_t cbSize, unsigned uImageFlags,
    1970                       const char *pszComment, unsigned uOpenFlags,
     2430                      const char *pszComment, uint32_t cCylinders,
     2431                      uint32_t cHeads, uint32_t cSectors, unsigned uOpenFlags,
    19712432                      PFNVMPROGRESS pfnProgress, void *pvUser,
    19722433                      PFNVDERROR pfnError, void *pvErrorUser,
    19732434                      void **ppvBackendData)
    19742435{
    1975     return VERR_NOT_IMPLEMENTED;
    1976 }
    1977 
    1978 static int vmdkClose(void *pBackendData)
     2436    int rc;
     2437    PVMDKIMAGE pImage;
     2438
     2439    /** @todo check the image file name for invalid characters, especially double quotes. */
     2440
     2441    /* Check open flags. All valid flags are supported. */
     2442    if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
     2443    {
     2444        rc = VERR_INVALID_PARAMETER;
     2445        goto out;
     2446    }
     2447
     2448    pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     2449    if (!pImage)
     2450    {
     2451        rc = VERR_NO_MEMORY;
     2452        goto out;
     2453    }
     2454    pImage->pszFilename = pszFilename;
     2455    pImage->File = NIL_RTFILE;
     2456    pImage->pExtents = NULL;
     2457    pImage->pGTCache = NULL;
     2458    pImage->pDescData = NULL;
     2459    pImage->pfnError = pfnError;
     2460    pImage->pvErrorUser = pvErrorUser;
     2461    pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
     2462    pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
     2463    if (!pImage->pDescData)
     2464    {
     2465        rc = VERR_NO_MEMORY;
     2466        goto out;
     2467    }
     2468
     2469    rc = vmdkCreateImage(pImage, pszFilename, enmType, cbSize, uImageFlags,
     2470                         cCylinders, cHeads, cSectors);
     2471    if (VBOX_SUCCESS(rc))
     2472    {
     2473        /* So far the image is opened in read/write mode. Make sure the
     2474         * image is opened in read-only mode if the caller requested that. */
     2475        if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
     2476        {
     2477            vmdkFreeImage(pImage, false);
     2478            rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
     2479            if (VBOX_FAILURE(rc))
     2480                goto out;
     2481        }
     2482        *ppvBackendData = pImage;
     2483    }
     2484
     2485out:
     2486    /** @todo implement meaningful progress stuff (especially for fixed images). */
     2487    if (    VBOX_SUCCESS(rc)
     2488        &&  pfnProgress)
     2489        pfnProgress(NULL /* WARNING! pVM=NULL  */, 100, pvUser);
     2490
     2491    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     2492    return rc;
     2493}
     2494
     2495static int vmdkClose(void *pBackendData, bool fDelete)
    19792496{
    19802497    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    19842501     * not signalled as an error. After all nothing bad happens. */
    19852502    if (pImage)
    1986         vmdkFreeImage(pImage);
     2503        vmdkFreeImage(pImage, fDelete);
    19872504
    19882505    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     
    23322849    /* Implement this operation via reopening the image. */
    23332850    pszFilename = pImage->pszFilename;
    2334     vmdkFreeImage(pImage);
     2851    vmdkFreeImage(pImage, false);
    23352852    rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
    23362853
     
    23722889                                "ddb.uuid.image", pUuid);
    23732890        if (VBOX_FAILURE(rc))
    2374             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor"));
     2891            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
    23752892        rc = VINF_SUCCESS;
    23762893    }
     
    24132930                                "ddb.uuid.modification", pUuid);
    24142931        if (VBOX_FAILURE(rc))
    2415             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor"));
     2932            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
    24162933        rc = VINF_SUCCESS;
    24172934    }
     
    24542971                                "ddb.uuid.parent", pUuid);
    24552972        if (VBOX_FAILURE(rc))
    2456             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor"));
     2973            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
    24572974        rc = VINF_SUCCESS;
    24582975    }
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