VirtualBox

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


Ignore:
Timestamp:
Dec 20, 2022 1:58:14 AM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
154922
Message:

Storage: Add VMDK resize. bugref:8707

Location:
trunk/src/VBox/Storage
Files:
3 edited

Legend:

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

    r97260 r97836  
    33 * VMDK disk image, core code.
    44 */
    5 
    65/*
    76 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
     
    3433#include <VBox/vd-plugin.h>
    3534#include <VBox/err.h>
    36 
    3735#include <iprt/assert.h>
    3836#include <iprt/alloc.h>
     
    9492# define DKIOCUNLOCKPHYSICALEXTENTS _IO(  'd', 83)
    9593#endif /* RT_OS_DARWIN */
    96 
    9794#include "VDBackends.h"
    9895
     
    10198*   Constants And Macros, Structures and Typedefs                                                                                *
    10299*********************************************************************************************************************************/
    103 
    104100/** Maximum encoded string size (including NUL) we allow for VMDK images.
    105101 * Deliberately not set high to avoid running out of descriptor space. */
    106102#define VMDK_ENCODED_COMMENT_MAX 1024
    107 
    108103/** VMDK descriptor DDB entry for PCHS cylinders. */
    109104#define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
    110 
    111105/** VMDK descriptor DDB entry for PCHS heads. */
    112106#define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
    113 
    114107/** VMDK descriptor DDB entry for PCHS sectors. */
    115108#define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
    116 
    117109/** VMDK descriptor DDB entry for LCHS cylinders. */
    118110#define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
    119 
    120111/** VMDK descriptor DDB entry for LCHS heads. */
    121112#define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
    122 
    123113/** VMDK descriptor DDB entry for LCHS sectors. */
    124114#define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
    125 
    126115/** VMDK descriptor DDB entry for image UUID. */
    127116#define VMDK_DDB_IMAGE_UUID "ddb.uuid.image"
    128 
    129117/** VMDK descriptor DDB entry for image modification UUID. */
    130118#define VMDK_DDB_MODIFICATION_UUID "ddb.uuid.modification"
    131 
    132119/** VMDK descriptor DDB entry for parent image UUID. */
    133120#define VMDK_DDB_PARENT_UUID "ddb.uuid.parent"
    134 
    135121/** VMDK descriptor DDB entry for parent image modification UUID. */
    136122#define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification"
    137 
    138123/** No compression for streamOptimized files. */
    139124#define VMDK_COMPRESSION_NONE 0
    140 
    141125/** Deflate compression for streamOptimized files. */
    142126#define VMDK_COMPRESSION_DEFLATE 1
    143 
    144127/** Marker that the actual GD value is stored in the footer. */
    145128#define VMDK_GD_AT_END 0xffffffffffffffffULL
    146 
    147129/** Marker for end-of-stream in streamOptimized images. */
    148130#define VMDK_MARKER_EOS 0
    149 
    150131/** Marker for grain table block in streamOptimized images. */
    151132#define VMDK_MARKER_GT 1
    152 
    153133/** Marker for grain directory block in streamOptimized images. */
    154134#define VMDK_MARKER_GD 2
    155 
    156135/** Marker for footer in streamOptimized images. */
    157136#define VMDK_MARKER_FOOTER 3
    158 
    159137/** Marker for unknown purpose in streamOptimized images.
    160138 * Shows up in very recent images created by vSphere, but only sporadically.
    161139 * They "forgot" to document that one in the VMDK specification. */
    162140#define VMDK_MARKER_UNSPECIFIED 4
    163 
    164141/** Dummy marker for "don't check the marker value". */
    165142#define VMDK_MARKER_IGNORE 0xffffffffU
    166 
    167143/**
    168144 * Magic number for hosted images created by VMware Workstation 4, VMware
     
    170146 */
    171147#define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
    172 
    173148/** VMDK sector size in bytes. */
    174149#define VMDK_SECTOR_SIZE 512
     
    179154/** Grain table size in bytes */
    180155#define VMDK_GRAIN_TABLE_SIZE 2048
    181 
    182156/**
    183157 * VMDK hosted binary extent header. The "Sparse" is a total misnomer, as
     
    207181} SparseExtentHeader;
    208182#pragma pack()
    209 
    210183/** The maximum allowed descriptor size in the extent header in sectors. */
    211184#define VMDK_SPARSE_DESCRIPTOR_SIZE_MAX UINT64_C(20480) /* 10MB */
    212 
    213185/** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
    214186 * divisible by the default grain size (64K) */
    215187#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
    216 
    217188/** VMDK streamOptimized file format marker. The type field may or may not
    218189 * be actually valid, but there's always data to read there. */
     
    225196} VMDKMARKER, *PVMDKMARKER;
    226197#pragma pack()
    227 
    228 
    229198/** Convert sector number/size to byte offset/size. */
    230199#define VMDK_SECTOR2BYTE(u) ((uint64_t)(u) << 9)
    231 
    232200/** Convert byte offset/size to sector number/size. */
    233201#define VMDK_BYTE2SECTOR(u) ((u) >> 9)
    234 
    235202/**
    236203 * VMDK extent type.
     
    247214    VMDKETYPE_VMFS
    248215} VMDKETYPE, *PVMDKETYPE;
    249 
    250216/**
    251217 * VMDK access type for a extent.
     
    260226    VMDKACCESS_READWRITE
    261227} VMDKACCESS, *PVMDKACCESS;
    262 
    263228/** Forward declaration for PVMDKIMAGE. */
    264229typedef struct VMDKIMAGE *PVMDKIMAGE;
    265 
    266230/**
    267231 * Extents files entry. Used for opening a particular file only once.
     
    288252    struct VMDKFILE *pPrev;
    289253} VMDKFILE, *PVMDKFILE;
    290 
    291254/**
    292255 * VMDK extent data structure.
     
    369332    struct VMDKIMAGE *pImage;
    370333} VMDKEXTENT, *PVMDKEXTENT;
    371 
    372334/**
    373335 * Grain table cache size. Allocated per image.
    374336 */
    375337#define VMDK_GT_CACHE_SIZE 256
    376 
    377338/**
    378339 * Grain table block size. Smaller than an actual grain table block to allow
     
    381342 */
    382343#define VMDK_GT_CACHELINE_SIZE 128
    383 
    384 
    385344/**
    386345 * Maximum number of lines in a descriptor file. Not worth the effort of
     
    390349 */
    391350#define VMDK_DESCRIPTOR_LINES_MAX   1100U
    392 
    393351/**
    394352 * Parsed descriptor information. Allows easy access and update of the
     
    414372    unsigned    aNextLines[VMDK_DESCRIPTOR_LINES_MAX];
    415373} VMDKDESCRIPTOR, *PVMDKDESCRIPTOR;
    416 
    417 
    418374/**
    419375 * Cache entry for translating extent/sector to a sector number in that
     
    429385    uint32_t    aGTData[VMDK_GT_CACHELINE_SIZE];
    430386} VMDKGTCACHEENTRY, *PVMDKGTCACHEENTRY;
    431 
    432387/**
    433388 * Cache data structure for blocks of grain table entries. For now this is a
     
    443398    unsigned            cEntries;
    444399} VMDKGTCACHE, *PVMDKGTCACHE;
    445 
    446400/**
    447401 * Complete VMDK image data structure. Mainly a collection of extents and a few
     
    454408    /** Descriptor file if applicable. */
    455409    PVMDKFILE         pFile;
    456 
    457410    /** Pointer to the per-disk VD interface list. */
    458411    PVDINTERFACE      pVDIfsDisk;
    459412    /** Pointer to the per-image VD interface list. */
    460413    PVDINTERFACE      pVDIfsImage;
    461 
    462414    /** Error interface. */
    463415    PVDINTERFACEERROR pIfError;
    464416    /** I/O interface. */
    465417    PVDINTERFACEIOINT pIfIo;
    466 
    467 
    468418    /** Pointer to the image extents. */
    469419    PVMDKEXTENT     pExtents;
     
    473423     * times only once (happens mainly with raw partition access). */
    474424    PVMDKFILE       pFiles;
    475 
    476425    /**
    477426     * Pointer to an array of segment entries for async I/O.
     
    483432    /** Entries available in the segments array. */
    484433    unsigned        cSegments;
    485 
    486434    /** Open flags passed by VBoxHD layer. */
    487435    unsigned        uOpenFlags;
     
    502450    /** Parent image modification UUID. */
    503451    RTUUID          ParentModificationUuid;
    504 
    505452    /** Pointer to grain table cache, if this image contains sparse extents. */
    506453    PVMDKGTCACHE    pGTCache;
     
    514461    VDREGIONLIST    RegionList;
    515462} VMDKIMAGE;
    516 
    517 
    518463/** State for the input/output callout of the inflate reader/deflate writer. */
    519464typedef struct VMDKCOMPRESSIO
     
    528473    void *pvCompGrain;
    529474} VMDKCOMPRESSIO;
    530 
    531 
    532475/** Tracks async grain allocation. */
    533476typedef struct VMDKGRAINALLOCASYNC
     
    551494    uint64_t    uRGTSector;
    552495} VMDKGRAINALLOCASYNC, *PVMDKGRAINALLOCASYNC;
    553 
    554496/**
    555497 * State information for vmdkRename() and helpers.
     
    594536*   Static Variables                                                                                                             *
    595537*********************************************************************************************************************************/
    596 
    597538/** NULL-terminated array of supported file extensions. */
    598539static const VDFILEEXTENSION s_aVmdkFileExtensions[] =
     
    601542    {NULL, VDTYPE_INVALID}
    602543};
    603 
    604544/** NULL-terminated array of configuration option. */
    605545static const VDCONFIGINFO s_aVmdkConfigInfo[] =
     
    610550    { "BootSector",                     NULL,                             VDCFGVALUETYPE_BYTES,        0 },
    611551    { "Relative",                       NULL,                             VDCFGVALUETYPE_INTEGER,      0 },
    612 
    613552    /* End of options list */
    614553    { NULL,                             NULL,                             VDCFGVALUETYPE_INTEGER,      0 }
     
    619558*   Internal Functions                                                                                                           *
    620559*********************************************************************************************************************************/
    621 
    622560static void vmdkFreeStreamBuffers(PVMDKEXTENT pExtent);
    623561static int vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
    624562                              bool fDelete);
    625 
    626563static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
    627564static int vmdkFlushImage(PVMDKIMAGE pImage, PVDIOCTX pIoCtx);
    628565static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment);
    629566static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete, bool fFlush);
    630 
    631567static DECLCALLBACK(int) vmdkAllocGrainComplete(void *pBackendData, PVDIOCTX pIoCtx,
    632568                                                void *pvUser, int rcReq);
    633 
    634569/**
    635570 * Internal: open a file (using a file descriptor cache to ensure each file
     
    641576    int rc = VINF_SUCCESS;
    642577    PVMDKFILE pVmdkFile;
    643 
    644578    for (pVmdkFile = pImage->pFiles;
    645579         pVmdkFile != NULL;
     
    650584            Assert(fOpen == pVmdkFile->fOpen);
    651585            pVmdkFile->uReferences++;
    652 
    653586            *ppVmdkFile = pVmdkFile;
    654 
    655587            return rc;
    656588        }
    657589    }
    658 
    659590    /* If we get here, there's no matching entry in the cache. */
    660591    pVmdkFile = (PVMDKFILE)RTMemAllocZ(sizeof(VMDKFILE));
     
    664595        return VERR_NO_MEMORY;
    665596    }
    666 
    667597    pVmdkFile->pszFilename = RTStrDup(pszFilename);
    668598    if (!pVmdkFile->pszFilename)
     
    672602        return VERR_NO_MEMORY;
    673603    }
    674 
    675604    if (pszBasename)
    676605    {
     
    684613        }
    685614    }
    686 
    687615    pVmdkFile->fOpen = fOpen;
    688 
    689616    rc = vdIfIoIntFileOpen(pImage->pIfIo, pszFilename, fOpen,
    690617                           &pVmdkFile->pStorage);
     
    705632        *ppVmdkFile = NULL;
    706633    }
    707 
    708634    return rc;
    709635}
    710 
    711636/**
    712637 * Internal: close a file, updating the file descriptor cache.
     
    716641    int rc = VINF_SUCCESS;
    717642    PVMDKFILE pVmdkFile = *ppVmdkFile;
    718 
    719643    AssertPtr(pVmdkFile);
    720 
    721644    pVmdkFile->fDelete |= fDelete;
    722645    Assert(pVmdkFile->uReferences);
     
    726649        PVMDKFILE pPrev;
    727650        PVMDKFILE pNext;
    728 
    729651        /* Unchain the element from the list. */
    730652        pPrev = pVmdkFile->pPrev;
    731653        pNext = pVmdkFile->pNext;
    732 
    733654        if (pNext)
    734655            pNext->pPrev = pPrev;
     
    737658        else
    738659            pImage->pFiles = pNext;
    739 
    740660        rc = vdIfIoIntFileClose(pImage->pIfIo, pVmdkFile->pStorage);
    741 
    742661        bool fFileDel = pVmdkFile->fDelete;
    743662        if (   pVmdkFile->pszBasename
     
    752671                fFileDel = false;
    753672        }
    754 
    755673        if (fFileDel)
    756674        {
     
    766684        RTMemFree(pVmdkFile);
    767685    }
    768 
    769686    *ppVmdkFile = NULL;
    770687    return rc;
    771688}
    772 
    773689/*#define VMDK_USE_BLOCK_DECOMP_API - test and enable */
    774690#ifndef VMDK_USE_BLOCK_DECOMP_API
     
    777693    VMDKCOMPRESSIO *pInflateState = (VMDKCOMPRESSIO *)pvUser;
    778694    size_t cbInjected = 0;
    779 
    780695    Assert(cbBuf);
    781696    if (pInflateState->iOffset < 0)
     
    803718}
    804719#endif
    805 
    806720/**
    807721 * Internal: read from a file and inflate the compressed data,
     
    819733    VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
    820734    size_t cbCompSize, cbActuallyRead;
    821 
    822735    if (!pcvMarker)
    823736    {
     
    834747        pMarker->cbSize = RT_H2LE_U32(pMarker->cbSize);
    835748    }
    836 
    837749    cbCompSize = RT_LE2H_U32(pMarker->cbSize);
    838750    if (cbCompSize == 0)
     
    841753        return VERR_VD_VMDK_INVALID_FORMAT;
    842754    }
    843 
    844755    /* Sanity check - the expansion ratio should be much less than 2. */
    845756    Assert(cbCompSize < 2 * cbToRead);
    846757    if (cbCompSize >= 2 * cbToRead)
    847758        return VERR_VD_VMDK_INVALID_FORMAT;
    848 
    849759    /* Compressed grain marker. Data follows immediately. */
    850760    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     
    856766                                          512)
    857767                               - RT_UOFFSETOF(VMDKMARKER, uType));
    858 
    859768    if (puLBA)
    860769        *puLBA = RT_LE2H_U64(pMarker->uSector);
     
    863772                                  + RT_UOFFSETOF(VMDKMARKER, uType),
    864773                                  512);
    865 
    866774#ifdef VMDK_USE_BLOCK_DECOMP_API
    867775    rc = RTZipBlockDecompress(RTZIPTYPE_ZLIB, 0 /*fFlags*/,
     
    874782    InflateState.cbCompGrain = cbCompSize + RT_UOFFSETOF(VMDKMARKER, uType);
    875783    InflateState.pvCompGrain = pExtent->pvCompGrain;
    876 
    877784    rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
    878785    if (RT_FAILURE(rc))
     
    891798    return rc;
    892799}
    893 
    894800static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf)
    895801{
    896802    VMDKCOMPRESSIO *pDeflateState = (VMDKCOMPRESSIO *)pvUser;
    897 
    898803    Assert(cbBuf);
    899804    if (pDeflateState->iOffset < 0)
     
    912817    return VINF_SUCCESS;
    913818}
    914 
    915819/**
    916820 * Internal: deflate the uncompressed data and write to a file,
     
    925829    PRTZIPCOMP pZip = NULL;
    926830    VMDKCOMPRESSIO DeflateState;
    927 
    928831    DeflateState.pImage = pImage;
    929832    DeflateState.iOffset = -1;
    930833    DeflateState.cbCompGrain = pExtent->cbCompGrain;
    931834    DeflateState.pvCompGrain = pExtent->pvCompGrain;
    932 
    933835    rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper,
    934836                         RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
     
    943845        Assert(   DeflateState.iOffset > 0
    944846               && (size_t)DeflateState.iOffset <= DeflateState.cbCompGrain);
    945 
    946847        /* pad with zeroes to get to a full sector size */
    947848        uint32_t uSize = DeflateState.iOffset;
     
    953854            uSize = uSizeAlign;
    954855        }
    955 
    956856        if (pcbMarkerData)
    957857            *pcbMarkerData = uSize;
    958 
    959858        /* Compressed grain marker. Data follows immediately. */
    960859        VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
     
    969868    return rc;
    970869}
    971 
    972 
    973870/**
    974871 * Internal: check if all files are closed, prevent leaking resources.
     
    978875    int rc = VINF_SUCCESS, rc2;
    979876    PVMDKFILE pVmdkFile;
    980 
    981877    Assert(pImage->pFiles == NULL);
    982878    for (pVmdkFile = pImage->pFiles;
     
    987883                pVmdkFile->pszFilename));
    988884        pImage->pFiles = pVmdkFile->pNext;
    989 
    990885        rc2 = vmdkFileClose(pImage, &pVmdkFile, pVmdkFile->fDelete);
    991 
    992886        if (RT_SUCCESS(rc))
    993887            rc = rc2;
     
    995889    return rc;
    996890}
    997 
    998891/**
    999892 * Internal: truncate a string (at a UTF8 code point boundary) and encode the
     
    1004897    char szEnc[VMDK_ENCODED_COMMENT_MAX + 3];
    1005898    char *pszDst = szEnc;
    1006 
    1007899    AssertPtr(psz);
    1008 
    1009900    for (; *psz; psz = RTStrNextCp(psz))
    1010901    {
     
    1037928    return RTStrDup(szEnc);
    1038929}
    1039 
    1040930/**
    1041931 * Internal: decode a string and store it into the specified string.
     
    1045935    int rc = VINF_SUCCESS;
    1046936    char szBuf[4];
    1047 
    1048937    if (!cb)
    1049938        return VERR_BUFFER_OVERFLOW;
    1050 
    1051939    AssertPtr(psz);
    1052 
    1053940    for (; *pszEncoded; pszEncoded = RTStrNextCp(pszEncoded))
    1054941    {
     
    1073960        else
    1074961            pszDst = RTStrPutCp(pszDst, Cp);
    1075 
    1076962        /* Need to leave space for terminating NUL. */
    1077963        if ((size_t)(pszDst - szBuf) + 1 >= cb)
     
    1086972    return rc;
    1087973}
    1088 
    1089974/**
    1090975 * Internal: free all buffers associated with grain directories.
     
    1103988    }
    1104989}
    1105 
    1106990/**
    1107991 * Internal: allocate the compressed/uncompressed buffers for streamOptimized
     
    1111995{
    1112996    int rc = VINF_SUCCESS;
    1113 
    1114997    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    1115998    {
     
    11301013            rc = VERR_NO_MEMORY;
    11311014    }
    1132 
    11331015    if (RT_FAILURE(rc))
    11341016        vmdkFreeStreamBuffers(pExtent);
    11351017    return rc;
    11361018}
    1137 
    11381019/**
    11391020 * Internal: allocate all buffers associated with grain directories.
     
    11441025    int rc = VINF_SUCCESS;
    11451026    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
    1146 
    11471027    pExtent->pGD = (uint32_t *)RTMemAllocZ(cbGD);
    11481028    if (RT_LIKELY(pExtent->pGD))
     
    11571037    else
    11581038        rc = VERR_NO_MEMORY;
    1159 
    11601039    if (RT_FAILURE(rc))
    11611040        vmdkFreeGrainDirectory(pExtent);
    11621041    return rc;
    11631042}
    1164 
    11651043/**
    11661044 * Converts the grain directory from little to host endianess.
     
    11731051{
    11741052    uint32_t *pGDTmp = pGD;
    1175 
    11761053    for (uint32_t i = 0; i < cGDEntries; i++, pGDTmp++)
    11771054        *pGDTmp = RT_LE2H_U32(*pGDTmp);
    11781055}
    1179 
    11801056/**
    11811057 * Read the grain directory and allocated grain tables verifying them against
     
    11901066    int rc = VINF_SUCCESS;
    11911067    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
    1192 
    11931068    AssertReturn((   pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
    11941069                  && pExtent->uSectorGD != VMDK_GD_AT_END
    11951070                  && pExtent->uSectorRGD != VMDK_GD_AT_END), VERR_INTERNAL_ERROR);
    1196 
    11971071    rc = vmdkAllocGrainDirectory(pImage, pExtent);
    11981072    if (RT_SUCCESS(rc))
     
    12061080        {
    12071081            vmdkGrainDirectoryConvToHost(pExtent->pGD, pExtent->cGDEntries);
    1208 
    12091082            if (   pExtent->uSectorRGD
    12101083                && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS))
     
    12181091                {
    12191092                    vmdkGrainDirectoryConvToHost(pExtent->pRGD, pExtent->cGDEntries);
    1220 
    12211093                    /* Check grain table and redundant grain table for consistency. */
    12221094                    size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
    12231095                    size_t cbGTBuffers = cbGT; /* Start with space for one GT. */
    12241096                    size_t cbGTBuffersMax = _1M;
    1225 
    12261097                    uint32_t *pTmpGT1 = (uint32_t *)RTMemAlloc(cbGTBuffers);
    12271098                    uint32_t *pTmpGT2 = (uint32_t *)RTMemAlloc(cbGTBuffers);
    1228 
    12291099                    if (   !pTmpGT1
    12301100                        || !pTmpGT2)
    12311101                        rc = VERR_NO_MEMORY;
    1232 
    12331102                    size_t i = 0;
    12341103                    uint32_t *pGDTmp = pExtent->pGD;
    12351104                    uint32_t *pRGDTmp = pExtent->pRGD;
    1236 
    12371105                    /* Loop through all entries. */
    12381106                    while (i < pExtent->cGDEntries)
     
    12411109                        uint32_t uRGTStart = *pRGDTmp;
    12421110                        size_t   cbGTRead = cbGT;
    1243 
    12441111                        /* If no grain table is allocated skip the entry. */
    12451112                        if (*pGDTmp == 0 && *pRGDTmp == 0)
     
    12481115                            continue;
    12491116                        }
    1250 
    12511117                        if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
    12521118                        {
     
    12581124                            break;
    12591125                        }
    1260 
    12611126                        i++;
    12621127                        pGDTmp++;
    12631128                        pRGDTmp++;
    1264 
    12651129                        /*
    12661130                         * Read a few tables at once if adjacent to decrease the number
     
    12761140                                continue;
    12771141                            }
    1278 
    12791142                            if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
    12801143                            {
     
    12861149                                break;
    12871150                            }
    1288 
    12891151                            /* Check that the start offsets are adjacent.*/
    12901152                            if (   VMDK_SECTOR2BYTE(uGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pGDTmp)
    12911153                                || VMDK_SECTOR2BYTE(uRGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pRGDTmp))
    12921154                                break;
    1293 
    12941155                            i++;
    12951156                            pGDTmp++;
     
    12971158                            cbGTRead += cbGT;
    12981159                        }
    1299 
    13001160                        /* Increase buffers if required. */
    13011161                        if (   RT_SUCCESS(rc)
     
    13151175                            else
    13161176                                rc = VERR_NO_MEMORY;
    1317 
    13181177                            if (rc == VERR_NO_MEMORY)
    13191178                            {
     
    13221181                                i -= cbGTRead / cbGT;
    13231182                                cbGTRead = cbGT;
    1324 
    13251183                                /* Don't try to increase the buffer again in the next run. */
    13261184                                cbGTBuffersMax = cbGTBuffers;
    13271185                            }
    13281186                        }
    1329 
    13301187                        if (RT_SUCCESS(rc))
    13311188                        {
     
    13601217                        }
    13611218                    } /* while (i < pExtent->cGDEntries) */
    1362 
    13631219                    /** @todo figure out what to do for unclean VMDKs. */
    13641220                    if (pTmpGT1)
     
    13761232                           N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname, rc);
    13771233    }
    1378 
    13791234    if (RT_FAILURE(rc))
    13801235        vmdkFreeGrainDirectory(pExtent);
    13811236    return rc;
    13821237}
    1383 
    13841238/**
    13851239 * Creates a new grain directory for the given extent at the given start sector.
     
    14001254    size_t cbGTRounded;
    14011255    uint64_t cbOverhead;
    1402 
    14031256    if (fPreAlloc)
    14041257    {
     
    14141267        cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded;
    14151268    }
    1416 
    14171269    /* For streamOptimized extents there is only one grain directory,
    14181270     * and for all others take redundant grain directory into account. */
     
    14291281        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead);
    14301282    }
    1431 
    14321283    if (RT_SUCCESS(rc))
    14331284    {
    14341285        pExtent->uAppendPosition = cbOverhead;
    14351286        pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
    1436 
    14371287        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    14381288        {
     
    14451295            pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
    14461296        }
    1447 
    14481297        rc = vmdkAllocStreamBuffers(pImage, pExtent);
    14491298        if (RT_SUCCESS(rc))
     
    14551304                uint32_t uGTSectorLE;
    14561305                uint64_t uOffsetSectors;
    1457 
    14581306                if (pExtent->pRGD)
    14591307                {
     
    14751323                    }
    14761324                }
    1477 
    14781325                if (RT_SUCCESS(rc))
    14791326                {
     
    14981345        }
    14991346    }
    1500 
    15011347    if (RT_FAILURE(rc))
    15021348        vmdkFreeGrainDirectory(pExtent);
    15031349    return rc;
    15041350}
    1505 
    15061351/**
    15071352 * Unquotes the given string returning the result in a separate buffer.
     
    15211366    char *pszQ;
    15221367    char *pszUnquoted;
    1523 
    15241368    /* Skip over whitespace. */
    15251369    while (*pszStr == ' ' || *pszStr == '\t')
    15261370        pszStr++;
    1527 
    15281371    if (*pszStr != '"')
    15291372    {
     
    15401383                             pImage->pszFilename, pszStart);
    15411384    }
    1542 
    15431385    pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
    15441386    if (!pszUnquoted)
     
    15511393    return VINF_SUCCESS;
    15521394}
    1553 
    15541395static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    15551396                           const char *pszLine)
     
    15571398    char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
    15581399    ssize_t cbDiff = strlen(pszLine) + 1;
    1559 
    15601400    if (    pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
    15611401        &&  pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    15621402        return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    1563 
    15641403    memcpy(pEnd, pszLine, cbDiff);
    15651404    pDescriptor->cLines++;
    15661405    pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
    15671406    pDescriptor->fDirty = true;
    1568 
    15691407    return VINF_SUCCESS;
    15701408}
    1571 
    15721409static bool vmdkDescGetStr(PVMDKDESCRIPTOR pDescriptor, unsigned uStart,
    15731410                           const char *pszKey, const char **ppszValue)
     
    15751412    size_t cbKey = strlen(pszKey);
    15761413    const char *pszValue;
    1577 
    15781414    while (uStart != 0)
    15791415    {
     
    15941430    return !!uStart;
    15951431}
    1596 
    15971432static int vmdkDescSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    15981433                          unsigned uStart,
     
    16021437    size_t cbKey = strlen(pszKey);
    16031438    unsigned uLast = 0;
    1604 
    16051439    while (uStart != 0)
    16061440    {
     
    16371471                > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    16381472                return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    1639 
    16401473            memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
    16411474                    pDescriptor->aLines[pDescriptor->cLines] - pszTmp - cbOldVal);
     
    17001533        for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    17011534            pDescriptor->aLines[i] += cbDiff;
    1702 
    17031535        /* Adjust starting line numbers of following descriptor sections. */
    17041536        if (uStart <= pDescriptor->uFirstExtent)
     
    17101542    return VINF_SUCCESS;
    17111543}
    1712 
    17131544static int vmdkDescBaseGetU32(PVMDKDESCRIPTOR pDescriptor, const char *pszKey,
    17141545                              uint32_t *puValue)
    17151546{
    17161547    const char *pszValue;
    1717 
    17181548    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
    17191549                        &pszValue))
     
    17211551    return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
    17221552}
    1723 
    17241553/**
    17251554 * Returns the value of the given key as a string allocating the necessary memory.
     
    17381567    const char *pszValue;
    17391568    char *pszValueUnquoted;
    1740 
    17411569    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
    17421570                        &pszValue))
     
    17481576    return rc;
    17491577}
    1750 
    17511578static int vmdkDescBaseSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17521579                              const char *pszKey, const char *pszValue)
    17531580{
    17541581    char *pszValueQuoted;
    1755 
    17561582    RTStrAPrintf(&pszValueQuoted, "\"%s\"", pszValue);
    17571583    if (!pszValueQuoted)
     
    17621588    return rc;
    17631589}
    1764 
    17651590static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
    17661591                                   PVMDKDESCRIPTOR pDescriptor)
     
    17691594    unsigned uEntry = pDescriptor->uFirstExtent;
    17701595    ssize_t cbDiff;
    1771 
    17721596    if (!uEntry)
    17731597        return;
    1774 
    17751598    cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
    17761599    /* Move everything including \0 in the entry marking the end of buffer. */
     
    17881611    if (pDescriptor->uFirstDDB)
    17891612        pDescriptor->uFirstDDB--;
    1790 
    17911613    return;
    17921614}
    1793 
     1615static void vmdkDescExtRemoveByLine(PVMDKIMAGE pImage,
     1616                                   PVMDKDESCRIPTOR pDescriptor, unsigned uLine)
     1617{
     1618    RT_NOREF1(pImage);
     1619    unsigned uEntry = uLine;
     1620    ssize_t cbDiff;
     1621    if (!uEntry)
     1622        return;
     1623    cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
     1624    /* Move everything including \0 in the entry marking the end of buffer. */
     1625    memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
     1626            pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
     1627    for (unsigned i = uEntry; i <= pDescriptor->cLines; i++)
     1628    {
     1629        if (i != uEntry)
     1630            pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
     1631        if (pDescriptor->aNextLines[i])
     1632            pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
     1633        else
     1634            pDescriptor->aNextLines[i - 1] = 0;
     1635    }
     1636    pDescriptor->cLines--;
     1637    if (pDescriptor->uFirstDDB)
     1638        pDescriptor->uFirstDDB--;
     1639    return;
     1640}
    17941641static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17951642                             VMDKACCESS enmAccess, uint64_t cNominalSectors,
     
    18031650    char szExt[1024];
    18041651    ssize_t cbDiff;
    1805 
    18061652    Assert((unsigned)enmAccess < RT_ELEMENTS(apszAccess));
    18071653    Assert((unsigned)enmType < RT_ELEMENTS(apszType));
    1808 
    18091654    /* Find last entry in extent description. */
    18101655    while (uStart)
     
    18141659        uStart = pDescriptor->aNextLines[uStart];
    18151660    }
    1816 
    18171661    if (enmType == VMDKETYPE_ZERO)
    18181662    {
     
    18331677    }
    18341678    cbDiff = strlen(szExt) + 1;
    1835 
    18361679    /* Check for buffer overflow. */
    18371680    if (   (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
    18381681        || (  pDescriptor->aLines[pDescriptor->cLines]
    18391682            - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
    1840         return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     1683    {
     1684        if ((pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
     1685            && !(pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1))
     1686        {
     1687            pImage->cbDescAlloc *= 2;
     1688            pDescriptor->cbDescAlloc *= 2;
     1689        }
     1690        else
     1691            return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
     1692    }
    18411693
    18421694    for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
     
    18581710    for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    18591711        pDescriptor->aLines[i] += cbDiff;
    1860 
    18611712    /* Adjust starting line numbers of following descriptor sections. */
    18621713    if (uStart <= pDescriptor->uFirstDDB)
    18631714        pDescriptor->uFirstDDB++;
    1864 
    18651715    pDescriptor->fDirty = true;
    18661716    return VINF_SUCCESS;
    18671717}
    1868 
    18691718/**
    18701719 * Returns the value of the given key from the DDB as a string allocating
     
    18841733    const char *pszValue;
    18851734    char *pszValueUnquoted;
    1886 
    18871735    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    18881736                        &pszValue))
     
    18941742    return rc;
    18951743}
    1896 
    18971744static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    18981745                             const char *pszKey, uint32_t *puValue)
     
    19001747    const char *pszValue;
    19011748    char *pszValueUnquoted;
    1902 
    19031749    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    19041750                        &pszValue))
     
    19111757    return rc;
    19121758}
    1913 
    19141759static int vmdkDescDDBGetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    19151760                              const char *pszKey, PRTUUID pUuid)
     
    19171762    const char *pszValue;
    19181763    char *pszValueUnquoted;
    1919 
    19201764    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    19211765                        &pszValue))
     
    19281772    return rc;
    19291773}
    1930 
    19311774static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    19321775                             const char *pszKey, const char *pszVal)
     
    19341777    int rc;
    19351778    char *pszValQuoted;
    1936 
    19371779    if (pszVal)
    19381780    {
     
    19491791    return rc;
    19501792}
    1951 
    19521793static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    19531794                              const char *pszKey, PCRTUUID pUuid)
    19541795{
    19551796    char *pszUuid;
    1956 
    19571797    RTStrAPrintf(&pszUuid, "\"%RTuuid\"", pUuid);
    19581798    if (!pszUuid)
     
    19631803    return rc;
    19641804}
    1965 
    19661805static int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    19671806                             const char *pszKey, uint32_t uValue)
    19681807{
    19691808    char *pszValue;
    1970 
    19711809    RTStrAPrintf(&pszValue, "\"%d\"", uValue);
    19721810    if (!pszValue)
     
    19771815    return rc;
    19781816}
    1979 
    19801817/**
    19811818 * Splits the descriptor data into individual lines checking for correct line
     
    19911828    unsigned cLine = 0;
    19921829    int rc = VINF_SUCCESS;
    1993 
    19941830    while (   RT_SUCCESS(rc)
    19951831           && *pszTmp != '\0')
     
    20021838            break;
    20031839        }
    2004 
    20051840        while (*pszTmp != '\0' && *pszTmp != '\n')
    20061841        {
     
    20201855            pszTmp++;
    20211856        }
    2022 
    20231857        if (RT_FAILURE(rc))
    20241858            break;
    2025 
    20261859        /* Get rid of LF character. */
    20271860        if (*pszTmp == '\n')
     
    20311864        }
    20321865    }
    2033 
    20341866    if (RT_SUCCESS(rc))
    20351867    {
     
    20381870        pDesc->aLines[cLine] = pszTmp;
    20391871    }
    2040 
    20411872    return rc;
    20421873}
    2043 
    20441874static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
    20451875                                    size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     
    20581888        {
    20591889            unsigned uLastNonEmptyLine = 0;
    2060 
    20611890            /* Initialize those, because we need to be able to reopen an image. */
    20621891            pDescriptor->uFirstDesc = 0;
     
    21241953        }
    21251954    }
    2126 
    21271955    return rc;
    21281956}
    2129 
    21301957static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
    21311958                                   PCVDGEOMETRY pPCHSGeometry)
     
    21461973    return rc;
    21471974}
    2148 
    21491975static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
    21501976                                   PCVDGEOMETRY pLCHSGeometry)
     
    21571983    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    21581984                           VMDK_DDB_GEO_LCHS_HEADS,
    2159 
    21601985                           pLCHSGeometry->cHeads);
    21611986    if (RT_FAILURE(rc))
     
    21661991    return rc;
    21671992}
    2168 
    21691993static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
    21701994                                size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     
    21782002    pDescriptor->aLines[pDescriptor->cLines] = pDescData;
    21792003    memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
    2180 
    21812004    int rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
    21822005    if (RT_SUCCESS(rc))
     
    22102033    {
    22112034        pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
    2212 
    22132035        /* Now that the framework is in place, use the normal functions to insert
    22142036         * the remaining keys. */
     
    22232045    if (RT_SUCCESS(rc))
    22242046        rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
    2225 
    22262047    return rc;
    22272048}
    2228 
    22292049static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
    22302050{
     
    22332053    unsigned uLine;
    22342054    unsigned i;
    2235 
    22362055    rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
    22372056                                  &pImage->Descriptor);
    22382057    if (RT_FAILURE(rc))
    22392058        return rc;
    2240 
    22412059    /* Check version, must be 1. */
    22422060    uint32_t uVersion;
     
    22462064    if (uVersion != 1)
    22472065        return vdIfError(pImage->pIfError, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
    2248 
    22492066    /* Get image creation type and determine image flags. */
    22502067    char *pszCreateType = NULL;   /* initialized to make gcc shut up */
     
    22642081        pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_ESX;
    22652082    RTMemTmpFree(pszCreateType);
    2266 
    22672083    /* Count the number of extent config entries. */
    22682084    for (uLine = pImage->Descriptor.uFirstExtent, cExtents = 0;
     
    22702086         uLine = pImage->Descriptor.aNextLines[uLine], cExtents++)
    22712087        /* nothing */;
    2272 
    22732088    if (!pImage->pDescData && cExtents != 1)
    22742089    {
     
    22762091        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);
    22772092    }
    2278 
    22792093    if (pImage->pDescData)
    22802094    {
     
    22842098            return rc;
    22852099    }
    2286 
    22872100    for (i = 0, uLine = pImage->Descriptor.uFirstExtent;
    22882101         i < cExtents; i++, uLine = pImage->Descriptor.aNextLines[uLine])
    22892102    {
    22902103        char *pszLine = pImage->Descriptor.aLines[uLine];
    2291 
    22922104        /* Access type of the extent. */
    22932105        if (!strncmp(pszLine, "RW", 2))
     
    23102122        if (*pszLine++ != ' ')
    23112123            return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    2312 
    23132124        /* Nominal size of the extent. */
    23142125        rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
     
    23182129        if (*pszLine++ != ' ')
    23192130            return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    2320 
    23212131        /* Type of the extent. */
    23222132        if (!strncmp(pszLine, "SPARSE", 6))
     
    23422152        else
    23432153            return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    2344 
    23452154        if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
    23462155        {
     
    23572166            if (*pszLine++ != ' ')
    23582167                return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    2359 
    23602168            /* Basename of the image. Surrounded by quotes. */
    23612169            char *pszBasename;
     
    23762184                }
    23772185            }
    2378 
    23792186            if (*pszLine != '\0')
    23802187                return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    23812188        }
    23822189    }
    2383 
    23842190    /* Determine PCHS geometry (autogenerate if necessary). */
    23852191    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     
    24162222        pImage->PCHSGeometry.cSectors = 63;
    24172223    }
    2418 
    24192224    /* Determine LCHS geometry (set to 0 if not specified). */
    24202225    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     
    24472252        pImage->LCHSGeometry.cSectors = 0;
    24482253    }
    2449 
    24502254    /* Get image UUID. */
    24512255    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_IMAGE_UUID,
     
    24712275    else if (RT_FAILURE(rc))
    24722276        return rc;
    2473 
    24742277    /* Get image modification UUID. */
    24752278    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
     
    24972300    else if (RT_FAILURE(rc))
    24982301        return rc;
    2499 
    25002302    /* Get UUID of parent image. */
    25012303    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_PARENT_UUID,
     
    25212323    else if (RT_FAILURE(rc))
    25222324        return rc;
    2523 
    25242325    /* Get parent image modification UUID. */
    25252326    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
     
    25452346    else if (RT_FAILURE(rc))
    25462347        return rc;
    2547 
    25482348    return VINF_SUCCESS;
    25492349}
    2550 
    25512350/**
    25522351 * Internal : Prepares the descriptor to write to the image.
     
    25562355{
    25572356    int rc = VINF_SUCCESS;
    2558 
    25592357    /*
    25602358     * Allocate temporary descriptor buffer.
     
    25652363    char *pszDescriptor = (char *)RTMemAllocZ(cbDescriptor);
    25662364    size_t offDescriptor = 0;
    2567 
    25682365    if (!pszDescriptor)
    25692366        return VERR_NO_MEMORY;
    2570 
    25712367    for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
    25722368    {
    25732369        const char *psz = pImage->Descriptor.aLines[i];
    25742370        size_t cb = strlen(psz);
    2575 
    25762371        /*
    25772372         * Increase the descriptor if there is no limit and
     
    25892384                char *pszDescriptorNew = NULL;
    25902385                LogFlow(("Increasing descriptor cache\n"));
    2591 
    25922386                pszDescriptorNew = (char *)RTMemRealloc(pszDescriptor, cbDescriptor + cb + 4 * _1K);
    25932387                if (!pszDescriptorNew)
     
    26002394            }
    26012395        }
    2602 
    26032396        if (cb > 0)
    26042397        {
     
    26062399            offDescriptor += cb;
    26072400        }
    2608 
    26092401        memcpy(pszDescriptor + offDescriptor, "\n", 1);
    26102402        offDescriptor++;
    26112403    }
    2612 
    26132404    if (RT_SUCCESS(rc))
    26142405    {
     
    26182409    else if (pszDescriptor)
    26192410        RTMemFree(pszDescriptor);
    2620 
    26212411    return rc;
    26222412}
    2623 
    26242413/**
    26252414 * Internal: write/update the descriptor part of the image.
     
    26332422    void *pvDescriptor = NULL;
    26342423    size_t cbDescriptor;
    2635 
    26362424    if (pImage->pDescData)
    26372425    {
     
    26512439    if (pDescFile == NULL)
    26522440        return VERR_INVALID_PARAMETER;
    2653 
    26542441    rc = vmdkDescriptorPrepare(pImage, cbLimit, &pvDescriptor, &cbDescriptor);
    26552442    if (RT_SUCCESS(rc))
     
    26632450            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    26642451    }
    2665 
    26662452    if (RT_SUCCESS(rc) && !cbLimit)
    26672453    {
     
    26702456            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
    26712457    }
    2672 
    26732458    if (RT_SUCCESS(rc))
    26742459        pImage->Descriptor.fDirty = false;
    2675 
    26762460    if (pvDescriptor)
    26772461        RTMemFree(pvDescriptor);
    26782462    return rc;
    2679 
    2680 }
    2681 
     2463}
    26822464/**
    26832465 * Internal: validate the consistency check values in a binary header.
     
    27132495    return rc;
    27142496}
    2715 
    27162497/**
    27172498 * Internal: read metadata belonging to an extent with binary header, i.e.
     
    27232504    SparseExtentHeader Header;
    27242505    int rc;
    2725 
    27262506    if (!fMagicAlreadyRead)
    27272507        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 0,
     
    27362516                                   - RT_UOFFSETOF(SparseExtentHeader, version));
    27372517    }
    2738 
    27392518    if (RT_SUCCESS(rc))
    27402519    {
     
    27432522        {
    27442523            uint64_t cbFile = 0;
    2745 
    27462524            if (    (RT_LE2H_U32(Header.flags) & RT_BIT(17))
    27472525                &&  RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
    27482526                pExtent->fFooter = true;
    2749 
    27502527            if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    27512528                || (   pExtent->fFooter
     
    27562533                    rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
    27572534            }
    2758 
    27592535            if (RT_SUCCESS(rc))
    27602536            {
    27612537                if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    27622538                    pExtent->uAppendPosition = RT_ALIGN_64(cbFile, 512);
    2763 
    27642539                if (   pExtent->fFooter
    27652540                    && (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     
    27752550                        rc = VERR_VD_VMDK_INVALID_HEADER;
    27762551                    }
    2777 
    27782552                    if (RT_SUCCESS(rc))
    27792553                        rc = vmdkValidateHeader(pImage, pExtent, &Header);
     
    27812555                    pExtent->uAppendPosition = 0;
    27822556                }
    2783 
    27842557                if (RT_SUCCESS(rc))
    27852558                {
     
    28042577                        pExtent->uSectorRGD     = 0;
    28052578                    }
    2806 
    28072579                    if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
    28082580                        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
    28092581                                       N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
    2810 
    28112582                    if (   RT_SUCCESS(rc)
    28122583                        && (   pExtent->uSectorGD == VMDK_GD_AT_END
     
    28162587                        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
    28172588                                       N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname);
    2818 
    28192589                    if (RT_SUCCESS(rc))
    28202590                    {
     
    28272597                            pExtent->cSectorsPerGDE = cSectorsPerGDE;
    28282598                            pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    2829 
    28302599                            /* Fix up the number of descriptor sectors, as some flat images have
    28312600                             * really just one, and this causes failures when inserting the UUID
     
    28502619        rc = VERR_VD_VMDK_INVALID_HEADER;
    28512620    }
    2852 
    28532621    if (RT_FAILURE(rc))
    28542622        vmdkFreeExtentData(pImage, pExtent, false);
    2855 
    28562623    return rc;
    28572624}
    2858 
    28592625/**
    28602626 * Internal: read additional metadata belonging to an extent. For those
     
    28642630{
    28652631    int rc = VINF_SUCCESS;
    2866 
    28672632/* disabled the check as there are too many truncated vmdk images out there */
    28682633#ifdef VBOX_WITH_VMDK_STRICT_SIZE_CHECK
     
    29042669                    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    29052670                        pExtent->uAppendPosition = 0;
    2906 
    29072671                    if (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    29082672                        || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     
    29182682        }
    29192683    }
    2920 
    29212684    if (RT_FAILURE(rc))
    29222685        vmdkFreeExtentData(pImage, pExtent, false);
    2923 
    29242686    return rc;
    29252687}
    2926 
    29272688/**
    29282689 * Internal: write/update the metadata for a sparse extent.
     
    29322693{
    29332694    SparseExtentHeader Header;
    2934 
    29352695    memset(&Header, '\0', sizeof(Header));
    29362696    Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
     
    29752735    Header.doubleEndLineChar2 = '\n';
    29762736    Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
    2977 
    29782737    int rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pExtent->pFile->pStorage,
    29792738                                    uOffset, &Header, sizeof(Header),
     
    29832742    return rc;
    29842743}
    2985 
    29862744/**
    29872745 * Internal: free the buffers used for streamOptimized images.
     
    30002758    }
    30012759}
    3002 
    30032760/**
    30042761 * Internal: free the memory used by the extent data structure, optionally
     
    30142771{
    30152772    int rc = VINF_SUCCESS;
    3016 
    30172773    vmdkFreeGrainDirectory(pExtent);
    30182774    if (pExtent->pDescData)
     
    30412797    }
    30422798    vmdkFreeStreamBuffers(pExtent);
    3043 
    30442799    return rc;
    30452800}
    3046 
    30472801/**
    30482802 * Internal: allocate grain table cache if necessary for this image.
     
    30512805{
    30522806    PVMDKEXTENT pExtent;
    3053 
    30542807    /* Allocate grain table cache if any sparse extent is present. */
    30552808    for (unsigned i = 0; i < pImage->cExtents; i++)
     
    30712824        }
    30722825    }
    3073 
    30742826    return VINF_SUCCESS;
    30752827}
    3076 
    30772828/**
    30782829 * Internal: allocate the given number of extents.
     
    31022853    else
    31032854        rc = VERR_NO_MEMORY;
    3104 
    31052855    return rc;
    31062856}
    31072857
    31082858/**
    3109  * Internal: allocate and describes an additional, file-backed extent
    3110  * for the given size. Preserves original extents.
     2859 * Internal: Create an additional file backed extent in split images.
     2860 * Supports split sparse and flat images.
     2861 *
     2862 * @returns VBox status code.
     2863 * @param   pImage              VMDK image instance.
     2864 * @param   cbSize              Desiried size in bytes of new extent.
    31112865 */
    31122866static int vmdkAddFileBackedExtent(PVMDKIMAGE pImage, uint64_t cbSize)
    31132867{
    31142868    int rc = VINF_SUCCESS;
     2869    unsigned uImageFlags = pImage->uImageFlags;
     2870
     2871    /* Check for unsupported image type. */
     2872    if ((uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
     2873        || (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     2874        || (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
     2875    {
     2876        return VERR_NOT_SUPPORTED;
     2877    }
     2878
     2879    /* Allocate array of extents and copy existing extents to it. */
    31152880    PVMDKEXTENT pNewExtents = (PVMDKEXTENT)RTMemAllocZ((pImage->cExtents + 1) * sizeof(VMDKEXTENT));
    3116     if (pNewExtents)
    3117     {
    3118         memcpy(pNewExtents, pImage->pExtents, pImage->cExtents * sizeof(VMDKEXTENT));
    3119         PVMDKEXTENT pExtent = &pNewExtents[pImage->cExtents];
    3120 
    3121         pExtent->pFile = NULL;
    3122         pExtent->pszBasename = NULL;
    3123         pExtent->pszFullname = NULL;
    3124         pExtent->pGD = NULL;
    3125         pExtent->pRGD = NULL;
    3126         pExtent->pDescData = NULL;
    3127         pExtent->uVersion = 1;
    3128         pExtent->uCompression = VMDK_COMPRESSION_NONE;
    3129         pExtent->uExtent = pImage->cExtents;
    3130         pExtent->pImage = pImage;
    3131         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     2881    if (!pNewExtents)
     2882    {
     2883        return VERR_NO_MEMORY;
     2884    }
     2885
     2886    memcpy(pNewExtents, pImage->pExtents, pImage->cExtents * sizeof(VMDKEXTENT));
     2887    /** @todo r=jack - free old extent pointer */
     2888
     2889    /* Locate newly created extent and populate default metadata. */
     2890    PVMDKEXTENT pExtent = &pNewExtents[pImage->cExtents];
     2891
     2892    pExtent->pFile = NULL;
     2893    pExtent->pszBasename = NULL;
     2894    pExtent->pszFullname = NULL;
     2895    pExtent->pGD = NULL;
     2896    pExtent->pRGD = NULL;
     2897    pExtent->pDescData = NULL;
     2898    pExtent->uVersion = 1;
     2899    pExtent->uCompression = VMDK_COMPRESSION_NONE;
     2900    pExtent->uExtent = pImage->cExtents;
     2901    pExtent->pImage = pImage;
     2902    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     2903    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2904    pExtent->uSectorOffset = 0;
     2905    pExtent->fMetaDirty = true;
     2906
     2907    /* Apply image type specific meta data. */
     2908    if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
     2909    {
    31322910        pExtent->enmType = VMDKETYPE_FLAT;
    3133         pExtent->enmAccess = VMDKACCESS_READWRITE;
    3134         pExtent->uSectorOffset = 0;
    3135 
    3136         char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    3137         AssertPtr(pszBasenameSubstr);
    3138 
    3139         char *pszBasenameSuff = RTPathSuffix(pszBasenameSubstr);
    3140         char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
    3141         RTPathStripSuffix(pszBasenameBase);
    3142         char *pszTmp;
    3143         size_t cbTmp;
    3144 
    3145         if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
    3146             RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
    3147                          pExtent->uExtent + 1, pszBasenameSuff);
    3148         else
    3149             RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, pExtent->uExtent + 1,
    3150                          pszBasenameSuff);
    3151 
    3152         RTStrFree(pszBasenameBase);
    3153         if (!pszTmp)
    3154             return VERR_NO_STR_MEMORY;
    3155         cbTmp = strlen(pszTmp) + 1;
    3156         char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
    3157         if (!pszBasename)
    3158         {
    3159             RTStrFree(pszTmp);
    3160             return VERR_NO_MEMORY;
    3161         }
    3162 
    3163         memcpy(pszBasename, pszTmp, cbTmp);
     2911    }
     2912    else
     2913    {
     2914        uint64_t cSectorsPerGDE, cSectorsPerGD;
     2915        pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     2916        pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K));
     2917        pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
     2918        pExtent->cGTEntries = 512;
     2919        cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     2920        pExtent->cSectorsPerGDE = cSectorsPerGDE;
     2921        pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     2922        cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     2923    }
     2924
     2925    /* Allocate and set file name for extent. */
     2926    char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
     2927    AssertPtr(pszBasenameSubstr);
     2928
     2929    char *pszBasenameSuff = RTPathSuffix(pszBasenameSubstr);
     2930    char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
     2931    RTPathStripSuffix(pszBasenameBase);
     2932    char *pszTmp;
     2933    size_t cbTmp;
     2934
     2935    if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
     2936        RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
     2937                        pExtent->uExtent + 1, pszBasenameSuff);
     2938    else
     2939        RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, pExtent->uExtent + 1,
     2940                        pszBasenameSuff);
     2941
     2942    RTStrFree(pszBasenameBase);
     2943    if (!pszTmp)
     2944        return VERR_NO_STR_MEMORY;
     2945    cbTmp = strlen(pszTmp) + 1;
     2946    char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
     2947    if (!pszBasename)
     2948    {
    31642949        RTStrFree(pszTmp);
    3165 
    3166         pExtent->pszBasename = pszBasename;
    3167 
    3168         char *pszBasedirectory = RTStrDup(pImage->pszFilename);
    3169         if (!pszBasedirectory)
    3170             return VERR_NO_STR_MEMORY;
    3171         RTPathStripFilename(pszBasedirectory);
    3172         char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename);
    3173         RTStrFree(pszBasedirectory);
    3174         if (!pszFullname)
    3175             return VERR_NO_STR_MEMORY;
    3176         pExtent->pszFullname = pszFullname;
    3177 
    3178         /* Create file for extent. */
    3179         rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
    3180                           VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
    3181                                                      true /* fCreate */));
    3182         if (RT_FAILURE(rc))
    3183             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
    3184 
    3185         rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
    3186                                pExtent->cNominalSectors, pExtent->enmType,
    3187                                pExtent->pszBasename, pExtent->uSectorOffset);
    3188         if (RT_FAILURE(rc))
    3189             return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
    3190 
     2950        return VERR_NO_MEMORY;
     2951    }
     2952
     2953    memcpy(pszBasename, pszTmp, cbTmp);
     2954    RTStrFree(pszTmp);
     2955
     2956    pExtent->pszBasename = pszBasename;
     2957
     2958    char *pszBasedirectory = RTStrDup(pImage->pszFilename);
     2959    if (!pszBasedirectory)
     2960        return VERR_NO_STR_MEMORY;
     2961    RTPathStripFilename(pszBasedirectory);
     2962    char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename);
     2963    RTStrFree(pszBasedirectory);
     2964    if (!pszFullname)
     2965        return VERR_NO_STR_MEMORY;
     2966    pExtent->pszFullname = pszFullname;
     2967
     2968    /* Create file for extent. */
     2969    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     2970                        VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
     2971                                                    true /* fCreate */));
     2972    if (RT_FAILURE(rc))
     2973        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
     2974
     2975    if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
     2976    {
     2977        /* For flat images: Pre allocate file space. */
    31912978        rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, cbSize,
    31922979                                            0 /* fFlags */, NULL, 0, 0);
    3193 
    31942980        if (RT_FAILURE(rc))
    31952981            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    3196 
    3197         pImage->pExtents = pNewExtents;
    3198         pImage->cExtents++;
    31992982    }
    32002983    else
    3201         rc = VERR_NO_MEMORY;
     2984    {
     2985        /* For sparse images: Allocate new grain directories/tables. */
     2986        /* fPreAlloc should never be false because VMware can't use such images. */
     2987        rc = vmdkCreateGrainDirectory(pImage, pExtent,
     2988                                      RT_MAX( pExtent->uDescriptorSector
     2989                                              + pExtent->cDescriptorSectors,
     2990                                              1),
     2991                                      true /* fPreAlloc */);
     2992        if (RT_FAILURE(rc))
     2993            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
     2994    }
     2995
     2996    /* Insert new extent into descriptor file. */
     2997    rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
     2998                           pExtent->cNominalSectors, pExtent->enmType,
     2999                           pExtent->pszBasename, pExtent->uSectorOffset);
     3000    if (RT_FAILURE(rc))
     3001        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
     3002
     3003    pImage->pExtents = pNewExtents;
     3004    pImage->cExtents++;
     3005
    32023006    return rc;
    32033007}
     3008
    32043009/**
    32053010 * Reads and processes the descriptor embedded in sparse images.
     
    32493054                {
    32503055                    uint64_t cDescriptorSectorsOld = pExtent->cDescriptorSectors;
    3251 
    32523056                    pExtent->cDescriptorSectors = 4;
    32533057                    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     
    33143118            rc = VERR_NO_MEMORY;
    33153119    }
    3316 
    33173120    return rc;
    33183121}
    3319 
    33203122/**
    33213123 * Reads the descriptor from a pure text file.
     
    34043206                        else
    34053207                            pExtent->pszFullname = NULL;
    3406 
    34073208                        unsigned uOpenFlags = pImage->uOpenFlags | ((pExtent->enmAccess == VMDKACCESS_READONLY) ? VD_OPEN_FLAGS_READONLY : 0);
    34083209                        switch (pExtent->enmType)
     
    34253226                                if (RT_FAILURE(rc))
    34263227                                    break;
    3427 
    34283228                                /* Mark extent as unclean if opened in read-write mode. */
    34293229                                if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     
    34623262    else if (RT_SUCCESS(rc))
    34633263        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor in '%s' is too short"), pImage->pszFilename);
    3464 
    34653264    return rc;
    34663265}
    3467 
    34683266/**
    34693267 * Read and process the descriptor based on the image type.
     
    34763274{
    34773275    uint32_t u32Magic;
    3478 
    34793276    /* Read magic (if present). */
    34803277    int rc = vdIfIoIntFileReadSync(pImage->pIfIo, pFile->pStorage, 0,
     
    34933290        rc = VERR_VD_VMDK_INVALID_HEADER;
    34943291    }
    3495 
    34963292    return rc;
    34973293}
    3498 
    34993294/**
    35003295 * Internal: Open an image, constructing all necessary data structures.
     
    35063301    pImage->pIfIo      = VDIfIoIntGet(pImage->pVDIfsImage);
    35073302    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
    3508 
    35093303    /*
    35103304     * Open the image.
     
    35193313    {
    35203314        pImage->pFile = pFile;
    3521 
    35223315        rc = vmdkDescriptorRead(pImage, pFile);
    35233316        if (RT_SUCCESS(rc))
     
    35373330                }
    35383331            }
    3539 
    35403332            /* Update the image metadata now in case has changed. */
    35413333            rc = vmdkFlushImage(pImage, NULL);
     
    35573349                             ||  pExtent->enmType == VMDKETYPE_ZERO)
    35583350                        pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
    3559 
    35603351                    pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
    35613352                }
    3562 
    35633353                if (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    35643354                    || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     
    35703360    /* else: Do NOT signal an appropriate error here, as the VD layer has the
    35713361     *       choice of retrying the open if it failed. */
    3572 
    35733362    if (RT_SUCCESS(rc))
    35743363    {
     
    35763365        pImage->RegionList.fFlags   = 0;
    35773366        pImage->RegionList.cRegions = 1;
    3578 
    35793367        pRegion->offRegion            = 0; /* Disk start. */
    35803368        pRegion->cbBlock              = 512;
     
    35893377    return rc;
    35903378}
    3591 
    35923379/**
    35933380 * Frees a raw descriptor.
     
    35983385    if (!pRawDesc)
    35993386        return VINF_SUCCESS;
    3600 
    36013387    RTStrFree(pRawDesc->pszRawDisk);
    36023388    pRawDesc->pszRawDisk = NULL;
    3603 
    36043389    /* Partitions: */
    36053390    for (unsigned i = 0; i < pRawDesc->cPartDescs; i++)
     
    36073392        RTStrFree(pRawDesc->pPartDescs[i].pszRawDevice);
    36083393        pRawDesc->pPartDescs[i].pszRawDevice = NULL;
    3609 
    36103394        RTMemFree(pRawDesc->pPartDescs[i].pvPartitionData);
    36113395        pRawDesc->pPartDescs[i].pvPartitionData = NULL;
    36123396    }
    3613 
    36143397    RTMemFree(pRawDesc->pPartDescs);
    36153398    pRawDesc->pPartDescs = NULL;
    3616 
    36173399    RTMemFree(pRawDesc);
    36183400    return VINF_SUCCESS;
    36193401}
    3620 
    36213402/**
    36223403 * Helper that grows the raw partition descriptor table by @a cToAdd entries,
     
    36353416        pRawDesc->cPartDescs = cNew;
    36363417        pRawDesc->pPartDescs = paNew;
    3637 
    36383418        *ppRet = &paNew[cOld];
    36393419        return VINF_SUCCESS;
     
    36443424                     pImage->pszFilename, cOld, cNew);
    36453425}
    3646 
    36473426/**
    36483427 * @callback_method_impl{FNRTSORTCMP}
     
    36543433    return iDelta < 0 ? -1 : iDelta > 0 ? 1 : 0;
    36553434}
    3656 
    36573435/**
    36583436 * Post processes the partition descriptors.
     
    36663444     */
    36673445    RTSortShell(pRawDesc->pPartDescs, pRawDesc->cPartDescs, sizeof(pRawDesc->pPartDescs[0]), vmdkRawDescPartComp, NULL);
    3668 
    36693446    /*
    36703447     * Check that we don't have overlapping descriptors.  If we do, that's an
     
    36813458                             paPartDescs[i].pvPartitionData ? " (data)" : "");
    36823459        offLast -= 1;
    3683 
    36843460        if (i + 1 < pRawDesc->cPartDescs && offLast >= paPartDescs[i + 1].offStartInVDisk)
    36853461            return vdIfError(pImage->pIfError, VERR_FILESYSTEM_CORRUPT /*?*/, RT_SRC_POS,
     
    36943470                             paPartDescs[i].pvPartitionData ? " (data)" : "", cbSize);
    36953471    }
    3696 
    36973472    return VINF_SUCCESS;
    36983473}
    3699 
    3700 
    37013474#ifdef RT_OS_LINUX
    37023475/**
     
    37213494    size_t const cchDir = RTPathEnsureTrailingSeparator(pszBlockDevDir, cbBlockDevDir);
    37223495    AssertReturn(cchDir > 0, VERR_BUFFER_OVERFLOW);
    3723 
    37243496    RTDIR hDir = NIL_RTDIR;
    37253497    int rc = RTDirOpen(&hDir, pszBlockDevDir);
     
    37393511                    rc = RTStrCopy(&pszBlockDevDir[cchDir], cbBlockDevDir - cchDir, Entry.szName);
    37403512                    AssertContinue(RT_SUCCESS(rc)); /* should not happen! */
    3741 
    37423513                    dev_t uThisDevNo = ~uDevToLocate;
    37433514                    rc = RTLinuxSysFsReadDevNumFile(&uThisDevNo, "%s/dev", pszBlockDevDir);
     
    37693540}
    37703541#endif /* RT_OS_LINUX */
    3771 
    37723542#ifdef RT_OS_FREEBSD
    3773 
    3774 
    37753543/**
    37763544 * Reads the config data from the provider and returns offset and size
     
    37853553    gconfig *pConfEntry;
    37863554    int rc = VERR_NOT_FOUND;
    3787 
    37883555    /*
    37893556     * Required parameters are located in the list containing key/value pairs.
     
    38163583    return rc;
    38173584}
    3818 
    3819 
    38203585/**
    38213586 * Searches the partition specified by name and calculates its size and absolute offset.
     
    38363601    AssertReturn(pcbAbsoluteOffset,  VERR_INVALID_PARAMETER);
    38373602    AssertReturn(pcbSize,            VERR_INVALID_PARAMETER);
    3838 
    38393603    ggeom *pParentGeom;
    38403604    int rc = VERR_NOT_FOUND;
     
    38493613    if (RT_FAILURE(rc))
    38503614        return rc;
    3851 
    38523615    gprovider *pProvider;
    38533616    /*
     
    38613624            return vmdkReadPartitionsParamsFromProvider(pProvider, pcbAbsoluteOffset, pcbSize);
    38623625    }
    3863 
    38643626    /*
    38653627     * No provider found. Go over the parent geom again
     
    38713633     * provider
    38723634     */
    3873 
    38743635    LIST_FOREACH(pProvider, &pParentGeom->lg_provider, lg_provider)
    38753636    {
     
    38793640        if (RT_FAILURE(rc))
    38803641            return rc;
    3881 
    38823642        uint64_t cbProviderOffset = 0;
    38833643        uint64_t cbProviderSize = 0;
     
    38903650        }
    38913651    }
    3892 
    38933652    return VERR_NOT_FOUND;
    38943653}
    38953654#endif
    3896 
    3897 
    38983655/**
    38993656 * Attempts to verify the raw partition path.
     
    39053662{
    39063663    RT_NOREF(pImage, pPartDesc, idxPartition, pszRawDrive, hRawDrive, cbSector, hVol);
    3907 
    39083664    /*
    39093665     * Try open the raw partition device.
     
    39153671                         N_("VMDK: Image path: '%s'. Failed to open partition #%u on '%s' via '%s' (%Rrc)"),
    39163672                         pImage->pszFilename, idxPartition, pszRawDrive, pPartDesc->pszRawDevice, rc);
    3917 
    39183673    /*
    39193674     * Compare the partition UUID if we can get it.
     
    39213676#ifdef RT_OS_WINDOWS
    39223677    DWORD cbReturned;
    3923 
    39243678    /* 1. Get the device numbers for both handles, they should have the same disk. */
    39253679    STORAGE_DEVICE_NUMBER DevNum1;
     
    39303684                       N_("VMDK: Image path: '%s'. IOCTL_STORAGE_GET_DEVICE_NUMBER failed on '%s': %u"),
    39313685                       pImage->pszFilename, pszRawDrive, GetLastError());
    3932 
    39333686    STORAGE_DEVICE_NUMBER DevNum2;
    39343687    RT_ZERO(DevNum2);
     
    40223775            rc = VERR_NO_TMP_MEMORY;
    40233776    }
    4024 
    40253777#elif defined(RT_OS_LINUX)
    40263778    RT_NOREF(hVol);
    4027 
    40283779    /* Stat the two devices first to get their device numbers.  (We probably
    40293780       could make some assumptions here about the major & minor number assignments
     
    40463797        {
    40473798            rc = vmdkFindSysBlockDevPath(pImage, szSysPath, sizeof(szSysPath), StDrive.st_rdev, pszRawDrive);
    4048 
    40493799            /* Now, scan the directories under that again for a partition device
    40503800               matching the hRawPart device's number: */
    40513801            if (RT_SUCCESS(rc))
    40523802                rc = vmdkFindSysBlockDevPath(pImage, szSysPath, sizeof(szSysPath), StPart.st_rdev, pPartDesc->pszRawDevice);
    4053 
    40543803            /* Having found the /sys/block/device/partition/ path, we can finally
    40553804               read the partition attributes and compare with hVol. */
     
    40643813                                   pImage->pszFilename, idxPartition, pPartDesc->pszRawDevice, pszRawDrive, iLnxPartition, idxPartition);
    40653814                /* else: ignore failure? */
    4066 
    40673815                /* start offset: */
    40683816                uint32_t const cbLnxSector = 512; /* It's hardcoded in the Linux kernel */
     
    40783826                    /* else: ignore failure? */
    40793827                }
    4080 
    40813828                /* the size: */
    40823829                if (RT_SUCCESS(rc))
     
    40953842        /* else: We've got nothing to work on, so only do content comparison. */
    40963843    }
    4097 
    40983844#elif defined(RT_OS_FREEBSD)
    40993845    char szDriveDevName[256];
     
    41263872                rc = vdIfError(pImage->pIfError, VERR_GENERAL_FAILURE, RT_SRC_POS,
    41273873                               N_("VMDK: Image path: '%s'. 'PART' class not found in the GEOM tree"), pImage->pszFilename);
    4128 
    4129 
    41303874            if (RT_SUCCESS(rc))
    41313875            {
     
    41503894                                   pImage->pszFilename, pPartDesc->pszRawDevice, pszRawDrive, rc);
    41513895            }
    4152 
    41533896            geom_deletetree(&geomMesh);
    41543897        }
     
    41573900                           N_("VMDK: Image path: '%s'. geom_gettree failed: %d"), pImage->pszFilename, err);
    41583901    }
    4159 
    41603902#elif defined(RT_OS_SOLARIS)
    41613903    RT_NOREF(hVol);
    4162 
    41633904    dk_cinfo dkiDriveInfo;
    41643905    dk_cinfo dkiPartInfo;
     
    42083949             * using another way. If there is an error, it returns errno which will be handled below.
    42093950             */
    4210 
    42113951            uint32_t numPartition = (uint32_t)dkiPartInfo.dki_partition;
    42123952            if (numPartition > NDKMAP)
     
    42433983                           N_("VMDK: Image path: '%s'. Partition #%u path ('%s') verification failed on '%s': Start offset %RI64, expected %RU64"),
    42443984                           pImage->pszFilename, idxPartition, pPartDesc->pszRawDevice, pszRawDrive, cbOffset, pPartDesc->offStartInVDisk);
    4245 
    42463985        if (RT_SUCCESS(rc) && cbSize != pPartDesc->cbData)
    42473986            rc = vdIfError(pImage->pIfError, VERR_MISMATCH, RT_SRC_POS,
     
    43194058#else
    43204059    RT_NOREF(hVol); /* PORTME */
    4321     rc = VERR_NOT_SUPPORTED;
    43224060#endif
    43234061    if (RT_SUCCESS(rc))
     
    43354073        {
    43364074            uint8_t *pbSector2 = pbSector1 + cbToCompare;
    4337 
    43384075            /* Do the comparing, we repeat if it fails and the data might be volatile. */
    43394076            uint64_t uPrevCrc1 = 0;
     
    43514088                        {
    43524089                            rc = VERR_MISMATCH;
    4353 
    43544090                            /* Do data stability checks before repeating: */
    43554091                            uint64_t const uCrc1 = RTCrc64(pbSector1, cbToCompare);
     
    43844120                    offMissmatch++;
    43854121                int cbSample = (int)RT_MIN(cbToCompare - offMissmatch, 16);
    4386 
    43874122                if (cStable > 0)
    43884123                    rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
     
    43984133                }
    43994134            }
    4400 
    44014135            RTMemTmpFree(pbSector1);
    44024136        }
     
    44094143    return rc;
    44104144}
    4411 
    44124145#ifdef RT_OS_WINDOWS
    44134146/**
     
    44314164}
    44324165#endif /* RT_OS_WINDOWS */
    4433 
    44344166/**
    44354167 * Worker for vmdkMakeRawDescriptor that adds partition descriptors when the
     
    44484180{
    44494181    *phVolToRelease = NIL_RTDVMVOLUME;
    4450 
    44514182    /* Check sanity/understanding. */
    44524183    Assert(fPartitions);
    44534184    Assert((fPartitions & fPartitionsReadOnly) == fPartitionsReadOnly); /* RO should be a sub-set */
    4454 
    44554185    /*
    44564186     * Allocate on descriptor for each volume up front.
    44574187     */
    44584188    uint32_t const cVolumes = RTDvmMapGetValidVolumes(hVolMgr);
    4459 
    44604189    PVDISKRAWPARTDESC paPartDescs = NULL;
    44614190    int rc = vmdkRawDescAppendPartDesc(pImage, pRawDesc, cVolumes, &paPartDescs);
    44624191    AssertRCReturn(rc, rc);
    4463 
    44644192    /*
    44654193     * Enumerate the partitions (volumes) on the disk and create descriptors for each of them.
     
    44844212        Assert(cRefs != UINT32_MAX); RT_NOREF(cRefs);
    44854213        *phVolToRelease = hVol = hVolNext;
    4486 
    44874214        /*
    44884215         * Depending on the fPartitions selector and associated read-only mask,
     
    44914218         */
    44924219        paPartDescs[i].cbData = RTDvmVolumeGetSize(hVol);
    4493 
    44944220        uint64_t offVolumeEndIgnored = 0;
    44954221        rc = RTDvmVolumeQueryRange(hVol, &paPartDescs[i].offStartInVDisk, &offVolumeEndIgnored);
     
    44994225                             pImage->pszFilename, i, pszRawDrive, rc);
    45004226        Assert(paPartDescs[i].cbData == offVolumeEndIgnored + 1 - paPartDescs[i].offStartInVDisk);
    4501 
    45024227        /* Note! The index must match IHostDrivePartition::number. */
    45034228        uint32_t idxPartition = RTDvmVolumeGetIndex(hVol, RTDVMVOLIDX_HOST);
     
    45084233            if (fPartitionsReadOnly & RT_BIT_32(idxPartition))
    45094234                paPartDescs[i].uFlags |= VDISKRAW_READONLY;
    4510 
    45114235            if (!fRelative)
    45124236            {
     
    45294253                 */
    45304254                paPartDescs[i].offStartInDevice = 0;
    4531 
    45324255#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    45334256                /* /dev/rdisk1 -> /dev/rdisk1s2 (s=slice) */
     
    45834306#endif
    45844307                AssertPtrReturn(paPartDescs[i].pszRawDevice, VERR_NO_STR_MEMORY);
    4585 
    45864308                rc = vmdkRawDescVerifyPartitionPath(pImage, &paPartDescs[i], idxPartition, pszRawDrive, hRawDrive, cbSector, hVol);
    45874309                AssertRCReturn(rc, rc);
     
    45954317        }
    45964318    } /* for each volume */
    4597 
    45984319    RTDvmVolumeRelease(hVol);
    45994320    *phVolToRelease = NIL_RTDVMVOLUME;
    4600 
    46014321    /*
    46024322     * Check that we found all the partitions the user selected.
     
    46134333                             pImage->pszFilename, pszRawDrive, szLeft);
    46144334    }
    4615 
    46164335    return VINF_SUCCESS;
    46174336}
    4618 
    46194337/**
    46204338 * Worker for vmdkMakeRawDescriptor that adds partition descriptors with copies
     
    46474365                         pImage->pszFilename, pszRawDrive, rc);
    46484366    AssertReturn(cLocations > 0 && cLocations < _16M, VERR_INTERNAL_ERROR_5);
    4649 
    46504367    /* We can allocate the partition descriptors here to save an intentation level. */
    46514368    PVDISKRAWPARTDESC paPartDescs = NULL;
    46524369    rc = vmdkRawDescAppendPartDesc(pImage, pRawDesc, (uint32_t)cLocations, &paPartDescs);
    46534370    AssertRCReturn(rc, rc);
    4654 
    46554371    /* Allocate the result table and repeat the location table query: */
    46564372    PRTDVMTABLELOCATION paLocations = (PRTDVMTABLELOCATION)RTMemAllocZ(sizeof(paLocations[0]) * cLocations);
     
    47324448    return rc;
    47334449}
    4734 
    47354450/**
    47364451 * Opens the volume manager for the raw drive when in selected-partition mode.
     
    47484463{
    47494464    *phVolMgr = NIL_RTDVM;
    4750 
    47514465    RTVFSFILE hVfsFile = NIL_RTVFSFILE;
    47524466    int rc = RTVfsFileFromRTFile(hRawDrive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, true /*fLeaveOpen*/, &hVfsFile);
     
    47554469                         N_("VMDK: Image path: '%s'.  RTVfsFileFromRTFile failed for '%s' handle (%Rrc)"),
    47564470                         pImage->pszFilename, pszRawDrive, rc);
    4757 
    47584471    RTDVM hVolMgr = NIL_RTDVM;
    47594472    rc = RTDvmCreate(&hVolMgr, hVfsFile, cbSector, 0 /*fFlags*/);
    4760 
    47614473    RTVfsFileRelease(hVfsFile);
    4762 
    47634474    if (RT_FAILURE(rc))
    47644475        return vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    47654476                         N_("VMDK: Image path: '%s'. Failed to create volume manager instance for '%s' (%Rrc)"),
    47664477                         pImage->pszFilename, pszRawDrive, rc);
    4767 
    47684478    rc = RTDvmMapOpen(hVolMgr);
    47694479    if (RT_SUCCESS(rc))
     
    47764486                     pImage->pszFilename, pszRawDrive, rc);
    47774487}
    4778 
    47794488/**
    47804489 * Opens the raw drive device and get the sizes for it.
     
    48004509                         N_("VMDK: Image path: '%s'. Failed to open the raw drive '%s' for reading (%Rrc)"),
    48014510                         pImage->pszFilename, pszRawDrive, rc);
    4802 
    48034511    /*
    48044512     * Get the sector size.
     
    48494557    return rc;
    48504558}
    4851 
    48524559/**
    48534560 * Reads the raw disk configuration, leaving initalization and cleanup to the
     
    48664573        return vdIfError(pImage->pIfError, VERR_INVALID_PARAMETER, RT_SRC_POS,
    48674574                         N_("VMDK: Image path: '%s'. Getting config interface failed"), pImage->pszFilename);
    4868 
    48694575    /*
    48704576     * RawDrive = path
     
    48754581                         N_("VMDK: Image path: '%s'. Getting 'RawDrive' configuration failed (%Rrc)"), pImage->pszFilename, rc);
    48764582    AssertPtrReturn(*ppszRawDrive, VERR_INTERNAL_ERROR_3);
    4877 
    48784583    /*
    48794584     * Partitions=n[r][,...]
     
    48814586    uint32_t const cMaxPartitionBits = sizeof(*pfPartitions) * 8 /* ASSUMES 8 bits per char */;
    48824587    *pfPartitions = *pfPartitionsReadOnly = 0;
    4883 
    48844588    rc = VDCFGQueryStringAlloc(pImgCfg, "Partitions", ppszFreeMe);
    48854589    if (RT_SUCCESS(rc))
     
    49154619                                 pImage->pszFilename, psz);
    49164620        }
    4917 
    49184621        RTStrFree(*ppszFreeMe);
    49194622        *ppszFreeMe = NULL;
     
    49224625        return vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    49234626                         N_("VMDK: Image path: '%s'. Getting 'Partitions' configuration failed (%Rrc)"), pImage->pszFilename, rc);
    4924 
    49254627    /*
    49264628     * BootSector=base64
     
    49424644                             N_("VMDK: Image path: '%s'. Custom bootsector for '%s' is way too big: %zu bytes, max 4MB"),
    49434645                             pImage->pszFilename, *ppszRawDrive, cbBootSector);
    4944 
    49454646        /* Refuse the boot sector if whole-drive.  This used to be done quietly,
    49464647           however, bird disagrees and thinks the user should be told that what
     
    49514652                             N_("VMDK: Image path: '%s'. Custom bootsector for '%s' is not supported for whole-drive configurations, only when selecting partitions"),
    49524653                             pImage->pszFilename, *ppszRawDrive);
    4953 
    49544654        *pcbBootSector = (size_t)cbBootSector;
    49554655        *ppvBootSector = RTMemAlloc((size_t)cbBootSector);
     
    49584658                             N_("VMDK: Image path: '%s'. Failed to allocate %zd bytes for the custom bootsector for '%s'"),
    49594659                             pImage->pszFilename, cbBootSector, *ppszRawDrive);
    4960 
    49614660        rc = RTBase64Decode(*ppszFreeMe, *ppvBootSector, cbBootSector, NULL /*pcbActual*/, NULL /*ppszEnd*/);
    49624661        if (RT_FAILURE(rc))
     
    49644663                              N_("VMDK: Image path: '%s'. Base64 decoding of the custom boot sector for '%s' failed (%Rrc)"),
    49654664                              pImage->pszFilename, *ppszRawDrive, rc);
    4966 
    49674665        RTStrFree(*ppszFreeMe);
    49684666        *ppszFreeMe = NULL;
     
    49714669        return vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    49724670                         N_("VMDK: Image path: '%s'. Getting 'BootSector' configuration failed (%Rrc)"), pImage->pszFilename, rc);
    4973 
    49744671    /*
    49754672     * Relative=0/1
     
    49994696        *pfRelative = false;
    50004697#endif
    5001 
    50024698    return VINF_SUCCESS;
    50034699}
    5004 
    50054700/**
    50064701 * Creates a raw drive (nee disk) descriptor.
     
    50214716    /* Make sure it's NULL. */
    50224717    *ppRaw = NULL;
    5023 
    50244718    /*
    50254719     * Read the configuration.
     
    50464740        if (RT_SUCCESS(rc))
    50474741        {
    5048             pImage->cbSize = cbSize;
    50494742            /*
    50504743             * Create the raw-drive descriptor
     
    50744767                    //pRawDesc->cPartDescs = 0;
    50754768                    //pRawDesc->pPartDescs = NULL;
    5076 
    50774769                    /* We need to parse the partition map to complete the descriptor: */
    50784770                    RTDVM hVolMgr = NIL_RTDVM;
     
    50864778                            pRawDesc->enmPartitioningType = enmFormatType == RTDVMFORMATTYPE_MBR
    50874779                                                          ? VDISKPARTTYPE_MBR : VDISKPARTTYPE_GPT;
    5088 
    50894780                            /* Add copies of the partition tables:  */
    50904781                            rc = vmdkRawDescDoCopyPartitionTables(pImage, hVolMgr, pRawDesc, pszRawDrive, hRawDrive,
     
    50984789                                                             fPartitions, fPartitionsReadOnly, fRelative, &hVolRelease);
    50994790                                RTDvmVolumeRelease(hVolRelease);
    5100 
    51014791                                /* Finally, sort the partition and check consistency (overlaps, etc): */
    51024792                                if (RT_SUCCESS(rc))
     
    51424832    return rc;
    51434833}
    5144 
    51454834/**
    51464835 * Internal: create VMDK images for raw disk/partition access.
     
    51514840    int rc = VINF_SUCCESS;
    51524841    PVMDKEXTENT pExtent;
    5153 
    51544842    if (pRaw->uFlags & VDISKRAW_DISK)
    51554843    {
     
    51664854        if (RT_FAILURE(rc))
    51674855            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
    5168 
    51694856        /* Set up basename for extent description. Cannot use StrDup. */
    51704857        size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
     
    51834870        pExtent->enmAccess = (pRaw->uFlags & VDISKRAW_READONLY) ? VMDKACCESS_READONLY : VMDKACCESS_READWRITE;
    51844871        pExtent->fMetaDirty = false;
    5185 
    51864872        /* Open flat image, the raw disk. */
    51874873        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    51964882         * file, write the partition information to a flat extent and
    51974883         * open all the (flat) raw disk partitions. */
    5198 
    51994884        /* First pass over the partition data areas to determine how many
    52004885         * extents we need. One data area can require up to 2 extents, as
     
    52084893                return vdIfError(pImage->pIfError, VERR_INVALID_PARAMETER, RT_SRC_POS,
    52094894                                 N_("VMDK: incorrect partition data area ordering set up by the caller in '%s'"), pImage->pszFilename);
    5210 
    52114895            if (uStart < pPart->offStartInVDisk)
    52124896                cExtents++;
     
    52174901        if (uStart != cbSize)
    52184902            cExtents++;
    5219 
    52204903        rc = vmdkCreateExtents(pImage, cExtents);
    52214904        if (RT_FAILURE(rc))
    52224905            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    5223 
    52244906        /* Create raw partition descriptor file. */
    52254907        rc = vmdkFileOpen(pImage, &pImage->pFile, NULL, pImage->pszFilename,
     
    52284910        if (RT_FAILURE(rc))
    52294911            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
    5230 
    52314912        /* Create base filename for the partition table extent. */
    52324913        /** @todo remove fixed buffer without creating memory leaks. */
     
    52434924                    pszBaseBase, pszSuff);
    52444925        RTStrFree(pszBaseBase);
    5245 
    52464926        /* Second pass over the partitions, now define all extents. */
    52474927        uint64_t uPartOffset = 0;
     
    52524932            PVDISKRAWPARTDESC pPart = &pRaw->pPartDescs[i];
    52534933            pExtent = &pImage->pExtents[cExtents++];
    5254 
    52554934            if (uStart < pPart->offStartInVDisk)
    52564935            {
     
    52664945            }
    52674946            uStart = pPart->offStartInVDisk + pPart->cbData;
    5268 
    52694947            if (pPart->pvPartitionData)
    52704948            {
     
    52764954                memcpy(pszBasename, pszPartition, cbBasename);
    52774955                pExtent->pszBasename = pszBasename;
    5278 
    52794956                /* Set up full name for partition extent. */
    52804957                char *pszDirname = RTStrDup(pImage->pszFilename);
     
    52924969                pExtent->enmAccess = VMDKACCESS_READWRITE;
    52934970                pExtent->fMetaDirty = false;
    5294 
    52954971                /* Create partition table flat image. */
    52964972                rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    53275003                    pExtent->enmAccess = (pPart->uFlags & VDISKRAW_READONLY) ? VMDKACCESS_READONLY : VMDKACCESS_READWRITE;
    53285004                    pExtent->fMetaDirty = false;
    5329 
    53305005                    /* Open flat image, the raw partition. */
    53315006                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    53605035        }
    53615036    }
    5362 
    53635037    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    53645038                            (pRaw->uFlags & VDISKRAW_DISK) ?
     
    53685042    return rc;
    53695043}
    5370 
    53715044/**
    53725045 * Internal: create a regular (i.e. file-backed) VMDK image.
     
    53805053    uint64_t cbOffset = 0;
    53815054    uint64_t cbRemaining = cbSize;
    5382 
    53835055    if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
    53845056    {
     
    53925064    if (RT_FAILURE(rc))
    53935065        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    5394 
    53955066    /* Basename strings needed for constructing the extent names. */
    53965067    char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    53975068    AssertPtr(pszBasenameSubstr);
    53985069    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    5399 
    54005070    /* Create separate descriptor file if necessary. */
    54015071    if (cExtents != 1 || (uImageFlags & VD_IMAGE_FLAGS_FIXED))
     
    54095079    else
    54105080        pImage->pFile = NULL;
    5411 
    54125081    /* Set up all extents. */
    54135082    for (unsigned i = 0; i < cExtents; i++)
     
    54155084        PVMDKEXTENT pExtent = &pImage->pExtents[i];
    54165085        uint64_t cbExtent = cbRemaining;
    5417 
    54185086        /* Set up fullname/basename for extent description. Cannot use StrDup
    54195087         * for basename, as it is not guaranteed that the memory can be freed
     
    54725140            return VERR_NO_STR_MEMORY;
    54735141        pExtent->pszFullname = pszFullname;
    5474 
    54755142        /* Create file for extent. */
    54765143        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    54885155                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    54895156        }
    5490 
    54915157        /* Place descriptor file information (where integrated). */
    54925158        if (cExtents == 1 && !(uImageFlags & VD_IMAGE_FLAGS_FIXED))
     
    54985164            pImage->pDescData = NULL;
    54995165        }
    5500 
    55015166        if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
    55025167        {
     
    55265191                pExtent->enmType = VMDKETYPE_FLAT;
    55275192        }
    5528 
    55295193        pExtent->enmAccess = VMDKACCESS_READWRITE;
    55305194        pExtent->fUncleanShutdown = true;
     
    55325196        pExtent->uSectorOffset = 0;
    55335197        pExtent->fMetaDirty = true;
    5534 
    55355198        if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
    55365199        {
     
    55445207                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
    55455208        }
    5546 
    55475209        cbOffset += cbExtent;
    5548 
    55495210        if (RT_SUCCESS(rc))
    55505211            vdIfProgress(pIfProgress, uPercentStart + cbOffset * uPercentSpan / cbSize);
    5551 
    55525212        cbRemaining -= cbExtent;
    55535213    }
    5554 
    55555214    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
    55565215    {
     
    55615220            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set controller type to lsilogic in '%s'"), pImage->pszFilename);
    55625221    }
    5563 
    55645222    const char *pszDescType = NULL;
    55655223    if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
     
    55875245    return rc;
    55885246}
    5589 
    55905247/**
    55915248 * Internal: Create a real stream optimized VMDK using only linear writes.
     
    55965253    if (RT_FAILURE(rc))
    55975254        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    5598 
    55995255    /* Basename strings needed for constructing the extent names. */
    56005256    const char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    56015257    AssertPtr(pszBasenameSubstr);
    56025258    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    5603 
    56045259    /* No separate descriptor file. */
    56055260    pImage->pFile = NULL;
    5606 
    56075261    /* Set up all extents. */
    56085262    PVMDKEXTENT pExtent = &pImage->pExtents[0];
    5609 
    56105263    /* Set up fullname/basename for extent description. Cannot use StrDup
    56115264     * for basename, as it is not guaranteed that the memory can be freed
     
    56175270    memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    56185271    pExtent->pszBasename = pszBasename;
    5619 
    56205272    char *pszBasedirectory = RTStrDup(pImage->pszFilename);
    56215273    RTPathStripFilename(pszBasedirectory);
     
    56255277        return VERR_NO_STR_MEMORY;
    56265278    pExtent->pszFullname = pszFullname;
    5627 
    56285279    /* Create file for extent. Make it write only, no reading allowed. */
    56295280    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname,
     
    56335284    if (RT_FAILURE(rc))
    56345285        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
    5635 
    56365286    /* Place descriptor file information. */
    56375287    pExtent->uDescriptorSector = 1;
     
    56405290    pExtent->pDescData = pImage->pDescData;
    56415291    pImage->pDescData = NULL;
    5642 
    56435292    uint64_t cSectorsPerGDE, cSectorsPerGD;
    56445293    pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     
    56505299    pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    56515300    cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
    5652 
    56535301    /* The spec says version is 1 for all VMDKs, but the vast
    56545302     * majority of streamOptimized VMDKs actually contain
     
    56575305    pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
    56585306    pExtent->fFooter = true;
    5659 
    56605307    pExtent->enmAccess = VMDKACCESS_READONLY;
    56615308    pExtent->fUncleanShutdown = false;
     
    56635310    pExtent->uSectorOffset = 0;
    56645311    pExtent->fMetaDirty = true;
    5665 
    56665312    /* Create grain directory, without preallocating it straight away. It will
    56675313     * be constructed on the fly when writing out the data and written when
     
    56725318    if (RT_FAILURE(rc))
    56735319        return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
    5674 
    56755320    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    56765321                            "streamOptimized");
    56775322    if (RT_FAILURE(rc))
    56785323        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
    5679 
    56805324    return rc;
    56815325}
    5682 
    56835326/**
    56845327 * Initializes the UUID fields in the DDB.
     
    57165359        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
    57175360                       N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
    5718 
    57195361    return rc;
    57205362}
    5721 
    57225363/**
    57235364 * Internal: The actual code for creating any VMDK variant currently in
     
    57325373{
    57335374    pImage->uImageFlags = uImageFlags;
    5734 
    57355375    pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
    57365376    pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
    57375377    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
    5738 
    57395378    int rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
    57405379                                  &pImage->Descriptor);
     
    57475386            rc = vmdkMakeRawDescriptor(pImage, &pRaw);
    57485387            if (RT_FAILURE(rc))
    5749                 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create raw descriptor for '%s'"),
    5750                     pImage->pszFilename);
    5751             if (!cbSize)
    5752                 cbSize = pImage->cbSize;
    5753 
     5388                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could get raw descriptor for '%s'"), pImage->pszFilename);
    57545389            rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
    57555390            vmdkRawDescFree(pRaw);
     
    57675402                                        uPercentSpan * 95 / 100);
    57685403        }
    5769 
    57705404        if (RT_SUCCESS(rc))
    57715405        {
    57725406            vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100);
    5773 
    57745407            pImage->cbSize = cbSize;
    5775 
    57765408            for (unsigned i = 0; i < pImage->cExtents; i++)
    57775409            {
    57785410                PVMDKEXTENT pExtent = &pImage->pExtents[i];
    5779 
    57805411                rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
    57815412                                       pExtent->cNominalSectors, pExtent->enmType,
     
    57875418                }
    57885419            }
    5789 
    57905420            if (RT_SUCCESS(rc))
    57915421                vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
    5792 
    5793             pImage->LCHSGeometry = *pLCHSGeometry;
    5794             pImage->PCHSGeometry = *pPCHSGeometry;
    5795 
    5796             if (RT_SUCCESS(rc))
    5797             {
    5798                 if (   pPCHSGeometry->cCylinders != 0
    5799                     && pPCHSGeometry->cHeads != 0
    5800                     && pPCHSGeometry->cSectors != 0)
    5801                     rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    5802                 else if (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)
    5803                 {
    5804                     VDGEOMETRY RawDiskPCHSGeometry;
    5805                     RawDiskPCHSGeometry.cCylinders = (uint32_t)RT_MIN(pImage->cbSize / 512 / 16 / 63, 16383);
    5806                     RawDiskPCHSGeometry.cHeads = 16;
    5807                     RawDiskPCHSGeometry.cSectors = 63;
    5808                     rc = vmdkDescSetPCHSGeometry(pImage, &RawDiskPCHSGeometry);
    5809                 }
    5810             }
    5811 
     5422            if (   RT_SUCCESS(rc)
     5423                && pPCHSGeometry->cCylinders != 0
     5424                && pPCHSGeometry->cHeads != 0
     5425                && pPCHSGeometry->cSectors != 0)
     5426                rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    58125427            if (   RT_SUCCESS(rc)
    58135428                && pLCHSGeometry->cCylinders != 0
     
    58155430                && pLCHSGeometry->cSectors != 0)
    58165431                rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    5817 
     5432            pImage->LCHSGeometry = *pLCHSGeometry;
     5433            pImage->PCHSGeometry = *pPCHSGeometry;
    58185434            pImage->ImageUuid = *pUuid;
    58195435            RTUuidClear(&pImage->ParentUuid);
    58205436            RTUuidClear(&pImage->ModificationUuid);
    58215437            RTUuidClear(&pImage->ParentModificationUuid);
    5822 
    58235438            if (RT_SUCCESS(rc))
    58245439                rc = vmdkCreateImageDdbUuidsInit(pImage);
    5825 
    58265440            if (RT_SUCCESS(rc))
    58275441                rc = vmdkAllocateGrainTableCache(pImage);
    5828 
    58295442            if (RT_SUCCESS(rc))
    58305443            {
     
    58335446                    rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
    58345447            }
    5835 
    58365448            if (RT_SUCCESS(rc))
    58375449            {
    58385450                vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 99 / 100);
    5839 
    58405451                if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    58415452                {
     
    58625473    else
    58635474        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
    5864 
    5865 
    58665475    if (RT_SUCCESS(rc))
    58675476    {
     
    58695478        pImage->RegionList.fFlags   = 0;
    58705479        pImage->RegionList.cRegions = 1;
    5871 
    58725480        pRegion->offRegion            = 0; /* Disk start. */
    58735481        pRegion->cbBlock              = 512;
     
    58775485        pRegion->cbMetadata           = 0;
    58785486        pRegion->cRegionBlocksOrBytes = pImage->cbSize;
    5879 
    58805487        vdIfProgress(pIfProgress, uPercentStart + uPercentSpan);
    58815488    }
     
    58845491    return rc;
    58855492}
    5886 
    58875493/**
    58885494 * Internal: Update image comment.
     
    58975503            return VERR_NO_MEMORY;
    58985504    }
    5899 
    59005505    int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
    59015506                               "ddb.comment", pszCommentEncoded);
     
    59065511    return VINF_SUCCESS;
    59075512}
    5908 
    59095513/**
    59105514 * Internal. Clear the grain table buffer for real stream optimized writing.
     
    59175521               VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t));
    59185522}
    5919 
    59205523/**
    59215524 * Internal. Flush the grain table buffer for real stream optimized writing.
     
    59265529    int rc = VINF_SUCCESS;
    59275530    uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
    5928 
    59295531    /* VMware does not write out completely empty grain tables in the case
    59305532     * of streamOptimized images, which according to my interpretation of
     
    59485550    if (fAllZero)
    59495551        return VINF_SUCCESS;
    5950 
    59515552    uint64_t uFileOffset = pExtent->uAppendPosition;
    59525553    if (!uFileOffset)
     
    59545555    /* Align to sector, as the previous write could have been any size. */
    59555556    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    5956 
    59575557    /* Grain table marker. */
    59585558    uint8_t aMarker[512];
     
    59655565    AssertRC(rc);
    59665566    uFileOffset += 512;
    5967 
    59685567    if (!pExtent->pGD || pExtent->pGD[uGDEntry])
    59695568        return VERR_INTERNAL_ERROR;
    5970 
    59715569    pExtent->pGD[uGDEntry] = VMDK_BYTE2SECTOR(uFileOffset);
    5972 
    59735570    for (uint32_t i = 0; i < cCacheLines; i++)
    59745571    {
     
    59785575        for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
    59795576            *pGTTmp = RT_H2LE_U32(*pGTTmp);
    5980 
    59815577        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, uFileOffset,
    59825578                                    &pImage->pGTCache->aGTCache[i].aGTData[0],
     
    59905586    return rc;
    59915587}
    5992 
    59935588/**
    59945589 * Internal. Free all allocated space for representing an image, and optionally
     
    59985593{
    59995594    int rc = VINF_SUCCESS;
    6000 
    60015595    /* Freeing a never allocated image (e.g. because the open failed) is
    60025596     * not signalled as an error. After all nothing bad happens. */
     
    60245618                        pImage->pExtents[i].fMetaDirty = true;
    60255619                    }
    6026 
    60275620                    /* From now on it's not safe to append any more data. */
    60285621                    pImage->pExtents[i].uAppendPosition = 0;
     
    60305623            }
    60315624        }
    6032 
    60335625        if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    60345626        {
     
    60495641                    AssertRC(rc);
    60505642                }
    6051 
    60525643                uint64_t uFileOffset = pExtent->uAppendPosition;
    60535644                if (!uFileOffset)
    60545645                    return VERR_INTERNAL_ERROR;
    60555646                uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    6056 
    60575647                /* From now on it's not safe to append any more data. */
    60585648                pExtent->uAppendPosition = 0;
    6059 
    60605649                /* Grain directory marker. */
    60615650                uint8_t aMarker[512];
     
    60685657                AssertRC(rc);
    60695658                uFileOffset += 512;
    6070 
    60715659                /* Write grain directory in little endian style. The array will
    60725660                 * not be used after this, so convert in place. */
     
    60785666                                            pExtent->cGDEntries * sizeof(uint32_t));
    60795667                AssertRC(rc);
    6080 
    60815668                pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
    60825669                pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
     
    60845671                                          + pExtent->cGDEntries * sizeof(uint32_t),
    60855672                                          512);
    6086 
    60875673                /* Footer marker. */
    60885674                memset(pMarker, '\0', sizeof(aMarker));
     
    60925678                                            uFileOffset, aMarker, sizeof(aMarker));
    60935679                AssertRC(rc);
    6094 
    60955680                uFileOffset += 512;
    60965681                rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset, NULL);
    60975682                AssertRC(rc);
    6098 
    60995683                uFileOffset += 512;
    61005684                /* End-of-stream marker. */
     
    61075691        else if (!fDelete && fFlush)
    61085692            vmdkFlushImage(pImage, NULL);
    6109 
    61105693        if (pImage->pExtents != NULL)
    61115694        {
     
    61295712        if (RT_SUCCESS(rc))
    61305713            rc = rc2; /* Propogate any error when closing the file. */
    6131 
    61325714        if (pImage->pGTCache)
    61335715        {
     
    61415723        }
    61425724    }
    6143 
    61445725    LogFlowFunc(("returns %Rrc\n", rc));
    61455726    return rc;
    61465727}
    6147 
    61485728/**
    61495729 * Internal. Flush image data (and metadata) to disk.
     
    61535733    PVMDKEXTENT pExtent;
    61545734    int rc = VINF_SUCCESS;
    6155 
    61565735    /* Update descriptor if changed. */
    61575736    if (pImage->Descriptor.fDirty)
    61585737        rc = vmdkWriteDescriptor(pImage, pIoCtx);
    6159 
    61605738    if (RT_SUCCESS(rc))
    61615739    {
     
    61935771                }
    61945772            }
    6195 
    61965773            if (RT_FAILURE(rc))
    61975774                break;
    6198 
    61995775            switch (pExtent->enmType)
    62005776            {
     
    62185794        }
    62195795    }
    6220 
    62215796    return rc;
    62225797}
    6223 
    62245798/**
    62255799 * Internal. Find extent corresponding to the sector number in the disk.
     
    62305804    PVMDKEXTENT pExtent = NULL;
    62315805    int rc = VINF_SUCCESS;
    6232 
    62335806    for (unsigned i = 0; i < pImage->cExtents; i++)
    62345807    {
     
    62415814        offSector -= pImage->pExtents[i].cNominalSectors;
    62425815    }
    6243 
    62445816    if (pExtent)
    62455817        *ppExtent = pExtent;
    62465818    else
    62475819        rc = VERR_IO_SECTOR_NOT_FOUND;
    6248 
    62495820    return rc;
    62505821}
    6251 
    62525822/**
    62535823 * Internal. Hash function for placing the grain table hash entries.
     
    62605830    return (uSector + uExtent) % pCache->cEntries;
    62615831}
    6262 
    62635832/**
    62645833 * Internal. Get sector number in the extent file from the relative sector
     
    62755844    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
    62765845    int rc;
    6277 
    62785846    /* For newly created and readonly/sequentially opened streamOptimized
    62795847     * images this must be a no-op, as the grain directory is not there. */
     
    62875855        return VINF_SUCCESS;
    62885856    }
    6289 
    62905857    uGDIndex = uSector / pExtent->cSectorsPerGDE;
    62915858    if (uGDIndex >= pExtent->cGDEntries)
     
    62995866        return VINF_SUCCESS;
    63005867    }
    6301 
    63025868    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
    63035869    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
     
    63285894    return VINF_SUCCESS;
    63295895}
    6330 
    63315896/**
    63325897 * Internal. Writes the grain and also if necessary the grain tables.
     
    63435908    const void *pData;
    63445909    int rc;
    6345 
    63465910    /* Very strict requirements: always write at least one full grain, with
    63475911     * proper alignment. Everything else would require reading of already
     
    63565920        || uSector + VMDK_BYTE2SECTOR(cbWrite) > pExtent->cNominalSectors)
    63575921        return VERR_INVALID_PARAMETER;
    6358 
    63595922    /* Clip write range to at most the rest of the grain. */
    63605923    cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
    6361 
    63625924    /* Do not allow to go back. */
    63635925    uGrain = uSector / pExtent->cSectorsPerGrain;
     
    63685930    if (uGrain < pExtent->uLastGrainAccess)
    63695931        return VERR_VD_VMDK_INVALID_WRITE;
    6370 
    63715932    /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
    63725933     * to allocate something, we also need to detect the situation ourself. */
     
    63745935        && vdIfIoIntIoCtxIsZero(pImage->pIfIo, pIoCtx, cbWrite, true /* fAdvance */))
    63755936        return VINF_SUCCESS;
    6376 
    63775937    if (uGDEntry != uLastGDEntry)
    63785938    {
     
    63885948        }
    63895949    }
    6390 
    63915950    uint64_t uFileOffset;
    63925951    uFileOffset = pExtent->uAppendPosition;
     
    63955954    /* Align to sector, as the previous write could have been any size. */
    63965955    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    6397 
    63985956    /* Paranoia check: extent type, grain table buffer presence and
    63995957     * grain table buffer space. Also grain table entry must be clear. */
     
    64035961        || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
    64045962        return VERR_INTERNAL_ERROR;
    6405 
    64065963    /* Update grain table entry. */
    64075964    pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
    6408 
    64095965    if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    64105966    {
     
    64195975        unsigned cSegments = 1;
    64205976        size_t cbSeg = 0;
    6421 
    64225977        cbSeg = vdIfIoIntIoCtxSegArrayCreate(pImage->pIfIo, pIoCtx, &Segment,
    64235978                                             &cSegments, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     
    64365991    pExtent->uLastGrainAccess = uGrain;
    64375992    pExtent->uAppendPosition += cbGrain;
    6438 
    64395993    return rc;
    64405994}
    6441 
    64425995/**
    64435996 * Internal: Updates the grain table during grain allocation.
     
    64536006    uint64_t uSector = pGrainAlloc->uSector;
    64546007    PVMDKGTCACHEENTRY pGTCacheEntry;
    6455 
    64566008    LogFlowFunc(("pImage=%#p pExtent=%#p pCache=%#p pIoCtx=%#p pGrainAlloc=%#p\n",
    64576009                 pImage, pExtent, pCache, pIoCtx, pGrainAlloc));
    6458 
    64596010    uGTSector = pGrainAlloc->uGTSector;
    64606011    uRGTSector = pGrainAlloc->uRGTSector;
    64616012    LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
    6462 
    64636013    /* Update the grain table (and the cache). */
    64646014    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
     
    65236073            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
    65246074    }
    6525 
    65266075    LogFlowFunc(("leaving rc=%Rrc\n", rc));
    65276076    return rc;
    65286077}
    6529 
    65306078/**
    65316079 * Internal - complete the grain allocation by updating disk grain table if required.
     
    65376085    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    65386086    PVMDKGRAINALLOCASYNC pGrainAlloc = (PVMDKGRAINALLOCASYNC)pvUser;
    6539 
    65406087    LogFlowFunc(("pBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc\n",
    65416088                 pBackendData, pIoCtx, pvUser, rcReq));
    6542 
    65436089    pGrainAlloc->cIoXfersPending--;
    65446090    if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded)
    65456091        rc = vmdkAllocGrainGTUpdate(pImage, pGrainAlloc->pExtent, pIoCtx, pGrainAlloc);
    6546 
    65476092    if (!pGrainAlloc->cIoXfersPending)
    65486093    {
     
    65506095        RTMemFree(pGrainAlloc);
    65516096    }
    6552 
    65536097    LogFlowFunc(("Leaving rc=%Rrc\n", rc));
    65546098    return rc;
    65556099}
    6556 
    65576100/**
    65586101 * Internal. Allocates a new grain table (if necessary).
     
    65666109    PVMDKGRAINALLOCASYNC pGrainAlloc = NULL;
    65676110    int rc;
    6568 
    65696111    LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n",
    65706112                 pCache, pExtent, pIoCtx, uSector, cbWrite));
    6571 
    65726113    pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC));
    65736114    if (!pGrainAlloc)
    65746115        return VERR_NO_MEMORY;
    6575 
    65766116    pGrainAlloc->pExtent = pExtent;
    65776117    pGrainAlloc->uSector = uSector;
    6578 
    65796118    uGDIndex = uSector / pExtent->cSectorsPerGDE;
    65806119    if (uGDIndex >= pExtent->cGDEntries)
     
    65916130    {
    65926131        LogFlow(("Allocating new grain table\n"));
    6593 
    65946132        /* There is no grain table referenced by this grain directory
    65956133         * entry. So there is absolutely no data in this area. Allocate
     
    66026140        }
    66036141        Assert(!(uFileOffset % 512));
    6604 
    66056142        uFileOffset = RT_ALIGN_64(uFileOffset, 512);
    66066143        uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
    6607 
    66086144        /* Normally the grain table is preallocated for hosted sparse extents
    66096145         * that support more than 32 bit sector numbers. So this shouldn't
     
    66146150            return VERR_VD_VMDK_INVALID_HEADER;
    66156151        }
    6616 
    66176152        /* Write grain table by writing the required number of grain table
    66186153         * cache chunks. Allocate memory dynamically here or we flood the
     
    66206155        size_t cbGTDataTmp = pExtent->cGTEntries * sizeof(uint32_t);
    66216156        uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp);
    6622 
    66236157        if (!paGTDataTmp)
    66246158        {
     
    66266160            return VERR_NO_MEMORY;
    66276161        }
    6628 
    66296162        memset(paGTDataTmp, '\0', cbGTDataTmp);
    66306163        rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pExtent->pFile->pStorage,
     
    66426175        pExtent->uAppendPosition = RT_ALIGN_64(  pExtent->uAppendPosition
    66436176                                               + cbGTDataTmp, 512);
    6644 
    66456177        if (pExtent->pRGD)
    66466178        {
     
    66516183            Assert(!(uFileOffset % 512));
    66526184            uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
    6653 
    66546185            /* Normally the redundant grain table is preallocated for hosted
    66556186             * sparse extents that support more than 32 bit sector numbers. So
     
    66606191                return VERR_VD_VMDK_INVALID_HEADER;
    66616192            }
    6662 
    66636193            /* Write grain table by writing the required number of grain table
    66646194             * cache chunks. Allocate memory dynamically here or we flood the
     
    66756205                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
    66766206            }
    6677 
    66786207            pExtent->uAppendPosition = pExtent->uAppendPosition + cbGTDataTmp;
    66796208        }
    6680 
    66816209        RTMemTmpFree(paGTDataTmp);
    6682 
    66836210        /* Update the grain directory on disk (doing it before writing the
    66846211         * grain table will result in a garbled extent if the operation is
     
    67066233                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
    67076234        }
    6708 
    67096235        /* As the final step update the in-memory copy of the GDs. */
    67106236        pExtent->pGD[uGDIndex] = uGTSector;
     
    67126238            pExtent->pRGD[uGDIndex] = uRGTSector;
    67136239    }
    6714 
    67156240    LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
    67166241    pGrainAlloc->uGTSector = uGTSector;
    67176242    pGrainAlloc->uRGTSector = uRGTSector;
    6718 
    67196243    uFileOffset = pExtent->uAppendPosition;
    67206244    if (!uFileOffset)
    67216245        return VERR_INTERNAL_ERROR;
    67226246    Assert(!(uFileOffset % 512));
    6723 
    67246247    pGrainAlloc->uGrainOffset = uFileOffset;
    6725 
    67266248    if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    67276249    {
     
    67296251                        ("Accesses to stream optimized images must be synchronous\n"),
    67306252                        VERR_INVALID_STATE);
    6731 
    67326253        if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    67336254            return vdIfError(pImage->pIfError, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
    6734 
    67356255        /* Invalidate cache, just in case some code incorrectly allows mixing
    67366256         * of reads and writes. Normally shouldn't be needed. */
    67376257        pExtent->uGrainSectorAbs = 0;
    6738 
    67396258        /* Write compressed data block and the markers. */
    67406259        uint32_t cbGrain = 0;
     
    67426261        RTSGSEG Segment;
    67436262        unsigned cSegments = 1;
    6744 
    67456263        cbSeg = vdIfIoIntIoCtxSegArrayCreate(pImage->pIfIo, pIoCtx, &Segment,
    67466264                                             &cSegments, cbWrite);
    67476265        Assert(cbSeg == cbWrite);
    6748 
    67496266        rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
    67506267                                 Segment.pvSeg, cbWrite, uSector, &cbGrain);
     
    67676284        else if (RT_FAILURE(rc))
    67686285            return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
    6769 
    67706286        pExtent->uAppendPosition += cbWrite;
    67716287    }
    6772 
    67736288    rc = vmdkAllocGrainGTUpdate(pImage, pExtent, pIoCtx, pGrainAlloc);
    6774 
    67756289    if (!pGrainAlloc->cIoXfersPending)
    67766290    {
     
    67786292        RTMemFree(pGrainAlloc);
    67796293    }
    6780 
    67816294    LogFlowFunc(("leaving rc=%Rrc\n", rc));
    6782 
    67836295    return rc;
    67846296}
    6785 
    67866297/**
    67876298 * Internal. Reads the contents by sequentially going over the compressed
     
    67936304{
    67946305    int rc;
    6795 
    67966306    LogFlowFunc(("pImage=%#p pExtent=%#p uSector=%llu pIoCtx=%#p cbRead=%llu\n",
    67976307                 pImage, pExtent, uSector, pIoCtx, cbRead));
    6798 
    67996308    AssertMsgReturn(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
    68006309                    ("Async I/O not supported for sequential stream optimized images\n"),
    68016310                    VERR_INVALID_STATE);
    6802 
    68036311    /* Do not allow to go back. */
    68046312    uint32_t uGrain = uSector / pExtent->cSectorsPerGrain;
     
    68066314        return VERR_VD_VMDK_INVALID_STATE;
    68076315    pExtent->uLastGrainAccess = uGrain;
    6808 
    68096316    /* After a previous error do not attempt to recover, as it would need
    68106317     * seeking (in the general case backwards which is forbidden). */
    68116318    if (!pExtent->uGrainSectorAbs)
    68126319        return VERR_VD_VMDK_INVALID_STATE;
    6813 
    68146320    /* Check if we need to read something from the image or if what we have
    68156321     * in the buffer is good to fulfill the request. */
     
    68186324        uint32_t uGrainSectorAbs =   pExtent->uGrainSectorAbs
    68196325                                   + VMDK_BYTE2SECTOR(pExtent->cbGrainStreamRead);
    6820 
    68216326        /* Get the marker from the next data block - and skip everything which
    68226327         * is not a compressed grain. If it's a compressed grain which is for
     
    68336338            Marker.uSector = RT_LE2H_U64(Marker.uSector);
    68346339            Marker.cbSize = RT_LE2H_U32(Marker.cbSize);
    6835 
    68366340            if (Marker.cbSize == 0)
    68376341            {
     
    69126416            }
    69136417        } while (Marker.uType != VMDK_MARKER_EOS);
    6914 
    69156418        pExtent->uGrainSectorAbs = uGrainSectorAbs;
    6916 
    69176419        if (!pExtent->cbGrainStreamRead && Marker.uType == VMDK_MARKER_EOS)
    69186420        {
     
    69236425        }
    69246426    }
    6925 
    69266427    if (pExtent->uGrain > uSector / pExtent->cSectorsPerGrain)
    69276428    {
     
    69316432        return VERR_VD_BLOCK_FREE;
    69326433    }
    6933 
    69346434    uint32_t uSectorInGrain = uSector % pExtent->cSectorsPerGrain;
    69356435    vdIfIoIntIoCtxCopyTo(pImage->pIfIo, pIoCtx,
     
    69396439    return VINF_SUCCESS;
    69406440}
    6941 
    69426441/**
    69436442 * Replaces a fragment of a string with the specified string.
     
    70086507    return pszNewStr;
    70096508}
    7010 
    7011 
    70126509/** @copydoc VDIMAGEBACKEND::pfnProbe */
    70136510static DECLCALLBACK(int) vmdkProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
     
    70376534        vmdkFreeImage(pImage, false, false /*fFlush*/);
    70386535        RTMemFree(pImage);
    7039 
    70406536        if (RT_SUCCESS(rc))
    70416537            *penmType = VDTYPE_HDD;
     
    70436539    else
    70446540        rc = VERR_NO_MEMORY;
    7045 
    70466541    LogFlowFunc(("returns %Rrc\n", rc));
    70476542    return rc;
    70486543}
    7049 
    70506544/** @copydoc VDIMAGEBACKEND::pfnOpen */
    70516545static DECLCALLBACK(int) vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
     
    70546548{
    70556549    RT_NOREF1(enmType); /**< @todo r=klaus make use of the type info. */
    7056 
    70576550    LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
    70586551                 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
    70596552    int rc;
    7060 
    70616553    /* Check open flags. All valid flags are supported. */
    70626554    AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
    70636555    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
    70646556    AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
    7065 
    70666557
    70676558    PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(RT_UOFFSETOF(VMDKIMAGE, RegionList.aRegions[1]));
     
    70766567        pImage->pVDIfsDisk = pVDIfsDisk;
    70776568        pImage->pVDIfsImage = pVDIfsImage;
    7078 
    70796569        rc = vmdkOpenImage(pImage, uOpenFlags);
    70806570        if (RT_SUCCESS(rc))
     
    70856575    else
    70866576        rc = VERR_NO_MEMORY;
    7087 
    70886577    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    70896578    return rc;
    70906579}
    7091 
    70926580/** @copydoc VDIMAGEBACKEND::pfnCreate */
    70936581static DECLCALLBACK(int) vmdkCreate(const char *pszFilename, uint64_t cbSize,
     
    71036591                 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
    71046592    int rc;
    7105 
    71066593    /* Check the VD container type and image flags. */
    71076594    if (   enmType != VDTYPE_HDD
    71086595        || (uImageFlags & ~VD_VMDK_IMAGE_FLAGS_MASK) != 0)
    71096596        return VERR_VD_INVALID_TYPE;
    7110 
    71116597    /* Check size. Maximum 256TB-64K for sparse images, otherwise unlimited. */
    71126598    if (   !(uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)
     
    71146600            || (!(uImageFlags & VD_IMAGE_FLAGS_FIXED) && cbSize >= _1T * 256 - _64K)))
    71156601        return VERR_VD_INVALID_SIZE;
    7116 
    71176602    /* Check image flags for invalid combinations. */
    71186603    if (   (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    71196604        && (uImageFlags & ~(VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED | VD_IMAGE_FLAGS_DIFF)))
    71206605        return VERR_INVALID_PARAMETER;
    7121 
    71226606    /* Check open flags. All valid flags are supported. */
    71236607    AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
     
    71296613                   && !(uImageFlags & VD_IMAGE_FLAGS_FIXED)),
    71306614                 VERR_INVALID_PARAMETER);
    7131 
    71326615    PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(RT_UOFFSETOF(VMDKIMAGE, RegionList.aRegions[1]));
    71336616    if (RT_LIKELY(pImage))
    71346617    {
    71356618        PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
    7136 
    71376619        pImage->pszFilename = pszFilename;
    71386620        pImage->pFile = NULL;
     
    71656647                    rc = vmdkOpenImage(pImage, uOpenFlags);
    71666648                }
    7167 
    71686649                if (RT_SUCCESS(rc))
    71696650                    *ppBackendData = pImage;
    71706651            }
    7171 
    71726652            if (RT_FAILURE(rc))
    71736653                RTMemFree(pImage->pDescData);
     
    71756655        else
    71766656            rc = VERR_NO_MEMORY;
    7177 
    71786657        if (RT_FAILURE(rc))
    71796658            RTMemFree(pImage);
     
    71816660    else
    71826661        rc = VERR_NO_MEMORY;
    7183 
    71846662    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    71856663    return rc;
    71866664}
    7187 
    71886665/**
    71896666 * Prepares the state for renaming a VMDK image, setting up the state and allocating
     
    71986675{
    71996676    AssertReturn(RTPathFilename(pszFilename) != NULL, VERR_INVALID_PARAMETER);
    7200 
    72016677    int rc = VINF_SUCCESS;
    7202 
    72036678    memset(&pRenameState->DescriptorCopy, 0, sizeof(pRenameState->DescriptorCopy));
    7204 
    72056679    /*
    72066680     * Allocate an array to store both old and new names of renamed files
     
    72286702            pRenameState->fEmbeddedDesc = true;
    72296703        }
    7230 
    72316704        /* Save the descriptor content. */
    72326705        pRenameState->DescriptorCopy.cLines = pImage->Descriptor.cLines;
     
    72406713            }
    72416714        }
    7242 
    72436715        if (RT_SUCCESS(rc))
    72446716        {
     
    72476719            AssertReturn(pRenameState->pszNewBaseName, VERR_NO_STR_MEMORY);
    72486720            RTPathStripSuffix(pRenameState->pszNewBaseName);
    7249 
    72506721            pRenameState->pszOldBaseName = RTStrDup(RTPathFilename(pImage->pszFilename));
    72516722            AssertReturn(pRenameState->pszOldBaseName, VERR_NO_STR_MEMORY);
    72526723            RTPathStripSuffix(pRenameState->pszOldBaseName);
    7253 
    72546724            /* Prepare both old and new full names used for string replacement.
    72556725               Note! Must abspath the stuff here, so the strstr weirdness later in
     
    72596729            AssertReturn(pRenameState->pszNewFullName, VERR_NO_STR_MEMORY);
    72606730            RTPathStripSuffix(pRenameState->pszNewFullName);
    7261 
    72626731            pRenameState->pszOldFullName = RTPathAbsDup(pImage->pszFilename);
    72636732            AssertReturn(pRenameState->pszOldFullName, VERR_NO_STR_MEMORY);
    72646733            RTPathStripSuffix(pRenameState->pszOldFullName);
    7265 
    72666734            /* Save the old name for easy access to the old descriptor file. */
    72676735            pRenameState->pszOldDescName = RTStrDup(pImage->pszFilename);
    72686736            AssertReturn(pRenameState->pszOldDescName, VERR_NO_STR_MEMORY);
    7269 
    72706737            /* Save old image name. */
    72716738            pRenameState->pszOldImageName = pImage->pszFilename;
     
    72746741    else
    72756742        rc = VERR_NO_TMP_MEMORY;
    7276 
    72776743    return rc;
    72786744}
    7279 
    72806745/**
    72816746 * Destroys the given rename state, freeing all allocated memory.
     
    73216786        RTStrFree(pRenameState->pszNewFullName);
    73226787}
    7323 
    73246788/**
    73256789 * Rolls back the rename operation to the original state.
     
    73326796{
    73336797    int rc = VINF_SUCCESS;
    7334 
    73356798    if (!pRenameState->fImageFreed)
    73366799    {
     
    73416804        vmdkFreeImage(pImage, false, true /*fFlush*/);
    73426805    }
    7343 
    73446806    /* Rename files back. */
    73456807    for (unsigned i = 0; i <= pRenameState->cExtents; i++)
     
    73806842    pImage->pszFilename = pRenameState->pszOldImageName;
    73816843    rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
    7382 
    73836844    return rc;
    73846845}
    7385 
    73866846/**
    73876847 * Rename worker doing the real work.
     
    73966856    int rc = VINF_SUCCESS;
    73976857    unsigned i, line;
    7398 
    73996858    /* Update the descriptor with modified extent names. */
    74006859    for (i = 0, line = pImage->Descriptor.uFirstExtent;
     
    74136872        pImage->Descriptor.aLines[line] = pRenameState->apszNewLines[i];
    74146873    }
    7415 
    74166874    if (RT_SUCCESS(rc))
    74176875    {
     
    74206878        /* Flush the descriptor now, in case it is embedded. */
    74216879        vmdkFlushImage(pImage, NULL);
    7422 
    74236880        /* Close and rename/move extents. */
    74246881        for (i = 0; i < pRenameState->cExtents; i++)
     
    74386895            if (RT_FAILURE(rc))
    74396896                break;;
    7440 
    74416897            /* Rename the extent file. */
    74426898            rc = vdIfIoIntFileMove(pImage->pIfIo, pExtent->pszFullname, pRenameState->apszNewName[i], 0);
     
    74466902            pRenameState->apszOldName[i] = RTStrDup(pExtent->pszFullname);
    74476903        }
    7448 
    74496904        if (RT_SUCCESS(rc))
    74506905        {
     
    74546909            {
    74556910                pRenameState->fImageFreed = true;
    7456 
    74576911                /* Last elements of new/old name arrays are intended for
    74586912                 * storing descriptor's names.
     
    74696923                    }
    74706924                }
    7471 
    74726925                /* Update pImage with the new information. */
    74736926                pImage->pszFilename = pszFilename;
    7474 
    74756927                /* Open the new image. */
    74766928                rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
     
    74786930        }
    74796931    }
    7480 
    74816932    return rc;
    74826933}
    7483 
    74846934/** @copydoc VDIMAGEBACKEND::pfnRename */
    74856935static DECLCALLBACK(int) vmdkRename(void *pBackendData, const char *pszFilename)
    74866936{
    74876937    LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
    7488 
    74896938    PVMDKIMAGE  pImage  = (PVMDKIMAGE)pBackendData;
    74906939    VMDKRENAMESTATE RenameState;
    7491 
    74926940    memset(&RenameState, 0, sizeof(RenameState));
    7493 
    74946941    /* Check arguments. */
    74956942    AssertPtrReturn(pImage, VERR_INVALID_POINTER);
     
    74976944    AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
    74986945    AssertReturn(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK), VERR_INVALID_PARAMETER);
    7499 
    75006946    int rc = vmdkRenameStatePrepare(pImage, &RenameState, pszFilename);
    75016947    if (RT_SUCCESS(rc))
    75026948    {
    75036949        /* --- Up to this point we have not done any damage yet. --- */
    7504 
    75056950        rc = vmdkRenameWorker(pImage, &RenameState, pszFilename);
    75066951        /* Roll back all changes in case of failure. */
     
    75116956        }
    75126957    }
    7513 
    75146958    vmdkRenameStateDestroy(&RenameState);
    75156959    LogFlowFunc(("returns %Rrc\n", rc));
    75166960    return rc;
    75176961}
    7518 
    75196962/** @copydoc VDIMAGEBACKEND::pfnClose */
    75206963static DECLCALLBACK(int) vmdkClose(void *pBackendData, bool fDelete)
     
    75226965    LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
    75236966    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    7524 
    75256967    int rc = vmdkFreeImage(pImage, fDelete, true /*fFlush*/);
    75266968    RTMemFree(pImage);
    7527 
    75286969    LogFlowFunc(("returns %Rrc\n", rc));
    75296970    return rc;
    75306971}
    7531 
    75326972/** @copydoc VDIMAGEBACKEND::pfnRead */
    75336973static DECLCALLBACK(int) vmdkRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
     
    75376977                 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
    75386978    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    7539 
    75406979    AssertPtr(pImage);
    75416980    Assert(uOffset % 512 == 0);
     
    75446983    AssertReturn(cbToRead, VERR_INVALID_PARAMETER);
    75456984    AssertReturn(uOffset + cbToRead <= pImage->cbSize, VERR_INVALID_PARAMETER);
    7546 
    75476985    /* Find the extent and check access permissions as defined in the extent descriptor. */
    75486986    PVMDKEXTENT pExtent;
     
    75556993        /* Clip read range to remain in this extent. */
    75566994        cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    7557 
    75586995        /* Handle the read according to the current extent type. */
    75596996        switch (pExtent->enmType)
     
    75626999            {
    75637000                uint64_t uSectorExtentAbs;
    7564 
    75657001                rc = vmdkGetSector(pImage, pIoCtx, pExtent, uSectorExtentRel, &uSectorExtentAbs);
    75667002                if (RT_FAILURE(rc))
     
    75867022                        AssertMsg(vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx),
    75877023                                  ("Async I/O is not supported for stream optimized VMDK's\n"));
    7588 
    75897024                        uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
    75907025                        uSectorExtentAbs -= uSectorInGrain;
     
    76277062            {
    76287063                size_t cbSet;
    7629 
    76307064                cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbToRead);
    76317065                Assert(cbSet == cbToRead);
     
    76387072    else if (RT_SUCCESS(rc))
    76397073        rc = VERR_VD_VMDK_INVALID_STATE;
    7640 
    76417074    LogFlowFunc(("returns %Rrc\n", rc));
    76427075    return rc;
    76437076}
    7644 
    76457077/** @copydoc VDIMAGEBACKEND::pfnWrite */
    76467078static DECLCALLBACK(int) vmdkWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
     
    76527084    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    76537085    int rc;
    7654 
    76557086    AssertPtr(pImage);
    76567087    Assert(uOffset % 512 == 0);
     
    76587089    AssertPtrReturn(pIoCtx, VERR_INVALID_POINTER);
    76597090    AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);
    7660 
    76617091    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    76627092    {
     
    76647094        uint64_t uSectorExtentRel;
    76657095        uint64_t uSectorExtentAbs;
    7666 
    76677096        /* No size check here, will do that later when the extent is located.
    76687097         * There are sparse images out there which according to the spec are
     
    76717100         * grain boundaries, and with the nominal size not being a multiple of the
    76727101         * grain size), this would prevent writing to the last grain. */
    7673 
    76747102        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
    76757103                            &pExtent, &uSectorExtentRel);
     
    77697197                }
    77707198            }
    7771 
    77727199            if (pcbWriteProcess)
    77737200                *pcbWriteProcess = cbToWrite;
     
    77767203    else
    77777204        rc = VERR_VD_IMAGE_READ_ONLY;
    7778 
    77797205    LogFlowFunc(("returns %Rrc\n", rc));
    77807206    return rc;
    77817207}
    7782 
    77837208/** @copydoc VDIMAGEBACKEND::pfnFlush */
    77847209static DECLCALLBACK(int) vmdkFlush(void *pBackendData, PVDIOCTX pIoCtx)
    77857210{
    77867211    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    7787 
    77887212    return vmdkFlushImage(pImage, pIoCtx);
    77897213}
    7790 
    77917214/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
    77927215static DECLCALLBACK(unsigned) vmdkGetVersion(void *pBackendData)
     
    77947217    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    77957218    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    7796 
    77977219    AssertPtrReturn(pImage, 0);
    7798 
    77997220    return VMDK_IMAGE_VERSION;
    78007221}
    7801 
    78027222/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
    78037223static DECLCALLBACK(uint64_t) vmdkGetFileSize(void *pBackendData)
     
    78067226    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    78077227    uint64_t cb = 0;
    7808 
    78097228    AssertPtrReturn(pImage, 0);
    7810 
    78117229    if (pImage->pFile != NULL)
    78127230    {
     
    78267244        }
    78277245    }
    7828 
    78297246    LogFlowFunc(("returns %lld\n", cb));
    78307247    return cb;
    78317248}
    7832 
    78337249/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
    78347250static DECLCALLBACK(int) vmdkGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
     
    78377253    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    78387254    int rc = VINF_SUCCESS;
    7839 
    78407255    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    7841 
    78427256    if (pImage->PCHSGeometry.cCylinders)
    78437257        *pPCHSGeometry = pImage->PCHSGeometry;
    78447258    else
    78457259        rc = VERR_VD_GEOMETRY_NOT_SET;
    7846 
    78477260    LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
    78487261    return rc;
    78497262}
    7850 
    78517263/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
    78527264static DECLCALLBACK(int) vmdkSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
     
    78567268    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    78577269    int rc = VINF_SUCCESS;
    7858 
    78597270    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    7860 
    78617271    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    78627272    {
     
    78727282    else
    78737283        rc = VERR_VD_IMAGE_READ_ONLY;
    7874 
    78757284    LogFlowFunc(("returns %Rrc\n", rc));
    78767285    return rc;
    78777286}
    7878 
    78797287/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
    78807288static DECLCALLBACK(int) vmdkGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
     
    78837291    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    78847292    int rc = VINF_SUCCESS;
    7885 
    78867293    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    7887 
    78887294    if (pImage->LCHSGeometry.cCylinders)
    78897295        *pLCHSGeometry = pImage->LCHSGeometry;
    78907296    else
    78917297        rc = VERR_VD_GEOMETRY_NOT_SET;
    7892 
    78937298    LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    78947299    return rc;
    78957300}
    7896 
    78977301/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
    78987302static DECLCALLBACK(int) vmdkSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
     
    79027306    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    79037307    int rc = VINF_SUCCESS;
    7904 
    79057308    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    7906 
    79077309    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    79087310    {
     
    79187320    else
    79197321        rc = VERR_VD_IMAGE_READ_ONLY;
    7920 
    79217322    LogFlowFunc(("returns %Rrc\n", rc));
    79227323    return rc;
    79237324}
    7924 
    79257325/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
    79267326static DECLCALLBACK(int) vmdkQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
     
    79287328    LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
    79297329    PVMDKIMAGE pThis = (PVMDKIMAGE)pBackendData;
    7930 
    79317330    AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
    7932 
    79337331    *ppRegionList = &pThis->RegionList;
    79347332    LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
    79357333    return VINF_SUCCESS;
    79367334}
    7937 
    79387335/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
    79397336static DECLCALLBACK(void) vmdkRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
     
    79437340    PVMDKIMAGE pThis = (PVMDKIMAGE)pBackendData;
    79447341    AssertPtr(pThis); RT_NOREF(pThis);
    7945 
    79467342    /* Nothing to do here. */
    79477343}
    7948 
    79497344/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
    79507345static DECLCALLBACK(unsigned) vmdkGetImageFlags(void *pBackendData)
     
    79527347    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    79537348    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    7954 
    79557349    AssertPtrReturn(pImage, 0);
    7956 
    79577350    LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
    79587351    return pImage->uImageFlags;
    79597352}
    7960 
    79617353/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
    79627354static DECLCALLBACK(unsigned) vmdkGetOpenFlags(void *pBackendData)
     
    79647356    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    79657357    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    7966 
    79677358    AssertPtrReturn(pImage, 0);
    7968 
    79697359    LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
    79707360    return pImage->uOpenFlags;
    79717361}
    7972 
    79737362/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
    79747363static DECLCALLBACK(int) vmdkSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
     
    79777366    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    79787367    int rc;
    7979 
    79807368    /* Image must be opened and the new flags must be valid. */
    79817369    if (!pImage || (uOpenFlags & ~(  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
     
    80007388        }
    80017389    }
    8002 
    80037390    LogFlowFunc(("returns %Rrc\n", rc));
    80047391    return rc;
    80057392}
    8006 
    80077393/** @copydoc VDIMAGEBACKEND::pfnGetComment */
    80087394static DECLCALLBACK(int) vmdkGetComment(void *pBackendData, char *pszComment, size_t cbComment)
     
    80107396    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
    80117397    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    8012 
    80137398    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8014 
    80157399    char *pszCommentEncoded = NULL;
    80167400    int rc = vmdkDescDDBGetStr(pImage, &pImage->Descriptor,
     
    80217405        rc = VINF_SUCCESS;
    80227406    }
    8023 
    80247407    if (RT_SUCCESS(rc))
    80257408    {
     
    80287411        else if (pszComment)
    80297412                *pszComment = '\0';
    8030 
    80317413        if (pszCommentEncoded)
    80327414            RTMemTmpFree(pszCommentEncoded);
    80337415    }
    8034 
    80357416    LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
    80367417    return rc;
    80377418}
    8038 
    80397419/** @copydoc VDIMAGEBACKEND::pfnSetComment */
    80407420static DECLCALLBACK(int) vmdkSetComment(void *pBackendData, const char *pszComment)
     
    80437423    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    80447424    int rc;
    8045 
    80467425    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8047 
    80487426    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    80497427    {
     
    80557433    else
    80567434        rc = VERR_VD_IMAGE_READ_ONLY;
    8057 
    80587435    LogFlowFunc(("returns %Rrc\n", rc));
    80597436    return rc;
    80607437}
    8061 
    80627438/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
    80637439static DECLCALLBACK(int) vmdkGetUuid(void *pBackendData, PRTUUID pUuid)
     
    80657441    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    80667442    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    8067 
    80687443    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8069 
    80707444    *pUuid = pImage->ImageUuid;
    8071 
    80727445    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    80737446    return VINF_SUCCESS;
    80747447}
    8075 
    80767448/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
    80777449static DECLCALLBACK(int) vmdkSetUuid(void *pBackendData, PCRTUUID pUuid)
     
    80807452    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    80817453    int rc = VINF_SUCCESS;
    8082 
    80837454    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8084 
    80857455    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    80867456    {
     
    80997469    else
    81007470        rc = VERR_VD_IMAGE_READ_ONLY;
    8101 
    81027471    LogFlowFunc(("returns %Rrc\n", rc));
    81037472    return rc;
    81047473}
    8105 
    81067474/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
    81077475static DECLCALLBACK(int) vmdkGetModificationUuid(void *pBackendData, PRTUUID pUuid)
     
    81097477    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    81107478    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    8111 
    81127479    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8113 
    81147480    *pUuid = pImage->ModificationUuid;
    8115 
    81167481    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    81177482    return VINF_SUCCESS;
    81187483}
    8119 
    81207484/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
    81217485static DECLCALLBACK(int) vmdkSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
     
    81247488    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    81257489    int rc = VINF_SUCCESS;
    8126 
    81277490    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8128 
    81297491    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    81307492    {
     
    81467508    else
    81477509        rc = VERR_VD_IMAGE_READ_ONLY;
    8148 
    81497510    LogFlowFunc(("returns %Rrc\n", rc));
    81507511    return rc;
    81517512}
    8152 
    81537513/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
    81547514static DECLCALLBACK(int) vmdkGetParentUuid(void *pBackendData, PRTUUID pUuid)
     
    81567516    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    81577517    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    8158 
    81597518    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8160 
    81617519    *pUuid = pImage->ParentUuid;
    8162 
    81637520    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    81647521    return VINF_SUCCESS;
    81657522}
    8166 
    81677523/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
    81687524static DECLCALLBACK(int) vmdkSetParentUuid(void *pBackendData, PCRTUUID pUuid)
     
    81717527    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    81727528    int rc = VINF_SUCCESS;
    8173 
    81747529    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8175 
    81767530    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    81777531    {
     
    81907544    else
    81917545        rc = VERR_VD_IMAGE_READ_ONLY;
    8192 
    81937546    LogFlowFunc(("returns %Rrc\n", rc));
    81947547    return rc;
    81957548}
    8196 
    81977549/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
    81987550static DECLCALLBACK(int) vmdkGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
     
    82007552    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    82017553    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    8202 
    82037554    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8204 
    82057555    *pUuid = pImage->ParentModificationUuid;
    8206 
    82077556    LogFlowFunc(("returns %Rrc (%RTuuid)\n", VINF_SUCCESS, pUuid));
    82087557    return VINF_SUCCESS;
    82097558}
    8210 
    82117559/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
    82127560static DECLCALLBACK(int) vmdkSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
     
    82157563    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    82167564    int rc = VINF_SUCCESS;
    8217 
    82187565    AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
    8219 
    82207566    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    82217567    {
     
    82337579    else
    82347580        rc = VERR_VD_IMAGE_READ_ONLY;
    8235 
    82367581    LogFlowFunc(("returns %Rrc\n", rc));
    82377582    return rc;
    82387583}
    8239 
    82407584/** @copydoc VDIMAGEBACKEND::pfnDump */
    82417585static DECLCALLBACK(void) vmdkDump(void *pBackendData)
    82427586{
    82437587    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    8244 
    82457588    AssertPtrReturnVoid(pImage);
    82467589    vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
     
    82547597}
    82557598
    8256 static int vmdkRepaceExtentSize(PVMDKIMAGE pImage, unsigned line, uint64_t cSectorsOld,
    8257                                 uint64_t cSectorsNew)
    8258 {
    8259     char * szOldExtentSectors = (char *)RTMemAlloc(UINT64_MAX_BUFF_SIZE);
    8260     if (!szOldExtentSectors)
    8261         return VERR_NO_MEMORY;
    8262 
    8263     int cbWritten = RTStrPrintf2(szOldExtentSectors, UINT64_MAX_BUFF_SIZE, "%llu", cSectorsOld);
    8264     if (cbWritten <= 0 || cbWritten > UINT64_MAX_BUFF_SIZE)
    8265     {
    8266         RTMemFree(szOldExtentSectors);
    8267         szOldExtentSectors = NULL;
    8268 
     7599/**
     7600 * Returns the size, in bytes, of the sparse extent overhead for
     7601 * the number of desired total sectors and based on the current
     7602 * sectors of the extent.
     7603 *
     7604 * @returns uint64_t size of new overhead in bytes.
     7605 * @param   pExtent         VMDK extent instance.
     7606 * @param   cSectorsNew     Number of desired total sectors.
     7607 */
     7608static uint64_t vmdkGetNewOverhead(PVMDKEXTENT pExtent, uint64_t cSectorsNew)
     7609{
     7610    uint64_t cNewDirEntries = cSectorsNew / pExtent->cSectorsPerGDE;
     7611    if (cSectorsNew % pExtent->cSectorsPerGDE)
     7612        cNewDirEntries++;
     7613
     7614    size_t cbNewGD = cNewDirEntries * sizeof(uint32_t);
     7615    uint64_t cbNewDirSize = RT_ALIGN_64(cbNewGD, 512);
     7616    uint64_t cbNewAllTablesSize = RT_ALIGN_64(cNewDirEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
     7617    uint64_t cbNewOverhead = RT_ALIGN_Z(RT_MAX(pExtent->uDescriptorSector
     7618                                                + pExtent->cDescriptorSectors, 1)
     7619                                                + cbNewDirSize + cbNewAllTablesSize, 512);
     7620    cbNewOverhead += cbNewDirSize + cbNewAllTablesSize;
     7621    cbNewOverhead = RT_ALIGN_64(cbNewOverhead,
     7622                                VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     7623
     7624    return cbNewOverhead;
     7625}
     7626
     7627/**
     7628 * Internal: Replaces the size (in sectors) of an extent in the descriptor file.
     7629 *
     7630 * @returns VBox status code.
     7631 * @param   pImage              VMDK image instance.
     7632 * @param   uLine                Line number of descriptor to change.
     7633 * @param   cSectorsOld         Existing number of sectors.
     7634 * @param   cSectorsNew         New number of sectors.
     7635 */
     7636static int vmdkReplaceExtentSize(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, unsigned uLine, uint64_t cSectorsOld,
     7637                                 uint64_t cSectorsNew)
     7638{
     7639    char szOldExtentSectors[UINT64_MAX_BUFF_SIZE];
     7640    char szNewExtentSectors[UINT64_MAX_BUFF_SIZE];
     7641
     7642    ssize_t cbWritten = RTStrPrintf2(szOldExtentSectors, sizeof(szOldExtentSectors), "%llu", cSectorsOld);
     7643    if (cbWritten <= 0 || cbWritten > (ssize_t)sizeof(szOldExtentSectors))
    82697644        return VERR_BUFFER_OVERFLOW;
    8270     }
    8271 
    8272     char * szNewExtentSectors = (char *)RTMemAlloc(UINT64_MAX_BUFF_SIZE);
    8273     if (!szNewExtentSectors)
    8274         return VERR_NO_MEMORY;
    8275 
    8276     cbWritten = RTStrPrintf2(szNewExtentSectors, UINT64_MAX_BUFF_SIZE, "%llu", cSectorsNew);
    8277     if (cbWritten <= 0 || cbWritten > UINT64_MAX_BUFF_SIZE)
    8278     {
    8279         RTMemFree(szOldExtentSectors);
    8280         szOldExtentSectors = NULL;
    8281 
    8282         RTMemFree(szNewExtentSectors);
    8283         szNewExtentSectors = NULL;
    8284 
     7645
     7646    cbWritten = RTStrPrintf2(szNewExtentSectors, sizeof(szNewExtentSectors), "%llu", cSectorsNew);
     7647    if (cbWritten <= 0 || cbWritten > (ssize_t)sizeof(szNewExtentSectors))
    82857648        return VERR_BUFFER_OVERFLOW;
    8286     }
    8287 
    8288     char * szNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[line],
     7649
     7650    char *pszNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[uLine],
    82897651                                            szOldExtentSectors,
    82907652                                            szNewExtentSectors);
    82917653
    8292     RTMemFree(szOldExtentSectors);
    8293     szOldExtentSectors = NULL;
    8294 
    8295     RTMemFree(szNewExtentSectors);
    8296     szNewExtentSectors = NULL;
    8297 
    8298     if (!szNewExtentLine)
     7654    if (RT_UNLIKELY(!pszNewExtentLine))
    82997655        return VERR_INVALID_PARAMETER;
    83007656
    8301     pImage->Descriptor.aLines[line] = szNewExtentLine;
     7657    vmdkDescExtRemoveByLine(pImage, &pImage->Descriptor, uLine);
     7658    vmdkDescExtInsert(pImage, &pImage->Descriptor,
     7659                      pExtent->enmAccess, cSectorsNew,
     7660                      pExtent->enmType, pExtent->pszBasename, pExtent->uSectorOffset);
     7661
     7662    RTStrFree(pszNewExtentLine);
     7663    pszNewExtentLine = NULL;
     7664
     7665    pImage->Descriptor.fDirty = true;
    83027666
    83037667    return VINF_SUCCESS;
     7668}
     7669
     7670/**
     7671 * Moves sectors down to make room for new overhead.
     7672 * Used for sparse extent resize.
     7673 *
     7674 * @returns VBox status code.
     7675 * @param   pImage          VMDK image instance.
     7676 * @param   pExtent         VMDK extent instance.
     7677 * @param   cSectorsNew     Number of sectors after resize.
     7678 */
     7679static int vmdkRelocateSectorsForSparseResize(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     7680                                              uint64_t cSectorsNew)
     7681{
     7682    int rc = VINF_SUCCESS;
     7683
     7684    uint64_t cbNewOverhead = vmdkGetNewOverhead(pExtent, cSectorsNew);
     7685
     7686    uint64_t cNewOverheadSectors = VMDK_BYTE2SECTOR(cbNewOverhead);
     7687    uint64_t cOverheadSectorDiff = cNewOverheadSectors - pExtent->cOverheadSectors;
     7688
     7689    uint64_t cbFile = 0;
     7690    rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbFile);
     7691
     7692    uint64_t uNewAppendPosition;
     7693
     7694    /* Calculate how many sectors need to be relocated. */
     7695    unsigned cSectorsReloc = cOverheadSectorDiff;
     7696    if (cbNewOverhead % VMDK_SECTOR_SIZE)
     7697        cSectorsReloc++;
     7698
     7699    if (cSectorsReloc < pExtent->cSectors)
     7700        uNewAppendPosition = RT_ALIGN_Z(cbFile + VMDK_SECTOR2BYTE(cOverheadSectorDiff), 512);
     7701    else
     7702        uNewAppendPosition = cbFile;
     7703
     7704    /*
     7705    * Get the blocks we need to relocate first, they are appended to the end
     7706    * of the image.
     7707    */
     7708    void *pvBuf = NULL, *pvZero = NULL;
     7709    do
     7710    {
     7711        /* Allocate data buffer. */
     7712        pvBuf = RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     7713        if (!pvBuf)
     7714        {
     7715            rc = VERR_NO_MEMORY;
     7716            break;
     7717        }
     7718
     7719        /* Allocate buffer for overwriting with zeroes. */
     7720        pvZero = RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     7721        if (!pvZero)
     7722        {
     7723            RTMemFree(pvBuf);
     7724            pvBuf = NULL;
     7725
     7726            rc = VERR_NO_MEMORY;
     7727            break;
     7728        }
     7729
     7730        uint32_t *aGTDataTmp = (uint32_t *)RTMemAllocZ(sizeof(uint32_t) * pExtent->cGTEntries);
     7731        if(!aGTDataTmp)
     7732        {
     7733            RTMemFree(pvBuf);
     7734            pvBuf = NULL;
     7735
     7736            RTMemFree(pvZero);
     7737            pvZero = NULL;
     7738
     7739            rc = VERR_NO_MEMORY;
     7740            break;
     7741        }
     7742
     7743        uint32_t *aRGTDataTmp = (uint32_t *)RTMemAllocZ(sizeof(uint32_t) * pExtent->cGTEntries);
     7744        if(!aRGTDataTmp)
     7745        {
     7746            RTMemFree(pvBuf);
     7747            pvBuf = NULL;
     7748
     7749            RTMemFree(pvZero);
     7750            pvZero = NULL;
     7751
     7752            RTMemFree(aGTDataTmp);
     7753            aGTDataTmp = NULL;
     7754
     7755            rc = VERR_NO_MEMORY;
     7756            break;
     7757        }
     7758
     7759        /* Search for overlap sector in the grain table. */
     7760        for (uint32_t idxGD = 0; idxGD < pExtent->cGDEntries; idxGD++)
     7761        {
     7762            uint64_t uGTSector = pExtent->pGD[idxGD];
     7763            uint64_t uRGTSector = pExtent->pRGD[idxGD];
     7764
     7765            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7766                                        VMDK_SECTOR2BYTE(uGTSector),
     7767                                        aGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries);
     7768
     7769            if (RT_FAILURE(rc))
     7770                break;
     7771
     7772            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7773                                        VMDK_SECTOR2BYTE(uRGTSector),
     7774                                        aRGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries);
     7775
     7776            if (RT_FAILURE(rc))
     7777                break;
     7778
     7779            for (uint32_t idxGT = 0; idxGT < pExtent->cGTEntries; idxGT++)
     7780            {
     7781                uint64_t aGTEntryLE = RT_LE2H_U64(aGTDataTmp[idxGT]);
     7782                uint64_t aRGTEntryLE = RT_LE2H_U64(aRGTDataTmp[idxGT]);
     7783
     7784                /**
     7785                 * Check if grain table is valid. If not dump out with an error.
     7786                 * Shoudln't ever get here (given other checks) but good sanity check.
     7787                */
     7788                if (aGTEntryLE != aRGTEntryLE)
     7789                {
     7790                    rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
     7791                                    N_("VMDK: inconsistent references within grain table in '%s'"), pExtent->pszFullname);
     7792                    break;
     7793                }
     7794
     7795                if (aGTEntryLE < cNewOverheadSectors
     7796                    && aGTEntryLE != 0)
     7797                {
     7798                    /* Read data and append grain to the end of the image. */
     7799                    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7800                                                VMDK_SECTOR2BYTE(aGTEntryLE), pvBuf,
     7801                                                VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     7802                    if (RT_FAILURE(rc))
     7803                        break;
     7804
     7805                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7806                                                uNewAppendPosition, pvBuf,
     7807                                                VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     7808                    if (RT_FAILURE(rc))
     7809                        break;
     7810
     7811                    /* Zero out the old block area. */
     7812                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7813                                                VMDK_SECTOR2BYTE(aGTEntryLE), pvZero,
     7814                                                VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     7815                    if (RT_FAILURE(rc))
     7816                        break;
     7817
     7818                    /* Write updated grain tables to file */
     7819                    aGTDataTmp[idxGT] = VMDK_BYTE2SECTOR(uNewAppendPosition);
     7820                    aRGTDataTmp[idxGT] = VMDK_BYTE2SECTOR(uNewAppendPosition);
     7821
     7822                    if (memcmp(aGTDataTmp, aRGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries))
     7823                    {
     7824                        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
     7825                                    N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname);
     7826                        break;
     7827                    }
     7828
     7829                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7830                                                VMDK_SECTOR2BYTE(uGTSector),
     7831                                                aGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries);
     7832
     7833                    if (RT_FAILURE(rc))
     7834                        break;
     7835
     7836                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7837                                                VMDK_SECTOR2BYTE(uRGTSector),
     7838                                                aRGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries);
     7839
     7840                    break;
     7841                }
     7842            }
     7843        }
     7844
     7845        RTMemFree(aGTDataTmp);
     7846        aGTDataTmp = NULL;
     7847
     7848        RTMemFree(aRGTDataTmp);
     7849        aRGTDataTmp = NULL;
     7850
     7851        if (RT_FAILURE(rc))
     7852            break;
     7853
     7854        uNewAppendPosition += VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain);
     7855    } while (0);
     7856
     7857    if (pvBuf)
     7858    {
     7859        RTMemFree(pvBuf);
     7860        pvBuf = NULL;
     7861    }
     7862
     7863    if (pvZero)
     7864    {
     7865        RTMemFree(pvZero);
     7866        pvZero = NULL;
     7867    }
     7868
     7869    // Update append position for extent
     7870    pExtent->uAppendPosition = uNewAppendPosition;
     7871
     7872    return rc;
     7873}
     7874
     7875/**
     7876 * Resizes meta/overhead for sparse extent resize.
     7877 *
     7878 * @returns VBox status code.
     7879 * @param   pImage          VMDK image instance.
     7880 * @param   pExtent         VMDK extent instance.
     7881 * @param   cSectorsNew     Number of sectors after resize.
     7882 */
     7883static int vmdkResizeSparseMeta(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     7884                                uint64_t cSectorsNew)
     7885{
     7886    int rc = VINF_SUCCESS;
     7887    uint32_t cOldGDEntries = pExtent->cGDEntries;
     7888
     7889    uint64_t cNewDirEntries = cSectorsNew / pExtent->cSectorsPerGDE;
     7890    if (cSectorsNew % pExtent->cSectorsPerGDE)
     7891        cNewDirEntries++;
     7892
     7893    size_t cbNewGD = cNewDirEntries * sizeof(uint32_t);
     7894
     7895    uint64_t cbNewDirSize = RT_ALIGN_64(cbNewGD, 512);
     7896    uint64_t cbCurrDirSize = RT_ALIGN_64(pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE, 512);
     7897    uint64_t cDirSectorDiff = VMDK_BYTE2SECTOR(cbNewDirSize - cbCurrDirSize);
     7898
     7899    uint64_t cbNewAllTablesSize = RT_ALIGN_64(cNewDirEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
     7900    uint64_t cbCurrAllTablesSize = RT_ALIGN_64(pExtent->cGDEntries * VMDK_GRAIN_TABLE_SIZE, 512);
     7901    uint64_t cTableSectorDiff = VMDK_BYTE2SECTOR(cbNewAllTablesSize - cbCurrAllTablesSize);
     7902
     7903    uint64_t cbNewOverhead = vmdkGetNewOverhead(pExtent, cSectorsNew);
     7904    uint64_t cNewOverheadSectors = VMDK_BYTE2SECTOR(cbNewOverhead);
     7905    uint64_t cOverheadSectorDiff = cNewOverheadSectors - pExtent->cOverheadSectors;
     7906
     7907    /*
     7908    * Get the blocks we need to relocate first, they are appended to the end
     7909    * of the image.
     7910    */
     7911    void *pvBuf = NULL, *pvZero = NULL;
     7912
     7913    do
     7914    {
     7915        /* Allocate data buffer. */
     7916        pvBuf = RTMemAllocZ(VMDK_GRAIN_TABLE_SIZE);
     7917        if (!pvBuf)
     7918        {
     7919            rc = VERR_NO_MEMORY;
     7920            break;
     7921        }
     7922
     7923        /* Allocate buffer for overwriting with zeroes. */
     7924        pvZero = RTMemAllocZ(VMDK_GRAIN_TABLE_SIZE);
     7925        if (!pvZero)
     7926        {
     7927            RTMemFree(pvBuf);
     7928            pvBuf = NULL;
     7929
     7930            rc = VERR_NO_MEMORY;
     7931            break;
     7932        }
     7933
     7934        uint32_t uGTStart = VMDK_SECTOR2BYTE(pExtent->uSectorGD) + (cOldGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     7935
     7936        // points to last element in the grain table
     7937        uint32_t uGTTail = uGTStart + (pExtent->cGDEntries * VMDK_GRAIN_TABLE_SIZE) - VMDK_GRAIN_TABLE_SIZE;
     7938        uint32_t cbGTOff = RT_ALIGN_Z(VMDK_SECTOR2BYTE(cDirSectorDiff + cTableSectorDiff + cDirSectorDiff), 512);
     7939
     7940        for (int i = pExtent->cGDEntries - 1; i >= 0; i--)
     7941        {
     7942            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7943                                        uGTTail, pvBuf,
     7944                                        VMDK_GRAIN_TABLE_SIZE);
     7945            if (RT_FAILURE(rc))
     7946                break;
     7947
     7948            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7949                                        RT_ALIGN_Z(uGTTail + cbGTOff, 512), pvBuf,
     7950                                        VMDK_GRAIN_TABLE_SIZE);
     7951            if (RT_FAILURE(rc))
     7952                break;
     7953
     7954            // This overshoots when i == 0, but we don't need it anymore.
     7955            uGTTail -= VMDK_GRAIN_TABLE_SIZE;
     7956        }
     7957
     7958
     7959        /* Find the end of the grain directory and start bumping everything down. Update locations of GT entries. */
     7960        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7961                                    VMDK_SECTOR2BYTE(pExtent->uSectorGD), pvBuf,
     7962                                    pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     7963        if (RT_FAILURE(rc))
     7964            break;
     7965
     7966        int * tmpBuf = (int *)pvBuf;
     7967
     7968        for (uint32_t i = 0; i < pExtent->cGDEntries; i++)
     7969        {
     7970            tmpBuf[i] = tmpBuf[i] + VMDK_BYTE2SECTOR(cbGTOff);
     7971            pExtent->pGD[i] = pExtent->pGD[i] + VMDK_BYTE2SECTOR(cbGTOff);
     7972        }
     7973
     7974        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7975                                    RT_ALIGN_Z(VMDK_SECTOR2BYTE(pExtent->uSectorGD + cTableSectorDiff + cDirSectorDiff), 512), pvBuf,
     7976                                    pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     7977        if (RT_FAILURE(rc))
     7978            break;
     7979
     7980        pExtent->uSectorGD = pExtent->uSectorGD + cDirSectorDiff + cTableSectorDiff;
     7981
     7982        /* Repeat both steps with the redundant grain table/directory. */
     7983
     7984        uint32_t uRGTStart = VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + (cOldGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     7985
     7986        // points to last element in the grain table
     7987        uint32_t uRGTTail = uRGTStart + (pExtent->cGDEntries * VMDK_GRAIN_TABLE_SIZE) - VMDK_GRAIN_TABLE_SIZE;
     7988        uint32_t cbRGTOff = RT_ALIGN_Z(VMDK_SECTOR2BYTE(cDirSectorDiff), 512);
     7989
     7990        for (int i = pExtent->cGDEntries - 1; i >= 0; i--)
     7991        {
     7992            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7993                                        uRGTTail, pvBuf,
     7994                                        VMDK_GRAIN_TABLE_SIZE);
     7995            if (RT_FAILURE(rc))
     7996                break;
     7997
     7998            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     7999                                        RT_ALIGN_Z(uRGTTail + cbRGTOff, 512), pvBuf,
     8000                                        VMDK_GRAIN_TABLE_SIZE);
     8001            if (RT_FAILURE(rc))
     8002                break;
     8003
     8004            // This overshoots when i == 0, but we don't need it anymore.
     8005            uRGTTail -= VMDK_GRAIN_TABLE_SIZE;
     8006        }
     8007
     8008        /* Update locations of GT entries. */
     8009        rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     8010                                    VMDK_SECTOR2BYTE(pExtent->uSectorRGD), pvBuf,
     8011                                    pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     8012        if (RT_FAILURE(rc))
     8013            break;
     8014
     8015        tmpBuf = (int *)pvBuf;
     8016
     8017        for (uint32_t i = 0; i < pExtent->cGDEntries; i++)
     8018        {
     8019            tmpBuf[i] = tmpBuf[i] + cDirSectorDiff;
     8020            pExtent->pRGD[i] = pExtent->pRGD[i] + cDirSectorDiff;
     8021        }
     8022
     8023        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     8024                                    VMDK_SECTOR2BYTE(pExtent->uSectorRGD), pvBuf,
     8025                                    pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     8026        if (RT_FAILURE(rc))
     8027            break;
     8028
     8029        pExtent->uSectorRGD = pExtent->uSectorRGD;
     8030        pExtent->cOverheadSectors += cOverheadSectorDiff;
     8031
     8032    } while (0);
     8033
     8034    if (pvBuf)
     8035    {
     8036        RTMemFree(pvBuf);
     8037        pvBuf = NULL;
     8038    }
     8039
     8040    if (pvZero)
     8041    {
     8042        RTMemFree(pvZero);
     8043        pvZero = NULL;
     8044    }
     8045
     8046    pExtent->cGDEntries = cNewDirEntries;
     8047
     8048    /* Allocate buffer for overwriting with zeroes. */
     8049    pvZero = RTMemAllocZ(VMDK_GRAIN_TABLE_SIZE);
     8050    if (!pvZero)
     8051        return VERR_NO_MEMORY;
     8052
     8053    // Allocate additional grain dir
     8054    pExtent->pGD = (uint32_t *) RTMemReallocZ(pExtent->pGD, pExtent->cGDEntries * sizeof(uint32_t), cbNewGD);
     8055    if (RT_LIKELY(pExtent->pGD))
     8056    {
     8057        if (pExtent->uSectorRGD)
     8058        {
     8059            pExtent->pRGD = (uint32_t *)RTMemReallocZ(pExtent->pRGD, pExtent->cGDEntries * sizeof(uint32_t), cbNewGD);
     8060            if (RT_UNLIKELY(!pExtent->pRGD))
     8061                rc = VERR_NO_MEMORY;
     8062        }
     8063    }
     8064    else
     8065        return VERR_NO_MEMORY;
     8066
     8067
     8068    uint32_t uTmpDirVal = pExtent->pGD[cOldGDEntries - 1] + VMDK_GRAIN_DIR_ENTRY_SIZE;
     8069    for (uint32_t i = cOldGDEntries; i < pExtent->cGDEntries; i++)
     8070    {
     8071        pExtent->pGD[i] = uTmpDirVal;
     8072
     8073        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     8074                                    VMDK_SECTOR2BYTE(uTmpDirVal), pvZero,
     8075                                    VMDK_GRAIN_TABLE_SIZE);
     8076
     8077        if (RT_FAILURE(rc))
     8078            return rc;
     8079
     8080        uTmpDirVal += VMDK_GRAIN_DIR_ENTRY_SIZE;
     8081    }
     8082
     8083    uint32_t uRTmpDirVal = pExtent->pRGD[cOldGDEntries - 1] + VMDK_GRAIN_DIR_ENTRY_SIZE;
     8084    for (uint32_t i = cOldGDEntries; i < pExtent->cGDEntries; i++)
     8085    {
     8086        pExtent->pRGD[i] = uRTmpDirVal;
     8087
     8088        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     8089                                    VMDK_SECTOR2BYTE(uRTmpDirVal), pvZero,
     8090                                    VMDK_GRAIN_TABLE_SIZE);
     8091
     8092        if (RT_FAILURE(rc))
     8093            return rc;
     8094
     8095        uRTmpDirVal += VMDK_GRAIN_DIR_ENTRY_SIZE;
     8096    }
     8097
     8098    RTMemFree(pvZero);
     8099    pvZero = NULL;
     8100
     8101    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     8102                                VMDK_SECTOR2BYTE(pExtent->uSectorGD), pExtent->pGD,
     8103                                pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     8104    if (RT_FAILURE(rc))
     8105        return rc;
     8106
     8107    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
     8108                                VMDK_SECTOR2BYTE(pExtent->uSectorRGD), pExtent->pRGD,
     8109                                pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE);
     8110    if (RT_FAILURE(rc))
     8111        return rc;
     8112
     8113    rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent + pExtent->uExtent,
     8114                                pExtent->cNominalSectors, cSectorsNew);
     8115    if (RT_FAILURE(rc))
     8116        return rc;
     8117
     8118    return rc;
    83048119}
    83058120
     
    83188133    unsigned uImageFlags = pImage->uImageFlags;
    83198134    PVMDKEXTENT pExtent = &pImage->pExtents[0];
     8135    pExtent->fMetaDirty = true;
    83208136
    83218137    uint64_t cSectorsNew = cbSize / VMDK_SECTOR_SIZE;   /** < New number of sectors in the image after the resize */
     
    83388154     */
    83398155    /** @todo implement making the image smaller, it is the responsibility of
    8340      * the user to know what he's doing. */
     8156     * the user to know what they're doing. */
    83418157    if (cbSize < pImage->cbSize)
    83428158        rc = VERR_VD_SHRINK_NOT_SUPPORTED;
     
    83588174                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    83598175
    8360             rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew);
     8176            rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew);
    83618177            if (RT_FAILURE(rc))
    83628178                return rc;
     
    83758191
    83768192            uint64_t cSectorsNeeded = cSectorsNew - cSectorsOld;
     8193
     8194            /** Space remaining in current last extent file that we don't need to create another one. */
    83778195            if (fSpaceAvailible && cSectorsNeeded + cLastExtentRemSectors <= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE))
    83788196            {
     
    83848202                    return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    83858203
    8386                 rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent + cExtents - 1,
    8387                                           pExtent->cNominalSectors, cSectorsNeeded + cLastExtentRemSectors);
     8204                rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent + cExtents - 1,
     8205                                           pExtent->cNominalSectors, cSectorsNeeded + cLastExtentRemSectors);
    83888206                if (RT_FAILURE(rc))
    83898207                    return rc;
    83908208            }
     8209            //** Need more extent files to handle all the requested space. */
    83918210            else
    83928211            {
     
    84028221                    cSectorsNeeded = cSectorsNeeded - VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE) + cLastExtentRemSectors;
    84038222
    8404                     rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent + cExtents - 1,
    8405                                               pExtent->cNominalSectors, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE));
     8223                    rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent + cExtents - 1,
     8224                                               pExtent->cNominalSectors, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE));
    84068225                    if (RT_FAILURE(rc))
    84078226                        return rc;
     
    84358254        }
    84368255
     8256        /**
     8257         * monolithicSparse.
     8258         */
     8259        if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE && !(uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G))
     8260        {
     8261            // 1. Calculate sectors needed for new overhead.
     8262
     8263            uint64_t cbNewOverhead = vmdkGetNewOverhead(pExtent, cSectorsNew);
     8264            uint64_t cNewOverheadSectors = VMDK_BYTE2SECTOR(cbNewOverhead);
     8265            uint64_t cOverheadSectorDiff = cNewOverheadSectors - pExtent->cOverheadSectors;
     8266
     8267            // 2. Relocate sectors to make room for new GD/GT, update entries in GD/GT
     8268            if (cOverheadSectorDiff > 0)
     8269            {
     8270                if (pExtent->cSectors > 0)
     8271                {
     8272                    /* Do the relocation. */
     8273                    LogFlow(("Relocating VMDK sectors\n"));
     8274                    rc = vmdkRelocateSectorsForSparseResize(pImage, pExtent, cSectorsNew);
     8275                    if (RT_FAILURE(rc))
     8276                        return rc;
     8277
     8278                    rc = vmdkFlushImage(pImage, NULL);
     8279                    if (RT_FAILURE(rc))
     8280                        return rc;
     8281                }
     8282
     8283                rc = vmdkResizeSparseMeta(pImage, pExtent, cSectorsNew);
     8284                if (RT_FAILURE(rc))
     8285                    return rc;
     8286            }
     8287        }
     8288
     8289        /**
     8290         * twoGbSparseExtent
     8291         */
     8292        if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE && (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G))
     8293        {
     8294            /* Check to see how much space remains in last extent */
     8295            bool fSpaceAvailible = false;
     8296            uint64_t cLastExtentRemSectors = cSectorsOld % VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE);
     8297            if (cLastExtentRemSectors)
     8298                fSpaceAvailible = true;
     8299
     8300            uint64_t cSectorsNeeded = cSectorsNew - cSectorsOld;
     8301
     8302            if (fSpaceAvailible && cSectorsNeeded + cLastExtentRemSectors <= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE))
     8303            {
     8304                pExtent = &pImage->pExtents[cExtents - 1];
     8305                rc = vmdkRelocateSectorsForSparseResize(pImage, pExtent, cSectorsNeeded + cLastExtentRemSectors);
     8306                if (RT_FAILURE(rc))
     8307                    return rc;
     8308
     8309                rc = vmdkFlushImage(pImage, NULL);
     8310                if (RT_FAILURE(rc))
     8311                    return rc;
     8312
     8313                rc = vmdkResizeSparseMeta(pImage, pExtent, cSectorsNeeded + cLastExtentRemSectors);
     8314                if (RT_FAILURE(rc))
     8315                    return rc;
     8316            }
     8317            else
     8318            {
     8319                if (fSpaceAvailible)
     8320                {
     8321                    pExtent = &pImage->pExtents[cExtents - 1];
     8322                    rc = vmdkRelocateSectorsForSparseResize(pImage, pExtent, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE));
     8323                    if (RT_FAILURE(rc))
     8324                        return rc;
     8325
     8326                    rc = vmdkFlushImage(pImage, NULL);
     8327                    if (RT_FAILURE(rc))
     8328                        return rc;
     8329
     8330                    rc = vmdkResizeSparseMeta(pImage, pExtent, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE));
     8331                    if (RT_FAILURE(rc))
     8332                        return rc;
     8333
     8334                    cSectorsNeeded = cSectorsNeeded - VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE) + cLastExtentRemSectors;
     8335                }
     8336
     8337                unsigned cNewExtents = VMDK_SECTOR2BYTE(cSectorsNeeded) / VMDK_2G_SPLIT_SIZE;
     8338                if (cNewExtents % VMDK_2G_SPLIT_SIZE || cNewExtents < VMDK_2G_SPLIT_SIZE)
     8339                    cNewExtents++;
     8340
     8341                for (unsigned i = cExtents;
     8342                     i < cExtents + cNewExtents && cSectorsNeeded >= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE);
     8343                     i++)
     8344                {
     8345                    rc = vmdkAddFileBackedExtent(pImage, VMDK_2G_SPLIT_SIZE);
     8346                    if (RT_FAILURE(rc))
     8347                        return rc;
     8348
     8349                    pExtent = &pImage->pExtents[i];
     8350
     8351                    rc = vmdkFlushImage(pImage, NULL);
     8352                    if (RT_FAILURE(rc))
     8353                        return rc;
     8354
     8355                    pExtent->cSectors = VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE);
     8356                    cSectorsNeeded -= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE);
     8357                }
     8358
     8359                if (cSectorsNeeded)
     8360                {
     8361                    rc = vmdkAddFileBackedExtent(pImage, VMDK_SECTOR2BYTE(cSectorsNeeded));
     8362                    if (RT_FAILURE(rc))
     8363                        return rc;
     8364
     8365                    pExtent = &pImage->pExtents[pImage->cExtents];
     8366
     8367                    rc = vmdkFlushImage(pImage, NULL);
     8368                    if (RT_FAILURE(rc))
     8369                        return rc;
     8370                }
     8371            }
     8372        }
     8373
    84378374        /* Successful resize. Update metadata */
    84388375        if (RT_SUCCESS(rc))
     
    84408377            /* Update size and new block count. */
    84418378            pImage->cbSize = cbSize;
    8442             /** @todo r=jack: update cExtents if needed */
    8443             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     8379            pExtent->cNominalSectors = cSectorsNew;
     8380            pExtent->cSectors = cSectorsNew;
    84448381
    84458382            /* Update geometry. */
     
    84498386
    84508387        /* Update header information in base image file. */
     8388        pImage->Descriptor.fDirty = true;
    84518389        rc = vmdkWriteDescriptor(pImage, NULL);
    84528390
    8453         if (RT_FAILURE(rc))
    8454             return rc;
    8455 
    8456         rc = vmdkFlushImage(pImage, NULL);
    8457 
    8458         if (RT_FAILURE(rc))
    8459             return rc;
     8391        if (RT_SUCCESS(rc))
     8392            rc = vmdkFlushImage(pImage, NULL);
    84608393    }
    84618394    /* Same size doesn't change the image at all. */
     
    84648397    return rc;
    84658398}
    8466 
    84678399
    84688400const VDIMAGEBACKEND g_VmdkBackend =
  • trunk/src/VBox/Storage/testcase/tstVDIo.cpp

    r96407 r97836  
    567567    bool fBase = false;
    568568    bool fDynamic = true;
     569    bool fSplit = false;
    569570
    570571    const char *pcszDisk = paScriptArgs[0].psz;
     
    583584    else if (!RTStrICmp(paScriptArgs[3].psz, "dynamic"))
    584585        fDynamic = true;
     586    else if (!RTStrICmp(paScriptArgs[3].psz, "vmdk-dynamic-split"))
     587        fSplit = true;
     588    else if (!RTStrICmp(paScriptArgs[3].psz, "vmdk-fixed-split"))
     589    {
     590        fDynamic = false;
     591        fSplit = true;
     592    }
    585593    else
    586594    {
     
    609617            if (fHonorSame)
    610618                fOpenFlags |= VD_OPEN_FLAGS_HONOR_SAME;
     619
     620            if (fSplit)
     621                fImageFlags |= VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
    611622
    612623            if (fBase)
     
    30123023    return RTEXITCODE_SUCCESS;
    30133024}
    3014 
  • trunk/src/VBox/Storage/testcase/tstVDResize.vd

    r96832 r97836  
    4040    destroydisk("test");
    4141
    42     print("Testing VMDK Flat");
    43     createdisk("test-vmdk-flat", true);
    44     create("test-vmdk-flat", "base", "test-vmdk-flat.vmdk", "fixed", "VMDK", 10G, false, false);
    45     io("test-vmdk-flat", false, 1, "seq", 64K, 1G, 2G, 10G, 100, "none");
    46     resize("test-vmdk-flat", 20000M);
    47     close("test-vmdk-flat", "single", true /* fDelete */);
    48     destroydisk("test-vmdk-flat");
     42    print("Testing VMDK Monolithic Flat");
     43    createdisk("test-vmdk-mflat", true);
     44    create("test-vmdk-mflat", "base", "test-vmdk-mflat.vmdk", "Fixed", "VMDK", 4G, false, false);
     45    io("test-vmdk-mflat", false, 1, "seq", 64K, 1G, 2G, 1G, 100, "none");
     46    resize("test-vmdk-mflat", 6000M);
     47    io("test-vmdk-mflat", false, 1, "seq", 64K, 4G, 5G, 1G, 100, "none");
     48    close("test-vmdk-mflat", "single", true /* fDelete */);
     49    destroydisk("test-vmdk-mflat");
     50
     51    print("Testing VMDK Split Flat");
     52    createdisk("test-vmdk-sflat", true);
     53    create("test-vmdk-sflat", "base", "test-vmdk-sflat.vmdk", "vmdk-fixed-split", "VMDK", 4G, false, false);
     54    io("test-vmdk-sflat", false, 1, "seq", 64K, 1G, 2G, 1G, 100, "none");
     55    resize("test-vmdk-sflat", 6000M);
     56    io("test-vmdk-sflat", false, 1, "seq", 64K, 4G, 5G, 1G, 100, "none");
     57    close("test-vmdk-sflat", "single", true /* fDelete */);
     58    destroydisk("test-vmdk-sflat");
     59
     60    print("Testing VMDK Sparse");
     61    createdisk("test-vmdk-sparse", true);
     62    create("test-vmdk-sparse", "base", "test-vmdk-sparse.vmdk", "Dynamic", "VMDK", 4G, false, false);
     63    io("test-vmdk-sparse", false, 1, "seq", 64K, 1G, 2G, 1G, 100, "none");
     64    resize("test-vmdk-sparse", 6000M);
     65    io("test-vmdk-sparse", false, 1, "seq", 64K, 4G, 5G, 1G, 100, "none");
     66    close("test-vmdk-sparse", "single", true /* fDelete */);
     67    destroydisk("test-vmdk-sparse");
     68
     69    print("Testing VMDK Sparse Split");
     70    createdisk("test-vmdk-sparse-split", true);
     71    create("test-vmdk-sparse-split", "base", "test-vmdk-sparse-split.vmdk", "vmdk-dynamic-split", "VMDK", 4G, false, false);
     72    io("test-vmdk-sparse-split", false, 1, "seq", 64K, 1G, 2G, 1G, 100, "none");
     73    resize("test-vmdk-sparse-split", 6000M);
     74    io("test-vmdk-sparse-split", false, 1, "seq", 64K, 4G, 5G, 1G, 100, "none");
     75    close("test-vmdk-sparse-split", "single", true /* fDelete */);
     76    destroydisk("test-vmdk-sparse-split");
    4977
    5078    iorngdestroy();
    5179}
    52 
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