VirtualBox

Changeset 18067 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Mar 18, 2009 2:17:49 PM (16 years ago)
Author:
vboxsync
Message:

Storage/VMDK: fix crash when create failed (recent regression), additionally fix dealing with streamOptimized VMDK files having a footer

File:
1 edited

Legend:

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

    r17970 r18067  
    304304    /** Flag whether the metadata in the extent header needs to be updated. */
    305305    bool        fMetaDirty;
     306    /** Flag whether there is a footer in this extent. */
     307    bool        fFooter;
    306308    /** Compression type for this extent. */
    307309    uint16_t    uCompression;
     
    24602462        &&  RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
    24612463    {
    2462         /* Extent with markers. Use this as criteria to read the footer, as
    2463          * the spec is as usual totally fuzzy what the criteria really is. */
     2464        /* Read the footer, which isn't compressed and comes before the
     2465         * end-of-stream marker. This is bending the VMDK 1.1 spec, but that's
     2466         * VMware reality. Theory and practice have very little in common. */
    24642467        uint64_t cbSize;
    24652468        rc = vmdkFileGetSize(pExtent->pFile, &cbSize);
     
    24712474        }
    24722475        cbSize = RT_ALIGN_64(cbSize, 512);
    2473         rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL, NULL);
     2476        rc = vmdkFileReadAt(pExtent->pFile, cbSize - 2*512, &Header, sizeof(Header), NULL);
    24742477        AssertRC(rc);
    24752478        if (RT_FAILURE(rc))
     
    24812484        if (RT_FAILURE(rc))
    24822485            goto out;
     2486        pExtent->fFooter = true;
    24832487    }
    24842488    pExtent->uVersion = RT_LE2H_U32(Header.version);
     
    26002604 * Internal: write/update the metadata for a sparse extent.
    26012605 */
    2602 static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent)
     2606static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent, uint64_t uOffset)
    26032607{
    26042608    SparseExtentHeader Header;
     
    26062610    memset(&Header, '\0', sizeof(Header));
    26072611    Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
    2608     Header.version = RT_H2LE_U32(1);
     2612    Header.version = RT_H2LE_U32(pExtent->uVersion);
    26092613    Header.flags = RT_H2LE_U32(RT_BIT(0));
    26102614    if (pExtent->pRGD)
     
    26172621    Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
    26182622    Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
    2619     if (pExtent->pRGD)
    2620     {
    2621         Assert(pExtent->uSectorRGD);
    2622         Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
    2623         Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2623    if (pExtent->fFooter && uOffset == 0)
     2624    {
     2625        if (pExtent->pRGD)
     2626        {
     2627            Assert(pExtent->uSectorRGD);
     2628            Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
     2629            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
     2630        }
     2631        else
     2632        {
     2633            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
     2634        }
    26242635    }
    26252636    else
    26262637    {
    2627         Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2638        if (pExtent->pRGD)
     2639        {
     2640            Assert(pExtent->uSectorRGD);
     2641            Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
     2642            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2643        }
     2644        else
     2645        {
     2646            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2647        }
    26282648    }
    26292649    Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
     
    26352655    Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
    26362656
    2637     int rc = vmdkFileWriteAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
     2657    int rc = vmdkFileWriteAt(pExtent->pFile, uOffset, &Header, sizeof(Header), NULL);
    26382658    AssertRC(rc);
    26392659    if (RT_FAILURE(rc))
     
    35623582            cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
    35633583            if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     3584            {
     3585                /* The spec says version is 1 for all VMDKs, but the vast
     3586                 * majority of streamOptimized VMDKs actually contain
     3587                 * version 3 - so go with the majority. Both are acepted. */
     3588                pExtent->uVersion = 3;
    35643589                pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
     3590            }
    35653591        }
    35663592        else
     
    38213847        }
    38223848    }
    3823     (void)vmdkFlushImage(pImage);
     3849    /* Don't attempt to flush the image if there is no file - usually happens
     3850     * when creating fails for whatever reason. */
     3851    if (pImage->pFile != NULL)
     3852        (void)vmdkFlushImage(pImage);
    38243853
    38253854    if (pImage->pExtents != NULL)
     
    38703899            {
    38713900                case VMDKETYPE_HOSTED_SPARSE:
    3872                     rc = vmdkWriteMetaSparseExtent(pExtent);
     3901                    rc = vmdkWriteMetaSparseExtent(pExtent, 0);
    38733902                    if (RT_FAILURE(rc))
    38743903                        goto out;
     3904                    if (pExtent->fFooter)
     3905                    {
     3906                        uint64_t cbSize;
     3907                        rc = vmdkFileGetSize(pExtent->pFile, &cbSize);
     3908                        if (RT_FAILURE(rc))
     3909                            goto out;
     3910                        cbSize = RT_ALIGN_64(cbSize, 512);
     3911                        rc = vmdkWriteMetaSparseExtent(pExtent, cbSize - 2*512);
     3912                        if (RT_FAILURE(rc))
     3913                            goto out;
     3914                    }
    38753915                    break;
    38763916#ifdef VBOX_WITH_VMDK_ESX
     
    40424082        uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    40434083        /* For writable streamOptimized extents the final sector is the
    4044          * end-of-stream marker. Will be re-added after the grain table. */
     4084         * end-of-stream marker. Will be re-added after the grain table.
     4085         * If the file has a footer it also will be re-added before EOS. */
    40454086        if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    40464087        {
     4088            uint64_t uEOSOff = 0;
    40474089            uGTSector--;
     4090            if (pExtent->fFooter)
     4091            {
     4092                uGTSector--;
     4093                uEOSOff = 512;
     4094                rc = vmdkWriteMetaSparseExtent(pExtent, VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t));
     4095                if (RT_FAILURE(rc))
     4096                    return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after grain table in '%s'"), pExtent->pszFullname);
     4097            }
    40484098            pExtent->uLastGrainSector = 0;
    40494099            uint8_t aEOS[512];
    40504100            memset(aEOS, '\0', sizeof(aEOS));
    40514101            rc = vmdkFileWriteAt(pExtent->pFile,
    4052                                  VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t),
     4102                                 VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t) + uEOSOff,
    40534103                                 aEOS, sizeof(aEOS), NULL);
    40544104            if (RT_FAILURE(rc))
     
    40844134            uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    40854135            /* For writable streamOptimized extents the final sector is the
    4086              * end-of-stream marker. Will be re-added after the grain table. */
     4136             * end-of-stream marker. Will be re-added after the grain table.
     4137             * If the file has a footer it also will be re-added before EOS. */
    40874138            if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    40884139            {
     4140                uint64_t uEOSOff = 0;
    40894141                uRGTSector--;
     4142                if (pExtent->fFooter)
     4143                {
     4144                    uRGTSector--;
     4145                    uEOSOff = 512;
     4146                    rc = vmdkWriteMetaSparseExtent(pExtent, VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t));
     4147                    if (RT_FAILURE(rc))
     4148                        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after redundant grain table in '%s'"), pExtent->pszFullname);
     4149                }
    40904150                pExtent->uLastGrainSector = 0;
    40914151                uint8_t aEOS[512];
    40924152                memset(aEOS, '\0', sizeof(aEOS));
    40934153                rc = vmdkFileWriteAt(pExtent->pFile,
    4094                                      VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t),
     4154                                     VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t) + uEOSOff,
    40954155                                     aEOS, sizeof(aEOS), NULL);
    40964156                if (RT_FAILURE(rc))
     
    41574217         * Additionally the end-of-stream marker needs to be written. */
    41584218        if (!pExtent->uLastGrainSector)
     4219        {
    41594220            cbExtentSize -= 512;
     4221            if (pExtent->fFooter)
     4222                cbExtentSize -= 512;
     4223        }
    41604224        else
    41614225            cbExtentSize = VMDK_SECTOR2BYTE(pExtent->uLastGrainSector) + pExtent->cbLastGrainWritten;
     
    41784242        pExtent->uGrainSector = uSector;
    41794243
     4244        uint64_t uEOSOff = 0;
     4245        if (pExtent->fFooter)
     4246        {
     4247            uEOSOff = 512;
     4248            rc = vmdkWriteMetaSparseExtent(pExtent, cbExtentSize + RT_ALIGN(cbGrain, 512));
     4249            if (RT_FAILURE(rc))
     4250                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after allocated data block in '%s'"), pExtent->pszFullname);
     4251        }
    41804252        uint8_t aEOS[512];
    41814253        memset(aEOS, '\0', sizeof(aEOS));
    4182         rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize + RT_ALIGN(cbGrain, 512),
     4254        rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize + RT_ALIGN(cbGrain, 512) + uEOSOff,
    41834255                             aEOS, sizeof(aEOS), NULL);
    41844256        if (RT_FAILURE(rc))
     
    49575029                    pExtent->cbLastGrainWritten = cbGrain;
    49585030
     5031                    uint64_t uEOSOff = 0;
     5032                    if (pExtent->fFooter)
     5033                    {
     5034                        uEOSOff = 512;
     5035                        rc = vmdkWriteMetaSparseExtent(pExtent, VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512));
     5036                        if (RT_FAILURE(rc))
     5037                            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write footer after data block in '%s'"), pExtent->pszFullname);
     5038                    }
    49595039                    uint8_t aEOS[512];
    49605040                    memset(aEOS, '\0', sizeof(aEOS));
    49615041                    rc = vmdkFileWriteAt(pExtent->pFile,
    4962                                          VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512),
     5042                                         VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512) + uEOSOff,
    49635043                                         aEOS, sizeof(aEOS), NULL);
    49645044                    if (RT_FAILURE(rc))
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