VirtualBox

Ignore:
Timestamp:
Feb 17, 2009 11:01:43 AM (16 years ago)
Author:
vboxsync
Message:

Storage/VMDK: implement VMDK 1.1 streamOptimized format. read only at the moment.

File:
1 edited

Legend:

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

    r15565 r16827  
    3535#include <iprt/string.h>
    3636#include <iprt/rand.h>
     37#include <iprt/zip.h>
    3738
    3839
     
    7475/** VMDK descriptor DDB entry for parent image modification UUID. */
    7576#define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification"
     77
     78/** No compression for streamOptimized files. */
     79#define VMDK_COMPRESSION_NONE 0
     80
     81/** Deflate compression for streamOptimized files. */
     82#define VMDK_COMPRESSION_DEFLATE 1
     83
     84/** Marker that the actual GD value is stored in the footer. */
     85#define VMDK_GD_AT_END 0xffffffffffffffffULL
     86
     87/** Marker for end-of-stream in streamOptimized images. */
     88#define VMDK_MARKER_EOS 0
     89
     90/** Marker for grain table block in streamOptimized images. */
     91#define VMDK_MARKER_GT 1
     92
     93/** Marker for grain directory block in streamOptimized images. */
     94#define VMDK_MARKER_GD 2
     95
     96/** Marker for footer in streamOptimized images. */
     97#define VMDK_MARKER_FOOTER 3
     98
     99/** Dummy marker for "don't check the marker value". */
     100#define VMDK_MARKER_IGNORE 0xffffffffU
    76101
    77102/**
     
    104129    char        doubleEndLineChar1;
    105130    char        doubleEndLineChar2;
    106     uint8_t     pad[435];
     131    uint16_t    compressAlgorithm;
     132    uint8_t     pad[433];
    107133} SparseExtentHeader;
    108134#pragma pack()
     
    111137 * divisible by the default grain size (64K) */
    112138#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
     139
     140/** VMDK streamOptimized file format marker. The type field may or may not
     141 * be actually valid, but there's always data to read there. */
     142#pragma pack(1)
     143typedef struct VMDKMARKER
     144{
     145    uint64_t uSector;
     146    uint32_t cbSize;
     147    uint32_t uType;
     148} VMDKMARKER;
     149#pragma pack()
    113150
    114151
     
    256293    uint32_t    *pGD;
    257294    /** Pointer to the redundant grain directory. */
    258     uint32_t     *pRGD;
     295    uint32_t    *pRGD;
     296    /** VMDK version of this extent. 1=1.0, 3=1.1 */
     297    uint32_t    uVersion;
    259298    /** Type of this extent. */
    260299    VMDKETYPE   enmType;
     
    265304    /** Flag whether the metadata in the extent header needs to be updated. */
    266305    bool        fMetaDirty;
     306    /** Compression type for this extent. */
     307    uint16_t    uCompression;
     308    /** Starting sector of the decompressed grain buffer. */
     309    uint64_t    uGrainSector;
     310    /** Decompressed grain buffer for streamOptimized extents. */
     311    void        *pvGrain;
    267312    /** Reference to the image in which this extent is used. Do not use this
    268313     * on a regular basis to avoid passing pImage references to functions
     
    415460} VMDKIMAGE;
    416461
     462
     463/** State for the input callout of the inflate reader. */
     464typedef struct VMDKINFLATESTATE
     465{
     466    /* File where the data is stored. */
     467    RTFILE File;
     468    /* Total size of the data to read. */
     469    size_t cbSize;
     470    /* Offset in the file to read. */
     471    uint64_t uFileOffset;
     472    /* Current read position. */
     473    ssize_t iOffset;
     474} VMDKINFLATESTATE;
     475
    417476/*******************************************************************************
    418477 *   Static Variables                                                           *
     
    654713    else
    655714        return RTFileFlush(pVmdkFile->File);
     715}
     716
     717
     718static DECLCALLBACK(int) vmdkFileInflateHelper(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
     719{
     720    VMDKINFLATESTATE *pInflateState = (VMDKINFLATESTATE *)pvUser;
     721
     722    Assert(cbBuf);
     723    if (pInflateState->iOffset < 0)
     724    {
     725        *(uint8_t *)pvBuf = RTZIPTYPE_ZLIB;
     726        if (pcbBuf)
     727            *pcbBuf = 1;
     728        pInflateState->iOffset = 0;
     729        return VINF_SUCCESS;
     730    }
     731    cbBuf = RT_MIN(cbBuf, pInflateState->cbSize);
     732    int rc = RTFileReadAt(pInflateState->File, pInflateState->uFileOffset, pvBuf, cbBuf, NULL);
     733    if (RT_FAILURE(rc))
     734        return rc;
     735    pInflateState->uFileOffset += cbBuf;
     736    pInflateState->iOffset += cbBuf;
     737    pInflateState->cbSize -= cbBuf;
     738    Assert(pcbBuf);
     739    *pcbBuf = cbBuf;
     740    return VINF_SUCCESS;
     741}
     742
     743/**
     744 * Internal: read from a file and inflate the compressed data,
     745 * distinguishing between async and normal operation
     746 */
     747DECLINLINE(int) vmdkFileInflateAt(PVMDKFILE pVmdkFile,
     748                                  uint64_t uOffset, void *pvBuf,
     749                                  size_t cbToRead, unsigned uMarker,
     750                                  uint64_t *puLBA)
     751{
     752    if (pVmdkFile->fAsyncIO)
     753    {
     754        AssertMsgFailed(("TODO\n"));
     755        return VERR_NOT_SUPPORTED;
     756    }
     757    else
     758    {
     759        int rc;
     760        PRTZIPDECOMP pZip = NULL;
     761        VMDKMARKER Marker;
     762        uint64_t uCompOffset, cbComp;
     763        VMDKINFLATESTATE InflateState;
     764        size_t cbActuallyRead;
     765
     766        rc = RTFileReadAt(pVmdkFile->File, uOffset, &Marker, sizeof(Marker), NULL);
     767        if (RT_FAILURE(rc))
     768            return rc;
     769        Marker.uSector = RT_LE2H_U64(Marker.uSector);
     770        Marker.cbSize = RT_LE2H_U32(Marker.cbSize);
     771        if (    uMarker != VMDK_MARKER_IGNORE
     772            &&  (   RT_LE2H_U32(Marker.uType) != uMarker
     773                 || Marker.cbSize != 0))
     774            return VERR_VD_VMDK_INVALID_FORMAT;
     775        if (Marker.cbSize != 0)
     776        {
     777            /* Compressed grain marker. Data follows immediately. */
     778            uCompOffset = uOffset + 12;
     779            cbComp = Marker.cbSize;
     780            if (puLBA)
     781                *puLBA = Marker.uSector;
     782        }
     783        else
     784        {
     785            Marker.uType = RT_LE2H_U32(Marker.uType);
     786            if (Marker.uType == VMDK_MARKER_EOS)
     787            {
     788                Assert(uMarker != VMDK_MARKER_EOS);
     789                return VERR_VD_VMDK_INVALID_FORMAT;
     790            }
     791            else if (   Marker.uType == VMDK_MARKER_GT
     792                     || Marker.uType == VMDK_MARKER_GD
     793                     || Marker.uType == VMDK_MARKER_FOOTER)
     794            {
     795                uCompOffset = uOffset + 512;
     796                cbComp = VMDK_SECTOR2BYTE(Marker.uSector);
     797            }
     798            else
     799            {
     800                AssertMsgFailed(("VMDK: unknown marker type %u\n", Marker.uType));
     801                return VERR_VD_VMDK_INVALID_FORMAT;
     802            }
     803        }
     804        InflateState.File = pVmdkFile->File;
     805        InflateState.cbSize = cbComp;
     806        InflateState.uFileOffset = uCompOffset;
     807        InflateState.iOffset = -1;
     808        /* Sanity check - the expansion ratio should be much less than 2. */
     809        Assert(cbComp < 2 * cbToRead);
     810        if (cbComp >= 2 * cbToRead)
     811            return VERR_VD_VMDK_INVALID_FORMAT;
     812
     813        rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
     814        if (RT_FAILURE(rc))
     815            return rc;
     816        rc = RTZipDecompress(pZip, pvBuf, cbToRead, &cbActuallyRead);
     817        RTZipDecompDestroy(pZip);
     818        if (RT_FAILURE(rc))
     819            return rc;
     820        if (cbActuallyRead != cbToRead)
     821            rc = VERR_VD_VMDK_INVALID_FORMAT;
     822        return rc;
     823    }
    656824}
    657825
     
    797965    }
    798966    pExtent->pGD = pGD;
     967    /* The VMDK 1.1 spec talks about compressed grain directories, but real
     968     * life files don't have them. The spec is wrong in creative ways. */
    799969    rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
    800970                        pGD, cbGD, NULL);
     
    802972    if (RT_FAILURE(rc))
    803973    {
    804         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s'"), pExtent->pszFullname);
     974        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname);
    805975        goto out;
    806976    }
     
    817987        }
    818988        pExtent->pRGD = pRGD;
     989        /* The VMDK 1.1 spec talks about compressed grain directories, but real
     990         * life files don't have them. The spec is wrong in creative ways. */
    819991        rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
    820992                            pRGD, cbGD, NULL);
     
    8621034                goto out;
    8631035            }
     1036            /* The VMDK 1.1 spec talks about compressed grain tables, but real
     1037             * life files don't have them. The spec is wrong in creative ways. */
    8641038            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp),
    8651039                                pTmpGT1, cbGT, NULL);
     
    8711045                goto out;
    8721046            }
     1047            /* The VMDK 1.1 spec talks about compressed grain tables, but real
     1048             * life files don't have them. The spec is wrong in creative ways. */
    8731049            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pRGDTmp),
    8741050                                pTmpGT2, cbGT, NULL);
     
    16701846        ||  !strcmp(pszCreateType, "twoGbMaxExtentFlat"))
    16711847        pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
    1672     if (    !strcmp(pszCreateType, "partitionedDevice")
    1673         || !strcmp(pszCreateType, "fullDevice"))
     1848    else if (   !strcmp(pszCreateType, "partitionedDevice")
     1849             || !strcmp(pszCreateType, "fullDevice"))
    16741850        pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_RAWDISK;
     1851    else if (!strcmp(pszCreateType, "streamOptimized"))
     1852        pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED;
    16751853    else
    16761854        pImage->uImageFlags = 0;
     
    19592137        return rc;
    19602138
     2139    /* Stream optimized images are always readonly. Nevertheless we opened the
     2140     * file as read/write to allow us to sneak in the UUID info. */
     2141    if (pImage->uImageFlags == VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     2142        pImage->uOpenFlags |= VD_OPEN_FLAGS_READONLY;
     2143
    19612144    return VINF_SUCCESS;
    19622145}
     
    20252208
    20262209/**
     2210 * Internal: validate the consistency check values in a binary header.
     2211 */
     2212static int vmdkValidateHeader(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, const SparseExtentHeader *pHeader)
     2213{
     2214    int rc = VINF_SUCCESS;
     2215    if (RT_LE2H_U32(pHeader->magicNumber) != VMDK_SPARSE_MAGICNUMBER)
     2216    {
     2217        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic in sparse extent header in '%s'"), pExtent->pszFullname);
     2218        return rc;
     2219    }
     2220    if (RT_LE2H_U32(pHeader->version) != 1 && RT_LE2H_U32(pHeader->version) != 3)
     2221    {
     2222        rc = vmdkError(pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: incorrect version in sparse extent header in '%s', not a VMDK 1.0/1.1 conforming file"), pExtent->pszFullname);
     2223        return rc;
     2224    }
     2225    if (    (RT_LE2H_U32(pHeader->flags) & 1)
     2226        &&  (   pHeader->singleEndLineChar != '\n'
     2227             || pHeader->nonEndLineChar != ' '
     2228             || pHeader->doubleEndLineChar1 != '\r'
     2229             || pHeader->doubleEndLineChar2 != '\n') )
     2230    {
     2231        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
     2232        return rc;
     2233    }
     2234    return rc;
     2235}
     2236
     2237/**
    20272238 * Internal: read metadata belonging to an extent with binary header, i.e.
    20282239 * as found in monolithic files.
     
    20372248    if (RT_FAILURE(rc))
    20382249    {
    2039         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
    2040         goto out;
    2041     }
    2042     if (RT_LE2H_U32(Header.magicNumber) != VMDK_SPARSE_MAGICNUMBER)
    2043     {
    2044         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic in sparse extent header in '%s'"), pExtent->pszFullname);
    2045         goto out;
    2046     }
    2047     if (RT_LE2H_U32(Header.version) != 1)
    2048     {
    2049         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: incorrect version in sparse extent header in '%s', not a VMDK 1.0 conforming file"), pExtent->pszFullname);
    2050         goto out;
    2051     }
    2052     if (    (RT_LE2H_U32(Header.flags) & 1)
    2053         &&  (   Header.singleEndLineChar != '\n'
    2054              || Header.nonEndLineChar != ' '
    2055              || Header.doubleEndLineChar1 != '\r'
    2056              || Header.doubleEndLineChar2 != '\n') )
    2057     {
    2058         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
    2059         goto out;
    2060     }
     2250        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
     2251        goto out;
     2252    }
     2253    rc = vmdkValidateHeader(pImage, pExtent, &Header);
     2254    if (RT_FAILURE(rc))
     2255        goto out;
     2256    if (    RT_LE2H_U32(Header.flags & RT_BIT(17))
     2257        &&  RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
     2258    {
     2259        /* Extent with markers. Use this as criteria to read the footer, as
     2260         * the spec is as usual totally fuzzy what the criteria really is. */
     2261        uint64_t cbSize;
     2262        rc = vmdkFileGetSize(pExtent->pFile, &cbSize);
     2263        AssertRC(rc);
     2264        if (RT_FAILURE(rc))
     2265        {
     2266            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
     2267            goto out;
     2268        }
     2269        cbSize = RT_ALIGN_64(cbSize, 512);
     2270        rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL);
     2271        AssertRC(rc);
     2272        if (RT_FAILURE(rc))
     2273        {
     2274            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent footer in '%s'"), pExtent->pszFullname);
     2275            goto out;
     2276        }
     2277        rc = vmdkValidateHeader(pImage, pExtent, &Header);
     2278        if (RT_FAILURE(rc))
     2279            goto out;
     2280    }
     2281    pExtent->uVersion = RT_LE2H_U32(Header.version);
    20612282    pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */
    20622283    pExtent->cSectors = RT_LE2H_U64(Header.capacity);
     
    20662287    if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
    20672288    {
    2068         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
     2289        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
    20692290        goto out;
    20702291    }
    20712292    pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
    2072     if (RT_LE2H_U32(Header.flags) & 2)
     2293    if (RT_LE2H_U32(Header.flags) & RT_BIT(1))
    20732294    {
    20742295        pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
     
    20772298    else
    20782299    {
    2079         /** @todo this is just guesswork, the spec doesn't document this
    2080          * properly and I don't have a vmdk without RGD. */
    2081         pExtent->uSectorGD = RT_LE2H_U64(Header.rgdOffset);
     2300        pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
    20822301        pExtent->uSectorRGD = 0;
     2302    }
     2303    if (pExtent->uSectorGD == VMDK_GD_AT_END || pExtent->uSectorRGD == VMDK_GD_AT_END)
     2304    {
     2305        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname);
     2306        goto out;
    20832307    }
    20842308    pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
    20852309    pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
     2310    pExtent->uCompression = RT_LE2H_U16(Header.compressAlgorithm);
    20862311    cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    20872312    if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
    20882313    {
    2089         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
     2314        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
    20902315        goto out;
    20912316    }
     
    21052330    }
    21062331
     2332    /* streamOptimized extents need a grain decryption buffer. */
     2333    if (pExtent->uVersion == 3)
     2334    {
     2335        pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
     2336        if (!pExtent->pvGrain)
     2337        {
     2338            rc = VERR_NO_MEMORY;
     2339            goto out;
     2340        }
     2341        pExtent->uGrainSector = 0xffffffffffffffffULL;
     2342    }
     2343
    21072344out:
    21082345    if (RT_FAILURE(rc))
     
    21272364    if (RT_FAILURE(rc))
    21282365    {
    2129         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     2366        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    21302367        goto out;
    21312368    }
     
    21352372        &&  (pExtent->enmType != VMDKETYPE_FLAT || pExtent->cNominalSectors + pExtent->uSectorOffset > VMDK_BYTE2SECTOR(cbExtentSize)))
    21362373    {
    2137         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname);
     2374        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname);
    21382375        goto out;
    21392376    }
     
    21472384        ||  pExtent->cSectorsPerGrain < 8)
    21482385    {
    2149         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
     2386        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
    21502387        goto out;
    21512388    }
     
    21562393        ||  pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)
    21572394    {
    2158         rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
     2395        rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
    21592396        goto out;
    21602397    }
     
    21792416    Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
    21802417    Header.version = RT_H2LE_U32(1);
    2181     Header.flags = RT_H2LE_U32(1 | ((pExtent->pRGD) ? 2 : 0));
     2418    Header.flags = RT_H2LE_U32(RT_BIT(0));
     2419    if (pExtent->pRGD)
     2420        Header.flags |= RT_H2LE_U32(RT_BIT(1));
     2421    if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     2422        Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17));
    21822423    Header.capacity = RT_H2LE_U64(pExtent->cSectors);
    21832424    Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
     
    21932434    else
    21942435    {
    2195         /** @todo this is just guesswork, the spec doesn't document this
    2196          * properly and I don't have a vmdk without RGD. */
    2197         Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2436        Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
    21982437    }
    21992438    Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
     
    22032442    Header.doubleEndLineChar1 = '\r';
    22042443    Header.doubleEndLineChar2 = '\n';
     2444    Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
    22052445
    22062446    int rc = vmdkFileWriteAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
     
    26352875    /* Make sure this is not reached accidentally with an error status. */
    26362876    AssertRC(rc);
     2877
     2878    /* VMDK 1.0/1.1 version paranoia. */
     2879    for (unsigned i = 0; i < pImage->cExtents; i++)
     2880    {
     2881        pExtent = &pImage->pExtents[i];
     2882        if (    (   pExtent->uVersion != 3
     2883                 && (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     2884            ||  (   pExtent->uVersion != 1
     2885                 && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)))
     2886        {
     2887            rc = vmdkError(pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: inconsistent version in extent header in '%s', not a VMDK 1.0/1.1 conforming file"), pExtent->pszFullname);
     2888            goto out;
     2889        }
     2890    }
    26372891
    26382892    /* Determine PCHS geometry if not set. */
     
    29853239        if (RT_FAILURE(rc))
    29863240            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename);
    2987         // @todo Is there any sense in the following line I've commented out?
    2988         //pImage->pszFilename = RTStrDup(pImage->pszFilename);
    29893241    }
    29903242    else
     
    42874539                rc = VERR_VD_BLOCK_FREE;
    42884540            else
    4289                 rc = vmdkFileReadAt(pExtent->pFile,
    4290                                     VMDK_SECTOR2BYTE(uSectorExtentAbs),
    4291                                     pvBuf, cbToRead, NULL);
     4541            {
     4542                if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     4543                {
     4544                    uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
     4545                    uSectorExtentAbs -= uSectorInGrain;
     4546                    uint64_t uLBA;
     4547                    if (pExtent->uGrainSector != uSectorExtentAbs)
     4548                    {
     4549                        rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4550                                               pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA);
     4551                        if (RT_FAILURE(rc))
     4552                        {
     4553                            pExtent->uGrainSector = 0xffffffffffffffffULL;
     4554                            AssertRC(rc);
     4555                            goto out;
     4556                        }
     4557                        pExtent->uGrainSector = uSectorExtentAbs;
     4558                        Assert(uLBA == uSectorExtentRel);
     4559                    }
     4560                    memcpy(pvBuf, (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), cbToRead);
     4561                }
     4562                else
     4563                {
     4564                    rc = vmdkFileReadAt(pExtent->pFile,
     4565                                        VMDK_SECTOR2BYTE(uSectorExtentAbs),
     4566                                        pvBuf, cbToRead, NULL);
     4567                }
     4568            }
    42924569            break;
    42934570        case VMDKETYPE_FLAT:
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