VirtualBox

Changeset 97255 in vbox for trunk/src/VBox/Storage


Ignore:
Timestamp:
Oct 20, 2022 2:56:36 PM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
154235
Message:

Storage/VMDK: Revert r141811 which eliminated all blank lines in the file by accident

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/VMDK.cpp

    r96842 r97255  
    33 * VMDK disk image, core code.
    44 */
     5
    56/*
    67 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
     
    3334#include <VBox/vd-plugin.h>
    3435#include <VBox/err.h>
     36
    3537#include <iprt/assert.h>
    3638#include <iprt/alloc.h>
     
    9294# define DKIOCUNLOCKPHYSICALEXTENTS _IO(  'd', 83)
    9395#endif /* RT_OS_DARWIN */
     96
    9497#include "VDBackends.h"
    9598
     
    98101*   Constants And Macros, Structures and Typedefs                                                                                *
    99102*********************************************************************************************************************************/
     103
    100104/** Maximum encoded string size (including NUL) we allow for VMDK images.
    101105 * Deliberately not set high to avoid running out of descriptor space. */
    102106#define VMDK_ENCODED_COMMENT_MAX 1024
     107
    103108/** VMDK descriptor DDB entry for PCHS cylinders. */
    104109#define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
     110
    105111/** VMDK descriptor DDB entry for PCHS heads. */
    106112#define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
     113
    107114/** VMDK descriptor DDB entry for PCHS sectors. */
    108115#define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
     116
    109117/** VMDK descriptor DDB entry for LCHS cylinders. */
    110118#define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
     119
    111120/** VMDK descriptor DDB entry for LCHS heads. */
    112121#define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
     122
    113123/** VMDK descriptor DDB entry for LCHS sectors. */
    114124#define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
     125
    115126/** VMDK descriptor DDB entry for image UUID. */
    116127#define VMDK_DDB_IMAGE_UUID "ddb.uuid.image"
     128
    117129/** VMDK descriptor DDB entry for image modification UUID. */
    118130#define VMDK_DDB_MODIFICATION_UUID "ddb.uuid.modification"
     131
    119132/** VMDK descriptor DDB entry for parent image UUID. */
    120133#define VMDK_DDB_PARENT_UUID "ddb.uuid.parent"
     134
    121135/** VMDK descriptor DDB entry for parent image modification UUID. */
    122136#define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification"
     137
    123138/** No compression for streamOptimized files. */
    124139#define VMDK_COMPRESSION_NONE 0
     140
    125141/** Deflate compression for streamOptimized files. */
    126142#define VMDK_COMPRESSION_DEFLATE 1
     143
    127144/** Marker that the actual GD value is stored in the footer. */
    128145#define VMDK_GD_AT_END 0xffffffffffffffffULL
     146
    129147/** Marker for end-of-stream in streamOptimized images. */
    130148#define VMDK_MARKER_EOS 0
     149
    131150/** Marker for grain table block in streamOptimized images. */
    132151#define VMDK_MARKER_GT 1
     152
    133153/** Marker for grain directory block in streamOptimized images. */
    134154#define VMDK_MARKER_GD 2
     155
    135156/** Marker for footer in streamOptimized images. */
    136157#define VMDK_MARKER_FOOTER 3
     158
    137159/** Marker for unknown purpose in streamOptimized images.
    138160 * Shows up in very recent images created by vSphere, but only sporadically.
    139161 * They "forgot" to document that one in the VMDK specification. */
    140162#define VMDK_MARKER_UNSPECIFIED 4
     163
    141164/** Dummy marker for "don't check the marker value". */
    142165#define VMDK_MARKER_IGNORE 0xffffffffU
     166
    143167/**
    144168 * Magic number for hosted images created by VMware Workstation 4, VMware
     
    146170 */
    147171#define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
     172
    148173/** VMDK sector size in bytes. */
    149174#define VMDK_SECTOR_SIZE 512
     
    154179/** Grain table size in bytes */
    155180#define VMDK_GRAIN_TABLE_SIZE 2048
     181
    156182/**
    157183 * VMDK hosted binary extent header. The "Sparse" is a total misnomer, as
     
    181207} SparseExtentHeader;
    182208#pragma pack()
     209
    183210/** The maximum allowed descriptor size in the extent header in sectors. */
    184211#define VMDK_SPARSE_DESCRIPTOR_SIZE_MAX UINT64_C(20480) /* 10MB */
     212
    185213/** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
    186214 * divisible by the default grain size (64K) */
    187215#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
     216
    188217/** VMDK streamOptimized file format marker. The type field may or may not
    189218 * be actually valid, but there's always data to read there. */
     
    196225} VMDKMARKER, *PVMDKMARKER;
    197226#pragma pack()
     227
     228
    198229/** Convert sector number/size to byte offset/size. */
    199230#define VMDK_SECTOR2BYTE(u) ((uint64_t)(u) << 9)
     231
    200232/** Convert byte offset/size to sector number/size. */
    201233#define VMDK_BYTE2SECTOR(u) ((u) >> 9)
     234
    202235/**
    203236 * VMDK extent type.
     
    214247    VMDKETYPE_VMFS
    215248} VMDKETYPE, *PVMDKETYPE;
     249
    216250/**
    217251 * VMDK access type for a extent.
     
    226260    VMDKACCESS_READWRITE
    227261} VMDKACCESS, *PVMDKACCESS;
     262
    228263/** Forward declaration for PVMDKIMAGE. */
    229264typedef struct VMDKIMAGE *PVMDKIMAGE;
     265
    230266/**
    231267 * Extents files entry. Used for opening a particular file only once.
     
    252288    struct VMDKFILE *pPrev;
    253289} VMDKFILE, *PVMDKFILE;
     290
    254291/**
    255292 * VMDK extent data structure.
     
    332369    struct VMDKIMAGE *pImage;
    333370} VMDKEXTENT, *PVMDKEXTENT;
     371
    334372/**
    335373 * Grain table cache size. Allocated per image.
    336374 */
    337375#define VMDK_GT_CACHE_SIZE 256
     376
    338377/**
    339378 * Grain table block size. Smaller than an actual grain table block to allow
     
    342381 */
    343382#define VMDK_GT_CACHELINE_SIZE 128
     383
     384
    344385/**
    345386 * Maximum number of lines in a descriptor file. Not worth the effort of
     
    349390 */
    350391#define VMDK_DESCRIPTOR_LINES_MAX   1100U
     392
    351393/**
    352394 * Parsed descriptor information. Allows easy access and update of the
     
    372414    unsigned    aNextLines[VMDK_DESCRIPTOR_LINES_MAX];
    373415} VMDKDESCRIPTOR, *PVMDKDESCRIPTOR;
     416
     417
    374418/**
    375419 * Cache entry for translating extent/sector to a sector number in that
     
    385429    uint32_t    aGTData[VMDK_GT_CACHELINE_SIZE];
    386430} VMDKGTCACHEENTRY, *PVMDKGTCACHEENTRY;
     431
    387432/**
    388433 * Cache data structure for blocks of grain table entries. For now this is a
     
    398443    unsigned            cEntries;
    399444} VMDKGTCACHE, *PVMDKGTCACHE;
     445
    400446/**
    401447 * Complete VMDK image data structure. Mainly a collection of extents and a few
     
    408454    /** Descriptor file if applicable. */
    409455    PVMDKFILE         pFile;
     456
    410457    /** Pointer to the per-disk VD interface list. */
    411458    PVDINTERFACE      pVDIfsDisk;
    412459    /** Pointer to the per-image VD interface list. */
    413460    PVDINTERFACE      pVDIfsImage;
     461
    414462    /** Error interface. */
    415463    PVDINTERFACEERROR pIfError;
    416464    /** I/O interface. */
    417465    PVDINTERFACEIOINT pIfIo;
     466
     467
    418468    /** Pointer to the image extents. */
    419469    PVMDKEXTENT     pExtents;
     
    423473     * times only once (happens mainly with raw partition access). */
    424474    PVMDKFILE       pFiles;
     475
    425476    /**
    426477     * Pointer to an array of segment entries for async I/O.
     
    432483    /** Entries available in the segments array. */
    433484    unsigned        cSegments;
     485
    434486    /** Open flags passed by VBoxHD layer. */
    435487    unsigned        uOpenFlags;
     
    450502    /** Parent image modification UUID. */
    451503    RTUUID          ParentModificationUuid;
     504
    452505    /** Pointer to grain table cache, if this image contains sparse extents. */
    453506    PVMDKGTCACHE    pGTCache;
     
    461514    VDREGIONLIST    RegionList;
    462515} VMDKIMAGE;
     516
     517
    463518/** State for the input/output callout of the inflate reader/deflate writer. */
    464519typedef struct VMDKCOMPRESSIO
     
    473528    void *pvCompGrain;
    474529} VMDKCOMPRESSIO;
     530
     531
    475532/** Tracks async grain allocation. */
    476533typedef struct VMDKGRAINALLOCASYNC
     
    494551    uint64_t    uRGTSector;
    495552} VMDKGRAINALLOCASYNC, *PVMDKGRAINALLOCASYNC;
     553
    496554/**
    497555 * State information for vmdkRename() and helpers.
     
    536594*   Static Variables                                                                                                             *
    537595*********************************************************************************************************************************/
     596
    538597/** NULL-terminated array of supported file extensions. */
    539598static const VDFILEEXTENSION s_aVmdkFileExtensions[] =
     
    542601    {NULL, VDTYPE_INVALID}
    543602};
     603
    544604/** NULL-terminated array of configuration option. */
    545605static const VDCONFIGINFO s_aVmdkConfigInfo[] =
     
    550610    { "BootSector",                     NULL,                             VDCFGVALUETYPE_BYTES,        0 },
    551611    { "Relative",                       NULL,                             VDCFGVALUETYPE_INTEGER,      0 },
     612
    552613    /* End of options list */
    553614    { NULL,                             NULL,                             VDCFGVALUETYPE_INTEGER,      0 }
     
    558619*   Internal Functions                                                                                                           *
    559620*********************************************************************************************************************************/
     621
    560622static void vmdkFreeStreamBuffers(PVMDKEXTENT pExtent);
    561623static int vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
    562624                              bool fDelete);
     625
    563626static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
    564627static int vmdkFlushImage(PVMDKIMAGE pImage, PVDIOCTX pIoCtx);
    565628static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment);
    566629static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete, bool fFlush);
     630
    567631static DECLCALLBACK(int) vmdkAllocGrainComplete(void *pBackendData, PVDIOCTX pIoCtx,
    568632                                                void *pvUser, int rcReq);
     633
    569634/**
    570635 * Internal: open a file (using a file descriptor cache to ensure each file
     
    576641    int rc = VINF_SUCCESS;
    577642    PVMDKFILE pVmdkFile;
     643
    578644    for (pVmdkFile = pImage->pFiles;
    579645         pVmdkFile != NULL;
     
    584650            Assert(fOpen == pVmdkFile->fOpen);
    585651            pVmdkFile->uReferences++;
     652
    586653            *ppVmdkFile = pVmdkFile;
     654
    587655            return rc;
    588656        }
    589657    }
     658
    590659    /* If we get here, there's no matching entry in the cache. */
    591660    pVmdkFile = (PVMDKFILE)RTMemAllocZ(sizeof(VMDKFILE));
     
    595664        return VERR_NO_MEMORY;
    596665    }
     666
    597667    pVmdkFile->pszFilename = RTStrDup(pszFilename);
    598668    if (!pVmdkFile->pszFilename)
     
    602672        return VERR_NO_MEMORY;
    603673    }
     674
    604675    if (pszBasename)
    605676    {
     
    613684        }
    614685    }
     686
    615687    pVmdkFile->fOpen = fOpen;
     688
    616689    rc = vdIfIoIntFileOpen(pImage->pIfIo, pszFilename, fOpen,
    617690                           &pVmdkFile->pStorage);
     
    632705        *ppVmdkFile = NULL;
    633706    }
     707
    634708    return rc;
    635709}
     710
    636711/**
    637712 * Internal: close a file, updating the file descriptor cache.
     
    641716    int rc = VINF_SUCCESS;
    642717    PVMDKFILE pVmdkFile = *ppVmdkFile;
     718
    643719    AssertPtr(pVmdkFile);
     720
    644721    pVmdkFile->fDelete |= fDelete;
    645722    Assert(pVmdkFile->uReferences);
     
    649726        PVMDKFILE pPrev;
    650727        PVMDKFILE pNext;
     728
    651729        /* Unchain the element from the list. */
    652730        pPrev = pVmdkFile->pPrev;
    653731        pNext = pVmdkFile->pNext;
     732
    654733        if (pNext)
    655734            pNext->pPrev = pPrev;
     
    658737        else
    659738            pImage->pFiles = pNext;
     739
    660740        rc = vdIfIoIntFileClose(pImage->pIfIo, pVmdkFile->pStorage);
     741
    661742        bool fFileDel = pVmdkFile->fDelete;
    662743        if (   pVmdkFile->pszBasename
     
    671752                fFileDel = false;
    672753        }
     754
    673755        if (fFileDel)
    674756        {
     
    684766        RTMemFree(pVmdkFile);
    685767    }
     768
    686769    *ppVmdkFile = NULL;
    687770    return rc;
    688771}
     772
    689773/*#define VMDK_USE_BLOCK_DECOMP_API - test and enable */
    690774#ifndef VMDK_USE_BLOCK_DECOMP_API
     
    693777    VMDKCOMPRESSIO *pInflateState = (VMDKCOMPRESSIO *)pvUser;
    694778    size_t cbInjected = 0;
     779
    695780    Assert(cbBuf);
    696781    if (pInflateState->iOffset < 0)
     
    718803}
    719804#endif
     805
    720806/**
    721807 * Internal: read from a file and inflate the compressed data,
     
    733819    VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
    734820    size_t cbCompSize, cbActuallyRead;
     821
    735822    if (!pcvMarker)
    736823    {
     
    747834        pMarker->cbSize = RT_H2LE_U32(pMarker->cbSize);
    748835    }
     836
    749837    cbCompSize = RT_LE2H_U32(pMarker->cbSize);
    750838    if (cbCompSize == 0)
     
    753841        return VERR_VD_VMDK_INVALID_FORMAT;
    754842    }
     843
    755844    /* Sanity check - the expansion ratio should be much less than 2. */
    756845    Assert(cbCompSize < 2 * cbToRead);
    757846    if (cbCompSize >= 2 * cbToRead)
    758847        return VERR_VD_VMDK_INVALID_FORMAT;
     848
    759849    /* Compressed grain marker. Data follows immediately. */
    760850    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     
    766856                                          512)
    767857                               - RT_UOFFSETOF(VMDKMARKER, uType));
     858
    768859    if (puLBA)
    769860        *puLBA = RT_LE2H_U64(pMarker->uSector);
     
    772863                                  + RT_UOFFSETOF(VMDKMARKER, uType),
    773864                                  512);
     865
    774866#ifdef VMDK_USE_BLOCK_DECOMP_API
    775867    rc = RTZipBlockDecompress(RTZIPTYPE_ZLIB, 0 /*fFlags*/,
     
    782874    InflateState.cbCompGrain = cbCompSize + RT_UOFFSETOF(VMDKMARKER, uType);
    783875    InflateState.pvCompGrain = pExtent->pvCompGrain;
     876
    784877    rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
    785878    if (RT_FAILURE(rc))
     
    798891    return rc;
    799892}
     893
    800894static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf)
    801895{
    802896    VMDKCOMPRESSIO *pDeflateState = (VMDKCOMPRESSIO *)pvUser;
     897
    803898    Assert(cbBuf);
    804899    if (pDeflateState->iOffset < 0)
     
    817912    return VINF_SUCCESS;
    818913}
     914
    819915/**
    820916 * Internal: deflate the uncompressed data and write to a file,
     
    829925    PRTZIPCOMP pZip = NULL;
    830926    VMDKCOMPRESSIO DeflateState;
     927
    831928    DeflateState.pImage = pImage;
    832929    DeflateState.iOffset = -1;
    833930    DeflateState.cbCompGrain = pExtent->cbCompGrain;
    834931    DeflateState.pvCompGrain = pExtent->pvCompGrain;
     932
    835933    rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper,
    836934                         RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
     
    845943        Assert(   DeflateState.iOffset > 0
    846944               && (size_t)DeflateState.iOffset <= DeflateState.cbCompGrain);
     945
    847946        /* pad with zeroes to get to a full sector size */
    848947        uint32_t uSize = DeflateState.iOffset;
     
    854953            uSize = uSizeAlign;
    855954        }
     955
    856956        if (pcbMarkerData)
    857957            *pcbMarkerData = uSize;
     958
    858959        /* Compressed grain marker. Data follows immediately. */
    859960        VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
     
    868969    return rc;
    869970}
     971
     972
    870973/**
    871974 * Internal: check if all files are closed, prevent leaking resources.
     
    875978    int rc = VINF_SUCCESS, rc2;
    876979    PVMDKFILE pVmdkFile;
     980
    877981    Assert(pImage->pFiles == NULL);
    878982    for (pVmdkFile = pImage->pFiles;
     
    883987                pVmdkFile->pszFilename));
    884988        pImage->pFiles = pVmdkFile->pNext;
     989
    885990        rc2 = vmdkFileClose(pImage, &pVmdkFile, pVmdkFile->fDelete);
     991
    886992        if (RT_SUCCESS(rc))
    887993            rc = rc2;
     
    889995    return rc;
    890996}
     997
    891998/**
    892999 * Internal: truncate a string (at a UTF8 code point boundary) and encode the
     
    8971004    char szEnc[VMDK_ENCODED_COMMENT_MAX + 3];
    8981005    char *pszDst = szEnc;
     1006
    8991007    AssertPtr(psz);
     1008
    9001009    for (; *psz; psz = RTStrNextCp(psz))
    9011010    {
     
    9281037    return RTStrDup(szEnc);
    9291038}
     1039
    9301040/**
    9311041 * Internal: decode a string and store it into the specified string.
     
    9351045    int rc = VINF_SUCCESS;
    9361046    char szBuf[4];
     1047
    9371048    if (!cb)
    9381049        return VERR_BUFFER_OVERFLOW;
     1050
    9391051    AssertPtr(psz);
     1052
    9401053    for (; *pszEncoded; pszEncoded = RTStrNextCp(pszEncoded))
    9411054    {
     
    9601073        else
    9611074            pszDst = RTStrPutCp(pszDst, Cp);
     1075
    9621076        /* Need to leave space for terminating NUL. */
    9631077        if ((size_t)(pszDst - szBuf) + 1 >= cb)
     
    9721086    return rc;
    9731087}
     1088
    9741089/**
    9751090 * Internal: free all buffers associated with grain directories.
     
    9881103    }
    9891104}
     1105
    9901106/**
    9911107 * Internal: allocate the compressed/uncompressed buffers for streamOptimized
     
    9951111{
    9961112    int rc = VINF_SUCCESS;
     1113
    9971114    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    9981115    {
     
    10131130            rc = VERR_NO_MEMORY;
    10141131    }
     1132
    10151133    if (RT_FAILURE(rc))
    10161134        vmdkFreeStreamBuffers(pExtent);
    10171135    return rc;
    10181136}
     1137
    10191138/**
    10201139 * Internal: allocate all buffers associated with grain directories.
     
    10251144    int rc = VINF_SUCCESS;
    10261145    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
     1146
    10271147    pExtent->pGD = (uint32_t *)RTMemAllocZ(cbGD);
    10281148    if (RT_LIKELY(pExtent->pGD))
     
    10371157    else
    10381158        rc = VERR_NO_MEMORY;
     1159
    10391160    if (RT_FAILURE(rc))
    10401161        vmdkFreeGrainDirectory(pExtent);
    10411162    return rc;
    10421163}
     1164
    10431165/**
    10441166 * Converts the grain directory from little to host endianess.
     
    10511173{
    10521174    uint32_t *pGDTmp = pGD;
     1175
    10531176    for (uint32_t i = 0; i < cGDEntries; i++, pGDTmp++)
    10541177        *pGDTmp = RT_LE2H_U32(*pGDTmp);
    10551178}
     1179
    10561180/**
    10571181 * Read the grain directory and allocated grain tables verifying them against
     
    10661190    int rc = VINF_SUCCESS;
    10671191    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
     1192
    10681193    AssertReturn((   pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
    10691194                  && pExtent->uSectorGD != VMDK_GD_AT_END
    10701195                  && pExtent->uSectorRGD != VMDK_GD_AT_END), VERR_INTERNAL_ERROR);
     1196
    10711197    rc = vmdkAllocGrainDirectory(pImage, pExtent);
    10721198    if (RT_SUCCESS(rc))
     
    10801206        {
    10811207            vmdkGrainDirectoryConvToHost(pExtent->pGD, pExtent->cGDEntries);
     1208
    10821209            if (   pExtent->uSectorRGD
    10831210                && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS))
     
    10911218                {
    10921219                    vmdkGrainDirectoryConvToHost(pExtent->pRGD, pExtent->cGDEntries);
     1220
    10931221                    /* Check grain table and redundant grain table for consistency. */
    10941222                    size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
    10951223                    size_t cbGTBuffers = cbGT; /* Start with space for one GT. */
    10961224                    size_t cbGTBuffersMax = _1M;
     1225
    10971226                    uint32_t *pTmpGT1 = (uint32_t *)RTMemAlloc(cbGTBuffers);
    10981227                    uint32_t *pTmpGT2 = (uint32_t *)RTMemAlloc(cbGTBuffers);
     1228
    10991229                    if (   !pTmpGT1
    11001230                        || !pTmpGT2)
    11011231                        rc = VERR_NO_MEMORY;
     1232
    11021233                    size_t i = 0;
    11031234                    uint32_t *pGDTmp = pExtent->pGD;
    11041235                    uint32_t *pRGDTmp = pExtent->pRGD;
     1236
    11051237                    /* Loop through all entries. */
    11061238                    while (i < pExtent->cGDEntries)
     
    11091241                        uint32_t uRGTStart = *pRGDTmp;
    11101242                        size_t   cbGTRead = cbGT;
     1243
    11111244                        /* If no grain table is allocated skip the entry. */
    11121245                        if (*pGDTmp == 0 && *pRGDTmp == 0)
     
    11151248                            continue;
    11161249                        }
     1250
    11171251                        if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
    11181252                        {
     
    11241258                            break;
    11251259                        }
     1260
    11261261                        i++;
    11271262                        pGDTmp++;
    11281263                        pRGDTmp++;
     1264
    11291265                        /*
    11301266                         * Read a few tables at once if adjacent to decrease the number
     
    11401276                                continue;
    11411277                            }
     1278
    11421279                            if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
    11431280                            {
     
    11491286                                break;
    11501287                            }
     1288
    11511289                            /* Check that the start offsets are adjacent.*/
    11521290                            if (   VMDK_SECTOR2BYTE(uGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pGDTmp)
    11531291                                || VMDK_SECTOR2BYTE(uRGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pRGDTmp))
    11541292                                break;
     1293
    11551294                            i++;
    11561295                            pGDTmp++;
     
    11581297                            cbGTRead += cbGT;
    11591298                        }
     1299
    11601300                        /* Increase buffers if required. */
    11611301                        if (   RT_SUCCESS(rc)
     
    11751315                            else
    11761316                                rc = VERR_NO_MEMORY;
     1317
    11771318                            if (rc == VERR_NO_MEMORY)
    11781319                            {
     
    11811322                                i -= cbGTRead / cbGT;
    11821323                                cbGTRead = cbGT;
     1324
    11831325                                /* Don't try to increase the buffer again in the next run. */
    11841326                                cbGTBuffersMax = cbGTBuffers;
    11851327                            }
    11861328                        }
     1329
    11871330                        if (RT_SUCCESS(rc))
    11881331                        {
     
    12171360                        }
    12181361                    } /* while (i < pExtent->cGDEntries) */
     1362
    12191363                    /** @todo figure out what to do for unclean VMDKs. */
    12201364                    if (pTmpGT1)
     
    12321376                           N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname, rc);
    12331377    }
     1378
    12341379    if (RT_FAILURE(rc))
    12351380        vmdkFreeGrainDirectory(pExtent);
    12361381    return rc;
    12371382}
     1383
    12381384/**
    12391385 * Creates a new grain directory for the given extent at the given start sector.
     
    12541400    size_t cbGTRounded;
    12551401    uint64_t cbOverhead;
     1402
    12561403    if (fPreAlloc)
    12571404    {
     
    12671414        cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded;
    12681415    }
     1416
    12691417    /* For streamOptimized extents there is only one grain directory,
    12701418     * and for all others take redundant grain directory into account. */
     
    12811429        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead);
    12821430    }
     1431
    12831432    if (RT_SUCCESS(rc))
    12841433    {
    12851434        pExtent->uAppendPosition = cbOverhead;
    12861435        pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
     1436
    12871437        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    12881438        {
     
    12951445            pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
    12961446        }
     1447
    12971448        rc = vmdkAllocStreamBuffers(pImage, pExtent);
    12981449        if (RT_SUCCESS(rc))
     
    13041455                uint32_t uGTSectorLE;
    13051456                uint64_t uOffsetSectors;
     1457
    13061458                if (pExtent->pRGD)
    13071459                {
     
    13231475                    }
    13241476                }
     1477
    13251478                if (RT_SUCCESS(rc))
    13261479                {
     
    13451498        }
    13461499    }
     1500
    13471501    if (RT_FAILURE(rc))
    13481502        vmdkFreeGrainDirectory(pExtent);
    13491503    return rc;
    13501504}
     1505
    13511506/**
    13521507 * Unquotes the given string returning the result in a separate buffer.
     
    13661521    char *pszQ;
    13671522    char *pszUnquoted;
     1523
    13681524    /* Skip over whitespace. */
    13691525    while (*pszStr == ' ' || *pszStr == '\t')
    13701526        pszStr++;
     1527
    13711528    if (*pszStr != '"')
    13721529    {
     
    13831540                             pImage->pszFilename, pszStart);
    13841541    }
     1542
    13851543    pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
    13861544    if (!pszUnquoted)
     
    13931551    return VINF_SUCCESS;
    13941552}
     1553
    13951554static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    13961555                           const char *pszLine)
     
    13981557    char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
    13991558    ssize_t cbDiff = strlen(pszLine) + 1;
     1559
    14001560    if (    pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
    14011561        &&  pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    14021562        return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     1563
    14031564    memcpy(pEnd, pszLine, cbDiff);
    14041565    pDescriptor->cLines++;
    14051566    pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
    14061567    pDescriptor->fDirty = true;
     1568
    14071569    return VINF_SUCCESS;
    14081570}
     1571
    14091572static bool vmdkDescGetStr(PVMDKDESCRIPTOR pDescriptor, unsigned uStart,
    14101573                           const char *pszKey, const char **ppszValue)
     
    14121575    size_t cbKey = strlen(pszKey);
    14131576    const char *pszValue;
     1577
    14141578    while (uStart != 0)
    14151579    {
     
    14301594    return !!uStart;
    14311595}
     1596
    14321597static int vmdkDescSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    14331598                          unsigned uStart,
     
    14371602    size_t cbKey = strlen(pszKey);
    14381603    unsigned uLast = 0;
     1604
    14391605    while (uStart != 0)
    14401606    {
     
    14711637                > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    14721638                return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     1639
    14731640            memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
    14741641                    pDescriptor->aLines[pDescriptor->cLines] - pszTmp - cbOldVal);
     
    15331700        for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    15341701            pDescriptor->aLines[i] += cbDiff;
     1702
    15351703        /* Adjust starting line numbers of following descriptor sections. */
    15361704        if (uStart <= pDescriptor->uFirstExtent)
     
    15421710    return VINF_SUCCESS;
    15431711}
     1712
    15441713static int vmdkDescBaseGetU32(PVMDKDESCRIPTOR pDescriptor, const char *pszKey,
    15451714                              uint32_t *puValue)
    15461715{
    15471716    const char *pszValue;
     1717
    15481718    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
    15491719                        &pszValue))
     
    15511721    return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
    15521722}
     1723
    15531724/**
    15541725 * Returns the value of the given key as a string allocating the necessary memory.
     
    15671738    const char *pszValue;
    15681739    char *pszValueUnquoted;
     1740
    15691741    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
    15701742                        &pszValue))
     
    15761748    return rc;
    15771749}
     1750
    15781751static int vmdkDescBaseSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    15791752                              const char *pszKey, const char *pszValue)
    15801753{
    15811754    char *pszValueQuoted;
     1755
    15821756    RTStrAPrintf(&pszValueQuoted, "\"%s\"", pszValue);
    15831757    if (!pszValueQuoted)
     
    15881762    return rc;
    15891763}
     1764
    15901765static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
    15911766                                   PVMDKDESCRIPTOR pDescriptor)
     
    15941769    unsigned uEntry = pDescriptor->uFirstExtent;
    15951770    ssize_t cbDiff;
     1771
    15961772    if (!uEntry)
    15971773        return;
     1774
    15981775    cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
    15991776    /* Move everything including \0 in the entry marking the end of buffer. */
     
    16111788    if (pDescriptor->uFirstDDB)
    16121789        pDescriptor->uFirstDDB--;
     1790
    16131791    return;
    16141792}
     1793
    16151794static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    16161795                             VMDKACCESS enmAccess, uint64_t cNominalSectors,
     
    16241803    char szExt[1024];
    16251804    ssize_t cbDiff;
     1805
    16261806    Assert((unsigned)enmAccess < RT_ELEMENTS(apszAccess));
    16271807    Assert((unsigned)enmType < RT_ELEMENTS(apszType));
     1808
    16281809    /* Find last entry in extent description. */
    16291810    while (uStart)
     
    16331814        uStart = pDescriptor->aNextLines[uStart];
    16341815    }
     1816
    16351817    if (enmType == VMDKETYPE_ZERO)
    16361818    {
     
    16511833    }
    16521834    cbDiff = strlen(szExt) + 1;
     1835
    16531836    /* Check for buffer overflow. */
    16541837    if (   (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
     
    16561839            - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
    16571840        return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     1841
    16581842    for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
    16591843    {
     
    16741858    for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    16751859        pDescriptor->aLines[i] += cbDiff;
     1860
    16761861    /* Adjust starting line numbers of following descriptor sections. */
    16771862    if (uStart <= pDescriptor->uFirstDDB)
    16781863        pDescriptor->uFirstDDB++;
     1864
    16791865    pDescriptor->fDirty = true;
    16801866    return VINF_SUCCESS;
    16811867}
     1868
    16821869/**
    16831870 * Returns the value of the given key from the DDB as a string allocating
     
    16971884    const char *pszValue;
    16981885    char *pszValueUnquoted;
     1886
    16991887    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    17001888                        &pszValue))
     
    17061894    return rc;
    17071895}
     1896
    17081897static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17091898                             const char *pszKey, uint32_t *puValue)
     
    17111900    const char *pszValue;
    17121901    char *pszValueUnquoted;
     1902
    17131903    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    17141904                        &pszValue))
     
    17211911    return rc;
    17221912}
     1913
    17231914static int vmdkDescDDBGetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17241915                              const char *pszKey, PRTUUID pUuid)
     
    17261917    const char *pszValue;
    17271918    char *pszValueUnquoted;
     1919
    17281920    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    17291921                        &pszValue))
     
    17361928    return rc;
    17371929}
     1930
    17381931static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17391932                             const char *pszKey, const char *pszVal)
     
    17411934    int rc;
    17421935    char *pszValQuoted;
     1936
    17431937    if (pszVal)
    17441938    {
     
    17551949    return rc;
    17561950}
     1951
    17571952static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17581953                              const char *pszKey, PCRTUUID pUuid)
    17591954{
    17601955    char *pszUuid;
     1956
    17611957    RTStrAPrintf(&pszUuid, "\"%RTuuid\"", pUuid);
    17621958    if (!pszUuid)
     
    17671963    return rc;
    17681964}
     1965
    17691966static int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17701967                             const char *pszKey, uint32_t uValue)
    17711968{
    17721969    char *pszValue;
     1970
    17731971    RTStrAPrintf(&pszValue, "\"%d\"", uValue);
    17741972    if (!pszValue)
     
    17791977    return rc;
    17801978}
     1979
    17811980/**
    17821981 * Splits the descriptor data into individual lines checking for correct line
     
    17921991    unsigned cLine = 0;
    17931992    int rc = VINF_SUCCESS;
     1993
    17941994    while (   RT_SUCCESS(rc)
    17951995           && *pszTmp != '\0')
     
    18022002            break;
    18032003        }
     2004
    18042005        while (*pszTmp != '\0' && *pszTmp != '\n')
    18052006        {
     
    18192020            pszTmp++;
    18202021        }
     2022
    18212023        if (RT_FAILURE(rc))
    18222024            break;
     2025
    18232026        /* Get rid of LF character. */
    18242027        if (*pszTmp == '\n')
     
    18282031        }
    18292032    }
     2033
    18302034    if (RT_SUCCESS(rc))
    18312035    {
     
    18342038        pDesc->aLines[cLine] = pszTmp;
    18352039    }
     2040
    18362041    return rc;
    18372042}
     2043
    18382044static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
    18392045                                    size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     
    18522058        {
    18532059            unsigned uLastNonEmptyLine = 0;
     2060
    18542061            /* Initialize those, because we need to be able to reopen an image. */
    18552062            pDescriptor->uFirstDesc = 0;
     
    19172124        }
    19182125    }
     2126
    19192127    return rc;
    19202128}
     2129
    19212130static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
    19222131                                   PCVDGEOMETRY pPCHSGeometry)
     
    19372146    return rc;
    19382147}
     2148
    19392149static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
    19402150                                   PCVDGEOMETRY pLCHSGeometry)
     
    19472157    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    19482158                           VMDK_DDB_GEO_LCHS_HEADS,
     2159
    19492160                           pLCHSGeometry->cHeads);
    19502161    if (RT_FAILURE(rc))
     
    19552166    return rc;
    19562167}
     2168
    19572169static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
    19582170                                size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     
    19662178    pDescriptor->aLines[pDescriptor->cLines] = pDescData;
    19672179    memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
     2180
    19682181    int rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
    19692182    if (RT_SUCCESS(rc))
     
    19972210    {
    19982211        pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
     2212
    19992213        /* Now that the framework is in place, use the normal functions to insert
    20002214         * the remaining keys. */
     
    20092223    if (RT_SUCCESS(rc))
    20102224        rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
     2225
    20112226    return rc;
    20122227}
     2228
    20132229static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
    20142230{
     
    20172233    unsigned uLine;
    20182234    unsigned i;
     2235
    20192236    rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
    20202237                                  &pImage->Descriptor);
    20212238    if (RT_FAILURE(rc))
    20222239        return rc;
     2240
    20232241    /* Check version, must be 1. */
    20242242    uint32_t uVersion;
     
    20282246    if (uVersion != 1)
    20292247        return vdIfError(pImage->pIfError, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
     2248
    20302249    /* Get image creation type and determine image flags. */
    20312250    char *pszCreateType = NULL;   /* initialized to make gcc shut up */
     
    20452264        pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_ESX;
    20462265    RTMemTmpFree(pszCreateType);
     2266
    20472267    /* Count the number of extent config entries. */
    20482268    for (uLine = pImage->Descriptor.uFirstExtent, cExtents = 0;
     
    20502270         uLine = pImage->Descriptor.aNextLines[uLine], cExtents++)
    20512271        /* nothing */;
     2272
    20522273    if (!pImage->pDescData && cExtents != 1)
    20532274    {
     
    20552276        return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image may only have one extent in '%s'"), pImage->pszFilename);
    20562277    }
     2278
    20572279    if (pImage->pDescData)
    20582280    {
     
    20622284            return rc;
    20632285    }
     2286
    20642287    for (i = 0, uLine = pImage->Descriptor.uFirstExtent;
    20652288         i < cExtents; i++, uLine = pImage->Descriptor.aNextLines[uLine])
    20662289    {
    20672290        char *pszLine = pImage->Descriptor.aLines[uLine];
     2291
    20682292        /* Access type of the extent. */
    20692293        if (!strncmp(pszLine, "RW", 2))
     
    20862310        if (*pszLine++ != ' ')
    20872311            return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
     2312
    20882313        /* Nominal size of the extent. */
    20892314        rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
     
    20932318        if (*pszLine++ != ' ')
    20942319            return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
     2320
    20952321        /* Type of the extent. */
    20962322        if (!strncmp(pszLine, "SPARSE", 6))
     
    21162342        else
    21172343            return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
     2344
    21182345        if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
    21192346        {
     
    21302357            if (*pszLine++ != ' ')
    21312358                return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
     2359
    21322360            /* Basename of the image. Surrounded by quotes. */
    21332361            char *pszBasename;
     
    21482376                }
    21492377            }
     2378
    21502379            if (*pszLine != '\0')
    21512380                return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    21522381        }
    21532382    }
     2383
    21542384    /* Determine PCHS geometry (autogenerate if necessary). */
    21552385    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     
    21862416        pImage->PCHSGeometry.cSectors = 63;
    21872417    }
     2418
    21882419    /* Determine LCHS geometry (set to 0 if not specified). */
    21892420    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     
    22162447        pImage->LCHSGeometry.cSectors = 0;
    22172448    }
     2449
    22182450    /* Get image UUID. */
    22192451    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_IMAGE_UUID,
     
    22392471    else if (RT_FAILURE(rc))
    22402472        return rc;
     2473
    22412474    /* Get image modification UUID. */
    22422475    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
     
    22642497    else if (RT_FAILURE(rc))
    22652498        return rc;
     2499
    22662500    /* Get UUID of parent image. */
    22672501    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_PARENT_UUID,
     
    22872521    else if (RT_FAILURE(rc))
    22882522        return rc;
     2523
    22892524    /* Get parent image modification UUID. */
    22902525    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
     
    23102545    else if (RT_FAILURE(rc))
    23112546        return rc;
     2547
    23122548    return VINF_SUCCESS;
    23132549}
     2550
    23142551/**
    23152552 * Internal : Prepares the descriptor to write to the image.
     
    23192556{
    23202557    int rc = VINF_SUCCESS;
     2558
    23212559    /*
    23222560     * Allocate temporary descriptor buffer.
     
    23272565    char *pszDescriptor = (char *)RTMemAllocZ(cbDescriptor);
    23282566    size_t offDescriptor = 0;
     2567
    23292568    if (!pszDescriptor)
    23302569        return VERR_NO_MEMORY;
     2570
    23312571    for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
    23322572    {
    23332573        const char *psz = pImage->Descriptor.aLines[i];
    23342574        size_t cb = strlen(psz);
     2575
    23352576        /*
    23362577         * Increase the descriptor if there is no limit and
     
    23482589                char *pszDescriptorNew = NULL;
    23492590                LogFlow(("Increasing descriptor cache\n"));
     2591
    23502592                pszDescriptorNew = (char *)RTMemRealloc(pszDescriptor, cbDescriptor + cb + 4 * _1K);
    23512593                if (!pszDescriptorNew)
     
    23582600            }
    23592601        }
     2602
    23602603        if (cb > 0)
    23612604        {
     
    23632606            offDescriptor += cb;
    23642607        }
     2608
    23652609        memcpy(pszDescriptor + offDescriptor, "\n", 1);
    23662610        offDescriptor++;
    23672611    }
     2612
    23682613    if (RT_SUCCESS(rc))
    23692614    {
     
    23732618    else if (pszDescriptor)
    23742619        RTMemFree(pszDescriptor);
     2620
    23752621    return rc;
    23762622}
     2623
    23772624/**
    23782625 * Internal: write/update the descriptor part of the image.
     
    23862633    void *pvDescriptor = NULL;
    23872634    size_t cbDescriptor;
     2635
    23882636    if (pImage->pDescData)
    23892637    {
     
    24032651    if (pDescFile == NULL)
    24042652        return VERR_INVALID_PARAMETER;
     2653
    24052654    rc = vmdkDescriptorPrepare(pImage, cbLimit, &pvDescriptor, &cbDescriptor);
    24062655    if (RT_SUCCESS(rc))
     
    24142663            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    24152664    }
     2665
    24162666    if (RT_SUCCESS(rc) && !cbLimit)
    24172667    {
     
    24202670            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
    24212671    }
     2672
    24222673    if (RT_SUCCESS(rc))
    24232674        pImage->Descriptor.fDirty = false;
     2675
    24242676    if (pvDescriptor)
    24252677        RTMemFree(pvDescriptor);
    24262678    return rc;
    2427 }
     2679
     2680}
     2681
    24282682/**
    24292683 * Internal: validate the consistency check values in a binary header.
     
    24592713    return rc;
    24602714}
     2715
    24612716/**
    24622717 * Internal: read metadata belonging to an extent with binary header, i.e.
     
    24682723    SparseExtentHeader Header;
    24692724    int rc;
     2725
    24702726    if (!fMagicAlreadyRead)
    24712727        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 0,
     
    24802736                                   - RT_UOFFSETOF(SparseExtentHeader, version));
    24812737    }
     2738
    24822739    if (RT_SUCCESS(rc))
    24832740    {
     
    24862743        {
    24872744            uint64_t cbFile = 0;
     2745
    24882746            if (    (RT_LE2H_U32(Header.flags) & RT_BIT(17))
    24892747                &&  RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
    24902748                pExtent->fFooter = true;
     2749
    24912750            if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    24922751                || (   pExtent->fFooter
     
    24972756                    rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
    24982757            }
     2758
    24992759            if (RT_SUCCESS(rc))
    25002760            {
    25012761                if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    25022762                    pExtent->uAppendPosition = RT_ALIGN_64(cbFile, 512);
     2763
    25032764                if (   pExtent->fFooter
    25042765                    && (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     
    25142775                        rc = VERR_VD_VMDK_INVALID_HEADER;
    25152776                    }
     2777
    25162778                    if (RT_SUCCESS(rc))
    25172779                        rc = vmdkValidateHeader(pImage, pExtent, &Header);
     
    25192781                    pExtent->uAppendPosition = 0;
    25202782                }
     2783
    25212784                if (RT_SUCCESS(rc))
    25222785                {
     
    25412804                        pExtent->uSectorRGD     = 0;
    25422805                    }
     2806
    25432807                    if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
    25442808                        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
    25452809                                       N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
     2810
    25462811                    if (   RT_SUCCESS(rc)
    25472812                        && (   pExtent->uSectorGD == VMDK_GD_AT_END
     
    25512816                        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
    25522817                                       N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname);
     2818
    25532819                    if (RT_SUCCESS(rc))
    25542820                    {
     
    25612827                            pExtent->cSectorsPerGDE = cSectorsPerGDE;
    25622828                            pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     2829
    25632830                            /* Fix up the number of descriptor sectors, as some flat images have
    25642831                             * really just one, and this causes failures when inserting the UUID
     
    25832850        rc = VERR_VD_VMDK_INVALID_HEADER;
    25842851    }
     2852
    25852853    if (RT_FAILURE(rc))
    25862854        vmdkFreeExtentData(pImage, pExtent, false);
     2855
    25872856    return rc;
    25882857}
     2858
    25892859/**
    25902860 * Internal: read additional metadata belonging to an extent. For those
     
    25942864{
    25952865    int rc = VINF_SUCCESS;
     2866
    25962867/* disabled the check as there are too many truncated vmdk images out there */
    25972868#ifdef VBOX_WITH_VMDK_STRICT_SIZE_CHECK
     
    26332904                    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    26342905                        pExtent->uAppendPosition = 0;
     2906
    26352907                    if (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    26362908                        || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     
    26462918        }
    26472919    }
     2920
    26482921    if (RT_FAILURE(rc))
    26492922        vmdkFreeExtentData(pImage, pExtent, false);
     2923
    26502924    return rc;
    26512925}
     2926
    26522927/**
    26532928 * Internal: write/update the metadata for a sparse extent.
     
    26572932{
    26582933    SparseExtentHeader Header;
     2934
    26592935    memset(&Header, '\0', sizeof(Header));
    26602936    Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
     
    26992975    Header.doubleEndLineChar2 = '\n';
    27002976    Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
     2977
    27012978    int rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pExtent->pFile->pStorage,
    27022979                                    uOffset, &Header, sizeof(Header),
     
    27062983    return rc;
    27072984}
     2985
    27082986/**
    27092987 * Internal: free the buffers used for streamOptimized images.
     
    27223000    }
    27233001}
     3002
    27243003/**
    27253004 * Internal: free the memory used by the extent data structure, optionally
     
    27353014{
    27363015    int rc = VINF_SUCCESS;
     3016
    27373017    vmdkFreeGrainDirectory(pExtent);
    27383018    if (pExtent->pDescData)
     
    27613041    }
    27623042    vmdkFreeStreamBuffers(pExtent);
     3043
    27633044    return rc;
    27643045}
     3046
    27653047/**
    27663048 * Internal: allocate grain table cache if necessary for this image.
     
    27693051{
    27703052    PVMDKEXTENT pExtent;
     3053
    27713054    /* Allocate grain table cache if any sparse extent is present. */
    27723055    for (unsigned i = 0; i < pImage->cExtents; i++)
     
    27883071        }
    27893072    }
     3073
    27903074    return VINF_SUCCESS;
    27913075}
     3076
    27923077/**
    27933078 * Internal: allocate the given number of extents.
     
    28173102    else
    28183103        rc = VERR_NO_MEMORY;
     3104
    28193105    return rc;
    28203106}
     3107
    28213108/**
    28223109 * Internal: allocate and describes an additional, file-backed extent
     
    29623249                {
    29633250                    uint64_t cDescriptorSectorsOld = pExtent->cDescriptorSectors;
     3251
    29643252                    pExtent->cDescriptorSectors = 4;
    29653253                    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     
    30263314            rc = VERR_NO_MEMORY;
    30273315    }
     3316
    30283317    return rc;
    30293318}
     3319
    30303320/**
    30313321 * Reads the descriptor from a pure text file.
     
    31143404                        else
    31153405                            pExtent->pszFullname = NULL;
     3406
    31163407                        unsigned uOpenFlags = pImage->uOpenFlags | ((pExtent->enmAccess == VMDKACCESS_READONLY) ? VD_OPEN_FLAGS_READONLY : 0);
    31173408                        switch (pExtent->enmType)
     
    31343425                                if (RT_FAILURE(rc))
    31353426                                    break;
     3427
    31363428                                /* Mark extent as unclean if opened in read-write mode. */
    31373429                                if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     
    31703462    else if (RT_SUCCESS(rc))
    31713463        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor in '%s' is too short"), pImage->pszFilename);
     3464
    31723465    return rc;
    31733466}
     3467
    31743468/**
    31753469 * Read and process the descriptor based on the image type.
     
    31823476{
    31833477    uint32_t u32Magic;
     3478
    31843479    /* Read magic (if present). */
    31853480    int rc = vdIfIoIntFileReadSync(pImage->pIfIo, pFile->pStorage, 0,
     
    31983493        rc = VERR_VD_VMDK_INVALID_HEADER;
    31993494    }
     3495
    32003496    return rc;
    32013497}
     3498
    32023499/**
    32033500 * Internal: Open an image, constructing all necessary data structures.
     
    32093506    pImage->pIfIo      = VDIfIoIntGet(pImage->pVDIfsImage);
    32103507    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
     3508
    32113509    /*
    32123510     * Open the image.
     
    32213519    {
    32223520        pImage->pFile = pFile;
     3521
    32233522        rc = vmdkDescriptorRead(pImage, pFile);
    32243523        if (RT_SUCCESS(rc))
     
    32383537                }
    32393538            }
     3539
    32403540            /* Update the image metadata now in case has changed. */
    32413541            rc = vmdkFlushImage(pImage, NULL);
     
    32573557                             ||  pExtent->enmType == VMDKETYPE_ZERO)
    32583558                        pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
     3559
    32593560                    pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
    32603561                }
     3562
    32613563                if (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    32623564                    || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     
    32683570    /* else: Do NOT signal an appropriate error here, as the VD layer has the
    32693571     *       choice of retrying the open if it failed. */
     3572
    32703573    if (RT_SUCCESS(rc))
    32713574    {
     
    32733576        pImage->RegionList.fFlags   = 0;
    32743577        pImage->RegionList.cRegions = 1;
     3578
    32753579        pRegion->offRegion            = 0; /* Disk start. */
    32763580        pRegion->cbBlock              = 512;
     
    32853589    return rc;
    32863590}
     3591
    32873592/**
    32883593 * Frees a raw descriptor.
     
    32933598    if (!pRawDesc)
    32943599        return VINF_SUCCESS;
     3600
    32953601    RTStrFree(pRawDesc->pszRawDisk);
    32963602    pRawDesc->pszRawDisk = NULL;
     3603
    32973604    /* Partitions: */
    32983605    for (unsigned i = 0; i < pRawDesc->cPartDescs; i++)
     
    33003607        RTStrFree(pRawDesc->pPartDescs[i].pszRawDevice);
    33013608        pRawDesc->pPartDescs[i].pszRawDevice = NULL;
     3609
    33023610        RTMemFree(pRawDesc->pPartDescs[i].pvPartitionData);
    33033611        pRawDesc->pPartDescs[i].pvPartitionData = NULL;
    33043612    }
     3613
    33053614    RTMemFree(pRawDesc->pPartDescs);
    33063615    pRawDesc->pPartDescs = NULL;
     3616
    33073617    RTMemFree(pRawDesc);
    33083618    return VINF_SUCCESS;
    33093619}
     3620
    33103621/**
    33113622 * Helper that grows the raw partition descriptor table by @a cToAdd entries,
     
    33243635        pRawDesc->cPartDescs = cNew;
    33253636        pRawDesc->pPartDescs = paNew;
     3637
    33263638        *ppRet = &paNew[cOld];
    33273639        return VINF_SUCCESS;
     
    33323644                     pImage->pszFilename, cOld, cNew);
    33333645}
     3646
    33343647/**
    33353648 * @callback_method_impl{FNRTSORTCMP}
     
    33413654    return iDelta < 0 ? -1 : iDelta > 0 ? 1 : 0;
    33423655}
     3656
    33433657/**
    33443658 * Post processes the partition descriptors.
     
    33523666     */
    33533667    RTSortShell(pRawDesc->pPartDescs, pRawDesc->cPartDescs, sizeof(pRawDesc->pPartDescs[0]), vmdkRawDescPartComp, NULL);
     3668
    33543669    /*
    33553670     * Check that we don't have overlapping descriptors.  If we do, that's an
     
    33663681                             paPartDescs[i].pvPartitionData ? " (data)" : "");
    33673682        offLast -= 1;
     3683
    33683684        if (i + 1 < pRawDesc->cPartDescs && offLast >= paPartDescs[i + 1].offStartInVDisk)
    33693685            return vdIfError(pImage->pIfError, VERR_FILESYSTEM_CORRUPT /*?*/, RT_SRC_POS,
     
    33783694                             paPartDescs[i].pvPartitionData ? " (data)" : "", cbSize);
    33793695    }
     3696
    33803697    return VINF_SUCCESS;
    33813698}
     3699
     3700
    33823701#ifdef RT_OS_LINUX
    33833702/**
     
    34023721    size_t const cchDir = RTPathEnsureTrailingSeparator(pszBlockDevDir, cbBlockDevDir);
    34033722    AssertReturn(cchDir > 0, VERR_BUFFER_OVERFLOW);
     3723
    34043724    RTDIR hDir = NIL_RTDIR;
    34053725    int rc = RTDirOpen(&hDir, pszBlockDevDir);
     
    34193739                    rc = RTStrCopy(&pszBlockDevDir[cchDir], cbBlockDevDir - cchDir, Entry.szName);
    34203740                    AssertContinue(RT_SUCCESS(rc)); /* should not happen! */
     3741
    34213742                    dev_t uThisDevNo = ~uDevToLocate;
    34223743                    rc = RTLinuxSysFsReadDevNumFile(&uThisDevNo, "%s/dev", pszBlockDevDir);
     
    34483769}
    34493770#endif /* RT_OS_LINUX */
     3771
    34503772#ifdef RT_OS_FREEBSD
     3773
     3774
    34513775/**
    34523776 * Reads the config data from the provider and returns offset and size
     
    34613785    gconfig *pConfEntry;
    34623786    int rc = VERR_NOT_FOUND;
     3787
    34633788    /*
    34643789     * Required parameters are located in the list containing key/value pairs.
     
    34913816    return rc;
    34923817}
     3818
     3819
    34933820/**
    34943821 * Searches the partition specified by name and calculates its size and absolute offset.
     
    35093836    AssertReturn(pcbAbsoluteOffset,  VERR_INVALID_PARAMETER);
    35103837    AssertReturn(pcbSize,            VERR_INVALID_PARAMETER);
     3838
    35113839    ggeom *pParentGeom;
    35123840    int rc = VERR_NOT_FOUND;
     
    35213849    if (RT_FAILURE(rc))
    35223850        return rc;
     3851
    35233852    gprovider *pProvider;
    35243853    /*
     
    35323861            return vmdkReadPartitionsParamsFromProvider(pProvider, pcbAbsoluteOffset, pcbSize);
    35333862    }
     3863
    35343864    /*
    35353865     * No provider found. Go over the parent geom again
     
    35413871     * provider
    35423872     */
     3873
    35433874    LIST_FOREACH(pProvider, &pParentGeom->lg_provider, lg_provider)
    35443875    {
     
    35483879        if (RT_FAILURE(rc))
    35493880            return rc;
     3881
    35503882        uint64_t cbProviderOffset = 0;
    35513883        uint64_t cbProviderSize = 0;
     
    35583890        }
    35593891    }
     3892
    35603893    return VERR_NOT_FOUND;
    35613894}
    35623895#endif
     3896
     3897
    35633898/**
    35643899 * Attempts to verify the raw partition path.
     
    35703905{
    35713906    RT_NOREF(pImage, pPartDesc, idxPartition, pszRawDrive, hRawDrive, cbSector, hVol);
     3907
    35723908    /*
    35733909     * Try open the raw partition device.
     
    35793915                         N_("VMDK: Image path: '%s'. Failed to open partition #%u on '%s' via '%s' (%Rrc)"),
    35803916                         pImage->pszFilename, idxPartition, pszRawDrive, pPartDesc->pszRawDevice, rc);
     3917
    35813918    /*
    35823919     * Compare the partition UUID if we can get it.
     
    35843921#ifdef RT_OS_WINDOWS
    35853922    DWORD cbReturned;
     3923
    35863924    /* 1. Get the device numbers for both handles, they should have the same disk. */
    35873925    STORAGE_DEVICE_NUMBER DevNum1;
     
    35923930                       N_("VMDK: Image path: '%s'. IOCTL_STORAGE_GET_DEVICE_NUMBER failed on '%s': %u"),
    35933931                       pImage->pszFilename, pszRawDrive, GetLastError());
     3932
    35943933    STORAGE_DEVICE_NUMBER DevNum2;
    35953934    RT_ZERO(DevNum2);
     
    36834022            rc = VERR_NO_TMP_MEMORY;
    36844023    }
     4024
    36854025#elif defined(RT_OS_LINUX)
    36864026    RT_NOREF(hVol);
     4027
    36874028    /* Stat the two devices first to get their device numbers.  (We probably
    36884029       could make some assumptions here about the major & minor number assignments
     
    37054046        {
    37064047            rc = vmdkFindSysBlockDevPath(pImage, szSysPath, sizeof(szSysPath), StDrive.st_rdev, pszRawDrive);
     4048
    37074049            /* Now, scan the directories under that again for a partition device
    37084050               matching the hRawPart device's number: */
    37094051            if (RT_SUCCESS(rc))
    37104052                rc = vmdkFindSysBlockDevPath(pImage, szSysPath, sizeof(szSysPath), StPart.st_rdev, pPartDesc->pszRawDevice);
     4053
    37114054            /* Having found the /sys/block/device/partition/ path, we can finally
    37124055               read the partition attributes and compare with hVol. */
     
    37214064                                   pImage->pszFilename, idxPartition, pPartDesc->pszRawDevice, pszRawDrive, iLnxPartition, idxPartition);
    37224065                /* else: ignore failure? */
     4066
    37234067                /* start offset: */
    37244068                uint32_t const cbLnxSector = 512; /* It's hardcoded in the Linux kernel */
     
    37344078                    /* else: ignore failure? */
    37354079                }
     4080
    37364081                /* the size: */
    37374082                if (RT_SUCCESS(rc))
     
    37504095        /* else: We've got nothing to work on, so only do content comparison. */
    37514096    }
     4097
    37524098#elif defined(RT_OS_FREEBSD)
    37534099    char szDriveDevName[256];
     
    37804126                rc = vdIfError(pImage->pIfError, VERR_GENERAL_FAILURE, RT_SRC_POS,
    37814127                               N_("VMDK: Image path: '%s'. 'PART' class not found in the GEOM tree"), pImage->pszFilename);
     4128
     4129
    37824130            if (RT_SUCCESS(rc))
    37834131            {
     
    38024150                                   pImage->pszFilename, pPartDesc->pszRawDevice, pszRawDrive, rc);
    38034151            }
     4152
    38044153            geom_deletetree(&geomMesh);
    38054154        }
     
    38084157                           N_("VMDK: Image path: '%s'. geom_gettree failed: %d"), pImage->pszFilename, err);
    38094158    }
     4159
    38104160#elif defined(RT_OS_SOLARIS)
    38114161    RT_NOREF(hVol);
     4162
    38124163    dk_cinfo dkiDriveInfo;
    38134164    dk_cinfo dkiPartInfo;
     
    38574208             * using another way. If there is an error, it returns errno which will be handled below.
    38584209             */
     4210
    38594211            uint32_t numPartition = (uint32_t)dkiPartInfo.dki_partition;
    38604212            if (numPartition > NDKMAP)
     
    38914243                           N_("VMDK: Image path: '%s'. Partition #%u path ('%s') verification failed on '%s': Start offset %RI64, expected %RU64"),
    38924244                           pImage->pszFilename, idxPartition, pPartDesc->pszRawDevice, pszRawDrive, cbOffset, pPartDesc->offStartInVDisk);
     4245
    38934246        if (RT_SUCCESS(rc) && cbSize != pPartDesc->cbData)
    38944247            rc = vdIfError(pImage->pIfError, VERR_MISMATCH, RT_SRC_POS,
     
    39664319#else
    39674320    RT_NOREF(hVol); /* PORTME */
     4321    rc = VERR_NOT_SUPPORTED;
    39684322#endif
    39694323    if (RT_SUCCESS(rc))
     
    39814335        {
    39824336            uint8_t *pbSector2 = pbSector1 + cbToCompare;
     4337
    39834338            /* Do the comparing, we repeat if it fails and the data might be volatile. */
    39844339            uint64_t uPrevCrc1 = 0;
     
    39964351                        {
    39974352                            rc = VERR_MISMATCH;
     4353
    39984354                            /* Do data stability checks before repeating: */
    39994355                            uint64_t const uCrc1 = RTCrc64(pbSector1, cbToCompare);
     
    40284384                    offMissmatch++;
    40294385                int cbSample = (int)RT_MIN(cbToCompare - offMissmatch, 16);
     4386
    40304387                if (cStable > 0)
    40314388                    rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
     
    40414398                }
    40424399            }
     4400
    40434401            RTMemTmpFree(pbSector1);
    40444402        }
     
    40514409    return rc;
    40524410}
     4411
    40534412#ifdef RT_OS_WINDOWS
    40544413/**
     
    40724431}
    40734432#endif /* RT_OS_WINDOWS */
     4433
    40744434/**
    40754435 * Worker for vmdkMakeRawDescriptor that adds partition descriptors when the
     
    40884448{
    40894449    *phVolToRelease = NIL_RTDVMVOLUME;
     4450
    40904451    /* Check sanity/understanding. */
    40914452    Assert(fPartitions);
    40924453    Assert((fPartitions & fPartitionsReadOnly) == fPartitionsReadOnly); /* RO should be a sub-set */
     4454
    40934455    /*
    40944456     * Allocate on descriptor for each volume up front.
    40954457     */
    40964458    uint32_t const cVolumes = RTDvmMapGetValidVolumes(hVolMgr);
     4459
    40974460    PVDISKRAWPARTDESC paPartDescs = NULL;
    40984461    int rc = vmdkRawDescAppendPartDesc(pImage, pRawDesc, cVolumes, &paPartDescs);
    40994462    AssertRCReturn(rc, rc);
     4463
    41004464    /*
    41014465     * Enumerate the partitions (volumes) on the disk and create descriptors for each of them.
     
    41204484        Assert(cRefs != UINT32_MAX); RT_NOREF(cRefs);
    41214485        *phVolToRelease = hVol = hVolNext;
     4486
    41224487        /*
    41234488         * Depending on the fPartitions selector and associated read-only mask,
     
    41264491         */
    41274492        paPartDescs[i].cbData = RTDvmVolumeGetSize(hVol);
     4493
    41284494        uint64_t offVolumeEndIgnored = 0;
    41294495        rc = RTDvmVolumeQueryRange(hVol, &paPartDescs[i].offStartInVDisk, &offVolumeEndIgnored);
     
    41334499                             pImage->pszFilename, i, pszRawDrive, rc);
    41344500        Assert(paPartDescs[i].cbData == offVolumeEndIgnored + 1 - paPartDescs[i].offStartInVDisk);
     4501
    41354502        /* Note! The index must match IHostDrivePartition::number. */
    41364503        uint32_t idxPartition = RTDvmVolumeGetIndex(hVol, RTDVMVOLIDX_HOST);
     
    41414508            if (fPartitionsReadOnly & RT_BIT_32(idxPartition))
    41424509                paPartDescs[i].uFlags |= VDISKRAW_READONLY;
     4510
    41434511            if (!fRelative)
    41444512            {
     
    41614529                 */
    41624530                paPartDescs[i].offStartInDevice = 0;
     4531
    41634532#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    41644533                /* /dev/rdisk1 -> /dev/rdisk1s2 (s=slice) */
     
    42144583#endif
    42154584                AssertPtrReturn(paPartDescs[i].pszRawDevice, VERR_NO_STR_MEMORY);
     4585
    42164586                rc = vmdkRawDescVerifyPartitionPath(pImage, &paPartDescs[i], idxPartition, pszRawDrive, hRawDrive, cbSector, hVol);
    42174587                AssertRCReturn(rc, rc);
     
    42254595        }
    42264596    } /* for each volume */
     4597
    42274598    RTDvmVolumeRelease(hVol);
    42284599    *phVolToRelease = NIL_RTDVMVOLUME;
     4600
    42294601    /*
    42304602     * Check that we found all the partitions the user selected.
     
    42414613                             pImage->pszFilename, pszRawDrive, szLeft);
    42424614    }
     4615
    42434616    return VINF_SUCCESS;
    42444617}
     4618
    42454619/**
    42464620 * Worker for vmdkMakeRawDescriptor that adds partition descriptors with copies
     
    42734647                         pImage->pszFilename, pszRawDrive, rc);
    42744648    AssertReturn(cLocations > 0 && cLocations < _16M, VERR_INTERNAL_ERROR_5);
     4649
    42754650    /* We can allocate the partition descriptors here to save an intentation level. */
    42764651    PVDISKRAWPARTDESC paPartDescs = NULL;
    42774652    rc = vmdkRawDescAppendPartDesc(pImage, pRawDesc, (uint32_t)cLocations, &paPartDescs);
    42784653    AssertRCReturn(rc, rc);
     4654
    42794655    /* Allocate the result table and repeat the location table query: */
    42804656    PRTDVMTABLELOCATION paLocations = (PRTDVMTABLELOCATION)RTMemAllocZ(sizeof(paLocations[0]) * cLocations);
     
    43564732    return rc;
    43574733}
     4734
    43584735/**
    43594736 * Opens the volume manager for the raw drive when in selected-partition mode.
     
    43714748{
    43724749    *phVolMgr = NIL_RTDVM;
     4750
    43734751    RTVFSFILE hVfsFile = NIL_RTVFSFILE;
    43744752    int rc = RTVfsFileFromRTFile(hRawDrive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, true /*fLeaveOpen*/, &hVfsFile);
     
    43774755                         N_("VMDK: Image path: '%s'.  RTVfsFileFromRTFile failed for '%s' handle (%Rrc)"),
    43784756                         pImage->pszFilename, pszRawDrive, rc);
     4757
    43794758    RTDVM hVolMgr = NIL_RTDVM;
    43804759    rc = RTDvmCreate(&hVolMgr, hVfsFile, cbSector, 0 /*fFlags*/);
     4760
    43814761    RTVfsFileRelease(hVfsFile);
     4762
    43824763    if (RT_FAILURE(rc))
    43834764        return vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    43844765                         N_("VMDK: Image path: '%s'. Failed to create volume manager instance for '%s' (%Rrc)"),
    43854766                         pImage->pszFilename, pszRawDrive, rc);
     4767
    43864768    rc = RTDvmMapOpen(hVolMgr);
    43874769    if (RT_SUCCESS(rc))
     
    43944776                     pImage->pszFilename, pszRawDrive, rc);
    43954777}
     4778
    43964779/**
    43974780 * Opens the raw drive device and get the sizes for it.
     
    44174800                         N_("VMDK: Image path: '%s'. Failed to open the raw drive '%s' for reading (%Rrc)"),
    44184801                         pImage->pszFilename, pszRawDrive, rc);
     4802
    44194803    /*
    44204804     * Get the sector size.
     
    44654849    return rc;
    44664850}
     4851
    44674852/**
    44684853 * Reads the raw disk configuration, leaving initalization and cleanup to the
     
    44814866        return vdIfError(pImage->pIfError, VERR_INVALID_PARAMETER, RT_SRC_POS,
    44824867                         N_("VMDK: Image path: '%s'. Getting config interface failed"), pImage->pszFilename);
     4868
    44834869    /*
    44844870     * RawDrive = path
     
    44894875                         N_("VMDK: Image path: '%s'. Getting 'RawDrive' configuration failed (%Rrc)"), pImage->pszFilename, rc);
    44904876    AssertPtrReturn(*ppszRawDrive, VERR_INTERNAL_ERROR_3);
     4877
    44914878    /*
    44924879     * Partitions=n[r][,...]
     
    44944881    uint32_t const cMaxPartitionBits = sizeof(*pfPartitions) * 8 /* ASSUMES 8 bits per char */;
    44954882    *pfPartitions = *pfPartitionsReadOnly = 0;
     4883
    44964884    rc = VDCFGQueryStringAlloc(pImgCfg, "Partitions", ppszFreeMe);
    44974885    if (RT_SUCCESS(rc))
     
    45274915                                 pImage->pszFilename, psz);
    45284916        }
     4917
    45294918        RTStrFree(*ppszFreeMe);
    45304919        *ppszFreeMe = NULL;
     
    45334922        return vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    45344923                         N_("VMDK: Image path: '%s'. Getting 'Partitions' configuration failed (%Rrc)"), pImage->pszFilename, rc);
     4924
    45354925    /*
    45364926     * BootSector=base64
     
    45524942                             N_("VMDK: Image path: '%s'. Custom bootsector for '%s' is way too big: %zu bytes, max 4MB"),
    45534943                             pImage->pszFilename, *ppszRawDrive, cbBootSector);
     4944
    45544945        /* Refuse the boot sector if whole-drive.  This used to be done quietly,
    45554946           however, bird disagrees and thinks the user should be told that what
     
    45604951                             N_("VMDK: Image path: '%s'. Custom bootsector for '%s' is not supported for whole-drive configurations, only when selecting partitions"),
    45614952                             pImage->pszFilename, *ppszRawDrive);
     4953
    45624954        *pcbBootSector = (size_t)cbBootSector;
    45634955        *ppvBootSector = RTMemAlloc((size_t)cbBootSector);
     
    45664958                             N_("VMDK: Image path: '%s'. Failed to allocate %zd bytes for the custom bootsector for '%s'"),
    45674959                             pImage->pszFilename, cbBootSector, *ppszRawDrive);
     4960
    45684961        rc = RTBase64Decode(*ppszFreeMe, *ppvBootSector, cbBootSector, NULL /*pcbActual*/, NULL /*ppszEnd*/);
    45694962        if (RT_FAILURE(rc))
     
    45714964                              N_("VMDK: Image path: '%s'. Base64 decoding of the custom boot sector for '%s' failed (%Rrc)"),
    45724965                              pImage->pszFilename, *ppszRawDrive, rc);
     4966
    45734967        RTStrFree(*ppszFreeMe);
    45744968        *ppszFreeMe = NULL;
     
    45774971        return vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    45784972                         N_("VMDK: Image path: '%s'. Getting 'BootSector' configuration failed (%Rrc)"), pImage->pszFilename, rc);
     4973
    45794974    /*
    45804975     * Relative=0/1
     
    46044999        *pfRelative = false;
    46055000#endif
     5001
    46065002    return VINF_SUCCESS;
    46075003}
     5004
    46085005/**
    46095006 * Creates a raw drive (nee disk) descriptor.
     
    46245021    /* Make sure it's NULL. */
    46255022    *ppRaw = NULL;
     5023
    46265024    /*
    46275025     * Read the configuration.
     
    46755073                    //pRawDesc->cPartDescs = 0;
    46765074                    //pRawDesc->pPartDescs = NULL;
     5075
    46775076                    /* We need to parse the partition map to complete the descriptor: */
    46785077                    RTDVM hVolMgr = NIL_RTDVM;
     
    46865085                            pRawDesc->enmPartitioningType = enmFormatType == RTDVMFORMATTYPE_MBR
    46875086                                                          ? VDISKPARTTYPE_MBR : VDISKPARTTYPE_GPT;
     5087
    46885088                            /* Add copies of the partition tables:  */
    46895089                            rc = vmdkRawDescDoCopyPartitionTables(pImage, hVolMgr, pRawDesc, pszRawDrive, hRawDrive,
     
    46975097                                                             fPartitions, fPartitionsReadOnly, fRelative, &hVolRelease);
    46985098                                RTDvmVolumeRelease(hVolRelease);
     5099
    46995100                                /* Finally, sort the partition and check consistency (overlaps, etc): */
    47005101                                if (RT_SUCCESS(rc))
     
    47405141    return rc;
    47415142}
     5143
    47425144/**
    47435145 * Internal: create VMDK images for raw disk/partition access.
     
    47485150    int rc = VINF_SUCCESS;
    47495151    PVMDKEXTENT pExtent;
     5152
    47505153    if (pRaw->uFlags & VDISKRAW_DISK)
    47515154    {
     
    47625165        if (RT_FAILURE(rc))
    47635166            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
     5167
    47645168        /* Set up basename for extent description. Cannot use StrDup. */
    47655169        size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
     
    47785182        pExtent->enmAccess = (pRaw->uFlags & VDISKRAW_READONLY) ? VMDKACCESS_READONLY : VMDKACCESS_READWRITE;
    47795183        pExtent->fMetaDirty = false;
     5184
    47805185        /* Open flat image, the raw disk. */
    47815186        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    47905195         * file, write the partition information to a flat extent and
    47915196         * open all the (flat) raw disk partitions. */
     5197
    47925198        /* First pass over the partition data areas to determine how many
    47935199         * extents we need. One data area can require up to 2 extents, as
     
    48015207                return vdIfError(pImage->pIfError, VERR_INVALID_PARAMETER, RT_SRC_POS,
    48025208                                 N_("VMDK: incorrect partition data area ordering set up by the caller in '%s'"), pImage->pszFilename);
     5209
    48035210            if (uStart < pPart->offStartInVDisk)
    48045211                cExtents++;
     
    48095216        if (uStart != cbSize)
    48105217            cExtents++;
     5218
    48115219        rc = vmdkCreateExtents(pImage, cExtents);
    48125220        if (RT_FAILURE(rc))
    48135221            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
     5222
    48145223        /* Create raw partition descriptor file. */
    48155224        rc = vmdkFileOpen(pImage, &pImage->pFile, NULL, pImage->pszFilename,
     
    48185227        if (RT_FAILURE(rc))
    48195228            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
     5229
    48205230        /* Create base filename for the partition table extent. */
    48215231        /** @todo remove fixed buffer without creating memory leaks. */
     
    48325242                    pszBaseBase, pszSuff);
    48335243        RTStrFree(pszBaseBase);
     5244
    48345245        /* Second pass over the partitions, now define all extents. */
    48355246        uint64_t uPartOffset = 0;
     
    48405251            PVDISKRAWPARTDESC pPart = &pRaw->pPartDescs[i];
    48415252            pExtent = &pImage->pExtents[cExtents++];
     5253
    48425254            if (uStart < pPart->offStartInVDisk)
    48435255            {
     
    48535265            }
    48545266            uStart = pPart->offStartInVDisk + pPart->cbData;
     5267
    48555268            if (pPart->pvPartitionData)
    48565269            {
     
    48625275                memcpy(pszBasename, pszPartition, cbBasename);
    48635276                pExtent->pszBasename = pszBasename;
     5277
    48645278                /* Set up full name for partition extent. */
    48655279                char *pszDirname = RTStrDup(pImage->pszFilename);
     
    48775291                pExtent->enmAccess = VMDKACCESS_READWRITE;
    48785292                pExtent->fMetaDirty = false;
     5293
    48795294                /* Create partition table flat image. */
    48805295                rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    49115326                    pExtent->enmAccess = (pPart->uFlags & VDISKRAW_READONLY) ? VMDKACCESS_READONLY : VMDKACCESS_READWRITE;
    49125327                    pExtent->fMetaDirty = false;
     5328
    49135329                    /* Open flat image, the raw partition. */
    49145330                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    49435359        }
    49445360    }
     5361
    49455362    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    49465363                            (pRaw->uFlags & VDISKRAW_DISK) ?
     
    49505367    return rc;
    49515368}
     5369
    49525370/**
    49535371 * Internal: create a regular (i.e. file-backed) VMDK image.
     
    49615379    uint64_t cbOffset = 0;
    49625380    uint64_t cbRemaining = cbSize;
     5381
    49635382    if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
    49645383    {
     
    49725391    if (RT_FAILURE(rc))
    49735392        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
     5393
    49745394    /* Basename strings needed for constructing the extent names. */
    49755395    char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    49765396    AssertPtr(pszBasenameSubstr);
    49775397    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     5398
    49785399    /* Create separate descriptor file if necessary. */
    49795400    if (cExtents != 1 || (uImageFlags & VD_IMAGE_FLAGS_FIXED))
     
    49875408    else
    49885409        pImage->pFile = NULL;
     5410
    49895411    /* Set up all extents. */
    49905412    for (unsigned i = 0; i < cExtents; i++)
     
    49925414        PVMDKEXTENT pExtent = &pImage->pExtents[i];
    49935415        uint64_t cbExtent = cbRemaining;
     5416
    49945417        /* Set up fullname/basename for extent description. Cannot use StrDup
    49955418         * for basename, as it is not guaranteed that the memory can be freed
     
    50485471            return VERR_NO_STR_MEMORY;
    50495472        pExtent->pszFullname = pszFullname;
     5473
    50505474        /* Create file for extent. */
    50515475        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    50635487                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    50645488        }
     5489
    50655490        /* Place descriptor file information (where integrated). */
    50665491        if (cExtents == 1 && !(uImageFlags & VD_IMAGE_FLAGS_FIXED))
     
    50725497            pImage->pDescData = NULL;
    50735498        }
     5499
    50745500        if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
    50755501        {
     
    50995525                pExtent->enmType = VMDKETYPE_FLAT;
    51005526        }
     5527
    51015528        pExtent->enmAccess = VMDKACCESS_READWRITE;
    51025529        pExtent->fUncleanShutdown = true;
     
    51045531        pExtent->uSectorOffset = 0;
    51055532        pExtent->fMetaDirty = true;
     5533
    51065534        if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
    51075535        {
     
    51155543                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
    51165544        }
     5545
    51175546        cbOffset += cbExtent;
     5547
    51185548        if (RT_SUCCESS(rc))
    51195549            vdIfProgress(pIfProgress, uPercentStart + cbOffset * uPercentSpan / cbSize);
     5550
    51205551        cbRemaining -= cbExtent;
    51215552    }
     5553
    51225554    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
    51235555    {
     
    51285560            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set controller type to lsilogic in '%s'"), pImage->pszFilename);
    51295561    }
     5562
    51305563    const char *pszDescType = NULL;
    51315564    if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
     
    51535586    return rc;
    51545587}
     5588
    51555589/**
    51565590 * Internal: Create a real stream optimized VMDK using only linear writes.
     
    51615595    if (RT_FAILURE(rc))
    51625596        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
     5597
    51635598    /* Basename strings needed for constructing the extent names. */
    51645599    const char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    51655600    AssertPtr(pszBasenameSubstr);
    51665601    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     5602
    51675603    /* No separate descriptor file. */
    51685604    pImage->pFile = NULL;
     5605
    51695606    /* Set up all extents. */
    51705607    PVMDKEXTENT pExtent = &pImage->pExtents[0];
     5608
    51715609    /* Set up fullname/basename for extent description. Cannot use StrDup
    51725610     * for basename, as it is not guaranteed that the memory can be freed
     
    51785616    memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    51795617    pExtent->pszBasename = pszBasename;
     5618
    51805619    char *pszBasedirectory = RTStrDup(pImage->pszFilename);
    51815620    RTPathStripFilename(pszBasedirectory);
     
    51855624        return VERR_NO_STR_MEMORY;
    51865625    pExtent->pszFullname = pszFullname;
     5626
    51875627    /* Create file for extent. Make it write only, no reading allowed. */
    51885628    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    51925632    if (RT_FAILURE(rc))
    51935633        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
     5634
    51945635    /* Place descriptor file information. */
    51955636    pExtent->uDescriptorSector = 1;
     
    51985639    pExtent->pDescData = pImage->pDescData;
    51995640    pImage->pDescData = NULL;
     5641
    52005642    uint64_t cSectorsPerGDE, cSectorsPerGD;
    52015643    pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     
    52075649    pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    52085650    cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     5651
    52095652    /* The spec says version is 1 for all VMDKs, but the vast
    52105653     * majority of streamOptimized VMDKs actually contain
     
    52135656    pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
    52145657    pExtent->fFooter = true;
     5658
    52155659    pExtent->enmAccess = VMDKACCESS_READONLY;
    52165660    pExtent->fUncleanShutdown = false;
     
    52185662    pExtent->uSectorOffset = 0;
    52195663    pExtent->fMetaDirty = true;
     5664
    52205665    /* Create grain directory, without preallocating it straight away. It will
    52215666     * be constructed on the fly when writing out the data and written when
     
    52265671    if (RT_FAILURE(rc))
    52275672        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
     5673
    52285674    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    52295675                            "streamOptimized");
    52305676    if (RT_FAILURE(rc))
    52315677        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
     5678
    52325679    return rc;
    52335680}
     5681
    52345682/**
    52355683 * Initializes the UUID fields in the DDB.
     
    52675715        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    52685716                       N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
     5717
    52695718    return rc;
    52705719}
     5720
    52715721/**
    52725722 * Internal: The actual code for creating any VMDK variant currently in
     
    52815731{
    52825732    pImage->uImageFlags = uImageFlags;
     5733
    52835734    pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
    52845735    pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
    52855736    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
     5737
    52865738    int rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
    52875739                                  &pImage->Descriptor);
     
    52955747            if (RT_FAILURE(rc))
    52965748                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could get raw descriptor for '%s'"), pImage->pszFilename);
     5749
    52975750            rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
    52985751            vmdkRawDescFree(pRaw);
     
    53105763                                        uPercentSpan * 95 / 100);
    53115764        }
     5765
    53125766        if (RT_SUCCESS(rc))
    53135767        {
    53145768            vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100);
     5769
    53155770            pImage->cbSize = cbSize;
     5771
    53165772            for (unsigned i = 0; i < pImage->cExtents; i++)
    53175773            {
    53185774                PVMDKEXTENT pExtent = &pImage->pExtents[i];
     5775
    53195776                rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
    53205777                                       pExtent->cNominalSectors, pExtent->enmType,
     
    53265783                }
    53275784            }
     5785
    53285786            if (RT_SUCCESS(rc))
    53295787                vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
     5788
    53305789            if (   RT_SUCCESS(rc)
    53315790                && pPCHSGeometry->cCylinders != 0
     
    53335792                && pPCHSGeometry->cSectors != 0)
    53345793                rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
     5794
    53355795            if (   RT_SUCCESS(rc)
    53365796                && pLCHSGeometry->cCylinders != 0
     
    53385798                && pLCHSGeometry->cSectors != 0)
    53395799                rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
     5800
    53405801            pImage->LCHSGeometry = *pLCHSGeometry;
    53415802            pImage->PCHSGeometry = *pPCHSGeometry;
     5803
    53425804            pImage->ImageUuid = *pUuid;
    53435805            RTUuidClear(&pImage->ParentUuid);
    53445806            RTUuidClear(&pImage->ModificationUuid);
    53455807            RTUuidClear(&pImage->ParentModificationUuid);
     5808
    53465809            if (RT_SUCCESS(rc))
    53475810                rc = vmdkCreateImageDdbUuidsInit(pImage);
     5811
    53485812            if (RT_SUCCESS(rc))
    53495813                rc = vmdkAllocateGrainTableCache(pImage);
     5814
    53505815            if (RT_SUCCESS(rc))
    53515816            {
     
    53545819                    rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
    53555820            }
     5821
    53565822            if (RT_SUCCESS(rc))
    53575823            {
    53585824                vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 99 / 100);
     5825
    53595826                if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    53605827                {
     
    53815848    else
    53825849        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
     5850
     5851
    53835852    if (RT_SUCCESS(rc))
    53845853    {
     
    53865855        pImage->RegionList.fFlags   = 0;
    53875856        pImage->RegionList.cRegions = 1;
     5857
    53885858        pRegion->offRegion            = 0; /* Disk start. */
    53895859        pRegion->cbBlock              = 512;
     
    53935863        pRegion->cbMetadata           = 0;
    53945864        pRegion->cRegionBlocksOrBytes = pImage->cbSize;
     5865
    53955866        vdIfProgress(pIfProgress, uPercentStart + uPercentSpan);
    53965867    }
     
    53995870    return rc;
    54005871}
     5872
    54015873/**
    54025874 * Internal: Update image comment.
     
    54115883            return VERR_NO_MEMORY;
    54125884    }
     5885
    54135886    int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
    54145887                               "ddb.comment", pszCommentEncoded);
     
    54195892    return VINF_SUCCESS;
    54205893}
     5894
    54215895/**
    54225896 * Internal. Clear the grain table buffer for real stream optimized writing.
     
    54295903               VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t));
    54305904}
     5905
    54315906/**
    54325907 * Internal. Flush the grain table buffer for real stream optimized writing.
     
    54375912    int rc = VINF_SUCCESS;
    54385913    uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
     5914
    54395915    /* VMware does not write out completely empty grain tables in the case
    54405916     * of streamOptimized images, which according to my interpretation of
     
    54585934    if (fAllZero)
    54595935        return VINF_SUCCESS;
     5936
    54605937    uint64_t uFileOffset = pExtent->uAppendPosition;
    54615938    if (!uFileOffset)
     
    54635940    /* Align to sector, as the previous write could have been any size. */
    54645941    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     5942
    54655943    /* Grain table marker. */
    54665944    uint8_t aMarker[512];
     
    54735951    AssertRC(rc);
    54745952    uFileOffset += 512;
     5953
    54755954    if (!pExtent->pGD || pExtent->pGD[uGDEntry])
    54765955        return VERR_INTERNAL_ERROR;
     5956
    54775957    pExtent->pGD[uGDEntry] = VMDK_BYTE2SECTOR(uFileOffset);
     5958
    54785959    for (uint32_t i = 0; i < cCacheLines; i++)
    54795960    {
     
    54835964        for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
    54845965            *pGTTmp = RT_H2LE_U32(*pGTTmp);
     5966
    54855967        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, uFileOffset,
    54865968                                    &pImage->pGTCache->aGTCache[i].aGTData[0],
     
    54945976    return rc;
    54955977}
     5978
    54965979/**
    54975980 * Internal. Free all allocated space for representing an image, and optionally
     
    55015984{
    55025985    int rc = VINF_SUCCESS;
     5986
    55035987    /* Freeing a never allocated image (e.g. because the open failed) is
    55045988     * not signalled as an error. After all nothing bad happens. */
     
    55266010                        pImage->pExtents[i].fMetaDirty = true;
    55276011                    }
     6012
    55286013                    /* From now on it's not safe to append any more data. */
    55296014                    pImage->pExtents[i].uAppendPosition = 0;
     
    55316016            }
    55326017        }
     6018
    55336019        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    55346020        {
     
    55496035                    AssertRC(rc);
    55506036                }
     6037
    55516038                uint64_t uFileOffset = pExtent->uAppendPosition;
    55526039                if (!uFileOffset)
    55536040                    return VERR_INTERNAL_ERROR;
    55546041                uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     6042
    55556043                /* From now on it's not safe to append any more data. */
    55566044                pExtent->uAppendPosition = 0;
     6045
    55576046                /* Grain directory marker. */
    55586047                uint8_t aMarker[512];
     
    55656054                AssertRC(rc);
    55666055                uFileOffset += 512;
     6056
    55676057                /* Write grain directory in little endian style. The array will
    55686058                 * not be used after this, so convert in place. */
     
    55746064                                            pExtent->cGDEntries * sizeof(uint32_t));
    55756065                AssertRC(rc);
     6066
    55766067                pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
    55776068                pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
     
    55796070                                          + pExtent->cGDEntries * sizeof(uint32_t),
    55806071                                          512);
     6072
    55816073                /* Footer marker. */
    55826074                memset(pMarker, '\0', sizeof(aMarker));
     
    55866078                                            uFileOffset, aMarker, sizeof(aMarker));
    55876079                AssertRC(rc);
     6080
    55886081                uFileOffset += 512;
    55896082                rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset, NULL);
    55906083                AssertRC(rc);
     6084
    55916085                uFileOffset += 512;
    55926086                /* End-of-stream marker. */
     
    55996093        else if (!fDelete && fFlush)
    56006094            vmdkFlushImage(pImage, NULL);
     6095
    56016096        if (pImage->pExtents != NULL)
    56026097        {
     
    56206115        if (RT_SUCCESS(rc))
    56216116            rc = rc2; /* Propogate any error when closing the file. */
     6117
    56226118        if (pImage->pGTCache)
    56236119        {
     
    56316127        }
    56326128    }
     6129
    56336130    LogFlowFunc(("returns %Rrc\n", rc));
    56346131    return rc;
    56356132}
     6133
    56366134/**
    56376135 * Internal. Flush image data (and metadata) to disk.
     
    56416139    PVMDKEXTENT pExtent;
    56426140    int rc = VINF_SUCCESS;
     6141
    56436142    /* Update descriptor if changed. */
    56446143    if (pImage->Descriptor.fDirty)
    56456144        rc = vmdkWriteDescriptor(pImage, pIoCtx);
     6145
    56466146    if (RT_SUCCESS(rc))
    56476147    {
     
    56796179                }
    56806180            }
     6181
    56816182            if (RT_FAILURE(rc))
    56826183                break;
     6184
    56836185            switch (pExtent->enmType)
    56846186            {
     
    57026204        }
    57036205    }
     6206
    57046207    return rc;
    57056208}
     6209
    57066210/**
    57076211 * Internal. Find extent corresponding to the sector number in the disk.
     
    57126216    PVMDKEXTENT pExtent = NULL;
    57136217    int rc = VINF_SUCCESS;
     6218
    57146219    for (unsigned i = 0; i < pImage->cExtents; i++)
    57156220    {
     
    57226227        offSector -= pImage->pExtents[i].cNominalSectors;
    57236228    }
     6229
    57246230    if (pExtent)
    57256231        *ppExtent = pExtent;
    57266232    else
    57276233        rc = VERR_IO_SECTOR_NOT_FOUND;
     6234
    57286235    return rc;
    57296236}
     6237
    57306238/**
    57316239 * Internal. Hash function for placing the grain table hash entries.
     
    57386246    return (uSector + uExtent) % pCache->cEntries;
    57396247}
     6248
    57406249/**
    57416250 * Internal. Get sector number in the extent file from the relative sector
     
    57526261    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
    57536262    int rc;
     6263
    57546264    /* For newly created and readonly/sequentially opened streamOptimized
    57556265     * images this must be a no-op, as the grain directory is not there. */
     
    57636273        return VINF_SUCCESS;
    57646274    }
     6275
    57656276    uGDIndex = uSector / pExtent->cSectorsPerGDE;
    57666277    if (uGDIndex >= pExtent->cGDEntries)
     
    57746285        return VINF_SUCCESS;
    57756286    }
     6287
    57766288    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
    57776289    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
     
    58026314    return VINF_SUCCESS;
    58036315}
     6316
    58046317/**
    58056318 * Internal. Writes the grain and also if necessary the grain tables.
     
    58166329    const void *pData;
    58176330    int rc;
     6331
    58186332    /* Very strict requirements: always write at least one full grain, with
    58196333     * proper alignment. Everything else would require reading of already
     
    58286342        || uSector + VMDK_BYTE2SECTOR(cbWrite) > pExtent->cNominalSectors)
    58296343        return VERR_INVALID_PARAMETER;
     6344
    58306345    /* Clip write range to at most the rest of the grain. */
    58316346    cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
     6347
    58326348    /* Do not allow to go back. */
    58336349    uGrain = uSector / pExtent->cSectorsPerGrain;
     
    58386354    if (uGrain < pExtent->uLastGrainAccess)
    58396355        return VERR_VD_VMDK_INVALID_WRITE;
     6356
    58406357    /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
    58416358     * to allocate something, we also need to detect the situation ourself. */
     
    58436360        && vdIfIoIntIoCtxIsZero(pImage->pIfIo, pIoCtx, cbWrite, true /* fAdvance */))
    58446361        return VINF_SUCCESS;
     6362
    58456363    if (uGDEntry != uLastGDEntry)
    58466364    {
     
    58566374        }
    58576375    }
     6376
    58586377    uint64_t uFileOffset;
    58596378    uFileOffset = pExtent->uAppendPosition;
     
    58626381    /* Align to sector, as the previous write could have been any size. */
    58636382    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     6383
    58646384    /* Paranoia check: extent type, grain table buffer presence and
    58656385     * grain table buffer space. Also grain table entry must be clear. */
     
    58696389        || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
    58706390        return VERR_INTERNAL_ERROR;
     6391
    58716392    /* Update grain table entry. */
    58726393    pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
     6394
    58736395    if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    58746396    {
     
    58836405        unsigned cSegments = 1;
    58846406        size_t cbSeg = 0;
     6407
    58856408        cbSeg = vdIfIoIntIoCtxSegArrayCreate(pImage->pIfIo, pIoCtx, &Segment,
    58866409                                             &cSegments, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     
    58996422    pExtent->uLastGrainAccess = uGrain;
    59006423    pExtent->uAppendPosition += cbGrain;
     6424
    59016425    return rc;
    59026426}
     6427
    59036428/**
    59046429 * Internal: Updates the grain table during grain allocation.
     
    59146439    uint64_t uSector = pGrainAlloc->uSector;
    59156440    PVMDKGTCACHEENTRY pGTCacheEntry;
     6441
    59166442    LogFlowFunc(("pImage=%#p pExtent=%#p pCache=%#p pIoCtx=%#p pGrainAlloc=%#p\n",
    59176443                 pImage, pExtent, pCache, pIoCtx, pGrainAlloc));
     6444
    59186445    uGTSector = pGrainAlloc->uGTSector;
    59196446    uRGTSector = pGrainAlloc->uRGTSector;
    59206447    LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
     6448
    59216449    /* Update the grain table (and the cache). */
    59226450    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
     
    59816509            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
    59826510    }
     6511
    59836512    LogFlowFunc(("leaving rc=%Rrc\n", rc));
    59846513    return rc;
    59856514}
     6515
    59866516/**
    59876517 * Internal - complete the grain allocation by updating disk grain table if required.
     
    59936523    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    59946524    PVMDKGRAINALLOCASYNC pGrainAlloc = (PVMDKGRAINALLOCASYNC)pvUser;
     6525
    59956526    LogFlowFunc(("pBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc\n",
    59966527                 pBackendData, pIoCtx, pvUser, rcReq));
     6528
    59976529    pGrainAlloc->cIoXfersPending--;
    59986530    if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded)
    59996531        rc = vmdkAllocGrainGTUpdate(pImage, pGrainAlloc->pExtent, pIoCtx, pGrainAlloc);
     6532
    60006533    if (!pGrainAlloc->cIoXfersPending)
    60016534    {
     
    60036536        RTMemFree(pGrainAlloc);
    60046537    }
     6538
    60056539    LogFlowFunc(("Leaving rc=%Rrc\n", rc));
    60066540    return rc;
    60076541}
     6542
    60086543/**
    60096544 * Internal. Allocates a new grain table (if necessary).
     
    60176552    PVMDKGRAINALLOCASYNC pGrainAlloc = NULL;
    60186553    int rc;
     6554
    60196555    LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n",
    60206556                 pCache, pExtent, pIoCtx, uSector, cbWrite));
     6557
    60216558    pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC));
    60226559    if (!pGrainAlloc)
    60236560        return VERR_NO_MEMORY;
     6561
    60246562    pGrainAlloc->pExtent = pExtent;
    60256563    pGrainAlloc->uSector = uSector;
     6564
    60266565    uGDIndex = uSector / pExtent->cSectorsPerGDE;
    60276566    if (uGDIndex >= pExtent->cGDEntries)
     
    60386577    {
    60396578        LogFlow(("Allocating new grain table\n"));
     6579
    60406580        /* There is no grain table referenced by this grain directory
    60416581         * entry. So there is absolutely no data in this area. Allocate
     
    60486588        }
    60496589        Assert(!(uFileOffset % 512));
     6590
    60506591        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    60516592        uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
     6593
    60526594        /* Normally the grain table is preallocated for hosted sparse extents
    60536595         * that support more than 32 bit sector numbers. So this shouldn't
     
    60586600            return VERR_VD_VMDK_INVALID_HEADER;
    60596601        }
     6602
    60606603        /* Write grain table by writing the required number of grain table
    60616604         * cache chunks. Allocate memory dynamically here or we flood the
     
    60636606        size_t cbGTDataTmp = pExtent->cGTEntries * sizeof(uint32_t);
    60646607        uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp);
     6608
    60656609        if (!paGTDataTmp)
    60666610        {
     
    60686612            return VERR_NO_MEMORY;
    60696613        }
     6614
    60706615        memset(paGTDataTmp, '\0', cbGTDataTmp);
    60716616        rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pExtent->pFile->pStorage,
     
    60836628        pExtent->uAppendPosition = RT_ALIGN_64(  pExtent->uAppendPosition
    60846629                                               + cbGTDataTmp, 512);
     6630
    60856631        if (pExtent->pRGD)
    60866632        {
     
    60916637            Assert(!(uFileOffset % 512));
    60926638            uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
     6639
    60936640            /* Normally the redundant grain table is preallocated for hosted
    60946641             * sparse extents that support more than 32 bit sector numbers. So
     
    60996646                return VERR_VD_VMDK_INVALID_HEADER;
    61006647            }
     6648
    61016649            /* Write grain table by writing the required number of grain table
    61026650             * cache chunks. Allocate memory dynamically here or we flood the
     
    61136661                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
    61146662            }
     6663
    61156664            pExtent->uAppendPosition = pExtent->uAppendPosition + cbGTDataTmp;
    61166665        }
     6666
    61176667        RTMemTmpFree(paGTDataTmp);
     6668
    61186669        /* Update the grain directory on disk (doing it before writing the
    61196670         * grain table will result in a garbled extent if the operation is
     
    61416692                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
    61426693        }
     6694
    61436695        /* As the final step update the in-memory copy of the GDs. */
    61446696        pExtent->pGD[uGDIndex] = uGTSector;
     
    61466698            pExtent->pRGD[uGDIndex] = uRGTSector;
    61476699    }
     6700
    61486701    LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
    61496702    pGrainAlloc->uGTSector = uGTSector;
    61506703    pGrainAlloc->uRGTSector = uRGTSector;
     6704
    61516705    uFileOffset = pExtent->uAppendPosition;
    61526706    if (!uFileOffset)
    61536707        return VERR_INTERNAL_ERROR;
    61546708    Assert(!(uFileOffset % 512));
     6709
    61556710    pGrainAlloc->uGrainOffset = uFileOffset;
     6711
    61566712    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    61576713    {
     
    61596715                        ("Accesses to stream optimized images must be synchronous\n"),
    61606716                        VERR_INVALID_STATE);
     6717
    61616718        if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    61626719            return vdIfError(pImage->pIfError, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
     6720
    61636721        /* Invalidate cache, just in case some code incorrectly allows mixing
    61646722         * of reads and writes. Normally shouldn't be needed. */
    61656723        pExtent->uGrainSectorAbs = 0;
     6724
    61666725        /* Write compressed data block and the markers. */
    61676726        uint32_t cbGrain = 0;
     
    61696728        RTSGSEG Segment;
    61706729        unsigned cSegments = 1;
     6730
    61716731        cbSeg = vdIfIoIntIoCtxSegArrayCreate(pImage->pIfIo, pIoCtx, &Segment,
    61726732                                             &cSegments, cbWrite);
    61736733        Assert(cbSeg == cbWrite);
     6734
    61746735        rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
    61756736                                 Segment.pvSeg, cbWrite, uSector, &cbGrain);
     
    61926753        else if (RT_FAILURE(rc))
    61936754            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
     6755
    61946756        pExtent->uAppendPosition += cbWrite;
    61956757    }
     6758
    61966759    rc = vmdkAllocGrainGTUpdate(pImage, pExtent, pIoCtx, pGrainAlloc);
     6760
    61976761    if (!pGrainAlloc->cIoXfersPending)
    61986762    {
     
    62006764        RTMemFree(pGrainAlloc);
    62016765    }
     6766
    62026767    LogFlowFunc(("leaving rc=%Rrc\n", rc));
     6768
    62036769    return rc;
    62046770}
     6771
    62056772/**
    62066773 * Internal. Reads the contents by sequentially going over the compressed
     
    62126779{
    62136780    int rc;
     6781
    62146782    LogFlowFunc(("pImage=%#p pExtent=%#p uSector=%llu pIoCtx=%#p cbRead=%llu\n",
    62156783                 pImage, pExtent, uSector, pIoCtx, cbRead));
     6784
    62166785    AssertMsgReturn(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
    62176786                    ("Async I/O not supported for sequential stream optimized images\n"),
    62186787                    VERR_INVALID_STATE);
     6788
    62196789    /* Do not allow to go back. */
    62206790    uint32_t uGrain = uSector / pExtent->cSectorsPerGrain;
     
    62226792        return VERR_VD_VMDK_INVALID_STATE;
    62236793    pExtent->uLastGrainAccess = uGrain;
     6794
    62246795    /* After a previous error do not attempt to recover, as it would need
    62256796     * seeking (in the general case backwards which is forbidden). */
    62266797    if (!pExtent->uGrainSectorAbs)
    62276798        return VERR_VD_VMDK_INVALID_STATE;
     6799
    62286800    /* Check if we need to read something from the image or if what we have
    62296801     * in the buffer is good to fulfill the request. */
     
    62326804        uint32_t uGrainSectorAbs =   pExtent->uGrainSectorAbs
    62336805                                   + VMDK_BYTE2SECTOR(pExtent->cbGrainStreamRead);
     6806
    62346807        /* Get the marker from the next data block - and skip everything which
    62356808         * is not a compressed grain. If it's a compressed grain which is for
     
    62466819            Marker.uSector = RT_LE2H_U64(Marker.uSector);
    62476820            Marker.cbSize = RT_LE2H_U32(Marker.cbSize);
     6821
    62486822            if (Marker.cbSize == 0)
    62496823            {
     
    63246898            }
    63256899        } while (Marker.uType != VMDK_MARKER_EOS);
     6900
    63266901        pExtent->uGrainSectorAbs = uGrainSectorAbs;
     6902
    63276903        if (!pExtent->cbGrainStreamRead && Marker.uType == VMDK_MARKER_EOS)
    63286904        {
     
    63336909        }
    63346910    }
     6911
    63356912    if (pExtent->uGrain > uSector / pExtent->cSectorsPerGrain)
    63366913    {
     
    63406917        return VERR_VD_BLOCK_FREE;
    63416918    }
     6919
    63426920    uint32_t uSectorInGrain = uSector % pExtent->cSectorsPerGrain;
    63436921    vdIfIoIntIoCtxCopyTo(pImage->pIfIo, pIoCtx,
     
    63476925    return VINF_SUCCESS;
    63486926}
     6927
    63496928/**
    63506929 * Replaces a fragment of a string with the specified string.
     
    64156994    return pszNewStr;
    64166995}
     6996
     6997
    64176998/** @copydoc VDIMAGEBACKEND::pfnProbe */
    64186999static DECLCALLBACK(int) vmdkProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
     
    64427023        vmdkFreeImage(pImage, false, false /*fFlush*/);
    64437024        RTMemFree(pImage);
     7025
    64447026        if (RT_SUCCESS(rc))
    64457027            *penmType = VDTYPE_HDD;
     
    64477029    else
    64487030        rc = VERR_NO_MEMORY;
     7031
    64497032    LogFlowFunc(("returns %Rrc\n", rc));
    64507033    return rc;
    64517034}
     7035
    64527036/** @copydoc VDIMAGEBACKEND::pfnOpen */
    64537037static DECLCALLBACK(int) vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
     
    64567040{
    64577041    RT_NOREF1(enmType); /**< @todo r=klaus make use of the type info. */
     7042
    64587043    LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
    64597044                 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
    64607045    int rc;
     7046
    64617047    /* Check open flags. All valid flags are supported. */
    64627048    AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
    64637049    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
    64647050    AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
     7051
    64657052
    64667053    PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(RT_UOFFSETOF(VMDKIMAGE, RegionList.aRegions[1]));
     
    64757062        pImage->pVDIfsDisk = pVDIfsDisk;
    64767063        pImage->pVDIfsImage = pVDIfsImage;
     7064
    64777065        rc = vmdkOpenImage(pImage, uOpenFlags);
    64787066        if (RT_SUCCESS(rc))
     
    64837071    else
    64847072        rc = VERR_NO_MEMORY;
     7073
    64857074    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    64867075    return rc;
    64877076}
     7077
    64887078/** @copydoc VDIMAGEBACKEND::pfnCreate */
    64897079static DECLCALLBACK(int) vmdkCreate(const char *pszFilename, uint64_t cbSize,
     
    64997089                 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
    65007090    int rc;
     7091
    65017092    /* Check the VD container type and image flags. */
    65027093    if (   enmType != VDTYPE_HDD
    65037094        || (uImageFlags & ~VD_VMDK_IMAGE_FLAGS_MASK) != 0)
    65047095        return VERR_VD_INVALID_TYPE;
     7096
    65057097    /* Check size. Maximum 256TB-64K for sparse images, otherwise unlimited. */
    65067098    if (   !(uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)
     
    65087100            || (!(uImageFlags & VD_IMAGE_FLAGS_FIXED) && cbSize >= _1T * 256 - _64K)))
    65097101        return VERR_VD_INVALID_SIZE;
     7102
    65107103    /* Check image flags for invalid combinations. */
    65117104    if (   (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    65127105        && (uImageFlags & ~(VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED | VD_IMAGE_FLAGS_DIFF)))
    65137106        return VERR_INVALID_PARAMETER;
     7107
    65147108    /* Check open flags. All valid flags are supported. */
    65157109    AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
     
    65217115                   && !(uImageFlags & VD_IMAGE_FLAGS_FIXED)),
    65227116                 VERR_INVALID_PARAMETER);
     7117
    65237118    PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(RT_UOFFSETOF(VMDKIMAGE, RegionList.aRegions[1]));
    65247119    if (RT_LIKELY(pImage))
    65257120    {
    65267121        PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
     7122
    65277123        pImage->pszFilename = pszFilename;
    65287124        pImage->pFile = NULL;
     
    65557151                    rc = vmdkOpenImage(pImage, uOpenFlags);
    65567152                }
     7153
    65577154                if (RT_SUCCESS(rc))
    65587155                    *ppBackendData = pImage;
    65597156            }
     7157
    65607158            if (RT_FAILURE(rc))
    65617159                RTMemFree(pImage->pDescData);
     
    65637161        else
    65647162            rc = VERR_NO_MEMORY;
     7163
    65657164        if (RT_FAILURE(rc))
    65667165            RTMemFree(pImage);
     
    65687167    else
    65697168        rc = VERR_NO_MEMORY;
     7169
    65707170    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    65717171    return rc;
    65727172}
     7173
    65737174/**
    65747175 * Prepares the state for renaming a VMDK image, setting up the state and allocating
     
    65837184{
    65847185    AssertReturn(RTPathFilename(pszFilename) != NULL, VERR_INVALID_PARAMETER);
     7186
    65857187    int rc = VINF_SUCCESS;
     7188
    65867189    memset(&pRenameState->DescriptorCopy, 0, sizeof(pRenameState->DescriptorCopy));
     7190
    65877191    /*
    65887192     * Allocate an array to store both old and new names of renamed files
     
    66107214            pRenameState->fEmbeddedDesc = true;
    66117215        }
     7216
    66127217        /* Save the descriptor content. */
    66137218        pRenameState->DescriptorCopy.cLines = pImage->Descriptor.cLines;
     
    66217226            }
    66227227        }
     7228
    66237229        if (RT_SUCCESS(rc))
    66247230        {
     
    66277233            AssertReturn(pRenameState->pszNewBaseName, VERR_NO_STR_MEMORY);
    66287234            RTPathStripSuffix(pRenameState->pszNewBaseName);
     7235
    66297236            pRenameState->pszOldBaseName = RTStrDup(RTPathFilename(pImage->pszFilename));
    66307237            AssertReturn(pRenameState->pszOldBaseName, VERR_NO_STR_MEMORY);
    66317238            RTPathStripSuffix(pRenameState->pszOldBaseName);
     7239
    66327240            /* Prepare both old and new full names used for string replacement.
    66337241               Note! Must abspath the stuff here, so the strstr weirdness later in
     
    66377245            AssertReturn(pRenameState->pszNewFullName, VERR_NO_STR_MEMORY);
    66387246            RTPathStripSuffix(pRenameState->pszNewFullName);
     7247
    66397248            pRenameState->pszOldFullName = RTPathAbsDup(pImage->pszFilename);
    66407249            AssertReturn(pRenameState->pszOldFullName, VERR_NO_STR_MEMORY);
    66417250            RTPathStripSuffix(pRenameState->pszOldFullName);
     7251
    66427252            /* Save the old name for easy access to the old descriptor file. */
    66437253            pRenameState->pszOldDescName = RTStrDup(pImage->pszFilename);
    66447254            AssertReturn(pRenameState->pszOldDescName, VERR_NO_STR_MEMORY);
     7255
    66457256            /* Save old image name. */
    66467257            pRenameState->pszOldImageName = pImage->pszFilename;
     
    66497260    else
    66507261        rc = VERR_NO_TMP_MEMORY;
     7262
    66517263    return rc;
    66527264}
     7265
    66537266/**
    66547267 * Destroys the given rename state, freeing all allocated memory.
     
    66947307        RTStrFree(pRenameState->pszNewFullName);
    66957308}
     7309
    66967310/**
    66977311 * Rolls back the rename operation to the original state.
     
    67047318{
    67057319    int rc = VINF_SUCCESS;
     7320
    67067321    if (!pRenameState->fImageFreed)
    67077322    {
     
    67127327        vmdkFreeImage(pImage, false, true /*fFlush*/);
    67137328    }
     7329
    67147330    /* Rename files back. */
    67157331    for (unsigned i = 0; i <= pRenameState->cExtents; i++)
     
    67507366    pImage->pszFilename = pRenameState->pszOldImageName;
    67517367    rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
     7368
    67527369    return rc;
    67537370}
     7371
    67547372/**
    67557373 * Rename worker doing the real work.
     
    67647382    int rc = VINF_SUCCESS;
    67657383    unsigned i, line;
     7384
    67667385    /* Update the descriptor with modified extent names. */
    67677386    for (i = 0, line = pImage->Descriptor.uFirstExtent;
     
    67807399        pImage->Descriptor.aLines[line] = pRenameState->apszNewLines[i];
    67817400    }
     7401
    67827402    if (RT_SUCCESS(rc))
    67837403    {
     
    67867406        /* Flush the descriptor now, in case it is embedded. */
    67877407        vmdkFlushImage(pImage, NULL);
     7408
    67887409        /* Close and rename/move extents. */
    67897410        for (i = 0; i < pRenameState->cExtents; i++)
     
    68037424            if (RT_FAILURE(rc))
    68047425                break;;
     7426
    68057427            /* Rename the extent file. */
    68067428            rc = vdIfIoIntFileMove(pImage->pIfIo, pExtent->pszFullname, pRenameState->apszNewName[i], 0);
     
    68107432            pRenameState->apszOldName[i] = RTStrDup(pExtent->pszFullname);
    68117433        }
     7434
    68127435        if (RT_SUCCESS(rc))
    68137436        {
     
    68177440            {
    68187441                pRenameState->fImageFreed = true;
     7442
    68197443                /* Last elements of new/old name arrays are intended for
    68207444                 * storing descriptor's names.
     
    68317455                    }
    68327456                }
     7457
    68337458                /* Update pImage with the new information. */
    68347459                pImage->pszFilename = pszFilename;
     7460
    68357461                /* Open the new image. */
    68367462                rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
     
    68387464        }
    68397465    }
     7466
    68407467    return rc;
    68417468}
     7469
    68427470/** @copydoc VDIMAGEBACKEND::pfnRename */
    68437471static DECLCALLBACK(int) vmdkRename(void *pBackendData, const char *pszFilename)
    68447472{
    68457473    LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
     7474
    68467475    PVMDKIMAGE  pImage  = (PVMDKIMAGE)pBackendData;
    68477476    VMDKRENAMESTATE RenameState;
     7477
    68487478    memset(&RenameState, 0, sizeof(RenameState));
     7479
    68497480    /* Check arguments. */
    68507481    AssertPtrReturn(pImage, VERR_INVALID_POINTER);
     
    68527483    AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
    68537484    AssertReturn(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK), VERR_INVALID_PARAMETER);
     7485
    68547486    int rc = vmdkRenameStatePrepare(pImage, &RenameState, pszFilename);
    68557487    if (RT_SUCCESS(rc))
    68567488    {
    68577489        /* --- Up to this point we have not done any damage yet. --- */
     7490
    68587491        rc = vmdkRenameWorker(pImage, &RenameState, pszFilename);
    68597492        /* Roll back all changes in case of failure. */
     
    68647497        }
    68657498    }
     7499
    68667500    vmdkRenameStateDestroy(&RenameState);
    68677501    LogFlowFunc(("returns %Rrc\n", rc));
    68687502    return rc;
    68697503}
     7504
    68707505/** @copydoc VDIMAGEBACKEND::pfnClose */
    68717506static DECLCALLBACK(int) vmdkClose(void *pBackendData, bool fDelete)
     
    68737508    LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
    68747509    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7510
    68757511    int rc = vmdkFreeImage(pImage, fDelete, true /*fFlush*/);
    68767512    RTMemFree(pImage);
     7513
    68777514    LogFlowFunc(("returns %Rrc\n", rc));
    68787515    return rc;
    68797516}
     7517
    68807518/** @copydoc VDIMAGEBACKEND::pfnRead */
    68817519static DECLCALLBACK(int) vmdkRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
     
    68857523                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
    68867524    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7525
    68877526    AssertPtr(pImage);
    68887527    Assert(uOffset % 512 == 0);
     
    68917530    AssertReturn(cbToRead, VERR_INVALID_PARAMETER);
    68927531    AssertReturn(uOffset + cbToRead <= pImage->cbSize, VERR_INVALID_PARAMETER);
     7532
    68937533    /* Find the extent and check access permissions as defined in the extent descriptor. */
    68947534    PVMDKEXTENT pExtent;
     
    69017541        /* Clip read range to remain in this extent. */
    69027542        cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     7543
    69037544        /* Handle the read according to the current extent type. */
    69047545        switch (pExtent->enmType)
     
    69077548            {
    69087549                uint64_t uSectorExtentAbs;
     7550
    69097551                rc = vmdkGetSector(pImage, pIoCtx, pExtent, uSectorExtentRel, &uSectorExtentAbs);
    69107552                if (RT_FAILURE(rc))
     
    69307572                        AssertMsg(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
    69317573                                  ("Async I/O is not supported for stream optimized VMDK's\n"));
     7574
    69327575                        uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
    69337576                        uSectorExtentAbs -= uSectorInGrain;
     
    69707613            {
    69717614                size_t cbSet;
     7615
    69727616                cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
    69737617                Assert(cbSet == cbToRead);
     
    69807624    else if (RT_SUCCESS(rc))
    69817625        rc = VERR_VD_VMDK_INVALID_STATE;
     7626
    69827627    LogFlowFunc(("returns %Rrc\n", rc));
    69837628    return rc;
    69847629}
     7630
    69857631/** @copydoc VDIMAGEBACKEND::pfnWrite */
    69867632static DECLCALLBACK(int) vmdkWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
     
    69927638    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    69937639    int rc;
     7640
    69947641    AssertPtr(pImage);
    69957642    Assert(uOffset % 512 == 0);
     
    69977644    AssertPtrReturn(pIoCtx, VERR_INVALID_POINTER);
    69987645    AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);
     7646
    69997647    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    70007648    {
     
    70027650        uint64_t uSectorExtentRel;
    70037651        uint64_t uSectorExtentAbs;
     7652
    70047653        /* No size check here, will do that later when the extent is located.
    70057654         * There are sparse images out there which according to the spec are
     
    70087657         * grain boundaries, and with the nominal size not being a multiple of the
    70097658         * grain size), this would prevent writing to the last grain. */
     7659
    70107660        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
    70117661                            &pExtent, &uSectorExtentRel);
     
    71057755                }
    71067756            }
     7757
    71077758            if (pcbWriteProcess)
    71087759                *pcbWriteProcess = cbToWrite;
     
    71117762    else
    71127763        rc = VERR_VD_IMAGE_READ_ONLY;
     7764
    71137765    LogFlowFunc(("returns %Rrc\n", rc));
    71147766    return rc;
    71157767}
     7768
    71167769/** @copydoc VDIMAGEBACKEND::pfnFlush */
    71177770static DECLCALLBACK(int) vmdkFlush(void *pBackendData, PVDIOCTX pIoCtx)
    71187771{
    71197772    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7773
    71207774    return vmdkFlushImage(pImage, pIoCtx);
    71217775}
     7776
    71227777/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
    71237778static DECLCALLBACK(unsigned) vmdkGetVersion(void *pBackendData)
     
    71257780    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    71267781    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7782
    71277783    AssertPtrReturn(pImage, 0);
     7784
    71287785    return VMDK_IMAGE_VERSION;
    71297786}
     7787
    71307788/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
    71317789static DECLCALLBACK(uint64_t) vmdkGetFileSize(void *pBackendData)
     
    71347792    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    71357793    uint64_t cb = 0;
     7794
    71367795    AssertPtrReturn(pImage, 0);
     7796
    71377797    if (pImage->pFile != NULL)
    71387798    {
     
    71527812        }
    71537813    }
     7814
    71547815    LogFlowFunc(("returns %lld\n", cb));
    71557816    return cb;
    71567817}
     7818
    71577819/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
    71587820static DECLCALLBACK(int) vmdkGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
     
    71617823    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    71627824    int rc = VINF_SUCCESS;
     7825
    71637826    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     7827
    71647828    if (pImage->PCHSGeometry.cCylinders)
    71657829        *pPCHSGeometry = pImage->PCHSGeometry;
    71667830    else
    71677831        rc = VERR_VD_GEOMETRY_NOT_SET;
     7832
    71687833    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
    71697834    return rc;
    71707835}
     7836
    71717837/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
    71727838static DECLCALLBACK(int) vmdkSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
     
    71767842    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    71777843    int rc = VINF_SUCCESS;
     7844
    71787845    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     7846
    71797847    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    71807848    {
     
    71907858    else
    71917859        rc = VERR_VD_IMAGE_READ_ONLY;
     7860
    71927861    LogFlowFunc(("returns %Rrc\n", rc));
    71937862    return rc;
    71947863}
     7864
    71957865/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
    71967866static DECLCALLBACK(int) vmdkGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
     
    71997869    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    72007870    int rc = VINF_SUCCESS;
     7871
    72017872    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     7873
    72027874    if (pImage->LCHSGeometry.cCylinders)
    72037875        *pLCHSGeometry = pImage->LCHSGeometry;
    72047876    else
    72057877        rc = VERR_VD_GEOMETRY_NOT_SET;
     7878
    72067879    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    72077880    return rc;
    72087881}
     7882
    72097883/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
    72107884static DECLCALLBACK(int) vmdkSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
     
    72147888    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    72157889    int rc = VINF_SUCCESS;
     7890
    72167891    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     7892
    72177893    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    72187894    {
     
    72287904    else
    72297905        rc = VERR_VD_IMAGE_READ_ONLY;
     7906
    72307907    LogFlowFunc(("returns %Rrc\n", rc));
    72317908    return rc;
    72327909}
     7910
    72337911/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
    72347912static DECLCALLBACK(int) vmdkQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
     
    72367914    LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
    72377915    PVMDKIMAGE pThis = (PVMDKIMAGE)pBackendData;
     7916
    72387917    AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
     7918
    72397919    *ppRegionList = &pThis->RegionList;
    72407920    LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
    72417921    return VINF_SUCCESS;
    72427922}
     7923
    72437924/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
    72447925static DECLCALLBACK(void) vmdkRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
     
    72487929    PVMDKIMAGE pThis = (PVMDKIMAGE)pBackendData;
    72497930    AssertPtr(pThis); RT_NOREF(pThis);
     7931
    72507932    /* Nothing to do here. */
    72517933}
     7934
    72527935/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
    72537936static DECLCALLBACK(unsigned) vmdkGetImageFlags(void *pBackendData)
     
    72557938    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    72567939    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7940
    72577941    AssertPtrReturn(pImage, 0);
     7942
    72587943    LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
    72597944    return pImage->uImageFlags;
    72607945}
     7946
    72617947/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
    72627948static DECLCALLBACK(unsigned) vmdkGetOpenFlags(void *pBackendData)
     
    72647950    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    72657951    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7952
    72667953    AssertPtrReturn(pImage, 0);
     7954
    72677955    LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
    72687956    return pImage->uOpenFlags;
    72697957}
     7958
    72707959/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
    72717960static DECLCALLBACK(int) vmdkSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
     
    72747963    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    72757964    int rc;
     7965
    72767966    /* Image must be opened and the new flags must be valid. */
    72777967    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
     
    72967986        }
    72977987    }
     7988
    72987989    LogFlowFunc(("returns %Rrc\n", rc));
    72997990    return rc;
    73007991}
     7992
    73017993/** @copydoc VDIMAGEBACKEND::pfnGetComment */
    73027994static DECLCALLBACK(int) vmdkGetComment(void *pBackendData, char *pszComment, size_t cbComment)
     
    73047996    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
    73057997    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     7998
    73067999    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8000
    73078001    char *pszCommentEncoded = NULL;
    73088002    int rc = vmdkDescDDBGetStr(pImage, &pImage->Descriptor,
     
    73138007        rc = VINF_SUCCESS;
    73148008    }
     8009
    73158010    if (RT_SUCCESS(rc))
    73168011    {
     
    73198014        else if (pszComment)
    73208015                *pszComment = '\0';
     8016
    73218017        if (pszCommentEncoded)
    73228018            RTMemTmpFree(pszCommentEncoded);
    73238019    }
     8020
    73248021    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
    73258022    return rc;
    73268023}
     8024
    73278025/** @copydoc VDIMAGEBACKEND::pfnSetComment */
    73288026static DECLCALLBACK(int) vmdkSetComment(void *pBackendData, const char *pszComment)
     
    73318029    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    73328030    int rc;
     8031
    73338032    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8033
    73348034    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    73358035    {
     
    73418041    else
    73428042        rc = VERR_VD_IMAGE_READ_ONLY;
     8043
    73438044    LogFlowFunc(("returns %Rrc\n", rc));
    73448045    return rc;
    73458046}
     8047
    73468048/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
    73478049static DECLCALLBACK(int) vmdkGetUuid(void *pBackendData, PRTUUID pUuid)
     
    73498051    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    73508052    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     8053
    73518054    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8055
    73528056    *pUuid = pImage->ImageUuid;
     8057
    73538058    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    73548059    return VINF_SUCCESS;
    73558060}
     8061
    73568062/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
    73578063static DECLCALLBACK(int) vmdkSetUuid(void *pBackendData, PCRTUUID pUuid)
     
    73608066    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    73618067    int rc = VINF_SUCCESS;
     8068
    73628069    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8070
    73638071    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    73648072    {
     
    73778085    else
    73788086        rc = VERR_VD_IMAGE_READ_ONLY;
     8087
    73798088    LogFlowFunc(("returns %Rrc\n", rc));
    73808089    return rc;
    73818090}
     8091
    73828092/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
    73838093static DECLCALLBACK(int) vmdkGetModificationUuid(void *pBackendData, PRTUUID pUuid)
     
    73858095    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    73868096    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     8097
    73878098    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8099
    73888100    *pUuid = pImage->ModificationUuid;
     8101
    73898102    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    73908103    return VINF_SUCCESS;
    73918104}
     8105
    73928106/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
    73938107static DECLCALLBACK(int) vmdkSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
     
    73968110    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    73978111    int rc = VINF_SUCCESS;
     8112
    73988113    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8114
    73998115    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    74008116    {
     
    74168132    else
    74178133        rc = VERR_VD_IMAGE_READ_ONLY;
     8134
    74188135    LogFlowFunc(("returns %Rrc\n", rc));
    74198136    return rc;
    74208137}
     8138
    74218139/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
    74228140static DECLCALLBACK(int) vmdkGetParentUuid(void *pBackendData, PRTUUID pUuid)
     
    74248142    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    74258143    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     8144
    74268145    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8146
    74278147    *pUuid = pImage->ParentUuid;
     8148
    74288149    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    74298150    return VINF_SUCCESS;
    74308151}
     8152
    74318153/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
    74328154static DECLCALLBACK(int) vmdkSetParentUuid(void *pBackendData, PCRTUUID pUuid)
     
    74358157    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    74368158    int rc = VINF_SUCCESS;
     8159
    74378160    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8161
    74388162    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    74398163    {
     
    74528176    else
    74538177        rc = VERR_VD_IMAGE_READ_ONLY;
     8178
    74548179    LogFlowFunc(("returns %Rrc\n", rc));
    74558180    return rc;
    74568181}
     8182
    74578183/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
    74588184static DECLCALLBACK(int) vmdkGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
     
    74608186    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    74618187    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     8188
    74628189    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8190
    74638191    *pUuid = pImage->ParentModificationUuid;
     8192
    74648193    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    74658194    return VINF_SUCCESS;
    74668195}
     8196
    74678197/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
    74688198static DECLCALLBACK(int) vmdkSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
     
    74718201    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    74728202    int rc = VINF_SUCCESS;
     8203
    74738204    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
     8205
    74748206    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    74758207    {
     
    74878219    else
    74888220        rc = VERR_VD_IMAGE_READ_ONLY;
     8221
    74898222    LogFlowFunc(("returns %Rrc\n", rc));
    74908223    return rc;
    74918224}
     8225
    74928226/** @copydoc VDIMAGEBACKEND::pfnDump */
    74938227static DECLCALLBACK(void) vmdkDump(void *pBackendData)
    74948228{
    74958229    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     8230
    74968231    AssertPtrReturnVoid(pImage);
    74978232    vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
     
    77158450    return rc;
    77168451}
     8452
    77178453
    77188454const VDIMAGEBACKEND g_VmdkBackend =
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