VirtualBox

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


Ignore:
Timestamp:
Mar 31, 2008 12:13:35 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
29164
Message:

Implement raw file backend for VBoxHDD-new.

File:
1 copied

Legend:

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

    r7245 r7654  
    11/** $Id$ */
    22/** @file
    3  * VMDK Disk image, Core Code.
     3 * Raw Disk image, Core Code.
    44 */
    55
     
    1919*   Header Files                                                               *
    2020*******************************************************************************/
    21 #define LOG_GROUP LOG_GROUP_VD_VMDK
     21#define LOG_GROUP LOG_GROUP_VD_RAW
    2222#include "VBoxHDD-newInternal.h"
    2323#include <VBox/err.h>
     
    2626#include <iprt/assert.h>
    2727#include <iprt/alloc.h>
    28 #include <iprt/uuid.h>
    2928#include <iprt/file.h>
    30 #include <iprt/path.h>
    31 #include <iprt/string.h>
    32 #include <iprt/rand.h>
    3329
    3430
     
    3733*******************************************************************************/
    3834
    39 /** VMDK descriptor DDB entry for PCHS cylinders. */
    40 #define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
    41 
    42 /** VMDK descriptor DDB entry for PCHS heads. */
    43 #define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
    44 
    45 /** VMDK descriptor DDB entry for PCHS sectors. */
    46 #define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
    47 
    48 /** VMDK descriptor DDB entry for LCHS cylinders. */
    49 #define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
    50 
    51 /** VMDK descriptor DDB entry for LCHS heads. */
    52 #define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
    53 
    54 /** VMDK descriptor DDB entry for LCHS sectors. */
    55 #define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
    56 
    57 /** VMDK descriptor DDB entry for image UUID. */
    58 #define VMDK_DDB_IMAGE_UUID "ddb.uuid.image"
    59 
    60 /** VMDK descriptor DDB entry for image modification UUID. */
    61 #define VMDK_DDB_MODIFICATION_UUID "ddb.uuid.modification"
    62 
    63 /** VMDK descriptor DDB entry for parent image UUID. */
    64 #define VMDK_DDB_PARENT_UUID "ddb.uuid.parent"
    65 
    66 /** VMDK descriptor DDB entry for parent image modification UUID. */
    67 #define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification"
    68 
    6935/**
    70  * Magic number for hosted images created by VMware Workstation 4, VMware
    71  * Workstation 5, VMware Server or VMware Player.
     36 * Raw image data structure.
    7237 */
    73 #define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
    74 
    75 /** VMDK hosted sparse extent header. */
    76 #pragma pack(1)
    77 typedef struct SparseExtentHeader
    78 {
    79     uint32_t    magicNumber;
    80     uint32_t    version;
    81     uint32_t    flags;
    82     uint64_t    capacity;
    83     uint64_t    grainSize;
    84     uint64_t    descriptorOffset;
    85     uint64_t    descriptorSize;
    86     uint32_t    numGTEsPerGT;
    87     uint64_t    rgdOffset;
    88     uint64_t    gdOffset;
    89     uint64_t    overHead;
    90     bool        uncleanShutdown;
    91     char        singleEndLineChar;
    92     char        nonEndLineChar;
    93     char        doubleEndLineChar1;
    94     char        doubleEndLineChar2;
    95     uint8_t     pad[435];
    96 } SparseExtentHeader;
    97 #pragma pack()
    98 
    99 /** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
    100  * divisible by the default grain size (64K) */
    101 #define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
    102 
    103 
    104 #ifdef VBOX_WITH_VMDK_ESX
    105 
    106 /** @todo the ESX code is not tested, not used, and lacks error messages. */
    107 
    108 /**
    109  * Magic number for images created by VMware GSX Server 3 or ESX Server 3.
    110  */
    111 #define VMDK_ESX_SPARSE_MAGICNUMBER 0x44574f43 /* 'C' 'O' 'W' 'D' */
    112 
    113 #pragma pack(1)
    114 typedef struct COWDisk_Header
    115 {
    116     uint32_t    magicNumber;
    117     uint32_t    version;
    118     uint32_t    flags;
    119     uint32_t    numSectors;
    120     uint32_t    grainSize;
    121     uint32_t    gdOffset;
    122     uint32_t    numGDEntries;
    123     uint32_t    freeSector;
    124     /* The spec incompletely documents quite a few further fields, but states
    125      * that they are unused by the current format. Replace them by padding. */
    126     char        reserved1[1604];
    127     uint32_t    savedGeneration;
    128     char        reserved2[8];
    129     uint32_t    uncleanShutdown;
    130     char        padding[396];
    131 } COWDisk_Header;
    132 #pragma pack()
    133 #endif /* VBOX_WITH_VMDK_ESX */
    134 
    135 
    136 /** Convert sector number/size to byte offset/size. */
    137 #define VMDK_SECTOR2BYTE(u) ((u) << 9)
    138 
    139 /** Convert byte offset/size to sector number/size. */
    140 #define VMDK_BYTE2SECTOR(u) ((u) >> 9)
    141 
    142 /**
    143  * VMDK extent type.
    144  */
    145 typedef enum VMDKETYPE
    146 {
    147     /** Hosted sparse extent. */
    148     VMDKETYPE_HOSTED_SPARSE = 1,
    149     /** Flat extent. */
    150     VMDKETYPE_FLAT,
    151     /** Zero extent. */
    152     VMDKETYPE_ZERO
    153 #ifdef VBOX_WITH_VMDK_ESX
    154     ,
    155     /** ESX sparse extent. */
    156     VMDKETYPE_ESX_SPARSE
    157 #endif /* VBOX_WITH_VMDK_ESX */
    158 } VMDKETYPE, *PVMDKETYPE;
    159 
    160 /**
    161  * VMDK access type for a extent.
    162  */
    163 typedef enum VMDKACCESS
    164 {
    165     /** No access allowed. */
    166     VMDKACCESS_NOACCESS = 0,
    167     /** Read-only access. */
    168     VMDKACCESS_READONLY,
    169     /** Read-write access. */
    170     VMDKACCESS_READWRITE
    171 } VMDKACCESS, *PVMDKACCESS;
    172 
    173 /**
    174  * VMDK extent data structure.
    175  */
    176 typedef struct VMDKEXTENT
    177 {
    178     /** File handle. */
    179     RTFILE      File;
    180     /** Base name of the image extent. */
    181     const char  *pszBasename;
    182     /** Full name of the image extent. */
    183     const char  *pszFullname;
    184     /** Number of sectors in this extent. */
    185     uint64_t    cSectors;
    186     /** Number of sectors per block (grain in VMDK speak). */
    187     uint64_t    cSectorsPerGrain;
    188     /** Starting sector number of descriptor. */
    189     uint64_t    uDescriptorSector;
    190     /** Size of descriptor in sectors. */
    191     uint64_t    cDescriptorSectors;
    192     /** Starting sector number of grain directory. */
    193     uint64_t    uSectorGD;
    194     /** Starting sector number of redundant grain directory. */
    195     uint64_t    uSectorRGD;
    196     /** Total number of metadata sectors. */
    197     uint64_t    cOverheadSectors;
    198     /** Nominal size (i.e. as described by the descriptor) of this extent. */
    199     uint64_t    cNominalSectors;
    200     /** Sector offset (i.e. as described by the descriptor) of this extent. */
    201     uint64_t    uSectorOffset;
    202     /** Number of entries in a grain table. */
    203     uint32_t    cGTEntries;
    204     /** Number of sectors reachable via a grain directory entry. */
    205     uint32_t    cSectorsPerGDE;
    206     /** Number of entries in the grain directory. */
    207     uint32_t    cGDEntries;
    208     /** Pointer to the next free sector. Legacy information. Do not use. */
    209     uint32_t    uFreeSector;
    210     /** Number of this extent in the list of images. */
    211     uint32_t    uExtent;
    212     /** Pointer to the descriptor (NULL if no descriptor in this extent). */
    213     char        *pDescData;
    214     /** Pointer to the grain directory. */
    215     uint32_t    *pGD;
    216     /** Pointer to the redundant grain directory. */
    217     uint32_t     *pRGD;
    218     /** Type of this extent. */
    219     VMDKETYPE   enmType;
    220     /** Access to this extent. */
    221     VMDKACCESS  enmAccess;
    222     /** Flag whether this extent is marked as unclean. */
    223     bool        fUncleanShutdown;
    224     /** Flag whether the metadata in the extent header needs to be updated. */
    225     bool        fMetaDirty;
    226     /** Reference to the image in which this extent is used. Do not use this
    227      * on a regular basis to avoid passing pImage references to functions
    228      * explicitly. */
    229     struct VMDKIMAGE *pImage;
    230 } VMDKEXTENT, *PVMDKEXTENT;
    231 
    232 /**
    233  * Grain table cache size. Allocated per image.
    234  */
    235 #define VMDK_GT_CACHE_SIZE 256
    236 
    237 /**
    238  * Grain table block size. Smaller than an actual grain table block to allow
    239  * more grain table blocks to be cached without having to allocate excessive
    240  * amounts of memory for the cache.
    241  */
    242 #define VMDK_GT_CACHELINE_SIZE 128
    243 
    244 
    245 /**
    246  * Maximum number of lines in a descriptor file. Not worth the effort of
    247  * making it variable. Descriptor files are generally very short (~20 lines).
    248  */
    249 #define VMDK_DESCRIPTOR_LINES_MAX   100U
    250 
    251 /**
    252  * Parsed descriptor information. Allows easy access and update of the
    253  * descriptor (whether separate file or not). Free form text files suck.
    254  */
    255 typedef struct VMDKDESCRIPTOR
    256 {
    257     /** Line number of first entry of the disk descriptor. */
    258     unsigned    uFirstDesc;
    259     /** Line number of first entry in the extent description. */
    260     unsigned    uFirstExtent;
    261     /** Line number of first disk database entry. */
    262     unsigned    uFirstDDB;
    263     /** Total number of lines. */
    264     unsigned    cLines;
    265     /** Total amount of memory available for the descriptor. */
    266     size_t      cbDescAlloc;
    267     /** Set if descriptor has been changed and not yet written to disk. */
    268     bool        fDirty;
    269     /** Array of pointers to the data in the descriptor. */
    270     char        *aLines[VMDK_DESCRIPTOR_LINES_MAX];
    271     /** Array of line indices pointing to the next non-comment line. */
    272     unsigned    aNextLines[VMDK_DESCRIPTOR_LINES_MAX];
    273 } VMDKDESCRIPTOR, *PVMDKDESCRIPTOR;
    274 
    275 
    276 /**
    277  * Cache entry for translating extent/sector to a sector number in that
    278  * extent.
    279  */
    280 typedef struct VMDKGTCACHEENTRY
    281 {
    282     /** Extent number for which this entry is valid. */
    283     uint32_t    uExtent;
    284     /** GT data block number. */
    285     uint64_t    uGTBlock;
    286     /** Data part of the cache entry. */
    287     uint32_t    aGTData[VMDK_GT_CACHELINE_SIZE];
    288 } VMDKGTCACHEENTRY, *PVMDKGTCACHEENTRY;
    289 
    290 /**
    291  * Cache data structure for blocks of grain table entries. For now this is a
    292  * fixed size direct mapping cache, but this should be adapted to the size of
    293  * the sparse image and maybe converted to a set-associative cache. The
    294  * implementation below implements a write-through cache with write allocate.
    295  */
    296 typedef struct VMDKGTCACHE
    297 {
    298     /** Cache entries. */
    299     VMDKGTCACHEENTRY    aGTCache[VMDK_GT_CACHE_SIZE];
    300     /** Number of cache entries (currently unused). */
    301     unsigned            cEntries;
    302 } VMDKGTCACHE, *PVMDKGTCACHE;
    303 
    304 /**
    305  * Complete VMDK image data structure. Mainly a collection of extents and a few
    306  * extra global data fields.
    307  */
    308 typedef struct VMDKIMAGE
    309 {
    310     /** Pointer to the image extents. */
    311     PVMDKEXTENT     pExtents;
    312     /** Number of image extents. */
    313     unsigned        cExtents;
    314 
     38typedef struct RAWIMAGE
     39{
    31540    /** Base image name. */
    31641    const char      *pszFilename;
    317     /** Descriptor file if applicable. */
     42    /** File descriptor. */
    31843    RTFILE          File;
    31944
     
    33257    uint64_t        cbSize;
    33358    /** Physical geometry of this image. */
    334     PDMMEDIAGEOMETRY   PCHSGeometry;
     59    PDMMEDIAGEOMETRY PCHSGeometry;
    33560    /** Logical geometry of this image. */
    336     PDMMEDIAGEOMETRY   LCHSGeometry;
    337     /** Image UUID. */
    338     RTUUID          ImageUuid;
    339     /** Image modification UUID. */
    340     RTUUID          ModificationUuid;
    341     /** Parent image UUID. */
    342     RTUUID          ParentUuid;
    343     /** Parent image modification UUID. */
    344     RTUUID          ParentModificationUuid;
    345 
    346     /** Pointer to grain table cache, if this image contains sparse extents. */
    347     PVMDKGTCACHE    pGTCache;
    348     /** Pointer to the descriptor (NULL if no separate descriptor file). */
    349     char            *pDescData;
    350     /** Allocation size of the descriptor file. */
    351     size_t          cbDescAlloc;
    352     /** Parsed descriptor file content. */
    353     VMDKDESCRIPTOR  Descriptor;
    354 } VMDKIMAGE, *PVMDKIMAGE;
     61    PDMMEDIAGEOMETRY LCHSGeometry;
     62
     63} RAWIMAGE, *PRAWIMAGE;
    35564
    35665
     
    35968*******************************************************************************/
    36069
    361 static int vmdkReadGrainDirectory(PVMDKEXTENT pExtent);
    362 static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent);
    363 
    364 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor);
    365 static int vmdkReadMetaSparseExtent(PVMDKEXTENT pExtent);
    366 static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent);
    367 #ifdef VBOX_WITH_VMDK_ESX
    368 static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent);
    369 #endif /* VBOX_WITH_VMDK_ESX */
    370 static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete);
    371 
    372 static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
    373 static int vmdkFlushImage(PVMDKIMAGE pImage);
    374 static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment);
    375 static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
     70static int rawFlushImage(PRAWIMAGE pImage);
     71static void rawFreeImage(PRAWIMAGE pImage, bool fDelete);
    37672
    37773
     
    37975 * Internal: signal an error to the frontend.
    38076 */
    381 DECLINLINE(int) vmdkError(PVMDKIMAGE pImage, int rc, RT_SRC_POS_DECL,
    382                           const char *pszFormat, ...)
     77DECLINLINE(int) rawError(PRAWIMAGE pImage, int rc, RT_SRC_POS_DECL,
     78                         const char *pszFormat, ...)
    38379{
    38480    va_list va;
     
    39288
    39389/**
    394  * Internal: truncate a string (at a UTF8 code point boundary) and encode the
    395  * critical non-ASCII characters.
    396  */
    397 static char *vmdkEncodeString(const char *psz)
    398 {
    399     /** @todo implement me. */
    400     return RTStrDup(psz);
    401 }
    402 
    403 /**
    404  * Internal: decode a string and store it into the specified string.
    405  */
    406 static int vmdkDecodeString(const char *pszEncoded, char *psz, size_t cb)
    407 {
    408     /** @todo implement me. */
    409     if (!cb)
    410         return VINF_SUCCESS;
    411     strncpy(psz, pszEncoded, cb);
    412     psz[cb - 1] = '\0';
    413     return VINF_SUCCESS;
    414 }
    415 
    416 static int vmdkReadGrainDirectory(PVMDKEXTENT pExtent)
    417 {
    418     int rc = VINF_SUCCESS;
    419     unsigned i;
    420     uint32_t *pGD = NULL, *pRGD = NULL, *pGDTmp, *pRGDTmp;
    421     size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
    422 
    423     pGD = (uint32_t *)RTMemAllocZ(cbGD);
    424     if (!pGD)
    425     {
    426         rc = VERR_NO_MEMORY;
    427         goto out;
    428     }
    429     pExtent->pGD = pGD;
    430     rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
    431                       pGD, cbGD, NULL);
    432     AssertRC(rc);
    433     if (VBOX_FAILURE(rc))
    434     {
    435         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s'"), pExtent->pszFullname);
    436         goto out;
    437     }
    438     for (i = 0, pGDTmp = pGD; i < pExtent->cGDEntries; i++, pGDTmp++)
    439         *pGDTmp = RT_LE2H_U32(*pGDTmp);
    440 
    441     if (pExtent->uSectorRGD)
    442     {
    443         pRGD = (uint32_t *)RTMemAllocZ(cbGD);
    444         if (!pRGD)
    445         {
    446             rc = VERR_NO_MEMORY;
    447             goto out;
    448         }
    449         pExtent->pRGD = pRGD;
    450         rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
    451                           pRGD, cbGD, NULL);
    452         AssertRC(rc);
    453         if (VBOX_FAILURE(rc))
    454         {
    455             rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname);
    456             goto out;
    457         }
    458         for (i = 0, pRGDTmp = pRGD; i < pExtent->cGDEntries; i++, pRGDTmp++)
    459             *pRGDTmp = RT_LE2H_U32(*pRGDTmp);
    460 
    461         /* Check grain table and redundant grain table for consistency. */
    462         size_t cbGT = pExtent->cGTEntries;
    463         uint32_t *pTmpGT1 = (uint32_t *)RTMemTmpAlloc(cbGT);
    464         if (!pTmpGT1)
    465         {
    466             rc = VERR_NO_MEMORY;
    467             goto out;
    468         }
    469         uint32_t *pTmpGT2 = (uint32_t *)RTMemTmpAlloc(cbGT);
    470         if (!pTmpGT2)
    471         {
    472             RTMemTmpFree(pTmpGT1);
    473             rc = VERR_NO_MEMORY;
    474             goto out;
    475         }
    476 
    477         for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD;
    478              i < pExtent->cGDEntries;
    479              i++, pGDTmp++, pRGDTmp++)
    480         {
    481             /* If no grain table is allocated skip the entry. */
    482             if (*pGDTmp == 0 && *pRGDTmp == 0)
    483                 continue;
    484 
    485             if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
    486             {
    487                 /* Just one grain directory entry refers to a not yet allocated
    488                  * grain table or both grain directory copies refer to the same
    489                  * grain table. Not allowed. */
    490                 RTMemTmpFree(pTmpGT1);
    491                 RTMemTmpFree(pTmpGT2);
    492                 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname);
    493                 goto out;
    494             }
    495             rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pGDTmp),
    496                               pTmpGT1, cbGT, NULL);
    497             if (VBOX_FAILURE(rc))
    498             {
    499                 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
    500                 RTMemTmpFree(pTmpGT1);
    501                 RTMemTmpFree(pTmpGT2);
    502                 goto out;
    503             }
    504             rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pRGDTmp),
    505                               pTmpGT2, cbGT, NULL);
    506             if (VBOX_FAILURE(rc))
    507             {
    508                 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname);
    509                 RTMemTmpFree(pTmpGT1);
    510                 RTMemTmpFree(pTmpGT2);
    511                 goto out;
    512             }
    513             if (memcmp(pTmpGT1, pTmpGT2, cbGT))
    514             {
    515                 RTMemTmpFree(pTmpGT1);
    516                 RTMemTmpFree(pTmpGT2);
    517                 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname);
    518                 goto out;
    519             }
    520         }
    521 
    522         /** @todo figure out what to do for unclean VMDKs. */
    523     }
    524 
    525 out:
    526     if (VBOX_FAILURE(rc))
    527         vmdkFreeGrainDirectory(pExtent);
    528     return rc;
    529 }
    530 
    531 static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector,
    532                                     bool fPreAlloc)
    533 {
    534     int rc = VINF_SUCCESS;
    535     unsigned i;
    536     uint32_t *pGD = NULL, *pRGD = NULL;
    537     size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
    538     size_t cbGDRounded = RT_ALIGN_64(pExtent->cGDEntries * sizeof(uint32_t), 512);
    539     size_t cbGTRounded;
    540     uint64_t cbOverhead;
    541 
    542     if (fPreAlloc)
    543         cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
    544     else
    545         cbGTRounded = 0;
    546 
    547     pGD = (uint32_t *)RTMemAllocZ(cbGD);
    548     if (!pGD)
    549     {
    550         rc = VERR_NO_MEMORY;
    551         goto out;
    552     }
    553     pExtent->pGD = pGD;
    554     pRGD = (uint32_t *)RTMemAllocZ(cbGD);
    555     if (!pRGD)
    556     {
    557         rc = VERR_NO_MEMORY;
    558         goto out;
    559     }
    560     pExtent->pRGD = pRGD;
    561 
    562     cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
    563     rc = RTFileSetSize(pExtent->File, cbOverhead);
    564     if (VBOX_FAILURE(rc))
    565         goto out;
    566     pExtent->uSectorRGD = uStartSector;
    567     pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
    568 
    569     if (fPreAlloc)
    570     {
    571         uint32_t uGTSectorLE;
    572         uint64_t uOffsetSectors;
    573 
    574         uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
    575         for (i = 0; i < pExtent->cGDEntries; i++)
    576         {
    577             pRGD[i] = uOffsetSectors;
    578             uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    579             /* Write the redundant grain directory entry to disk. */
    580             rc = RTFileWriteAt(pExtent->File,
    581                                VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
    582                                &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    583             if (VBOX_FAILURE(rc))
    584                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
    585             uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
    586         }
    587 
    588         uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded);
    589         for (i = 0; i < pExtent->cGDEntries; i++)
    590         {
    591             pGD[i] = uOffsetSectors;
    592             uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    593             /* Write the grain directory entry to disk. */
    594             rc = RTFileWriteAt(pExtent->File,
    595                                VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
    596                                &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    597             if (VBOX_FAILURE(rc))
    598                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
    599             uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
    600         }
    601     }
    602     pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
    603 
    604 out:
    605     if (VBOX_FAILURE(rc))
    606         vmdkFreeGrainDirectory(pExtent);
    607     return rc;
    608 }
    609 
    610 static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent)
    611 {
    612     if (pExtent->pGD)
    613     {
    614         RTMemFree(pExtent->pGD);
    615         pExtent->pGD = NULL;
    616     }
    617     if (pExtent->pRGD)
    618     {
    619         RTMemFree(pExtent->pRGD);
    620         pExtent->pRGD = NULL;
    621     }
    622 }
    623 
    624 static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr,
    625                              char **ppszUnquoted, char **ppszNext)
    626 {
    627     char *pszQ;
    628     char *pszUnquoted;
    629 
    630     /* Skip over whitespace. */
    631     while (*pszStr == ' ' || *pszStr == '\t')
    632         pszStr++;
    633     if (*pszStr++ != '"')
    634         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
    635 
    636     pszQ = (char *)strchr(pszStr, '"');
    637     if (pszQ == NULL)
    638         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
    639     pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
    640     if (!pszUnquoted)
    641         return VERR_NO_MEMORY;
    642     memcpy(pszUnquoted, pszStr, pszQ - pszStr);
    643     pszUnquoted[pszQ - pszStr] = '\0';
    644     *ppszUnquoted = pszUnquoted;
    645     if (ppszNext)
    646         *ppszNext = pszQ + 1;
    647     return VINF_SUCCESS;
    648 }
    649 
    650 static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    651                            const char *pszLine)
    652 {
    653     char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
    654     ssize_t cbDiff = strlen(pszLine) + 1;
    655 
    656     if (    pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
    657         &&  pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    658         return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    659 
    660     memcpy(pEnd, pszLine, cbDiff);
    661     pDescriptor->cLines++;
    662     pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
    663     pDescriptor->fDirty = true;
    664 
    665     return VINF_SUCCESS;
    666 }
    667 
    668 static bool vmdkDescGetStr(PVMDKDESCRIPTOR pDescriptor, unsigned uStart,
    669                            const char *pszKey, const char **ppszValue)
    670 {
    671     size_t cbKey = strlen(pszKey);
    672     const char *pszValue;
    673 
    674     while (uStart != 0)
    675     {
    676         if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
    677         {
    678             /* Key matches, check for a '=' (preceded by whitespace). */
    679             pszValue = pDescriptor->aLines[uStart] + cbKey;
    680             while (*pszValue == ' ' || *pszValue == '\t')
    681                 pszValue++;
    682             if (*pszValue == '=')
    683             {
    684                 *ppszValue = pszValue + 1;
    685                 break;
    686             }
    687         }
    688         uStart = pDescriptor->aNextLines[uStart];
    689     }
    690     return !!uStart;
    691 }
    692 
    693 static int vmdkDescSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    694                           unsigned uStart,
    695                           const char *pszKey, const char *pszValue)
    696 {
    697     char *pszTmp;
    698     size_t cbKey = strlen(pszKey);
    699     unsigned uLast = 0;
    700 
    701     while (uStart != 0)
    702     {
    703         if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
    704         {
    705             /* Key matches, check for a '=' (preceded by whitespace). */
    706             pszTmp = pDescriptor->aLines[uStart] + cbKey;
    707             while (*pszTmp == ' ' || *pszTmp == '\t')
    708                 pszTmp++;
    709             if (*pszTmp == '=')
    710             {
    711                 while (*pszTmp == ' ' || *pszTmp == '\t')
    712                     pszTmp++;
    713                 break;
    714             }
    715         }
    716         if (!pDescriptor->aNextLines[uStart])
    717             uLast = uStart;
    718         uStart = pDescriptor->aNextLines[uStart];
    719     }
    720     if (uStart)
    721     {
    722         if (pszValue)
    723         {
    724             /* Key already exists, replace existing value. */
    725             size_t cbOldVal = strlen(pszTmp);
    726             size_t cbNewVal = strlen(pszValue);
    727             ssize_t cbDiff = cbNewVal - cbOldVal;
    728             /* Check for buffer overflow. */
    729             if (    pDescriptor->aLines[pDescriptor->cLines]
    730                 -   pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
    731                 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    732 
    733             memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
    734                     pDescriptor->aLines[pDescriptor->cLines] - pszTmp - cbOldVal);
    735             memcpy(pszTmp, pszValue, cbNewVal + 1);
    736             for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    737                 pDescriptor->aLines[i] += cbDiff;
    738         }
    739         else
    740         {
    741             memmove(pDescriptor->aLines[uStart], pDescriptor->aLines[uStart+1],
    742                     pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uStart+1] + 1);
    743             for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    744             {
    745                 pDescriptor->aLines[i-1] = pDescriptor->aLines[i];
    746                 if (pDescriptor->aNextLines[i])
    747                     pDescriptor->aNextLines[i-1] = pDescriptor->aNextLines[i] - 1;
    748                 else
    749                     pDescriptor->aNextLines[i-1] = 0;
    750             }
    751             pDescriptor->cLines--;
    752             /* Adjust starting line numbers of following descriptor sections. */
    753             if (uStart < pDescriptor->uFirstExtent)
    754                 pDescriptor->uFirstExtent--;
    755             if (uStart < pDescriptor->uFirstDDB)
    756                 pDescriptor->uFirstDDB--;
    757         }
    758     }
    759     else
    760     {
    761         /* Key doesn't exist, append after the last entry in this category. */
    762         if (!pszValue)
    763         {
    764             /* Key doesn't exist, and it should be removed. Simply a no-op. */
    765             return VINF_SUCCESS;
    766         }
    767         size_t cbKey = strlen(pszKey);
    768         size_t cbValue = strlen(pszValue);
    769         ssize_t cbDiff = cbKey + 1 + cbValue + 1;
    770         /* Check for buffer overflow. */
    771         if (   (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
    772             || (  pDescriptor->aLines[pDescriptor->cLines]
    773                 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
    774             return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    775         for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
    776         {
    777             pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
    778             if (pDescriptor->aNextLines[i - 1])
    779                 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
    780             else
    781                 pDescriptor->aNextLines[i] = 0;
    782         }
    783         uStart = uLast + 1;
    784         pDescriptor->aNextLines[uLast] = uStart;
    785         pDescriptor->aNextLines[uStart] = 0;
    786         pDescriptor->cLines++;
    787         pszTmp = pDescriptor->aLines[uStart];
    788         memmove(pszTmp + cbDiff, pszTmp,
    789                 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
    790         memcpy(pDescriptor->aLines[uStart], pszKey, cbKey);
    791         pDescriptor->aLines[uStart][cbKey] = '=';
    792         memcpy(pDescriptor->aLines[uStart] + cbKey + 1, pszValue, cbValue + 1);
    793         for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    794             pDescriptor->aLines[i] += cbDiff;
    795 
    796         /* Adjust starting line numbers of following descriptor sections. */
    797         if (uStart <= pDescriptor->uFirstExtent)
    798             pDescriptor->uFirstExtent++;
    799         if (uStart <= pDescriptor->uFirstDDB)
    800             pDescriptor->uFirstDDB++;
    801     }
    802     pDescriptor->fDirty = true;
    803     return VINF_SUCCESS;
    804 }
    805 
    806 static int vmdkDescBaseGetU32(PVMDKDESCRIPTOR pDescriptor, const char *pszKey,
    807                               uint32_t *puValue)
    808 {
    809     const char *pszValue;
    810 
    811     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
    812                         &pszValue))
    813         return VERR_VDI_VALUE_NOT_FOUND;
    814     return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
    815 }
    816 
    817 static int vmdkDescBaseGetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    818                               const char *pszKey, const char **ppszValue)
    819 {
    820     const char *pszValue;
    821     char *pszValueUnquoted;
    822 
    823     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
    824                         &pszValue))
    825         return VERR_VDI_VALUE_NOT_FOUND;
    826     int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
    827     if (VBOX_FAILURE(rc))
    828         return rc;
    829     *ppszValue = pszValueUnquoted;
    830     return rc;
    831 }
    832 
    833 static int vmdkDescBaseSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    834                               const char *pszKey, const char *pszValue)
    835 {
    836     char *pszValueQuoted;
    837 
    838     int rc = RTStrAPrintf(&pszValueQuoted, "\"%s\"", pszValue);
    839     if (VBOX_FAILURE(rc))
    840         return rc;
    841     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey,
    842                         pszValueQuoted);
    843     RTStrFree(pszValueQuoted);
    844     return rc;
    845 }
    846 
    847 static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
    848                                    PVMDKDESCRIPTOR pDescriptor)
    849 {
    850     unsigned uEntry = pDescriptor->uFirstExtent;
    851     ssize_t cbDiff;
    852 
    853     if (!uEntry)
    854         return;
    855 
    856     cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
    857     /* Move everything including \0 in the entry marking the end of buffer. */
    858     memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
    859             pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
    860     for (unsigned i = uEntry + 1; i <= pDescriptor->cLines; i++)
    861     {
    862         pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
    863         if (pDescriptor->aNextLines[i])
    864             pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
    865         else
    866             pDescriptor->aNextLines[i - 1] = 0;
    867     }
    868     pDescriptor->cLines--;
    869     if (pDescriptor->uFirstDDB)
    870         pDescriptor->uFirstDDB--;
    871 
    872     return;
    873 }
    874 
    875 static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    876                              VMDKACCESS enmAccess, uint64_t cNominalSectors,
    877                              VMDKETYPE enmType, const char *pszBasename,
    878                              uint64_t uSectorOffset)
    879 {
    880     static const char *apszAccess[] = { "NOACCESS", "RDONLY", "RW" };
    881     static const char *apszType[] = { "", "SPARSE", "FLAT", "ZERO" };
    882     char *pszTmp;
    883     unsigned uStart = pDescriptor->uFirstExtent, uLast = 0;
    884     char szExt[1024];
    885     ssize_t cbDiff;
    886 
    887     /* Find last entry in extent description. */
    888     while (uStart)
    889     {
    890         if (!pDescriptor->aNextLines[uStart])
    891             uLast = uStart;
    892         uStart = pDescriptor->aNextLines[uStart];
    893     }
    894 
    895     if (enmType == VMDKETYPE_ZERO)
    896     {
    897         RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s ", apszAccess[enmAccess],
    898                     cNominalSectors, apszType[enmType]);
    899     }
    900     else
    901     {
    902         if (!uSectorOffset)
    903             RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\"",
    904                         apszAccess[enmAccess], cNominalSectors,
    905                         apszType[enmType], pszBasename);
    906         else
    907             RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\" %llu",
    908                         apszAccess[enmAccess], cNominalSectors,
    909                         apszType[enmType], pszBasename, uSectorOffset);
    910     }
    911     cbDiff = strlen(szExt) + 1;
    912 
    913     /* Check for buffer overflow. */
    914     if (   (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
    915         || (  pDescriptor->aLines[pDescriptor->cLines]
    916             - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
    917         return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    918 
    919     for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
    920     {
    921         pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
    922         if (pDescriptor->aNextLines[i - 1])
    923             pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
    924         else
    925             pDescriptor->aNextLines[i] = 0;
    926     }
    927     uStart = uLast + 1;
    928     pDescriptor->aNextLines[uLast] = uStart;
    929     pDescriptor->aNextLines[uStart] = 0;
    930     pDescriptor->cLines++;
    931     pszTmp = pDescriptor->aLines[uStart];
    932     memmove(pszTmp + cbDiff, pszTmp,
    933             pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
    934     memcpy(pDescriptor->aLines[uStart], szExt, cbDiff);
    935     for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
    936         pDescriptor->aLines[i] += cbDiff;
    937 
    938     /* Adjust starting line numbers of following descriptor sections. */
    939     if (uStart <= pDescriptor->uFirstDDB)
    940         pDescriptor->uFirstDDB++;
    941 
    942     pDescriptor->fDirty = true;
    943     return VINF_SUCCESS;
    944 }
    945 
    946 static int vmdkDescDDBGetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    947                              const char *pszKey, const char **ppszValue)
    948 {
    949     const char *pszValue;
    950     char *pszValueUnquoted;
    951 
    952     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    953                         &pszValue))
    954         return VERR_VDI_VALUE_NOT_FOUND;
    955     int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
    956     if (VBOX_FAILURE(rc))
    957         return rc;
    958     *ppszValue = pszValueUnquoted;
    959     return rc;
    960 }
    961 
    962 static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    963                              const char *pszKey, uint32_t *puValue)
    964 {
    965     const char *pszValue;
    966     char *pszValueUnquoted;
    967 
    968     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    969                         &pszValue))
    970         return VERR_VDI_VALUE_NOT_FOUND;
    971     int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
    972     if (VBOX_FAILURE(rc))
    973         return rc;
    974     rc = RTStrToUInt32Ex(pszValueUnquoted, NULL, 10, puValue);
    975     RTMemTmpFree(pszValueUnquoted);
    976     return rc;
    977 }
    978 
    979 static int vmdkDescDDBGetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    980                               const char *pszKey, PRTUUID pUuid)
    981 {
    982     const char *pszValue;
    983     char *pszValueUnquoted;
    984 
    985     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
    986                         &pszValue))
    987         return VERR_VDI_VALUE_NOT_FOUND;
    988     int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
    989     if (VBOX_FAILURE(rc))
    990         return rc;
    991     rc = RTUuidFromStr(pUuid, pszValueUnquoted);
    992     RTMemTmpFree(pszValueUnquoted);
    993     return rc;
    994 }
    995 
    996 static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    997                              const char *pszKey, const char *pszVal)
    998 {
    999     int rc;
    1000     char *pszValQuoted;
    1001 
    1002     if (pszVal)
    1003     {
    1004         rc = RTStrAPrintf(&pszValQuoted, "\"%s\"", pszVal);
    1005         if (VBOX_FAILURE(rc))
    1006             return rc;
    1007     }
    1008     else
    1009         pszValQuoted = NULL;
    1010     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
    1011                         pszValQuoted);
    1012     if (pszValQuoted)
    1013         RTStrFree(pszValQuoted);
    1014     return rc;
    1015 }
    1016 
    1017 static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    1018                               const char *pszKey, PCRTUUID pUuid)
    1019 {
    1020     char *pszUuid;
    1021 
    1022     int rc = RTStrAPrintf(&pszUuid, "\"%Vuuid\"", pUuid);
    1023     if (VBOX_FAILURE(rc))
    1024         return rc;
    1025     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
    1026                         pszUuid);
    1027     RTStrFree(pszUuid);
    1028     return rc;
    1029 }
    1030 
    1031 static int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    1032                              const char *pszKey, uint32_t uValue)
    1033 {
    1034     char *pszValue;
    1035 
    1036     int rc = RTStrAPrintf(&pszValue, "\"%d\"", uValue);
    1037     if (VBOX_FAILURE(rc))
    1038         return rc;
    1039     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
    1040                         pszValue);
    1041     RTStrFree(pszValue);
    1042     return rc;
    1043 }
    1044 
    1045 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
    1046                                     size_t cbDescData,
    1047                                     PVMDKDESCRIPTOR pDescriptor)
    1048 {
    1049     int rc = VINF_SUCCESS;
    1050     unsigned cLine = 0, uLastNonEmptyLine = 0;
    1051     char *pTmp = pDescData;
    1052 
    1053     pDescriptor->cbDescAlloc = cbDescData;
    1054     while (*pTmp != '\0')
    1055     {
    1056         pDescriptor->aLines[cLine++] = pTmp;
    1057         if (cLine >= VMDK_DESCRIPTOR_LINES_MAX)
    1058         {
    1059             rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
    1060             goto out;
    1061         }
    1062 
    1063         while (*pTmp != '\0' && *pTmp != '\n')
    1064         {
    1065             if (*pTmp == '\r')
    1066             {
    1067                 if (*(pTmp + 1) != '\n')
    1068                 {
    1069                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor in '%s'"), pImage->pszFilename);
    1070                     goto out;
    1071                 }
    1072                 else
    1073                 {
    1074                     /* Get rid of CR character. */
    1075                     *pTmp = '\0';
    1076                 }
    1077             }
    1078             pTmp++;
    1079         }
    1080         /* Get rid of LF character. */
    1081         if (*pTmp == '\n')
    1082         {
    1083             *pTmp = '\0';
    1084             pTmp++;
    1085         }
    1086     }
    1087     pDescriptor->cLines = cLine;
    1088     /* Pointer right after the end of the used part of the buffer. */
    1089     pDescriptor->aLines[cLine] = pTmp;
    1090 
    1091     if (strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile"))
    1092     {
    1093         rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
    1094         goto out;
    1095     }
    1096 
    1097     /* Initialize those, because we need to be able to reopen an image. */
    1098     pDescriptor->uFirstDesc = 0;
    1099     pDescriptor->uFirstExtent = 0;
    1100     pDescriptor->uFirstDDB = 0;
    1101     for (unsigned i = 0; i < cLine; i++)
    1102     {
    1103         if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0')
    1104         {
    1105             if (    !strncmp(pDescriptor->aLines[i], "RW", 2)
    1106                 ||  !strncmp(pDescriptor->aLines[i], "RDONLY", 6)
    1107                 ||  !strncmp(pDescriptor->aLines[i], "NOACCESS", 8) )
    1108             {
    1109                 /* An extent descriptor. */
    1110                 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB)
    1111                 {
    1112                     /* Incorrect ordering of entries. */
    1113                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
    1114                     goto out;
    1115                 }
    1116                 if (!pDescriptor->uFirstExtent)
    1117                 {
    1118                     pDescriptor->uFirstExtent = i;
    1119                     uLastNonEmptyLine = 0;
    1120                 }
    1121             }
    1122             else if (!strncmp(pDescriptor->aLines[i], "ddb.", 4))
    1123             {
    1124                 /* A disk database entry. */
    1125                 if (!pDescriptor->uFirstDesc || !pDescriptor->uFirstExtent)
    1126                 {
    1127                     /* Incorrect ordering of entries. */
    1128                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
    1129                     goto out;
    1130                 }
    1131                 if (!pDescriptor->uFirstDDB)
    1132                 {
    1133                     pDescriptor->uFirstDDB = i;
    1134                     uLastNonEmptyLine = 0;
    1135                 }
    1136             }
    1137             else
    1138             {
    1139                 /* A normal entry. */
    1140                 if (pDescriptor->uFirstExtent || pDescriptor->uFirstDDB)
    1141                 {
    1142                     /* Incorrect ordering of entries. */
    1143                     rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
    1144                     goto out;
    1145                 }
    1146                 if (!pDescriptor->uFirstDesc)
    1147                 {
    1148                     pDescriptor->uFirstDesc = i;
    1149                     uLastNonEmptyLine = 0;
    1150                 }
    1151             }
    1152             if (uLastNonEmptyLine)
    1153                 pDescriptor->aNextLines[uLastNonEmptyLine] = i;
    1154             uLastNonEmptyLine = i;
    1155         }
    1156     }
    1157 
    1158 out:
    1159     return rc;
    1160 }
    1161 
    1162 static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
    1163                                    PCPDMMEDIAGEOMETRY pPCHSGeometry)
    1164 {
    1165     int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    1166                            VMDK_DDB_GEO_PCHS_CYLINDERS,
    1167                            pPCHSGeometry->cCylinders);
    1168     if (VBOX_FAILURE(rc))
    1169         return rc;
    1170     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    1171                            VMDK_DDB_GEO_PCHS_HEADS,
    1172                            pPCHSGeometry->cHeads);
    1173     if (VBOX_FAILURE(rc))
    1174         return rc;
    1175     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    1176                            VMDK_DDB_GEO_PCHS_SECTORS,
    1177                            pPCHSGeometry->cSectors);
    1178     return rc;
    1179 }
    1180 
    1181 static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
    1182                                    PCPDMMEDIAGEOMETRY pLCHSGeometry)
    1183 {
    1184     int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    1185                            VMDK_DDB_GEO_LCHS_CYLINDERS,
    1186                            pLCHSGeometry->cCylinders);
    1187     if (VBOX_FAILURE(rc))
    1188         return rc;
    1189     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    1190                            VMDK_DDB_GEO_LCHS_HEADS,
    1191                            pLCHSGeometry->cHeads);
    1192     if (VBOX_FAILURE(rc))
    1193         return rc;
    1194     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    1195                            VMDK_DDB_GEO_LCHS_SECTORS,
    1196                            pLCHSGeometry->cSectors);
    1197     return rc;
    1198 }
    1199 
    1200 static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
    1201                                 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
    1202 {
    1203     int rc;
    1204 
    1205     pDescriptor->uFirstDesc = 0;
    1206     pDescriptor->uFirstExtent = 0;
    1207     pDescriptor->uFirstDDB = 0;
    1208     pDescriptor->cLines = 0;
    1209     pDescriptor->cbDescAlloc = cbDescData;
    1210     pDescriptor->fDirty = false;
    1211     pDescriptor->aLines[pDescriptor->cLines] = pDescData;
    1212     memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
    1213 
    1214     rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
    1215     if (VBOX_FAILURE(rc))
    1216         goto out;
    1217     rc = vmdkDescInitStr(pImage, pDescriptor, "version=1");
    1218     if (VBOX_FAILURE(rc))
    1219         goto out;
    1220     pDescriptor->uFirstDesc = pDescriptor->cLines - 1;
    1221     rc = vmdkDescInitStr(pImage, pDescriptor, "");
    1222     if (VBOX_FAILURE(rc))
    1223         goto out;
    1224     rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description");
    1225     if (VBOX_FAILURE(rc))
    1226         goto out;
    1227     rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO ");
    1228     if (VBOX_FAILURE(rc))
    1229         goto out;
    1230     pDescriptor->uFirstExtent = pDescriptor->cLines - 1;
    1231     rc = vmdkDescInitStr(pImage, pDescriptor, "");
    1232     if (VBOX_FAILURE(rc))
    1233         goto out;
    1234     /* The trailing space is created by VMware, too. */
    1235     rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base ");
    1236     if (VBOX_FAILURE(rc))
    1237         goto out;
    1238     rc = vmdkDescInitStr(pImage, pDescriptor, "#DDB");
    1239     if (VBOX_FAILURE(rc))
    1240         goto out;
    1241     rc = vmdkDescInitStr(pImage, pDescriptor, "");
    1242     if (VBOX_FAILURE(rc))
    1243         goto out;
    1244     rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\"");
    1245     if (VBOX_FAILURE(rc))
    1246         goto out;
    1247     pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
    1248 
    1249     /* Now that the framework is in place, use the normal functions to insert
    1250      * the remaining keys. */
    1251     char szBuf[9];
    1252     RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
    1253     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
    1254                         "CID", szBuf);
    1255     if (VBOX_FAILURE(rc))
    1256         goto out;
    1257     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
    1258                         "parentCID", "ffffffff");
    1259     if (VBOX_FAILURE(rc))
    1260         goto out;
    1261 
    1262     rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
    1263     if (VBOX_FAILURE(rc))
    1264         goto out;
    1265 
    1266 out:
    1267     return rc;
    1268 }
    1269 
    1270 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData,
    1271                                size_t cbDescData)
    1272 {
    1273     int rc;
    1274     unsigned cExtents;
    1275     unsigned uLine;
    1276 
    1277     rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
    1278                                   &pImage->Descriptor);
    1279     if (VBOX_FAILURE(rc))
    1280         return rc;
    1281 
    1282     /* Check version, must be 1. */
    1283     uint32_t uVersion;
    1284     rc = vmdkDescBaseGetU32(&pImage->Descriptor, "version", &uVersion);
    1285     if (VBOX_FAILURE(rc))
    1286         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error finding key 'version' in descriptor in '%s'"), pImage->pszFilename);
    1287     if (uVersion != 1)
    1288         return vmdkError(pImage, VERR_VDI_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
    1289 
    1290     /* Get image creation type and determine image flags. */
    1291     const char *pszCreateType;
    1292     rc = vmdkDescBaseGetStr(pImage, &pImage->Descriptor, "createType",
    1293                             &pszCreateType);
    1294     if (VBOX_FAILURE(rc))
    1295         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get image type from descriptor in '%s'"), pImage->pszFilename);
    1296     if (    !strcmp(pszCreateType, "twoGbMaxExtentSparse")
    1297         ||  !strcmp(pszCreateType, "twoGbMaxExtentFlat"))
    1298         pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
    1299     if (    !strcmp(pszCreateType, "partitionedDevice")
    1300         ||  !strcmp(pszCreateType, "fullDevice"))
    1301         pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_RAWDISK;
    1302     else
    1303         pImage->uImageFlags = 0;
    1304     RTStrFree((char *)(void *)pszCreateType);
    1305 
    1306     /* Count the number of extent config entries. */
    1307     for (uLine = pImage->Descriptor.uFirstExtent, cExtents = 0;
    1308          uLine != 0;
    1309          uLine = pImage->Descriptor.aNextLines[uLine], cExtents++)
    1310         /* nothing */;
    1311 
    1312     if (!pImage->pDescData && cExtents != 1)
    1313     {
    1314         /* Monolithic image, must have only one extent (already opened). */
    1315         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image may only have one extent in '%s'"), pImage->pszFilename);
    1316     }
    1317 
    1318     if (pImage->pDescData)
    1319     {
    1320         /* Non-monolithic image, extents need to be allocated. */
    1321         rc = vmdkCreateExtents(pImage, cExtents);
    1322         if (VBOX_FAILURE(rc))
    1323             return rc;
    1324     }
    1325 
    1326     for (unsigned i = 0, uLine = pImage->Descriptor.uFirstExtent;
    1327          i < cExtents; i++, uLine = pImage->Descriptor.aNextLines[uLine])
    1328     {
    1329         char *pszLine = pImage->Descriptor.aLines[uLine];
    1330 
    1331         /* Access type of the extent. */
    1332         if (!strncmp(pszLine, "RW", 2))
    1333         {
    1334             pImage->pExtents[i].enmAccess = VMDKACCESS_READWRITE;
    1335             pszLine += 2;
    1336         }
    1337         else if (!strncmp(pszLine, "RDONLY", 6))
    1338         {
    1339             pImage->pExtents[i].enmAccess = VMDKACCESS_READONLY;
    1340             pszLine += 6;
    1341         }
    1342         else if (!strncmp(pszLine, "NOACCESS", 8))
    1343         {
    1344             pImage->pExtents[i].enmAccess = VMDKACCESS_NOACCESS;
    1345             pszLine += 8;
    1346         }
    1347         else
    1348             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1349         if (*pszLine++ != ' ')
    1350             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1351 
    1352         /* Nominal size of the extent. */
    1353         rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
    1354                              &pImage->pExtents[i].cNominalSectors);
    1355         if (VBOX_FAILURE(rc))
    1356             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1357         if (*pszLine++ != ' ')
    1358             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1359 
    1360         /* Type of the extent. */
    1361 #ifdef VBOX_WITH_VMDK_ESX
    1362         /** @todo Add the ESX extent types. Not necessary for now because
    1363          * the ESX extent types are only used inside an ESX server. They are
    1364          * automatically converted if the VMDK is exported. */
    1365 #endif /* VBOX_WITH_VMDK_ESX */
    1366         if (!strncmp(pszLine, "SPARSE", 6))
    1367         {
    1368             pImage->pExtents[i].enmType = VMDKETYPE_HOSTED_SPARSE;
    1369             pszLine += 6;
    1370         }
    1371         else if (!strncmp(pszLine, "FLAT", 4))
    1372         {
    1373             pImage->pExtents[i].enmType = VMDKETYPE_FLAT;
    1374             pszLine += 4;
    1375         }
    1376         else if (!strncmp(pszLine, "ZERO", 4))
    1377         {
    1378             pImage->pExtents[i].enmType = VMDKETYPE_ZERO;
    1379             pszLine += 4;
    1380         }
    1381         else
    1382             return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1383         if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
    1384         {
    1385             /* This one has no basename or offset. */
    1386             if (*pszLine == ' ')
    1387                 pszLine++;
    1388             if (*pszLine != '\0')
    1389                 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1390             pImage->pExtents[i].pszBasename = NULL;
    1391         }
    1392         else
    1393         {
    1394             /* All other extent types have basename and optional offset. */
    1395             if (*pszLine++ != ' ')
    1396                 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1397 
    1398             /* Basename of the image. Surrounded by quotes. */
    1399             char *pszBasename;
    1400             rc = vmdkStringUnquote(pImage, pszLine, &pszBasename, &pszLine);
    1401             if (VBOX_FAILURE(rc))
    1402                 return rc;
    1403             pImage->pExtents[i].pszBasename = pszBasename;
    1404             if (*pszLine == ' ')
    1405             {
    1406                 pszLine++;
    1407                 if (*pszLine != '\0')
    1408                 {
    1409                     /* Optional offset in extent specified. */
    1410                     rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
    1411                                          &pImage->pExtents[i].uSectorOffset);
    1412                     if (VBOX_FAILURE(rc))
    1413                         return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1414                 }
    1415             }
    1416 
    1417             if (*pszLine != '\0')
    1418                 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
    1419         }
    1420     }
    1421 
    1422     /* Determine PCHS geometry (autogenerate if necessary). */
    1423     rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1424                            VMDK_DDB_GEO_PCHS_CYLINDERS,
    1425                            &pImage->PCHSGeometry.cCylinders);
    1426     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1427         pImage->PCHSGeometry.cCylinders = 0;
    1428     else if (VBOX_FAILURE(rc))
    1429         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    1430     rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1431                            VMDK_DDB_GEO_PCHS_HEADS,
    1432                            &pImage->PCHSGeometry.cHeads);
    1433     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1434         pImage->PCHSGeometry.cHeads = 0;
    1435     else if (VBOX_FAILURE(rc))
    1436         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    1437     rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1438                            VMDK_DDB_GEO_PCHS_SECTORS,
    1439                            &pImage->PCHSGeometry.cSectors);
    1440     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1441         pImage->PCHSGeometry.cSectors = 0;
    1442     else if (VBOX_FAILURE(rc))
    1443         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    1444     if (    pImage->PCHSGeometry.cCylinders == 0
    1445         ||  pImage->PCHSGeometry.cHeads == 0
    1446         ||  pImage->PCHSGeometry.cHeads > 16
    1447         ||  pImage->PCHSGeometry.cSectors == 0
    1448         ||  pImage->PCHSGeometry.cSectors > 63)
    1449     {
    1450         /* Mark PCHS geometry as not yet valid (can't do the calculation here
    1451          * as the total image size isn't known yet). */
    1452         pImage->PCHSGeometry.cCylinders = 0;
    1453         pImage->PCHSGeometry.cHeads = 16;
    1454         pImage->PCHSGeometry.cSectors = 63;
    1455     }
    1456 
    1457     /* Determine LCHS geometry (set to 0 if not specified). */
    1458     rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1459                            VMDK_DDB_GEO_LCHS_CYLINDERS,
    1460                            &pImage->LCHSGeometry.cCylinders);
    1461     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1462         pImage->LCHSGeometry.cCylinders = 0;
    1463     else if (VBOX_FAILURE(rc))
    1464         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
    1465     rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1466                            VMDK_DDB_GEO_LCHS_HEADS,
    1467                            &pImage->LCHSGeometry.cHeads);
    1468     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1469         pImage->LCHSGeometry.cHeads = 0;
    1470     else if (VBOX_FAILURE(rc))
    1471         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
    1472     rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1473                            VMDK_DDB_GEO_LCHS_SECTORS,
    1474                            &pImage->LCHSGeometry.cSectors);
    1475     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1476         pImage->LCHSGeometry.cSectors = 0;
    1477     else if (VBOX_FAILURE(rc))
    1478         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
    1479     if (    pImage->LCHSGeometry.cCylinders == 0
    1480         ||  pImage->LCHSGeometry.cHeads == 0
    1481         ||  pImage->LCHSGeometry.cSectors == 0)
    1482     {
    1483         pImage->LCHSGeometry.cCylinders = 0;
    1484         pImage->LCHSGeometry.cHeads = 0;
    1485         pImage->LCHSGeometry.cSectors = 0;
    1486     }
    1487 
    1488     /* Get image UUID. */
    1489     rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_IMAGE_UUID,
    1490                             &pImage->ImageUuid);
    1491     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1492     {
    1493         /* Image without UUID. Probably created by VMware and not yet used
    1494          * by VirtualBox. Can only be added for images opened in read/write
    1495          * mode, so don't bother producing a sensible UUID otherwise. */
    1496         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    1497             RTUuidClear(&pImage->ImageUuid);
    1498         else
    1499         {
    1500             rc = RTUuidCreate(&pImage->ImageUuid);
    1501             if (VBOX_FAILURE(rc))
    1502                 return rc;
    1503             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    1504                                     VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
    1505             if (VBOX_FAILURE(rc))
    1506                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
    1507         }
    1508     }
    1509     else if (VBOX_FAILURE(rc))
    1510         return rc;
    1511 
    1512     /* Get image modification UUID. */
    1513     rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
    1514                             VMDK_DDB_MODIFICATION_UUID,
    1515                             &pImage->ModificationUuid);
    1516     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1517     {
    1518         /* Image without UUID. Probably created by VMware and not yet used
    1519          * by VirtualBox. Can only be added for images opened in read/write
    1520          * mode, so don't bother producing a sensible UUID otherwise. */
    1521         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    1522             RTUuidClear(&pImage->ModificationUuid);
    1523         else
    1524         {
    1525             rc = RTUuidCreate(&pImage->ModificationUuid);
    1526             if (VBOX_FAILURE(rc))
    1527                 return rc;
    1528             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    1529                                     VMDK_DDB_MODIFICATION_UUID,
    1530                                     &pImage->ModificationUuid);
    1531             if (VBOX_FAILURE(rc))
    1532                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
    1533         }
    1534     }
    1535     else if (VBOX_FAILURE(rc))
    1536         return rc;
    1537 
    1538     /* Get UUID of parent image. */
    1539     rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_PARENT_UUID,
    1540                             &pImage->ParentUuid);
    1541     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1542     {
    1543         /* Image without UUID. Probably created by VMware and not yet used
    1544          * by VirtualBox. Can only be added for images opened in read/write
    1545          * mode, so don't bother producing a sensible UUID otherwise. */
    1546         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    1547             RTUuidClear(&pImage->ParentUuid);
    1548         else
    1549         {
    1550             rc = RTUuidClear(&pImage->ParentUuid);
    1551             if (VBOX_FAILURE(rc))
    1552                 return rc;
    1553             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    1554                                     VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
    1555             if (VBOX_FAILURE(rc))
    1556                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent UUID in descriptor in '%s'"), pImage->pszFilename);
    1557         }
    1558     }
    1559     else if (VBOX_FAILURE(rc))
    1560         return rc;
    1561 
    1562     /* Get parent image modification UUID. */
    1563     rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
    1564                             VMDK_DDB_PARENT_MODIFICATION_UUID,
    1565                             &pImage->ParentModificationUuid);
    1566     if (rc == VERR_VDI_VALUE_NOT_FOUND)
    1567     {
    1568         /* Image without UUID. Probably created by VMware and not yet used
    1569          * by VirtualBox. Can only be added for images opened in read/write
    1570          * mode, so don't bother producing a sensible UUID otherwise. */
    1571         if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    1572             RTUuidClear(&pImage->ParentModificationUuid);
    1573         else
    1574         {
    1575             rc = RTUuidCreate(&pImage->ParentModificationUuid);
    1576             if (VBOX_FAILURE(rc))
    1577                 return rc;
    1578             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    1579                                     VMDK_DDB_PARENT_MODIFICATION_UUID,
    1580                                     &pImage->ParentModificationUuid);
    1581             if (VBOX_FAILURE(rc))
    1582                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in descriptor in '%s'"), pImage->pszFilename);
    1583         }
    1584     }
    1585     else if (VBOX_FAILURE(rc))
    1586         return rc;
    1587 
    1588     return VINF_SUCCESS;
    1589 }
    1590 
    1591 /**
    1592  * Internal: write/update the descriptor part of the image.
    1593  */
    1594 static int vmdkWriteDescriptor(PVMDKIMAGE pImage)
    1595 {
    1596     int rc = VINF_SUCCESS;
    1597     uint64_t cbLimit;
    1598     uint64_t uOffset;
    1599     RTFILE DescFile;
    1600 
    1601     if (pImage->pDescData)
    1602     {
    1603         /* Separate descriptor file. */
    1604         uOffset = 0;
    1605         cbLimit = 0;
    1606         DescFile = pImage->File;
    1607     }
    1608     else
    1609     {
    1610         /* Embedded descriptor file. */
    1611         uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
    1612         cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
    1613         cbLimit += uOffset;
    1614         DescFile = pImage->pExtents[0].File;
    1615     }
    1616     for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
    1617     {
    1618         const char *psz = pImage->Descriptor.aLines[i];
    1619         size_t cb = strlen(psz);
    1620 
    1621         if (cbLimit && uOffset + cb + 1 > cbLimit)
    1622             return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
    1623         rc = RTFileWriteAt(DescFile, uOffset, psz, cb, NULL);
    1624         if (VBOX_FAILURE(rc))
    1625             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    1626         uOffset += cb;
    1627         rc = RTFileWriteAt(DescFile, uOffset, "\n", 1, NULL);
    1628         if (VBOX_FAILURE(rc))
    1629             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    1630         uOffset++;
    1631     }
    1632     if (cbLimit)
    1633     {
    1634         /* Inefficient, but simple. */
    1635         while (uOffset < cbLimit)
    1636         {
    1637             rc = RTFileWriteAt(DescFile, uOffset, "", 1, NULL);
    1638             if (VBOX_FAILURE(rc))
    1639                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
    1640             uOffset++;
    1641         }
    1642     }
    1643     else
    1644     {
    1645         rc = RTFileSetSize(DescFile, uOffset);
    1646         if (VBOX_FAILURE(rc))
    1647             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
    1648     }
    1649     pImage->Descriptor.fDirty = false;
    1650     return rc;
    1651 }
    1652 
    1653 /**
    1654  * Internal: read metadata belonging to a sparse extent.
    1655  */
    1656 static int vmdkReadMetaSparseExtent(PVMDKEXTENT pExtent)
    1657 {
    1658     SparseExtentHeader Header;
    1659     uint64_t cbExtentSize, cSectorsPerGDE;
    1660 
    1661     int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
    1662     AssertRC(rc);
    1663     if (VBOX_FAILURE(rc))
    1664     {
    1665         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
    1666         goto out;
    1667     }
    1668     if (    RT_LE2H_U32(Header.magicNumber) != VMDK_SPARSE_MAGICNUMBER
    1669         ||  RT_LE2H_U32(Header.version) != 1)
    1670     {
    1671         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic/version in extent header in '%s'"), pExtent->pszFullname);
    1672         goto out;
    1673     }
    1674     /* The image must be a multiple of a sector in size. If not, it means the
    1675      * image is at least truncated, or even seriously garbled. */
    1676     rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    1677     if (VBOX_FAILURE(rc))
    1678     {
    1679         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    1680         goto out;
    1681     }
    1682     if (    (RT_LE2H_U32(Header.flags) & 1)
    1683         &&  (   Header.singleEndLineChar != '\n'
    1684              || Header.nonEndLineChar != ' '
    1685              || Header.doubleEndLineChar1 != '\r'
    1686              || Header.doubleEndLineChar2 != '\n') )
    1687     {
    1688         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
    1689         goto out;
    1690     }
    1691     pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
    1692     pExtent->cSectors = RT_LE2H_U64(Header.capacity);
    1693     pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize);
    1694     /* The spec says that this must be a power of two and greater than 8,
    1695      * but probably they meant not less than 8. */
    1696     if (    (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
    1697         ||  pExtent->cSectorsPerGrain < 8)
    1698     {
    1699         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
    1700         goto out;
    1701     }
    1702     pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset);
    1703     pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize);
    1704     if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
    1705     {
    1706         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
    1707         goto out;
    1708     }
    1709     pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
    1710     /* This code requires that a grain table must hold a power of two multiple
    1711      * of the number of entries per GT cache entry. */
    1712     if (    (pExtent->cGTEntries & (pExtent->cGTEntries - 1))
    1713         ||  pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)
    1714     {
    1715         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
    1716         goto out;
    1717     }
    1718     if (RT_LE2H_U32(Header.flags) & 2)
    1719     {
    1720         pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
    1721         pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
    1722     }
    1723     else
    1724     {
    1725         /** @todo this is just guesswork, the spec doesn't document this
    1726          * properly and I don't have a vmdk without RGD. */
    1727         pExtent->uSectorGD = RT_LE2H_U64(Header.rgdOffset);
    1728         pExtent->uSectorRGD = 0;
    1729     }
    1730     pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
    1731     pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
    1732     cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    1733     if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
    1734     {
    1735         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
    1736         goto out;
    1737     }
    1738     pExtent->cSectorsPerGDE = cSectorsPerGDE;
    1739     pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    1740 
    1741     rc = vmdkReadGrainDirectory(pExtent);
    1742 
    1743 out:
    1744     if (VBOX_FAILURE(rc))
    1745         vmdkFreeExtentData(pExtent, false);
    1746 
    1747     return rc;
    1748 }
    1749 
    1750 /**
    1751  * Internal: write/update the metadata for a sparse extent.
    1752  */
    1753 static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent)
    1754 {
    1755     SparseExtentHeader Header;
    1756 
    1757     memset(&Header, '\0', sizeof(Header));
    1758     Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
    1759     Header.version = RT_H2LE_U32(1);
    1760     Header.flags = RT_H2LE_U32(1 | ((pExtent->pRGD) ? 2 : 0));
    1761     Header.capacity = RT_H2LE_U64(pExtent->cSectors);
    1762     Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
    1763     Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
    1764     Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
    1765     Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
    1766     if (pExtent->pRGD)
    1767     {
    1768         Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
    1769         Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
    1770     }
    1771     else
    1772     {
    1773         /** @todo this is just guesswork, the spec doesn't document this
    1774          * properly and I don't have a vmdk without RGD. */
    1775         Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorGD);
    1776     }
    1777     Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
    1778     Header.uncleanShutdown = pExtent->fUncleanShutdown;
    1779     Header.singleEndLineChar = '\n';
    1780     Header.nonEndLineChar = ' ';
    1781     Header.doubleEndLineChar1 = '\r';
    1782     Header.doubleEndLineChar2 = '\n';
    1783 
    1784     int rc = RTFileWriteAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
    1785     AssertRC(rc);
    1786     if (VBOX_FAILURE(rc))
    1787         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
    1788     return rc;
    1789 }
    1790 
    1791 #ifdef VBOX_WITH_VMDK_ESX
    1792 /**
    1793  * Internal: unused code to read the metadata of a sparse ESX extent.
    1794  *
    1795  * Such extents never leave ESX server, so this isn't ever used.
    1796  */
    1797 static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent)
    1798 {
    1799     COWDisk_Header Header;
    1800     uint64_t cSectorsPerGDE;
    1801 
    1802     int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
    1803     AssertRC(rc);
    1804     if (VBOX_FAILURE(rc))
    1805         goto out;
    1806     if (    RT_LE2H_U32(Header.magicNumber) != VMDK_ESX_SPARSE_MAGICNUMBER
    1807         ||  RT_LE2H_U32(Header.version) != 1
    1808         ||  RT_LE2H_U32(Header.flags) != 3)
    1809     {
    1810         rc = VERR_VDI_INVALID_HEADER;
    1811         goto out;
    1812     }
    1813     pExtent->enmType = VMDKETYPE_ESX_SPARSE;
    1814     pExtent->cSectors = RT_LE2H_U32(Header.numSectors);
    1815     pExtent->cSectorsPerGrain = RT_LE2H_U32(Header.grainSize);
    1816     /* The spec says that this must be between 1 sector and 1MB. This code
    1817      * assumes it's a power of two, so check that requirement, too. */
    1818     if (    (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
    1819         ||  pExtent->cSectorsPerGrain == 0
    1820         ||  pExtent->cSectorsPerGrain > 2048)
    1821     {
    1822         rc = VERR_VDI_INVALID_HEADER;
    1823         goto out;
    1824     }
    1825     pExtent->uDescriptorSector = 0;
    1826     pExtent->cDescriptorSectors = 0;
    1827     pExtent->uSectorGD = RT_LE2H_U32(Header.gdOffset);
    1828     pExtent->uSectorRGD = 0;
    1829     pExtent->cOverheadSectors = 0;
    1830     pExtent->cGTEntries = 4096;
    1831     cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    1832     if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
    1833     {
    1834         rc = VERR_VDI_INVALID_HEADER;
    1835         goto out;
    1836     }
    1837     pExtent->cSectorsPerGDE = cSectorsPerGDE;
    1838     pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    1839     if (pExtent->cGDEntries != RT_LE2H_U32(Header.numGDEntries))
    1840     {
    1841         /* Inconsistency detected. Computed number of GD entries doesn't match
    1842          * stored value. Better be safe than sorry. */
    1843         rc = VERR_VDI_INVALID_HEADER;
    1844         goto out;
    1845     }
    1846     pExtent->uFreeSector = RT_LE2H_U32(Header.freeSector);
    1847     pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
    1848 
    1849     rc = vmdkReadGrainDirectory(pExtent);
    1850 
    1851 out:
    1852     if (VBOX_FAILURE(rc))
    1853         vmdkFreeExtentData(pExtent, false);
    1854 
    1855     return rc;
    1856 }
    1857 #endif /* VBOX_WITH_VMDK_ESX */
    1858 
    1859 /**
    1860  * Internal: free the memory used by the extent data structure, optionally
    1861  * deleting the referenced files.
    1862  */
    1863 static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete)
    1864 {
    1865     vmdkFreeGrainDirectory(pExtent);
    1866     if (pExtent->pDescData)
    1867     {
    1868         RTMemFree(pExtent->pDescData);
    1869         pExtent->pDescData = NULL;
    1870     }
    1871     if (pExtent->File != NIL_RTFILE)
    1872     {
    1873         RTFileClose(pExtent->File);
    1874         pExtent->File = NIL_RTFILE;
    1875         if (    fDelete
    1876             &&  strcmp(pExtent->pszFullname, pExtent->pszBasename) != 0
    1877             && pExtent->pszFullname)
    1878             RTFileDelete(pExtent->pszFullname);
    1879     }
    1880     if (pExtent->pszBasename)
    1881     {
    1882         RTMemTmpFree((void *)pExtent->pszBasename);
    1883         pExtent->pszBasename = NULL;
    1884     }
    1885     if (pExtent->pszFullname)
    1886     {
    1887         RTStrFree((char *)(void *)pExtent->pszFullname);
    1888         pExtent->pszFullname = NULL;
    1889     }
    1890 }
    1891 
    1892 /**
    1893  * Internal: allocate grain table cache if necessary for this image.
    1894  */
    1895 static int vmdkAllocateGrainTableCache(PVMDKIMAGE pImage)
    1896 {
    1897     PVMDKEXTENT pExtent;
    1898 
    1899     /* Allocate grain table cache if any sparse extent is present. */
    1900     for (unsigned i = 0; i < pImage->cExtents; i++)
    1901     {
    1902         pExtent = &pImage->pExtents[i];
    1903         if (    pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
    1904 #ifdef VBOX_WITH_VMDK_ESX
    1905             ||  pExtent->enmType == VMDKETYPE_ESX_SPARSE
    1906 #endif /* VBOX_WITH_VMDK_ESX */
    1907            )
    1908         {
    1909             /* Allocate grain table cache. */
    1910             pImage->pGTCache = (PVMDKGTCACHE)RTMemAllocZ(sizeof(VMDKGTCACHE));
    1911             if (!pImage->pGTCache)
    1912                 return VERR_NO_MEMORY;
    1913             for (unsigned i = 0; i < VMDK_GT_CACHE_SIZE; i++)
    1914             {
    1915                 PVMDKGTCACHEENTRY pGCE = &pImage->pGTCache->aGTCache[i];
    1916                 pGCE->uExtent = UINT32_MAX;
    1917             }
    1918             pImage->pGTCache->cEntries = VMDK_GT_CACHE_SIZE;
    1919             break;
    1920         }
    1921     }
    1922 
    1923     return VINF_SUCCESS;
    1924 }
    1925 
    1926 /**
    1927  * Internal: allocate the given number of extents.
    1928  */
    1929 static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents)
    1930 {
    1931     int rc = VINF_SUCCESS;
    1932     PVMDKEXTENT pExtents = (PVMDKEXTENT)RTMemAllocZ(cExtents * sizeof(VMDKEXTENT));
    1933     if (pImage)
    1934     {
    1935         for (unsigned i = 0; i < cExtents; i++)
    1936         {
    1937             pExtents[i].File = NIL_RTFILE;
    1938             pExtents[i].pszBasename = NULL;
    1939             pExtents[i].pszFullname = NULL;
    1940             pExtents[i].pGD = NULL;
    1941             pExtents[i].pRGD = NULL;
    1942             pExtents[i].pDescData = NULL;
    1943             pExtents[i].uExtent = i;
    1944             pExtents[i].pImage = pImage;
    1945         }
    1946         pImage->pExtents = pExtents;
    1947         pImage->cExtents = cExtents;
    1948     }
    1949     else
    1950         rc = VERR_NO_MEMORY;
    1951 
    1952     return rc;
    1953 }
    1954 
    1955 /**
    195690 * Internal: Open an image, constructing all necessary data structures.
    195791 */
    1958 static int vmdkOpenImage(PVMDKIMAGE pImage, unsigned uOpenFlags)
    1959 {
    1960     int rc;
    1961     uint32_t u32Magic;
     92static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
     93{
     94    int rc;
    196295    RTFILE File;
    1963     PVMDKEXTENT pExtent;
    196496
    196597    pImage->uOpenFlags = uOpenFlags;
    1966 
    1967     /** @todo check whether the same file is used somewhere else. don't open any file twice, leads to locking problems and can cause trouble with file caching. */
    196898
    196999    /*
     
    1982112    pImage->File = File;
    1983113
    1984     /* Read magic (if present). */
    1985     rc = RTFileReadAt(File, 0, &u32Magic, sizeof(u32Magic), NULL);
     114    rc = RTFileGetSize(pImage->File, &pImage->cbSize);
    1986115    if (VBOX_FAILURE(rc))
    1987     {
    1988         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading the magic number in '%s'"), pImage->pszFilename);
    1989         goto out;
    1990     }
    1991 
    1992     /* Handle the file according to its magic number. */
    1993     if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
    1994     {
    1995         /* It's a hosted sparse single-extent image. */
    1996         rc = vmdkCreateExtents(pImage, 1);
     116        goto out;
     117    if (pImage->cbSize % 512)
     118    {
     119        rc = VERR_VDI_INVALID_HEADER;
     120        goto out;
     121    }
     122    pImage->enmImageType = VD_IMAGE_TYPE_FIXED;
     123
     124out:
     125    if (VBOX_FAILURE(rc))
     126        rawFreeImage(pImage, false);
     127    return rc;
     128}
     129
     130/**
     131 * Internal: Create a raw image.
     132 */
     133static int rawCreateImage(PRAWIMAGE pImage, VDIMAGETYPE enmType,
     134                          uint64_t cbSize, unsigned uImageFlags,
     135                          const char *pszComment,
     136                          PCPDMMEDIAGEOMETRY pPCHSGeometry,
     137                          PCPDMMEDIAGEOMETRY pLCHSGeometry,
     138                          PFNVMPROGRESS pfnProgress, void *pvUser,
     139                          unsigned uPercentStart, unsigned uPercentSpan)
     140{
     141    int rc;
     142    RTFILE File;
     143    RTFOFF cbFree = 0;
     144    uint64_t uOff;
     145    size_t cbBuf = 128 * _1K;
     146    void *pvBuf = NULL;
     147
     148    if (enmType != VD_IMAGE_TYPE_FIXED)
     149    {
     150        rc = rawError(pImage, VERR_VDI_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
     151        goto out;
     152    }
     153
     154    pImage->enmImageType = enmType;
     155    pImage->uImageFlags = uImageFlags;
     156    pImage->PCHSGeometry = *pPCHSGeometry;
     157    pImage->LCHSGeometry = *pLCHSGeometry;
     158
     159    /* Create image file. */
     160    rc = RTFileOpen(&File, pImage->pszFilename,
     161                    RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL);
     162    if (VBOX_FAILURE(rc))
     163    {
     164        rc = rawError(pImage, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
     165        goto out;
     166    }
     167    pImage->File = File;
     168
     169    /* Check the free space on the disk and leave early if there is not
     170     * sufficient space available. */
     171    rc = RTFsQuerySizes(pImage->pszFilename, NULL, &cbFree, NULL, NULL);
     172    if (VBOX_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
     173    {
     174        rc = rawError(pImage, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
     175        goto out;
     176    }
     177
     178    /* Allocate & commit whole file if fixed image, it must be more
     179     * effective than expanding file by write operations. */
     180    rc = RTFileSetSize(File, cbSize);
     181    if (VBOX_FAILURE(rc))
     182    {
     183        rc = rawError(pImage, rc, RT_SRC_POS, N_("Raw: setting image size failed for '%s'"), pImage->pszFilename);
     184        goto out;
     185    }
     186
     187    /* Fill image with zeroes. We do this for every fixed-size image since on
     188     * some systems (for example Windows Vista), it takes ages to write a block
     189     * near the end of a sparse file and the guest could complain about an ATA
     190     * timeout. */
     191    pvBuf = RTMemTmpAllocZ(cbBuf);
     192    if (!pvBuf)
     193    {
     194        rc = VERR_NO_MEMORY;
     195        goto out;
     196    }
     197
     198    uOff = 0;
     199    /* Write data to all image blocks. */
     200    while (uOff < cbSize)
     201    {
     202        unsigned cbChunk = (unsigned)RT_MIN(cbSize, cbBuf);
     203
     204        rc = RTFileWriteAt(File, uOff, pvBuf, cbChunk, NULL);
    1997205        if (VBOX_FAILURE(rc))
    1998             goto out;
    1999         /* The opened file is passed to the extent. No separate descriptor
    2000          * file, so no need to keep anything open for the image. */
    2001         pExtent = &pImage->pExtents[0];
    2002         pExtent->File = File;
    2003         pImage->File = NIL_RTFILE;
    2004         rc = vmdkReadMetaSparseExtent(pExtent);
    2005         if (VBOX_FAILURE(rc))
    2006             goto out;
    2007         /* As we're dealing with a monolithic sparse image here, there must
    2008          * be a descriptor embedded in the image file. */
    2009         if (!pExtent->uDescriptorSector || !pExtent->cDescriptorSectors)
    2010206        {
    2011             rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in '%s'"), pImage->pszFilename);
     207            rc = rawError(pImage, rc, RT_SRC_POS, N_("Raw: writing block failed for '%s'"), pImage->pszFilename);
    2012208            goto out;
    2013209        }
    2014         /* Read the descriptor from the extent. */
    2015         pExtent->pDescData = (char *)RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
    2016         if (!pExtent->pDescData)
     210
     211        uOff += cbChunk;
     212
     213        if (pfnProgress)
    2017214        {
    2018             rc = VERR_NO_MEMORY;
    2019             goto out;
     215            rc = pfnProgress(NULL /* WARNING! pVM=NULL  */,
     216                             uPercentStart + uOff * uPercentSpan * 98 / (cbSize * 100),
     217                             pvUser);
     218            if (VBOX_FAILURE(rc))
     219                goto out;
    2020220        }
    2021         rc = RTFileReadAt(pExtent->File,
    2022                           VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
    2023                           pExtent->pDescData,
    2024                           VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
    2025         AssertRC(rc);
    2026         if (VBOX_FAILURE(rc))
    2027         {
    2028             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pExtent->pszFullname);
    2029             goto out;
    2030         }
    2031 
    2032         rc = vmdkParseDescriptor(pImage, pExtent->pDescData,
    2033                                  VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
    2034         if (VBOX_FAILURE(rc))
    2035             goto out;
    2036 
    2037         /* Mark the extent as unclean if opened in read-write mode. */
    2038         if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
    2039         {
    2040             pExtent->fUncleanShutdown = true;
    2041             pExtent->fMetaDirty = true;
    2042         }
    2043     }
    2044     else
    2045     {
    2046         pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
    2047         pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
    2048         if (!pImage->pDescData)
    2049         {
    2050             rc = VERR_NO_MEMORY;
    2051             goto out;
    2052         }
    2053 
    2054         size_t cbRead;
    2055         rc = RTFileReadAt(pImage->File, 0, pImage->pDescData,
    2056                           pImage->cbDescAlloc, &cbRead);
    2057         if (VBOX_FAILURE(rc))
    2058         {
    2059             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pImage->pszFilename);
    2060             goto out;
    2061         }
    2062         if (cbRead == pImage->cbDescAlloc)
    2063         {
    2064             /* Likely the read is truncated. Better fail a bit too early
    2065              * (normally the descriptor is much smaller than our buffer). */
    2066             rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in '%s'"), pImage->pszFilename);
    2067             goto out;
    2068         }
    2069 
    2070         rc = vmdkParseDescriptor(pImage, pImage->pDescData,
    2071                                  pImage->cbDescAlloc);
    2072         if (VBOX_FAILURE(rc))
    2073             goto out;
    2074 
    2075         for (unsigned i = 0; i < pImage->cExtents; i++)
    2076         {
    2077             PVMDKEXTENT pExtent = &pImage->pExtents[i];
    2078 
    2079             if (pExtent->pszBasename)
    2080             {
    2081                 /* Hack to figure out whether the specified name in the
    2082                  * extent descriptor is absolute. Doesn't always work, but
    2083                  * should be good enough for now. */
    2084                 char *pszFullname;
    2085                 /** @todo implement proper path absolute check. */
    2086                 if (pExtent->pszBasename[0] == RTPATH_SLASH)
    2087                 {
    2088                     pszFullname = RTStrDup(pExtent->pszBasename);
    2089                     if (!pszFullname)
    2090                     {
    2091                         rc = VERR_NO_MEMORY;
    2092                         goto out;
    2093                     }
    2094                 }
    2095                 else
    2096                 {
    2097                     size_t cbDirname;
    2098                     char *pszDirname = RTStrDup(pImage->pszFilename);
    2099                     if (!pszDirname)
    2100                     {
    2101                         rc = VERR_NO_MEMORY;
    2102                         goto out;
    2103                     }
    2104                     RTPathStripFilename(pszDirname);
    2105                     cbDirname = strlen(pszDirname);
    2106                     rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
    2107                                       RTPATH_SLASH, pExtent->pszBasename);
    2108                     RTStrFree(pszDirname);
    2109                     if (VBOX_FAILURE(rc))
    2110                         goto out;
    2111                 }
    2112                 pExtent->pszFullname = pszFullname;
    2113             }
    2114             else
    2115                 pExtent->pszFullname = NULL;
    2116 
    2117             switch (pExtent->enmType)
    2118             {
    2119                 case VMDKETYPE_HOSTED_SPARSE:
    2120                     rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2121                                     uOpenFlags & VD_OPEN_FLAGS_READONLY
    2122                                       ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
    2123                                       : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2124                     if (VBOX_FAILURE(rc))
    2125                     {
    2126                         /* Do NOT signal an appropriate error here, as the VD
    2127                          * layer has the choice of retrying the open if it
    2128                          * failed. */
    2129                         goto out;
    2130                     }
    2131                     rc = vmdkReadMetaSparseExtent(pExtent);
    2132                     if (VBOX_FAILURE(rc))
    2133                         goto out;
    2134 
    2135                     /* Mark extent as unclean if opened in read-write mode. */
    2136                     if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
    2137                     {
    2138                         pExtent->fUncleanShutdown = true;
    2139                         pExtent->fMetaDirty = true;
    2140                     }
    2141                     break;
    2142                 case VMDKETYPE_FLAT:
    2143                     rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2144                                     uOpenFlags & VD_OPEN_FLAGS_READONLY
    2145                                       ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
    2146                                       : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2147                     if (VBOX_FAILURE(rc))
    2148                     {
    2149                         /* Do NOT signal an appropriate error here, as the VD
    2150                          * layer has the choice of retrying the open if it
    2151                          * failed. */
    2152                         goto out;
    2153                     }
    2154                     break;
    2155                 case VMDKETYPE_ZERO:
    2156                     /* Nothing to do. */
    2157                     break;
    2158                 default:
    2159                     AssertMsgFailed(("unknown vmdk extent type %d\n", pExtent->enmType));
    2160             }
    2161         }
    2162     }
    2163 
    2164     /* Make sure this is not reached accidentally with an error status. */
    2165     AssertRC(rc);
    2166 
    2167     /* Determine PCHS geometry if not set. */
    2168     if (pImage->PCHSGeometry.cCylinders == 0)
    2169     {
    2170         uint64_t cCylinders =   VMDK_BYTE2SECTOR(pImage->cbSize)
    2171                               / pImage->PCHSGeometry.cHeads
    2172                               / pImage->PCHSGeometry.cSectors;
    2173         pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
    2174         if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    2175         {
    2176             rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
    2177             AssertRC(rc);
    2178         }
    2179     }
    2180 
    2181     /* Update the image metadata now in case has changed. */
    2182     rc = vmdkFlushImage(pImage);
    2183     if (VBOX_FAILURE(rc))
    2184         goto out;
    2185 
    2186     /* Figure out a few per-image constants from the extents. */
    2187     pImage->cbSize = 0;
    2188     for (unsigned i = 0; i < pImage->cExtents; i++)
    2189     {
    2190         pExtent = &pImage->pExtents[i];
    2191         if (    pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
    2192 #ifdef VBOX_WITH_VMDK_ESX
    2193             ||  pExtent->enmType == VMDKETYPE_ESX_SPARSE
    2194 #endif /* VBOX_WITH_VMDK_ESX */
    2195            )
    2196         {
    2197             /* Here used to be a check whether the nominal size of an extent
    2198              * is a multiple of the grain size. The spec says that this is
    2199              * always the case, but unfortunately some files out there in the
    2200              * wild violate the spec (e.g. ReactOS 0.3.1). */
    2201         }
    2202         pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
    2203     }
    2204 
    2205     pImage->enmImageType = VD_IMAGE_TYPE_NORMAL;
    2206     for (unsigned i = 0; i < pImage->cExtents; i++)
    2207     {
    2208         pExtent = &pImage->pExtents[i];
    2209         if (    pImage->pExtents[i].enmType == VMDKETYPE_FLAT
    2210             ||  pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
    2211         {
    2212             pImage->enmImageType = VD_IMAGE_TYPE_FIXED;
    2213             break;
    2214         }
    2215     }
    2216 
    2217     rc = vmdkAllocateGrainTableCache(pImage);
    2218     if (VBOX_FAILURE(rc))
    2219         goto out;
    2220 
    2221 out:
    2222     if (VBOX_FAILURE(rc))
    2223         vmdkFreeImage(pImage, false);
    2224     return rc;
    2225 }
    2226 
    2227 /**
    2228  * Internal: create VMDK images for raw disk/partition access.
    2229  */
    2230 static int vmdkCreateRawImage(PVMDKIMAGE pImage, const PVBOXHDDRAW pRaw,
    2231                               uint64_t cbSize)
    2232 {
    2233     int rc = VINF_SUCCESS;
    2234     PVMDKEXTENT pExtent;
    2235 
    2236     if (pRaw->fRawDisk)
    2237     {
    2238         /* Full raw disk access. This requires setting up a descriptor
    2239          * file and open the (flat) raw disk. */
    2240         rc = vmdkCreateExtents(pImage, 1);
    2241         if (VBOX_FAILURE(rc))
    2242             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    2243         pExtent = &pImage->pExtents[0];
    2244         /* Create raw disk descriptor file. */
    2245         rc = RTFileOpen(&pImage->File, pImage->pszFilename,
    2246                         RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
    2247         if (VBOX_FAILURE(rc))
    2248             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
    2249 
    2250         /* Set up basename for extent description. Cannot use StrDup. */
    2251         size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
    2252         char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2253         if (!pszBasename)
    2254             return VERR_NO_MEMORY;
    2255         memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
    2256         pExtent->pszBasename = pszBasename;
    2257         /* For raw disks the full name is identical to the base name. */
    2258         pExtent->pszFullname = RTStrDup(pszBasename);
    2259         if (!pExtent->pszFullname)
    2260             return VERR_NO_MEMORY;
    2261         pExtent->enmType = VMDKETYPE_FLAT;
    2262         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
    2263         pExtent->uSectorOffset = 0;
    2264         pExtent->enmAccess = VMDKACCESS_READWRITE;
    2265         pExtent->fMetaDirty = false;
    2266 
    2267         /* Open flat image, the raw disk. */
    2268         rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2269                         RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2270         if (VBOX_FAILURE(rc))
    2271             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
    2272     }
    2273     else
    2274     {
    2275         /* Raw partition access. This requires setting up a descriptor
    2276          * file, write the partition information to a flat extent and
    2277          * open all the (flat) raw disk partitions. */
    2278 
    2279         /* First pass over the partitions to determine how many
    2280          * extents we need. One partition can require up to 4 extents.
    2281          * One to skip over unpartitioned space, one for the
    2282          * partitioning data, one to skip over unpartitioned space
    2283          * and one for the partition data. */
    2284         unsigned cExtents = 0;
    2285         uint64_t uStart = 0;
    2286         for (unsigned i = 0; i < pRaw->cPartitions; i++)
    2287         {
    2288             PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
    2289             if (pPart->cbPartitionData)
    2290             {
    2291                 if (uStart > pPart->uPartitionDataStart)
    2292                     return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pImage->pszFilename);
    2293                 else if (uStart != pPart->uPartitionDataStart)
    2294                     cExtents++;
    2295                 uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
    2296                 cExtents++;
    2297             }
    2298             if (pPart->cbPartition)
    2299             {
    2300                 if (uStart > pPart->uPartitionStart)
    2301                     return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pImage->pszFilename);
    2302                 else if (uStart != pPart->uPartitionStart)
    2303                     cExtents++;
    2304                 uStart = pPart->uPartitionStart + pPart->cbPartition;
    2305                 cExtents++;
    2306             }
    2307         }
    2308         /* Another extent for filling up the rest of the image. */
    2309         if (uStart != cbSize)
    2310             cExtents++;
    2311 
    2312         rc = vmdkCreateExtents(pImage, cExtents);
    2313         if (VBOX_FAILURE(rc))
    2314             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    2315 
    2316         /* Create raw partition descriptor file. */
    2317         rc = RTFileOpen(&pImage->File, pImage->pszFilename,
    2318                         RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
    2319         if (VBOX_FAILURE(rc))
    2320             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
    2321 
    2322         /* Create base filename for the partition table extent. */
    2323         /** @todo remove fixed buffer without creating memory leaks. */
    2324         char pszPartition[1024];
    2325         const char *pszBase = RTPathFilename(pImage->pszFilename);
    2326         const char *pszExt = RTPathExt(pszBase);
    2327         if (pszExt == NULL)
    2328             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pImage->pszFilename);
    2329         char *pszBaseBase = RTStrDup(pszBase);
    2330         if (!pszBaseBase)
    2331             return VERR_NO_MEMORY;
    2332         RTPathStripExt(pszBaseBase);
    2333         RTStrPrintf(pszPartition, sizeof(pszPartition), "%s-pt%s",
    2334                     pszBaseBase, pszExt);
    2335         RTStrFree(pszBaseBase);
    2336 
    2337         /* Second pass over the partitions, now define all extents. */
    2338         uint64_t uPartOffset = 0;
    2339         cExtents = 0;
    2340         uStart = 0;
    2341         for (unsigned i = 0; i < pRaw->cPartitions; i++)
    2342         {
    2343             PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
    2344             if (pPart->cbPartitionData)
    2345             {
    2346                 if (uStart != pPart->uPartitionDataStart)
    2347                 {
    2348                     pExtent = &pImage->pExtents[cExtents++];
    2349                     pExtent->pszBasename = NULL;
    2350                     pExtent->pszFullname = NULL;
    2351                     pExtent->enmType = VMDKETYPE_ZERO;
    2352                     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart);
    2353                     pExtent->uSectorOffset = 0;
    2354                     pExtent->enmAccess = VMDKACCESS_READWRITE;
    2355                     pExtent->fMetaDirty = false;
    2356                 }
    2357                 uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
    2358                 pExtent = &pImage->pExtents[cExtents++];
    2359                 /* Set up basename for extent description. Can't use StrDup. */
    2360                 size_t cbBasename = strlen(pszPartition) + 1;
    2361                 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2362                 if (!pszBasename)
    2363                     return VERR_NO_MEMORY;
    2364                 memcpy(pszBasename, pszPartition, cbBasename);
    2365                 pExtent->pszBasename = pszBasename;
    2366 
    2367                 /* Set up full name for partition extent. */
    2368                 size_t cbDirname;
    2369                 char *pszDirname = RTStrDup(pImage->pszFilename);
    2370                 if (!pszDirname)
    2371                     return VERR_NO_MEMORY;
    2372                 RTPathStripFilename(pszDirname);
    2373                 cbDirname = strlen(pszDirname);
    2374                 char *pszFullname;
    2375                 rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
    2376                                   RTPATH_SLASH, pExtent->pszBasename);
    2377                 RTStrFree(pszDirname);
    2378                 if (VBOX_FAILURE(rc))
    2379                     return rc;
    2380                 pExtent->pszFullname = pszFullname;
    2381                 pExtent->enmType = VMDKETYPE_FLAT;
    2382                 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData);
    2383                 pExtent->uSectorOffset = uPartOffset;
    2384                 pExtent->enmAccess = VMDKACCESS_READWRITE;
    2385                 pExtent->fMetaDirty = false;
    2386 
    2387                 /* Create partition table flat image. */
    2388                 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2389                                 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
    2390                 if (VBOX_FAILURE(rc))
    2391                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
    2392                 rc = RTFileWriteAt(pExtent->File,
    2393                                    VMDK_SECTOR2BYTE(uPartOffset),
    2394                                    pPart->pvPartitionData,
    2395                                    pPart->cbPartitionData, NULL);
    2396                 if (VBOX_FAILURE(rc))
    2397                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
    2398                 uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData);
    2399             }
    2400             if (pPart->cbPartition)
    2401             {
    2402                 if (uStart != pPart->uPartitionStart)
    2403                 {
    2404                     pExtent = &pImage->pExtents[cExtents++];
    2405                     pExtent->pszBasename = NULL;
    2406                     pExtent->pszFullname = NULL;
    2407                     pExtent->enmType = VMDKETYPE_ZERO;
    2408                     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart);
    2409                     pExtent->uSectorOffset = 0;
    2410                     pExtent->enmAccess = VMDKACCESS_READWRITE;
    2411                     pExtent->fMetaDirty = false;
    2412                 }
    2413                 uStart = pPart->uPartitionStart + pPart->cbPartition;
    2414                 pExtent = &pImage->pExtents[cExtents++];
    2415                 if (pPart->pszRawDevice)
    2416                 {
    2417                     /* Set up basename for extent descr. Can't use StrDup. */
    2418                     size_t cbBasename = strlen(pPart->pszRawDevice) + 1;
    2419                     char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2420                     if (!pszBasename)
    2421                         return VERR_NO_MEMORY;
    2422                     memcpy(pszBasename, pPart->pszRawDevice, cbBasename);
    2423                     pExtent->pszBasename = pszBasename;
    2424                     /* For raw disks full name is identical to base name. */
    2425                     pExtent->pszFullname = RTStrDup(pszBasename);
    2426                     if (!pExtent->pszFullname)
    2427                         return VERR_NO_MEMORY;
    2428                     pExtent->enmType = VMDKETYPE_FLAT;
    2429                     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
    2430                     pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset);
    2431                     pExtent->enmAccess = VMDKACCESS_READWRITE;
    2432                     pExtent->fMetaDirty = false;
    2433 
    2434                     /* Open flat image, the raw partition. */
    2435                     rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2436                                     RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2437                     if (VBOX_FAILURE(rc))
    2438                         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
    2439                 }
    2440                 else
    2441                 {
    2442                     pExtent->pszBasename = NULL;
    2443                     pExtent->pszFullname = NULL;
    2444                     pExtent->enmType = VMDKETYPE_ZERO;
    2445                     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
    2446                     pExtent->uSectorOffset = 0;
    2447                     pExtent->enmAccess = VMDKACCESS_READWRITE;
    2448                     pExtent->fMetaDirty = false;
    2449                 }
    2450             }
    2451         }
    2452         /* Another extent for filling up the rest of the image. */
    2453         if (uStart != cbSize)
    2454         {
    2455             pExtent = &pImage->pExtents[cExtents++];
    2456             pExtent->pszBasename = NULL;
    2457             pExtent->pszFullname = NULL;
    2458             pExtent->enmType = VMDKETYPE_ZERO;
    2459             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart);
    2460             pExtent->uSectorOffset = 0;
    2461             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2462             pExtent->fMetaDirty = false;
    2463         }
    2464     }
    2465 
    2466     rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    2467                             pRaw->fRawDisk ?
    2468                             "fullDevice" : "partitionedDevice");
    2469     if (VBOX_FAILURE(rc))
    2470         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
    2471     return rc;
    2472 }
    2473 
    2474 /**
    2475  * Internal: create a regular (i.e. file-backed) VMDK image.
    2476  */
    2477 static int vmdkCreateRegularImage(PVMDKIMAGE pImage, VDIMAGETYPE enmType,
    2478                                   uint64_t cbSize, unsigned uImageFlags,
    2479                                   PFNVMPROGRESS pfnProgress, void *pvUser,
    2480                                   unsigned uPercentStart, unsigned uPercentSpan)
    2481 {
    2482     int rc = VINF_SUCCESS;
    2483     unsigned cExtents = 1;
    2484     uint64_t cbOffset = 0;
    2485     uint64_t cbRemaining = cbSize;
    2486 
    2487     if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
    2488     {
    2489         cExtents = cbSize / VMDK_2G_SPLIT_SIZE;
    2490         /* Do proper extent computation: need one smaller extent if the total
    2491          * size isn't evenly divisible by the split size. */
    2492         if (cbSize % VMDK_2G_SPLIT_SIZE)
    2493             cExtents++;
    2494     }
    2495     rc = vmdkCreateExtents(pImage, cExtents);
    2496     if (VBOX_FAILURE(rc))
    2497         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
    2498 
    2499     /* Basename strings needed for constructing the extent names. */
    2500     char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
    2501     Assert(pszBasenameSubstr);
    2502     size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    2503 
    2504     /* Create searate descriptor file if necessary. */
    2505     if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED)
    2506     {
    2507         rc = RTFileOpen(&pImage->File, pImage->pszFilename,
    2508                         RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
    2509         if (VBOX_FAILURE(rc))
    2510             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename);
    2511         pImage->pszFilename = RTStrDup(pImage->pszFilename);
    2512     }
    2513     else
    2514         pImage->File = NIL_RTFILE;
    2515 
    2516     /* Set up all extents. */
    2517     for (unsigned i = 0; i < cExtents; i++)
    2518     {
    2519         PVMDKEXTENT pExtent = &pImage->pExtents[i];
    2520         uint64_t cbExtent = cbRemaining;
    2521 
    2522         /* Set up fullname/basename for extent description. Cannot use StrDup
    2523          * for basename, as it is not guaranteed that the memory can be freed
    2524          * with RTMemTmpFree, which must be used as in other code paths
    2525          * StrDup is not usable. */
    2526         if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED)
    2527         {
    2528             char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
    2529             if (!pszBasename)
    2530                 return VERR_NO_MEMORY;
    2531             memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    2532             pExtent->pszBasename = pszBasename;
    2533         }
    2534         else
    2535         {
    2536             char *pszBasenameExt = RTPathExt(pszBasenameSubstr);
    2537             char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
    2538             RTPathStripExt(pszBasenameBase);
    2539             char *pszTmp;
    2540             size_t cbTmp;
    2541             if (enmType == VD_IMAGE_TYPE_FIXED)
    2542             {
    2543                 if (cExtents == 1)
    2544                     rc = RTStrAPrintf(&pszTmp, "%s-flat%s", pszBasenameBase,
    2545                                       pszBasenameExt);
    2546                 else
    2547                     rc = RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
    2548                                       i+1, pszBasenameExt);
    2549             }
    2550             else
    2551                 rc = RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, i+1,
    2552                                   pszBasenameExt);
    2553             RTStrFree(pszBasenameBase);
    2554             if (VBOX_FAILURE(rc))
    2555                 return rc;
    2556             cbTmp = strlen(pszTmp) + 1;
    2557             char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
    2558             if (!pszBasename)
    2559                 return VERR_NO_MEMORY;
    2560             memcpy(pszBasename, pszTmp, cbTmp);
    2561             RTStrFree(pszTmp);
    2562             pExtent->pszBasename = pszBasename;
    2563             cbExtent = RT_MIN(cbRemaining, VMDK_2G_SPLIT_SIZE);
    2564         }
    2565         char *pszBasedirectory = RTStrDup(pImage->pszFilename);
    2566         RTPathStripFilename(pszBasedirectory);
    2567         char *pszFN;
    2568         rc = RTStrAPrintf(&pszFN, "%s%c%s", pszBasedirectory, RTPATH_SLASH,
    2569                           pExtent->pszBasename);
    2570         RTStrFree(pszBasedirectory);
    2571         if (VBOX_FAILURE(rc))
    2572             return rc;
    2573         pExtent->pszFullname = pszFN;
    2574 
    2575         /* Create file for extent. */
    2576         rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2577                         RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
    2578         if (VBOX_FAILURE(rc))
    2579             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
    2580         if (enmType == VD_IMAGE_TYPE_FIXED)
    2581         {
    2582             rc = RTFileSetSize(pExtent->File, cbExtent);
    2583             if (VBOX_FAILURE(rc))
    2584                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    2585         }
    2586 
    2587         /* Place descriptor file information (where integrated). */
    2588         if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED)
    2589         {
    2590             pExtent->uDescriptorSector = 1;
    2591             pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
    2592             /* The descriptor is part of the (only) extent. */
    2593             pExtent->pDescData = pImage->pDescData;
    2594             pImage->pDescData = NULL;
    2595         }
    2596 
    2597         if (enmType == VD_IMAGE_TYPE_NORMAL)
    2598         {
    2599             uint64_t cSectorsPerGDE, cSectorsPerGD;
    2600             pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
    2601             pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbExtent, 65536));
    2602             pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
    2603             pExtent->cGTEntries = 512;
    2604             cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    2605             pExtent->cSectorsPerGDE = cSectorsPerGDE;
    2606             pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    2607             cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
    2608         }
    2609         else
    2610             pExtent->enmType = VMDKETYPE_FLAT;
    2611 
    2612         pExtent->enmAccess = VMDKACCESS_READWRITE;
    2613         pExtent->fUncleanShutdown = true;
    2614         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbExtent);
    2615         pExtent->uSectorOffset = VMDK_BYTE2SECTOR(cbOffset);
    2616         pExtent->fMetaDirty = true;
    2617 
    2618         if (enmType == VD_IMAGE_TYPE_NORMAL)
    2619         {
    2620             rc = vmdkCreateGrainDirectory(pExtent,
    2621                                             pExtent->uDescriptorSector
    2622                                           + pExtent->cDescriptorSectors,
    2623                                           true);
    2624             if (VBOX_FAILURE(rc))
    2625                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
    2626         }
    2627 
    2628         if (VBOX_SUCCESS(rc) && pfnProgress)
    2629             pfnProgress(NULL /* WARNING! pVM=NULL  */,
    2630                         uPercentStart + i * uPercentSpan / cExtents,
    2631                         pvUser);
    2632 
    2633         cbRemaining -= cbExtent;
    2634         cbOffset += cbExtent;
    2635     }
    2636 
    2637     const char *pszDescType = NULL;
    2638     if (enmType == VD_IMAGE_TYPE_FIXED)
    2639     {
    2640         pszDescType =   (cExtents == 1)
    2641                       ? "monolithicFlat" : "twoGbMaxExtentFlat";
    2642     }
    2643     else if (enmType == VD_IMAGE_TYPE_NORMAL)
    2644     {
    2645         pszDescType =   (cExtents == 1)
    2646                       ? "monolithicSparse" : "twoGbMaxExtentSparse";
    2647     }
    2648     else
    2649         AssertMsgFailed(("invalid image type %d\n", enmType));
    2650     rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
    2651                             pszDescType);
    2652     if (VBOX_FAILURE(rc))
    2653         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
    2654     return rc;
    2655 }
    2656 
    2657 /**
    2658  * Internal: The actual code for creating any VMDK variant currently in
    2659  * existence on hosted environments.
    2660  */
    2661 static int vmdkCreateImage(PVMDKIMAGE pImage, VDIMAGETYPE enmType,
    2662                            uint64_t cbSize, unsigned uImageFlags,
    2663                            const char *pszComment,
    2664                            PCPDMMEDIAGEOMETRY pPCHSGeometry,
    2665                            PCPDMMEDIAGEOMETRY pLCHSGeometry,
    2666                            PFNVMPROGRESS pfnProgress, void *pvUser,
    2667                            unsigned uPercentStart, unsigned uPercentSpan)
    2668 {
    2669     int rc;
    2670 
    2671     pImage->uImageFlags = uImageFlags;
    2672     rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
    2673                               &pImage->Descriptor);
    2674     if (VBOX_FAILURE(rc))
    2675     {
    2676         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
    2677         goto out;
    2678     }
    2679 
    2680     if (    enmType == VD_IMAGE_TYPE_FIXED
    2681         &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
    2682     {
    2683         /* Raw disk image (includes raw partition). */
    2684         const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
    2685         /* As the comment is misused, zap it so that no garbage comment
    2686          * is set below. */
    2687         pszComment = NULL;
    2688         rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
    2689     }
    2690     else if (   enmType == VD_IMAGE_TYPE_FIXED
    2691              || enmType == VD_IMAGE_TYPE_NORMAL)
    2692     {
    2693         /* Regular fixed or sparse image (monolithic or split). */
    2694         rc = vmdkCreateRegularImage(pImage, enmType, cbSize, uImageFlags,
    2695                                     pfnProgress, pvUser, uPercentStart,
    2696                                     uPercentSpan * 95 / 100);
    2697     }
    2698     else
    2699     {
    2700         /* Unknown/invalid image type. */
    2701         rc = VERR_NOT_IMPLEMENTED;
    2702     }
    2703 
    2704     if (VBOX_FAILURE(rc))
    2705         goto out;
     221    }
     222    RTMemTmpFree(pvBuf);
    2706223
    2707224    if (VBOX_SUCCESS(rc) && pfnProgress)
     
    2712229    pImage->cbSize = cbSize;
    2713230
    2714     for (unsigned i = 0; i < pImage->cExtents; i++)
    2715     {
    2716         PVMDKEXTENT pExtent = &pImage->pExtents[i];
    2717 
    2718         rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
    2719                                pExtent->cNominalSectors, pExtent->enmType,
    2720                                pExtent->pszBasename, pExtent->uSectorOffset);
    2721         if (VBOX_FAILURE(rc))
    2722         {
    2723             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
    2724             goto out;
    2725         }
    2726     }
    2727     vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
    2728 
    2729     if (    pPCHSGeometry->cCylinders == 0
    2730         ||  pPCHSGeometry->cHeads == 0
    2731         ||  pPCHSGeometry->cSectors == 0)
    2732     {
    2733         rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    2734         if (VBOX_FAILURE(rc))
    2735             goto out;
    2736     }
    2737     if (    pLCHSGeometry->cCylinders == 0
    2738         ||  pLCHSGeometry->cHeads == 0
    2739         ||  pLCHSGeometry->cSectors == 0)
    2740     {
    2741         rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    2742         if (VBOX_FAILURE(rc))
    2743             goto out;
    2744     }
    2745 
    2746     pImage->LCHSGeometry = *pLCHSGeometry;
    2747     pImage->PCHSGeometry = *pPCHSGeometry;
    2748 
    2749     rc = RTUuidCreate(&pImage->ImageUuid);
    2750     if (VBOX_FAILURE(rc))
    2751         goto out;
    2752     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    2753                             VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
    2754     if (VBOX_FAILURE(rc))
    2755     {
    2756         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
    2757         goto out;
    2758     }
    2759     RTUuidClear(&pImage->ParentUuid);
    2760     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    2761                             VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
    2762     if (VBOX_FAILURE(rc))
    2763     {
    2764         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
    2765         goto out;
    2766     }
    2767     RTUuidClear(&pImage->ModificationUuid);
    2768     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    2769                             VMDK_DDB_MODIFICATION_UUID,
    2770                             &pImage->ModificationUuid);
    2771     if (VBOX_FAILURE(rc))
    2772     {
    2773         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
    2774         goto out;
    2775     }
    2776     RTUuidClear(&pImage->ParentModificationUuid);
    2777     rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    2778                             VMDK_DDB_PARENT_MODIFICATION_UUID,
    2779                             &pImage->ParentModificationUuid);
    2780     if (VBOX_FAILURE(rc))
    2781     {
    2782         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
    2783         goto out;
    2784     }
    2785 
    2786     rc = vmdkAllocateGrainTableCache(pImage);
    2787     if (VBOX_FAILURE(rc))
    2788         goto out;
    2789 
    2790     rc = vmdkSetImageComment(pImage, pszComment);
    2791     if (VBOX_FAILURE(rc))
    2792     {
    2793         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
    2794         goto out;
    2795     }
    2796 
    2797     if (VBOX_SUCCESS(rc) && pfnProgress)
    2798         pfnProgress(NULL /* WARNING! pVM=NULL  */,
    2799                     uPercentStart + uPercentSpan * 99 / 100, pvUser);
    2800 
    2801     rc = vmdkFlushImage(pImage);
     231    rc = rawFlushImage(pImage);
    2802232
    2803233out:
     
    2807237
    2808238    if (VBOX_FAILURE(rc))
    2809         vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
    2810     return rc;
    2811 }
    2812 
    2813 /**
    2814  * Internal: Update image comment.
    2815  */
    2816 static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment)
    2817 {
    2818     char *pszCommentEncoded;
    2819     if (pszComment)
    2820     {
    2821         pszCommentEncoded = vmdkEncodeString(pszComment);
    2822         if (!pszCommentEncoded)
    2823             return VERR_NO_MEMORY;
    2824     }
    2825     else
    2826         pszCommentEncoded = NULL;
    2827     int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
    2828                           "ddb.comment", pszCommentEncoded);
    2829     if (pszComment)
    2830         RTStrFree(pszCommentEncoded);
    2831     if (VBOX_FAILURE(rc))
    2832         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image comment in descriptor in '%s'"), pImage->pszFilename);
    2833     return VINF_SUCCESS;
     239        rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
     240    return rc;
    2834241}
    2835242
     
    2838245 * delete the image from disk.
    2839246 */
    2840 static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete)
     247static void rawFreeImage(PRAWIMAGE pImage, bool fDelete)
    2841248{
    2842249    Assert(pImage);
     
    2845252    {
    2846253        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    2847         {
    2848             /* Mark all extents as clean. */
    2849             for (unsigned i = 0; i < pImage->cExtents; i++)
    2850             {
    2851                 if ((   pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
    2852 #ifdef VBOX_WITH_VMDK_ESX
    2853                      || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
    2854 #endif /* VBOX_WITH_VMDK_ESX */
    2855                     )
    2856                     &&  pImage->pExtents[i].fUncleanShutdown)
    2857                 {
    2858                     pImage->pExtents[i].fUncleanShutdown = false;
    2859                     pImage->pExtents[i].fMetaDirty = true;
    2860                 }
    2861             }
    2862         }
    2863         (void)vmdkFlushImage(pImage);
    2864     }
    2865     if (pImage->pExtents != NULL)
    2866     {
    2867         for (unsigned i = 0 ; i < pImage->cExtents; i++)
    2868             vmdkFreeExtentData(&pImage->pExtents[i], fDelete);
    2869         RTMemFree(pImage->pExtents);
    2870         pImage->pExtents = NULL;
     254            rawFlushImage(pImage);
    2871255    }
    2872256    if (pImage->File != NIL_RTFILE)
     
    2880264
    2881265/**
    2882  * Internal. Flush image data (and metadata) to disk.
     266 * Internal. Flush image data to disk.
    2883267 */
    2884 static int vmdkFlushImage(PVMDKIMAGE pImage)
    2885 {
    2886     PVMDKEXTENT pExtent;
     268static int rawFlushImage(PRAWIMAGE pImage)
     269{
    2887270    int rc = VINF_SUCCESS;
    2888271
    2889     /* Update descriptor if changed. */
    2890     if (pImage->Descriptor.fDirty)
    2891     {
    2892         rc = vmdkWriteDescriptor(pImage);
    2893         if (VBOX_FAILURE(rc))
    2894             goto out;
    2895     }
    2896 
    2897     for (unsigned i = 0; i < pImage->cExtents; i++)
    2898     {
    2899         pExtent = &pImage->pExtents[i];
    2900         if (pExtent->File != NIL_RTFILE && pExtent->fMetaDirty)
    2901         {
    2902             switch (pExtent->enmType)
    2903             {
    2904                 case VMDKETYPE_HOSTED_SPARSE:
    2905                     rc = vmdkWriteMetaSparseExtent(pExtent);
    2906                     if (VBOX_FAILURE(rc))
    2907                         goto out;
    2908                     break;
    2909 #ifdef VBOX_WITH_VMDK_ESX
    2910                 case VMDKETYPE_ESX_SPARSE:
    2911                     /** @todo update the header. */
    2912                     break;
    2913 #endif /* VBOX_WITH_VMDK_ESX */
    2914                 case VMDKETYPE_FLAT:
    2915                     /* Nothing to do. */
    2916                     break;
    2917                 case VMDKETYPE_ZERO:
    2918                 default:
    2919                     AssertMsgFailed(("extent with type %d marked as dirty\n",
    2920                                      pExtent->enmType));
    2921                     break;
    2922             }
    2923         }
    2924         switch (pExtent->enmType)
    2925         {
    2926             case VMDKETYPE_HOSTED_SPARSE:
    2927 #ifdef VBOX_WITH_VMDK_ESX
    2928             case VMDKETYPE_ESX_SPARSE:
    2929 #endif /* VBOX_WITH_VMDK_ESX */
    2930             case VMDKETYPE_FLAT:
    2931                 /** @todo implement proper path absolute check. */
    2932                 if (   pExtent->File != NIL_RTFILE
    2933                     && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    2934                     && !(pExtent->pszBasename[0] == RTPATH_SLASH))
    2935                     rc = RTFileFlush(pExtent->File);
    2936                 break;
    2937             case VMDKETYPE_ZERO:
    2938                 /* No need to do anything for this extent. */
    2939                 break;
    2940             default:
    2941                 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
    2942                 break;
    2943         }
    2944     }
    2945 
    2946 out:
    2947     return rc;
    2948 }
    2949 
    2950 /**
    2951  * Internal. Find extent corresponding to the sector number in the disk.
    2952  */
    2953 static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector,
    2954                           PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
    2955 {
    2956     PVMDKEXTENT pExtent = NULL;
    2957     int rc = VINF_SUCCESS;
    2958 
    2959     for (unsigned i = 0; i < pImage->cExtents; i++)
    2960     {
    2961         if (offSector < pImage->pExtents[i].cNominalSectors)
    2962         {
    2963             pExtent = &pImage->pExtents[i];
    2964             *puSectorInExtent = offSector + pImage->pExtents[i].uSectorOffset;
    2965             break;
    2966         }
    2967         offSector -= pImage->pExtents[i].cNominalSectors;
    2968     }
    2969 
    2970     if (pExtent)
    2971         *ppExtent = pExtent;
    2972     else
    2973         rc = VERR_IO_SECTOR_NOT_FOUND;
    2974 
    2975     return rc;
    2976 }
    2977 
    2978 /**
    2979  * Internal. Hash function for placing the grain table hash entries.
    2980  */
    2981 static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector,
    2982                                 unsigned uExtent)
    2983 {
    2984     /** @todo this hash function is quite simple, maybe use a better one which
    2985      * scrambles the bits better. */
    2986     return (uSector + uExtent) % pCache->cEntries;
    2987 }
    2988 
    2989 /**
    2990  * Internal. Get sector number in the extent file from the relative sector
    2991  * number in the extent.
    2992  */
    2993 static int vmdkGetSector(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
    2994                          uint64_t uSector, uint64_t *puExtentSector)
    2995 {
    2996     uint64_t uGDIndex, uGTSector, uGTBlock;
    2997     uint32_t uGTHash, uGTBlockIndex;
    2998     PVMDKGTCACHEENTRY pGTCacheEntry;
    2999     uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
    3000     int rc;
    3001 
    3002     uGDIndex = uSector / pExtent->cSectorsPerGDE;
    3003     if (uGDIndex >= pExtent->cGDEntries)
    3004         return VERR_OUT_OF_RANGE;
    3005     uGTSector = pExtent->pGD[uGDIndex];
    3006     if (!uGTSector)
    3007     {
    3008         /* There is no grain table referenced by this grain directory
    3009          * entry. So there is absolutely no data in this area. */
    3010         *puExtentSector = 0;
    3011         return VINF_SUCCESS;
    3012     }
    3013 
    3014     uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
    3015     uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
    3016     pGTCacheEntry = &pCache->aGTCache[uGTHash];
    3017     if (    pGTCacheEntry->uExtent != pExtent->uExtent
    3018         ||  pGTCacheEntry->uGTBlock != uGTBlock)
    3019     {
    3020         /* Cache miss, fetch data from disk. */
    3021         rc = RTFileReadAt(pExtent->File,
    3022                           VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3023                           aGTDataTmp, sizeof(aGTDataTmp), NULL);
    3024         if (VBOX_FAILURE(rc))
    3025             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
    3026         pGTCacheEntry->uExtent = pExtent->uExtent;
    3027         pGTCacheEntry->uGTBlock = uGTBlock;
    3028         for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
    3029             pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
    3030     }
    3031     uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
    3032     uint64_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
    3033     if (uGrainSector)
    3034         *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
    3035     else
    3036         *puExtentSector = 0;
    3037     return VINF_SUCCESS;
    3038 }
    3039 
    3040 /**
    3041  * Internal. Allocates a new grain table (if necessary), writes the grain
    3042  * and updates the grain table. The cache is also updated by this operation.
    3043  * This is separate from vmdkGetSector, because that should be as fast as
    3044  * possible. Most code from vmdkGetSector also appears here.
    3045  */
    3046 static int vmdkAllocGrain(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
    3047                           uint64_t uSector, const void *pvBuf,
    3048                           uint64_t cbWrite)
    3049 {
    3050     uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
    3051     uint64_t cbExtentSize;
    3052     uint32_t uGTHash, uGTBlockIndex;
    3053     PVMDKGTCACHEENTRY pGTCacheEntry;
    3054     uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
    3055     int rc;
    3056 
    3057     uGDIndex = uSector / pExtent->cSectorsPerGDE;
    3058     if (uGDIndex >= pExtent->cGDEntries)
    3059         return VERR_OUT_OF_RANGE;
    3060     uGTSector = pExtent->pGD[uGDIndex];
    3061     uRGTSector = pExtent->pRGD[uGDIndex];
    3062     if (!uGTSector)
    3063     {
    3064         /* There is no grain table referenced by this grain directory
    3065          * entry. So there is absolutely no data in this area. Allocate
    3066          * a new grain table and put the reference to it in the GDs. */
    3067         rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    3068         if (VBOX_FAILURE(rc))
    3069             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    3070         Assert(!(cbExtentSize % 512));
    3071         uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    3072         /* Normally the grain table is preallocated for hosted sparse extents
    3073          * that support more than 32 bit sector numbers. So this shouldn't
    3074          * ever happen on a valid extent. */
    3075         if (uGTSector > UINT32_MAX)
    3076             return VERR_VDI_INVALID_HEADER;
    3077         /* Write grain table by writing the required number of grain table
    3078          * cache chunks. Avoids dynamic memory allocation, but is a bit
    3079          * slower. But as this is a pretty infrequently occurring case it
    3080          * should be acceptable. */
    3081         memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
    3082         for (unsigned i = 0;
    3083              i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
    3084              i++)
    3085         {
    3086             rc = RTFileWriteAt(pExtent->File,
    3087                                VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
    3088                                aGTDataTmp, sizeof(aGTDataTmp), NULL);
    3089             if (VBOX_FAILURE(rc))
    3090                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
    3091         }
    3092         if (pExtent->pRGD)
    3093         {
    3094             rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    3095             if (VBOX_FAILURE(rc))
    3096                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    3097             Assert(!(cbExtentSize % 512));
    3098             uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    3099             /* Write backup grain table by writing the required number of grain
    3100              * table cache chunks. Avoids dynamic memory allocation, but is a
    3101              * bit slower. But as this is a pretty infrequently occurring case
    3102              * it should be acceptable. */
    3103             for (unsigned i = 0;
    3104                  i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
    3105                  i++)
    3106             {
    3107                 rc = RTFileWriteAt(pExtent->File,
    3108                                    VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
    3109                                    aGTDataTmp, sizeof(aGTDataTmp), NULL);
    3110                 if (VBOX_FAILURE(rc))
    3111                     return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
    3112             }
    3113         }
    3114 
    3115         /* Update the grain directory on disk (doing it before writing the
    3116          * grain table will result in a garbled extent if the operation is
    3117          * aborted for some reason. Otherwise the worst that can happen is
    3118          * some unused sectors in the extent. */
    3119         uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
    3120         rc = RTFileWriteAt(pExtent->File,
    3121                            VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
    3122                            &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    3123         if (VBOX_FAILURE(rc))
    3124             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
    3125         if (pExtent->pRGD)
    3126         {
    3127             uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
    3128             rc = RTFileWriteAt(pExtent->File,
    3129                                VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
    3130                                &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
    3131             if (VBOX_FAILURE(rc))
    3132                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
    3133         }
    3134 
    3135         /* As the final step update the in-memory copy of the GDs. */
    3136         pExtent->pGD[uGDIndex] = uGTSector;
    3137         if (pExtent->pRGD)
    3138             pExtent->pRGD[uGDIndex] = uRGTSector;
    3139     }
    3140 
    3141     rc = RTFileGetSize(pExtent->File, &cbExtentSize);
    3142     if (VBOX_FAILURE(rc))
    3143         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    3144     Assert(!(cbExtentSize % 512));
    3145 
    3146     /* Write the data. */
    3147     rc = RTFileWriteAt(pExtent->File, cbExtentSize, pvBuf, cbWrite, NULL);
    3148     if (VBOX_FAILURE(rc))
    3149         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
    3150 
    3151     /* Update the grain table (and the cache). */
    3152     uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
    3153     uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
    3154     pGTCacheEntry = &pCache->aGTCache[uGTHash];
    3155     if (    pGTCacheEntry->uExtent != pExtent->uExtent
    3156         ||  pGTCacheEntry->uGTBlock != uGTBlock)
    3157     {
    3158         /* Cache miss, fetch data from disk. */
    3159         rc = RTFileReadAt(pExtent->File,
    3160                           VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3161                           aGTDataTmp, sizeof(aGTDataTmp), NULL);
    3162         if (VBOX_FAILURE(rc))
    3163             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
    3164         pGTCacheEntry->uExtent = pExtent->uExtent;
    3165         pGTCacheEntry->uGTBlock = uGTBlock;
    3166         for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
    3167             pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
    3168     }
    3169     else
    3170     {
    3171         /* Cache hit. Convert grain table block back to disk format, otherwise
    3172          * the code below will write garbage for all but the updated entry. */
    3173         for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
    3174             aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
    3175     }
    3176     uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
    3177     aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(cbExtentSize));
    3178     pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(cbExtentSize);
    3179     /* Update grain table on disk. */
    3180     rc = RTFileWriteAt(pExtent->File,
    3181                        VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3182                        aGTDataTmp, sizeof(aGTDataTmp), NULL);
    3183     if (VBOX_FAILURE(rc))
    3184         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
    3185     if (pExtent->pRGD)
    3186     {
    3187         /* Update backup grain table on disk. */
    3188         rc = RTFileWriteAt(pExtent->File,
    3189                            VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    3190                            aGTDataTmp, sizeof(aGTDataTmp), NULL);
    3191         if (VBOX_FAILURE(rc))
    3192             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
    3193     }
    3194 #ifdef VBOX_WITH_VMDK_ESX
    3195     if (VBOX_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
    3196     {
    3197         pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
    3198         pExtent->fMetaDirty = true;
    3199     }
    3200 #endif /* VBOX_WITH_VMDK_ESX */
     272    if (   pImage->File != NIL_RTFILE
     273        && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     274        rc = RTFileFlush(pImage->File);
     275
    3201276    return rc;
    3202277}
     
    3204279
    3205280/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
    3206 static int vmdkCheckIfValid(const char *pszFilename)
     281static int rawCheckIfValid(const char *pszFilename)
    3207282{
    3208283    LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
    3209284    int rc = VINF_SUCCESS;
    3210     PVMDKIMAGE pImage;
    3211 
    3212     if (   !pszFilename
    3213         || !*pszFilename
    3214         || strchr(pszFilename, '"'))
     285
     286    if (   !VALID_PTR(pszFilename)
     287        || !*pszFilename)
    3215288    {
    3216289        rc = VERR_INVALID_PARAMETER;
     
    3218291    }
    3219292
    3220     pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     293    /* Always return failure, to avoid opening everything as a raw image. */
     294    rc = VERR_VDI_INVALID_HEADER;
     295
     296out:
     297    LogFlowFunc(("returns %Vrc\n", rc));
     298    return rc;
     299}
     300
     301/** @copydoc VBOXHDDBACKEND::pfnOpen */
     302static int rawOpen(const char *pszFilename, unsigned uOpenFlags,
     303                    PFNVDERROR pfnError, void *pvErrorUser,
     304                    void **ppBackendData)
     305{
     306    LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x ppBackendData=%#p\n", pszFilename, uOpenFlags, ppBackendData));
     307    int rc;
     308    PRAWIMAGE pImage;
     309
     310    /* Check open flags. All valid flags are supported. */
     311    if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
     312    {
     313        rc = VERR_INVALID_PARAMETER;
     314        goto out;
     315    }
     316
     317    /* Check remaining arguments. */
     318    if (   !VALID_PTR(pszFilename)
     319        || !*pszFilename)
     320    {
     321        rc = VERR_INVALID_PARAMETER;
     322        goto out;
     323    }
     324
     325
     326    pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
    3221327    if (!pImage)
    3222328    {
     
    3226332    pImage->pszFilename = pszFilename;
    3227333    pImage->File = NIL_RTFILE;
    3228     pImage->pExtents = NULL;
    3229     pImage->pGTCache = NULL;
    3230     pImage->pDescData = NULL;
    3231     pImage->pfnError = NULL;
    3232     pImage->pvErrorUser = NULL;
    3233     /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
    3234      * much as possible in vmdkOpenImage. */
    3235     rc = vmdkOpenImage(pImage, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
    3236     vmdkFreeImage(pImage, false);
     334    pImage->pfnError = pfnError;
     335    pImage->pvErrorUser = pvErrorUser;
     336
     337    rc = rawOpenImage(pImage, uOpenFlags);
     338    if (VBOX_SUCCESS(rc))
     339        *ppBackendData = pImage;
    3237340
    3238341out:
    3239     LogFlowFunc(("returns %Vrc\n", rc));
    3240     return rc;
    3241 }
    3242 
    3243 /** @copydoc VBOXHDDBACKEND::pfnOpen */
    3244 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
    3245                     PFNVDERROR pfnError, void *pvErrorUser,
    3246                     void **ppBackendData)
    3247 {
    3248     LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x ppBackendData=%#p\n", pszFilename, uOpenFlags, ppBackendData));
    3249     int rc;
    3250     PVMDKIMAGE pImage;
     342    LogFlowFunc(("returns %Vrc (pBackendData=%#p)\n", rc, *ppBackendData));
     343    return rc;
     344}
     345
     346/** @copydoc VBOXHDDBACKEND::pfnCreate */
     347static int rawCreate(const char *pszFilename, VDIMAGETYPE enmType,
     348                     uint64_t cbSize, unsigned uImageFlags,
     349                     const char *pszComment,
     350                     PCPDMMEDIAGEOMETRY pPCHSGeometry,
     351                     PCPDMMEDIAGEOMETRY pLCHSGeometry,
     352                     unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     353                     void *pvUser, unsigned uPercentStart,
     354                     unsigned uPercentSpan, PFNVDERROR pfnError,
     355                     void *pvErrorUser, void **ppBackendData)
     356{
     357    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
     358    int rc;
     359    PRAWIMAGE pImage;
    3251360
    3252361    /* Check open flags. All valid flags are supported. */
     
    3260369    if (   !VALID_PTR(pszFilename)
    3261370        || !*pszFilename
    3262         || strchr(pszFilename, '"'))
     371        || (enmType != VD_IMAGE_TYPE_FIXED)
     372        || !VALID_PTR(pPCHSGeometry)
     373        || !VALID_PTR(pLCHSGeometry))
    3263374    {
    3264375        rc = VERR_INVALID_PARAMETER;
     
    3266377    }
    3267378
    3268 
    3269     pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     379    pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
    3270380    if (!pImage)
    3271381    {
     
    3275385    pImage->pszFilename = pszFilename;
    3276386    pImage->File = NIL_RTFILE;
    3277     pImage->pExtents = NULL;
    3278     pImage->pGTCache = NULL;
    3279     pImage->pDescData = NULL;
    3280387    pImage->pfnError = pfnError;
    3281388    pImage->pvErrorUser = pvErrorUser;
    3282389
    3283     rc = vmdkOpenImage(pImage, uOpenFlags);
    3284     if (VBOX_SUCCESS(rc))
    3285         *ppBackendData = pImage;
    3286 
    3287 out:
    3288     LogFlowFunc(("returns %Vrc (pBackendData=%#p)\n", rc, *ppBackendData));
    3289     return rc;
    3290 }
    3291 
    3292 /** @copydoc VBOXHDDBACKEND::pfnCreate */
    3293 static int vmdkCreate(const char *pszFilename, VDIMAGETYPE enmType,
    3294                       uint64_t cbSize, unsigned uImageFlags,
    3295                       const char *pszComment,
    3296                       PCPDMMEDIAGEOMETRY pPCHSGeometry,
    3297                       PCPDMMEDIAGEOMETRY pLCHSGeometry,
    3298                       unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
    3299                       void *pvUser, unsigned uPercentStart,
    3300                       unsigned uPercentSpan, PFNVDERROR pfnError,
    3301                       void *pvErrorUser, void **ppBackendData)
    3302 {
    3303     LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
    3304     int rc;
    3305     PVMDKIMAGE pImage;
    3306 
    3307     /* Check open flags. All valid flags are supported. */
    3308     if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
    3309     {
    3310         rc = VERR_INVALID_PARAMETER;
    3311         goto out;
    3312     }
    3313 
    3314     /* Check remaining arguments. */
    3315     if (   !VALID_PTR(pszFilename)
    3316         || !*pszFilename
    3317         || strchr(pszFilename, '"')
    3318         || (enmType != VD_IMAGE_TYPE_NORMAL && enmType != VD_IMAGE_TYPE_FIXED)
    3319         || !VALID_PTR(pPCHSGeometry)
    3320         || !VALID_PTR(pLCHSGeometry))
    3321     {
    3322         rc = VERR_INVALID_PARAMETER;
    3323         goto out;
    3324     }
    3325 
    3326     pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
    3327     if (!pImage)
    3328     {
    3329         rc = VERR_NO_MEMORY;
    3330         goto out;
    3331     }
    3332     pImage->pszFilename = pszFilename;
    3333     pImage->File = NIL_RTFILE;
    3334     pImage->pExtents = NULL;
    3335     pImage->pGTCache = NULL;
    3336     pImage->pDescData = NULL;
    3337     pImage->pfnError = pfnError;
    3338     pImage->pvErrorUser = pvErrorUser;
    3339     pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
    3340     pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
    3341     if (!pImage->pDescData)
    3342     {
    3343         rc = VERR_NO_MEMORY;
    3344         goto out;
    3345     }
    3346 
    3347     rc = vmdkCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
    3348                          pPCHSGeometry, pLCHSGeometry,
    3349                          pfnProgress, pvUser, uPercentStart, uPercentSpan);
     390    rc = rawCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
     391                        pPCHSGeometry, pLCHSGeometry,
     392                        pfnProgress, pvUser, uPercentStart, uPercentSpan);
    3350393    if (VBOX_SUCCESS(rc))
    3351394    {
     
    3354397        if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
    3355398        {
    3356             vmdkFreeImage(pImage, false);
    3357             rc = vmdkOpenImage(pImage, uOpenFlags);
     399            rawFreeImage(pImage, false);
     400            rc = rawOpenImage(pImage, uOpenFlags);
    3358401            if (VBOX_FAILURE(rc))
    3359402                goto out;
     
    3368411
    3369412/** @copydoc VBOXHDDBACKEND::pfnRename */
    3370 static int vmdkRename(void *pBackendData, const char *pszFilename)
     413static int rawRename(void *pBackendData, const char *pszFilename)
    3371414{
    3372415    LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
     
    3378421
    3379422/** @copydoc VBOXHDDBACKEND::pfnClose */
    3380 static int vmdkClose(void *pBackendData, bool fDelete)
     423static int rawClose(void *pBackendData, bool fDelete)
    3381424{
    3382425    LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
    3383     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     426    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3384427    int rc = VINF_SUCCESS;
    3385428
     
    3387430     * not signalled as an error. After all nothing bad happens. */
    3388431    if (pImage)
    3389         vmdkFreeImage(pImage, fDelete);
     432        rawFreeImage(pImage, fDelete);
    3390433
    3391434    LogFlowFunc(("returns %Vrc\n", rc));
     
    3394437
    3395438/** @copydoc VBOXHDDBACKEND::pfnRead */
    3396 static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
    3397                     size_t cbToRead, size_t *pcbActuallyRead)
     439static int rawRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
     440                   size_t cbToRead, size_t *pcbActuallyRead)
    3398441{
    3399442    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
    3400     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3401     PVMDKEXTENT pExtent;
    3402     uint64_t uSectorExtentRel;
    3403     uint64_t uSectorExtentAbs;
     443    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3404444    int rc;
    3405445
     
    3415455    }
    3416456
    3417     rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
    3418                         &pExtent, &uSectorExtentRel);
    3419     if (VBOX_FAILURE(rc))
    3420         goto out;
    3421 
    3422     /* Check access permissions as defined in the extent descriptor. */
    3423     if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
    3424     {
    3425         rc = VERR_VDI_INVALID_STATE;
    3426         goto out;
    3427     }
    3428 
    3429     /* Clip read range to remain in this extent. */
    3430     cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    3431 
    3432     /* Handle the read according to the current extent type. */
    3433     switch (pExtent->enmType)
    3434     {
    3435         case VMDKETYPE_HOSTED_SPARSE:
    3436 #ifdef VBOX_WITH_VMDK_ESX
    3437         case VMDKETYPE_ESX_SPARSE:
    3438 #endif /* VBOX_WITH_VMDK_ESX */
    3439             rc = vmdkGetSector(pImage->pGTCache, pExtent, uSectorExtentRel,
    3440                                &uSectorExtentAbs);
    3441             if (VBOX_FAILURE(rc))
    3442                 goto out;
    3443             /* Clip read range to at most the rest of the grain. */
    3444             cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
    3445             Assert(!(cbToRead % 512));
    3446             if (uSectorExtentAbs == 0)
    3447                 rc = VERR_VDI_BLOCK_FREE;
    3448             else
    3449                 rc = RTFileReadAt(pExtent->File,
    3450                                   VMDK_SECTOR2BYTE(uSectorExtentAbs),
    3451                                   pvBuf, cbToRead, NULL);
    3452             break;
    3453         case VMDKETYPE_FLAT:
    3454             rc = RTFileReadAt(pExtent->File,
    3455                               VMDK_SECTOR2BYTE(uSectorExtentRel),
    3456                               pvBuf, cbToRead, NULL);
    3457             break;
    3458         case VMDKETYPE_ZERO:
    3459             memset(pvBuf, '\0', cbToRead);
    3460             break;
    3461     }
     457    rc = RTFileReadAt(pImage->File, uOffset, pvBuf, cbToRead, NULL);
    3462458    *pcbActuallyRead = cbToRead;
    3463459
     
    3468464
    3469465/** @copydoc VBOXHDDBACKEND::pfnWrite */
    3470 static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
    3471                      size_t cbToWrite, size_t *pcbWriteProcess,
    3472                      size_t *pcbPreRead, size_t *pcbPostRead)
     466static int rawWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
     467                    size_t cbToWrite, size_t *pcbWriteProcess,
     468                    size_t *pcbPreRead, size_t *pcbPostRead)
    3473469{
    3474470    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
    3475     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3476     PVMDKEXTENT pExtent;
    3477     uint64_t uSectorExtentRel;
    3478     uint64_t uSectorExtentAbs;
     471    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3479472    int rc;
    3480473
     
    3489482    }
    3490483
    3491     if (cbToWrite == 0)
     484    if (   uOffset + cbToWrite > pImage->cbSize
     485        || cbToWrite == 0)
    3492486    {
    3493487        rc = VERR_INVALID_PARAMETER;
     
    3495489    }
    3496490
    3497     /* No size check here, will do that later when the extent is located.
    3498      * There are sparse images out there which according to the spec are
    3499      * invalid, because the total size is not a multiple of the grain size.
    3500      * Also for sparse images which are stitched together in odd ways (not at
    3501      * grain boundaries, and with the nominal size not being a multiple of the
    3502      * grain size), this would prevent writing to the last grain. */
    3503 
    3504     rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
    3505                         &pExtent, &uSectorExtentRel);
    3506     if (VBOX_FAILURE(rc))
    3507         goto out;
    3508 
    3509     /* Check access permissions as defined in the extent descriptor. */
    3510     if (pExtent->enmAccess != VMDKACCESS_READWRITE)
    3511     {
    3512         rc = VERR_VDI_INVALID_STATE;
    3513         goto out;
    3514     }
    3515 
    3516     /** @todo implement suppressing of zero data writes (a bit tricky in this
    3517      * case, as VMDK has no marker for zero blocks). We somehow need to get the
    3518      * information whether the information in this area is all zeroes as of the
    3519      * parent image. Then (based on the assumption that parent images are
    3520      * immutable) the write can be ignored. */
    3521 
    3522     /* Handle the write according to the current extent type. */
    3523     switch (pExtent->enmType)
    3524     {
    3525         case VMDKETYPE_HOSTED_SPARSE:
    3526 #ifdef VBOX_WITH_VMDK_ESX
    3527         case VMDKETYPE_ESX_SPARSE:
    3528 #endif /* VBOX_WITH_VMDK_ESX */
    3529             rc = vmdkGetSector(pImage->pGTCache, pExtent, uSectorExtentRel,
    3530                                &uSectorExtentAbs);
    3531             if (VBOX_FAILURE(rc))
    3532                 goto out;
    3533             /* Clip write range to at most the rest of the grain. */
    3534             cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
    3535             if (uSectorExtentAbs == 0)
    3536             {
    3537                 if (cbToWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
    3538                 {
    3539                     /* Full block write to a previously unallocated block.
    3540                      * Allocate GT and find out where to store the grain. */
    3541                     rc = vmdkAllocGrain(pImage->pGTCache, pExtent,
    3542                                         uSectorExtentRel, pvBuf, cbToWrite);
    3543                     *pcbPreRead = 0;
    3544                     *pcbPostRead = 0;
    3545                 }
    3546                 else
    3547                 {
    3548                     /* Clip write range to remain in this extent. */
    3549                     cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    3550                     *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
    3551                     *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite - *pcbPreRead;
    3552                     rc = VERR_VDI_BLOCK_FREE;
    3553                 }
    3554             }
    3555             else
    3556                 rc = RTFileWriteAt(pExtent->File,
    3557                                    VMDK_SECTOR2BYTE(uSectorExtentAbs),
    3558                                    pvBuf, cbToWrite, NULL);
    3559             break;
    3560         case VMDKETYPE_FLAT:
    3561             /* Clip write range to remain in this extent. */
    3562             cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    3563             rc = RTFileWriteAt(pExtent->File,
    3564                                VMDK_SECTOR2BYTE(uSectorExtentRel),
    3565                                pvBuf, cbToWrite, NULL);
    3566             break;
    3567         case VMDKETYPE_ZERO:
    3568             /* Clip write range to remain in this extent. */
    3569             cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    3570             break;
    3571     }
     491    rc = RTFileWriteAt(pImage->File, uOffset, pvBuf, cbToWrite, NULL);
    3572492    if (pcbWriteProcess)
    3573493        *pcbWriteProcess = cbToWrite;
     
    3579499
    3580500/** @copydoc VBOXHDDBACKEND::pfnFlush */
    3581 static int vmdkFlush(void *pBackendData)
     501static int rawFlush(void *pBackendData)
    3582502{
    3583503    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    3584     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3585     int rc;
    3586 
    3587     rc = vmdkFlushImage(pImage);
     504    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     505    int rc;
     506
     507    rc = rawFlushImage(pImage);
    3588508    LogFlowFunc(("returns %Vrc\n", rc));
    3589509    return rc;
     
    3591511
    3592512/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
    3593 static unsigned vmdkGetVersion(void *pBackendData)
     513static unsigned rawGetVersion(void *pBackendData)
    3594514{
    3595515    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    3596     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3597 
    3598     Assert(pImage);
    3599 
    3600     if (pImage)
    3601         return VMDK_IMAGE_VERSION;
     516    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     517
     518    Assert(pImage);
     519
     520    if (pImage)
     521        return 1;
    3602522    else
    3603523        return 0;
     
    3605525
    3606526/** @copydoc VBOXHDDBACKEND::pfnGetImageType */
    3607 static int vmdkGetImageType(void *pBackendData, PVDIMAGETYPE penmImageType)
     527static int rawGetImageType(void *pBackendData, PVDIMAGETYPE penmImageType)
    3608528{
    3609529    LogFlowFunc(("pBackendData=%#p penmImageType=%#p\n", pBackendData, penmImageType));
    3610     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     530    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3611531    int rc = VINF_SUCCESS;
    3612532
     
    3614534    Assert(penmImageType);
    3615535
    3616     if (pImage && pImage->cExtents != 0)
     536    if (pImage)
    3617537        *penmImageType = pImage->enmImageType;
    3618538    else
     
    3624544
    3625545/** @copydoc VBOXHDDBACKEND::pfnGetSize */
    3626 static uint64_t vmdkGetSize(void *pBackendData)
     546static uint64_t rawGetSize(void *pBackendData)
    3627547{
    3628548    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    3629     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     549    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3630550
    3631551    Assert(pImage);
     
    3638558
    3639559/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
    3640 static uint64_t vmdkGetFileSize(void *pBackendData)
     560static uint64_t rawGetFileSize(void *pBackendData)
    3641561{
    3642562    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    3643     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     563    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3644564    uint64_t cb = 0;
    3645565
     
    3654574            if (VBOX_SUCCESS(rc))
    3655575                cb += cbFile;
    3656             for (unsigned i = 0; i <= pImage->cExtents; i++)
    3657             {
    3658                 rc = RTFileGetSize(pImage->File, &cbFile);
    3659                 if (VBOX_SUCCESS(rc))
    3660                     cb += cbFile;
    3661             }
    3662576        }
    3663577    }
     
    3668582
    3669583/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
    3670 static int vmdkGetPCHSGeometry(void *pBackendData,
    3671                                PPDMMEDIAGEOMETRY pPCHSGeometry)
     584static int rawGetPCHSGeometry(void *pBackendData,
     585                              PPDMMEDIAGEOMETRY pPCHSGeometry)
    3672586{
    3673587    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
    3674     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     588    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3675589    int rc;
    3676590
     
    3695609
    3696610/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
    3697 static int vmdkSetPCHSGeometry(void *pBackendData,
    3698                                PCPDMMEDIAGEOMETRY pPCHSGeometry)
     611static int rawSetPCHSGeometry(void *pBackendData,
     612                              PCPDMMEDIAGEOMETRY pPCHSGeometry)
    3699613{
    3700614    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
    3701     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     615    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3702616    int rc;
    3703617
     
    3711625            goto out;
    3712626        }
    3713         rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    3714         if (VBOX_FAILURE(rc))
    3715             goto out;
    3716627
    3717628        pImage->PCHSGeometry = *pPCHSGeometry;
     
    3727638
    3728639/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
    3729 static int vmdkGetLCHSGeometry(void *pBackendData,
    3730                                PPDMMEDIAGEOMETRY pLCHSGeometry)
     640static int rawGetLCHSGeometry(void *pBackendData,
     641                              PPDMMEDIAGEOMETRY pLCHSGeometry)
    3731642{
    3732643     LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
    3733     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     644    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3734645    int rc;
    3735646
     
    3754665
    3755666/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
    3756 static int vmdkSetLCHSGeometry(void *pBackendData,
     667static int rawSetLCHSGeometry(void *pBackendData,
    3757668                               PCPDMMEDIAGEOMETRY pLCHSGeometry)
    3758669{
    3759670    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    3760     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     671    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3761672    int rc;
    3762673
     
    3770681            goto out;
    3771682        }
    3772         rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    3773         if (VBOX_FAILURE(rc))
    3774             goto out;
    3775683
    3776684        pImage->LCHSGeometry = *pLCHSGeometry;
     
    3786694
    3787695/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
    3788 static unsigned vmdkGetImageFlags(void *pBackendData)
     696static unsigned rawGetImageFlags(void *pBackendData)
    3789697{
    3790698    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    3791     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     699    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3792700    unsigned uImageFlags;
    3793701
     
    3804712
    3805713/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
    3806 static unsigned vmdkGetOpenFlags(void *pBackendData)
     714static unsigned rawGetOpenFlags(void *pBackendData)
    3807715{
    3808716    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
    3809     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     717    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3810718    unsigned uOpenFlags;
    3811719
     
    3822730
    3823731/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
    3824 static int vmdkSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
     732static int rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
    3825733{
    3826734    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
    3827     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     735    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3828736    int rc;
    3829737    const char *pszFilename;
     
    3839747    /* Implement this operation via reopening the image. */
    3840748    pszFilename = pImage->pszFilename;
    3841     vmdkFreeImage(pImage, false);
    3842     rc = vmdkOpenImage(pImage, uOpenFlags);
     749    rawFreeImage(pImage, false);
     750    rc = rawOpenImage(pImage, uOpenFlags);
    3843751
    3844752out:
     
    3848756
    3849757/** @copydoc VBOXHDDBACKEND::pfnGetComment */
    3850 static int vmdkGetComment(void *pBackendData, char *pszComment,
     758static int rawGetComment(void *pBackendData, char *pszComment,
    3851759                          size_t cbComment)
    3852760{
    3853761    LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
    3854     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3855     int rc;
    3856 
    3857     Assert(pImage);
    3858 
    3859     if (pImage)
    3860     {
    3861         const char *pszCommentEncoded = NULL;
    3862         rc = vmdkDescDDBGetStr(pImage, &pImage->Descriptor,
    3863                               "ddb.comment", &pszCommentEncoded);
    3864         if (rc == VERR_VDI_VALUE_NOT_FOUND)
    3865             pszCommentEncoded = NULL;
    3866         else if (VBOX_FAILURE(rc))
    3867             goto out;
    3868 
     762    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     763    int rc;
     764
     765    Assert(pImage);
     766
     767    if (pImage)
     768    {
    3869769        if (pszComment)
    3870             rc = vmdkDecodeString(pszCommentEncoded, pszComment, cbComment);
     770            *pszComment = '\0';
     771        rc = VINF_SUCCESS;
     772    }
     773    else
     774        rc = VERR_VDI_NOT_OPENED;
     775
     776    LogFlowFunc(("returns %Vrc comment='%s'\n", rc, pszComment));
     777    return rc;
     778}
     779
     780/** @copydoc VBOXHDDBACKEND::pfnSetComment */
     781static int rawSetComment(void *pBackendData, const char *pszComment)
     782{
     783    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
     784    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     785    int rc;
     786
     787    Assert(pImage);
     788
     789    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     790    {
     791        rc = VERR_VDI_IMAGE_READ_ONLY;
     792        goto out;
     793    }
     794
     795    if (pImage)
     796        rc = VERR_NOT_SUPPORTED;
     797    else
     798        rc = VERR_VDI_NOT_OPENED;
     799
     800out:
     801    LogFlowFunc(("returns %Vrc\n", rc));
     802    return rc;
     803}
     804
     805/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
     806static int rawGetUuid(void *pBackendData, PRTUUID pUuid)
     807{
     808    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
     809    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     810    int rc;
     811
     812    Assert(pImage);
     813
     814    if (pImage)
     815        rc = VERR_NOT_SUPPORTED;
     816    else
     817        rc = VERR_VDI_NOT_OPENED;
     818
     819    LogFlowFunc(("returns %Vrc (%Vuuid)\n", rc, pUuid));
     820    return rc;
     821}
     822
     823/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
     824static int rawSetUuid(void *pBackendData, PCRTUUID pUuid)
     825{
     826    LogFlowFunc(("pBackendData=%#p Uuid=%Vuuid\n", pBackendData, pUuid));
     827    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     828    int rc;
     829
     830    LogFlowFunc(("%Vuuid\n", pUuid));
     831    Assert(pImage);
     832
     833    if (pImage)
     834    {
     835        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     836            rc = VERR_NOT_SUPPORTED;
    3871837        else
    3872         {
    3873             *pszComment = '\0';
    3874             rc = VINF_SUCCESS;
    3875         }
    3876         if (pszCommentEncoded)
    3877             RTStrFree((char *)(void *)pszCommentEncoded);
    3878     }
    3879     else
    3880         rc = VERR_VDI_NOT_OPENED;
    3881 
    3882 out:
    3883     LogFlowFunc(("returns %Vrc comment='%s'\n", rc, pszComment));
    3884     return rc;
    3885 }
    3886 
    3887 /** @copydoc VBOXHDDBACKEND::pfnSetComment */
    3888 static int vmdkSetComment(void *pBackendData, const char *pszComment)
    3889 {
    3890     LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
    3891     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3892     int rc;
    3893 
    3894     Assert(pImage);
    3895 
    3896     if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    3897     {
    3898         rc = VERR_VDI_IMAGE_READ_ONLY;
    3899         goto out;
    3900     }
    3901 
    3902     if (pImage)
    3903         rc = vmdkSetImageComment(pImage, pszComment);
    3904     else
    3905         rc = VERR_VDI_NOT_OPENED;
    3906 
    3907 out:
    3908     LogFlowFunc(("returns %Vrc\n", rc));
    3909     return rc;
    3910 }
    3911 
    3912 /** @copydoc VBOXHDDBACKEND::pfnGetUuid */
    3913 static int vmdkGetUuid(void *pBackendData, PRTUUID pUuid)
     838            rc = VERR_VDI_IMAGE_READ_ONLY;
     839    }
     840    else
     841        rc = VERR_VDI_NOT_OPENED;
     842
     843    LogFlowFunc(("returns %Vrc\n", rc));
     844    return rc;
     845}
     846
     847/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
     848static int rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
    3914849{
    3915850    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    3916     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3917     int rc;
    3918 
    3919     Assert(pImage);
    3920 
    3921     if (pImage)
    3922     {
    3923         *pUuid = pImage->ImageUuid;
    3924         rc = VINF_SUCCESS;
    3925     }
     851    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     852    int rc;
     853
     854    Assert(pImage);
     855
     856    if (pImage)
     857        rc = VERR_NOT_SUPPORTED;
    3926858    else
    3927859        rc = VERR_VDI_NOT_OPENED;
     
    3931863}
    3932864
    3933 /** @copydoc VBOXHDDBACKEND::pfnSetUuid */
    3934 static int vmdkSetUuid(void *pBackendData, PCRTUUID pUuid)
     865/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
     866static int rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
    3935867{
    3936868    LogFlowFunc(("pBackendData=%#p Uuid=%Vuuid\n", pBackendData, pUuid));
    3937     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3938     int rc;
    3939 
    3940     LogFlowFunc(("%Vuuid\n", pUuid));
     869    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     870    int rc;
     871
    3941872    Assert(pImage);
    3942873
     
    3944875    {
    3945876        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    3946         {
    3947             pImage->ImageUuid = *pUuid;
    3948             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    3949                                     VMDK_DDB_IMAGE_UUID, pUuid);
    3950             if (VBOX_FAILURE(rc))
    3951                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
    3952             rc = VINF_SUCCESS;
    3953         }
    3954         else
    3955             rc = VERR_VDI_IMAGE_READ_ONLY;
    3956     }
    3957     else
    3958         rc = VERR_VDI_NOT_OPENED;
    3959 
    3960     LogFlowFunc(("returns %Vrc\n", rc));
    3961     return rc;
    3962 }
    3963 
    3964 /** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
    3965 static int vmdkGetModificationUuid(void *pBackendData, PRTUUID pUuid)
     877            rc = VERR_NOT_SUPPORTED;
     878        else
     879            rc = VERR_VDI_IMAGE_READ_ONLY;
     880    }
     881    else
     882        rc = VERR_VDI_NOT_OPENED;
     883
     884    LogFlowFunc(("returns %Vrc\n", rc));
     885    return rc;
     886}
     887
     888/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
     889static int rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
    3966890{
    3967891    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    3968     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3969     int rc;
    3970 
    3971     Assert(pImage);
    3972 
    3973     if (pImage)
    3974     {
    3975         *pUuid = pImage->ModificationUuid;
    3976         rc = VINF_SUCCESS;
    3977     }
     892    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     893    int rc;
     894
     895    Assert(pImage);
     896
     897    if (pImage)
     898        rc = VERR_NOT_SUPPORTED;
    3978899    else
    3979900        rc = VERR_VDI_NOT_OPENED;
     
    3983904}
    3984905
    3985 /** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
    3986 static int vmdkSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
     906/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
     907static int rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
    3987908{
    3988909    LogFlowFunc(("pBackendData=%#p Uuid=%Vuuid\n", pBackendData, pUuid));
    3989     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     910    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    3990911    int rc;
    3991912
     
    3995916    {
    3996917        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    3997         {
    3998             pImage->ModificationUuid = *pUuid;
    3999             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4000                                     VMDK_DDB_MODIFICATION_UUID, pUuid);
    4001             if (VBOX_FAILURE(rc))
    4002                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
    4003             rc = VINF_SUCCESS;
    4004         }
    4005         else
    4006             rc = VERR_VDI_IMAGE_READ_ONLY;
    4007     }
    4008     else
    4009         rc = VERR_VDI_NOT_OPENED;
    4010 
    4011     LogFlowFunc(("returns %Vrc\n", rc));
    4012     return rc;
    4013 }
    4014 
    4015 /** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
    4016 static int vmdkGetParentUuid(void *pBackendData, PRTUUID pUuid)
     918            rc = VERR_NOT_SUPPORTED;
     919        else
     920            rc = VERR_VDI_IMAGE_READ_ONLY;
     921    }
     922    else
     923        rc = VERR_VDI_NOT_OPENED;
     924
     925    LogFlowFunc(("returns %Vrc\n", rc));
     926    return rc;
     927}
     928
     929/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
     930static int rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
    4017931{
    4018932    LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    4019     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    4020     int rc;
    4021 
    4022     Assert(pImage);
    4023 
    4024     if (pImage)
    4025     {
    4026         *pUuid = pImage->ParentUuid;
    4027         rc = VINF_SUCCESS;
    4028     }
     933    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
     934    int rc;
     935
     936    Assert(pImage);
     937
     938    if (pImage)
     939        rc = VERR_NOT_SUPPORTED;
    4029940    else
    4030941        rc = VERR_VDI_NOT_OPENED;
     
    4034945}
    4035946
    4036 /** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
    4037 static int vmdkSetParentUuid(void *pBackendData, PCRTUUID pUuid)
     947/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
     948static int rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
    4038949{
    4039950    LogFlowFunc(("pBackendData=%#p Uuid=%Vuuid\n", pBackendData, pUuid));
    4040     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     951    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    4041952    int rc;
    4042953
     
    4046957    {
    4047958        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    4048         {
    4049             pImage->ParentUuid = *pUuid;
    4050             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4051                                     VMDK_DDB_PARENT_UUID, pUuid);
    4052             if (VBOX_FAILURE(rc))
    4053                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
    4054             rc = VINF_SUCCESS;
    4055         }
    4056         else
    4057             rc = VERR_VDI_IMAGE_READ_ONLY;
    4058     }
    4059     else
    4060         rc = VERR_VDI_NOT_OPENED;
    4061 
    4062     LogFlowFunc(("returns %Vrc\n", rc));
    4063     return rc;
    4064 }
    4065 
    4066 /** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
    4067 static int vmdkGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
    4068 {
    4069     LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
    4070     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    4071     int rc;
    4072 
    4073     Assert(pImage);
    4074 
    4075     if (pImage)
    4076     {
    4077         *pUuid = pImage->ParentModificationUuid;
    4078         rc = VINF_SUCCESS;
    4079     }
    4080     else
    4081         rc = VERR_VDI_NOT_OPENED;
    4082 
    4083     LogFlowFunc(("returns %Vrc (%Vuuid)\n", rc, pUuid));
    4084     return rc;
    4085 }
    4086 
    4087 /** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
    4088 static int vmdkSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
    4089 {
    4090     LogFlowFunc(("pBackendData=%#p Uuid=%Vuuid\n", pBackendData, pUuid));
    4091     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    4092     int rc;
    4093 
    4094     Assert(pImage);
    4095 
    4096     if (pImage)
    4097     {
    4098         if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    4099         {
    4100             pImage->ParentModificationUuid = *pUuid;
    4101             rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    4102                                     VMDK_DDB_PARENT_MODIFICATION_UUID, pUuid);
    4103             if (VBOX_FAILURE(rc))
    4104                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
    4105             rc = VINF_SUCCESS;
    4106         }
    4107         else
    4108             rc = VERR_VDI_IMAGE_READ_ONLY;
     959            rc = VERR_NOT_SUPPORTED;
     960        else
     961            rc = VERR_VDI_IMAGE_READ_ONLY;
    4109962    }
    4110963    else
     
    4116969
    4117970/** @copydoc VBOXHDDBACKEND::pfnDump */
    4118 static void vmdkDump(void *pBackendData)
    4119 {
    4120     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     971static void rawDump(void *pBackendData)
     972{
     973    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    4121974
    4122975    Assert(pImage);
     
    4126979                    pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
    4127980                    pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
    4128                     VMDK_BYTE2SECTOR(pImage->cbSize));
    4129         RTLogPrintf("Header: uuidCreation={%Vuuid}\n", pImage->ImageUuid);
    4130         RTLogPrintf("Header: uuidModification={%Vuuid}\n", pImage->ModificationUuid);
    4131         RTLogPrintf("Header: uuidParent={%Vuuid}\n", pImage->ParentUuid);
    4132     }
    4133 }
    4134 
    4135 
    4136 VBOXHDDBACKEND g_VmdkBackend =
     981                    pImage->cbSize / 512);
     982    }
     983}
     984
     985
     986VBOXHDDBACKEND g_RawBackend =
    4137987{
    4138988    /* pszBackendName */
    4139     "VMDK",
     989    "raw",
    4140990    /* cbSize */
    4141991    sizeof(VBOXHDDBACKEND),
    4142992    /* pfnCheckIfValid */
    4143     vmdkCheckIfValid,
     993    rawCheckIfValid,
    4144994    /* pfnOpen */
    4145     vmdkOpen,
     995    rawOpen,
    4146996    /* pfnCreate */
    4147     vmdkCreate,
     997    rawCreate,
    4148998    /* pfnRename */
    4149     vmdkRename,
     999    rawRename,
    41501000    /* pfnClose */
    4151     vmdkClose,
     1001    rawClose,
    41521002    /* pfnRead */
    4153     vmdkRead,
     1003    rawRead,
    41541004    /* pfnWrite */
    4155     vmdkWrite,
     1005    rawWrite,
    41561006    /* pfnFlush */
    4157     vmdkFlush,
     1007    rawFlush,
    41581008    /* pfnGetVersion */
    4159     vmdkGetVersion,
     1009    rawGetVersion,
    41601010    /* pfnGetImageType */
    4161     vmdkGetImageType,
     1011    rawGetImageType,
    41621012    /* pfnGetSize */
    4163     vmdkGetSize,
     1013    rawGetSize,
    41641014    /* pfnGetFileSize */
    4165     vmdkGetFileSize,
     1015    rawGetFileSize,
    41661016    /* pfnGetPCHSGeometry */
    4167     vmdkGetPCHSGeometry,
     1017    rawGetPCHSGeometry,
    41681018    /* pfnSetPCHSGeometry */
    4169     vmdkSetPCHSGeometry,
     1019    rawSetPCHSGeometry,
    41701020    /* pfnGetLCHSGeometry */
    4171     vmdkGetLCHSGeometry,
     1021    rawGetLCHSGeometry,
    41721022    /* pfnSetLCHSGeometry */
    4173     vmdkSetLCHSGeometry,
     1023    rawSetLCHSGeometry,
    41741024    /* pfnGetImageFlags */
    4175     vmdkGetImageFlags,
     1025    rawGetImageFlags,
    41761026    /* pfnGetOpenFlags */
    4177     vmdkGetOpenFlags,
     1027    rawGetOpenFlags,
    41781028    /* pfnSetOpenFlags */
    4179     vmdkSetOpenFlags,
     1029    rawSetOpenFlags,
    41801030    /* pfnGetComment */
    4181     vmdkGetComment,
     1031    rawGetComment,
    41821032    /* pfnSetComment */
    4183     vmdkSetComment,
     1033    rawSetComment,
    41841034    /* pfnGetUuid */
    4185     vmdkGetUuid,
     1035    rawGetUuid,
    41861036    /* pfnSetUuid */
    4187     vmdkSetUuid,
     1037    rawSetUuid,
    41881038    /* pfnGetModificationUuid */
    4189     vmdkGetModificationUuid,
     1039    rawGetModificationUuid,
    41901040    /* pfnSetModificationUuid */
    4191     vmdkSetModificationUuid,
     1041    rawSetModificationUuid,
    41921042    /* pfnGetParentUuid */
    4193     vmdkGetParentUuid,
     1043    rawGetParentUuid,
    41941044    /* pfnSetParentUuid */
    4195     vmdkSetParentUuid,
     1045    rawSetParentUuid,
    41961046    /* pfnGetParentModificationUuid */
    4197     vmdkGetParentModificationUuid,
     1047    rawGetParentModificationUuid,
    41981048    /* pfnSetParentModificationUuid */
    4199     vmdkSetParentModificationUuid,
     1049    rawSetParentModificationUuid,
    42001050    /* pfnDump */
    4201     vmdkDump
     1051    rawDump
    42021052};
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