VirtualBox

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


Ignore:
Timestamp:
Sep 9, 2008 3:51:08 PM (16 years ago)
Author:
vboxsync
Message:

Storage/VMDK: make it understand the really odd vmdk variant used by haiku. Their images are still broken (one byte too short), and I don't want to ignore truncated images.

File:
1 edited

Legend:

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

    r11484 r12306  
    7777/**
    7878 * Magic number for hosted images created by VMware Workstation 4, VMware
    79  * Workstation 5, VMware Server or VMware Player.
     79 * Workstation 5, VMware Server or VMware Player. Not necessarily sparse.
    8080 */
    8181#define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
    8282
    83 /** VMDK hosted sparse extent header. */
     83/**
     84 * VMDK hosted binary extent header. The "Sparse" is a total misnomer, as
     85 * this header is also used for monolithic flat images.
     86 */
    8487#pragma pack(1)
    8588typedef struct SparseExtentHeader
     
    784787    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
    785788
     789    if (pExtent->enmType != VMDKETYPE_HOSTED_SPARSE)
     790        goto out;
     791
    786792    pGD = (uint32_t *)RTMemAllocZ(cbGD);
    787793    if (!pGD)
     
    14531459    pDescriptor->aLines[cLine] = pTmp;
    14541460
    1455     if (strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile"))
     1461    if (    strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile")
     1462        &&  strcmp(pDescriptor->aLines[0], "# Disk Descriptor File"))
    14561463    {
    14571464        rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
     
    20162023
    20172024/**
    2018  * Internal: read metadata belonging to a sparse extent.
     2025 * Internal: read metadata belonging to an extent with binary header, i.e.
     2026 * as found in monolithic files.
    20192027 */
    2020 static int vmdkReadMetaSparseExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
     2028static int vmdkReadBinaryMetaExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
    20212029{
    20222030    SparseExtentHeader Header;
    2023     uint64_t cbExtentSize, cSectorsPerGDE;
     2031    uint64_t cSectorsPerGDE;
    20242032
    20252033    int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
     
    20342042    {
    20352043        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic/version in extent header in '%s'"), pExtent->pszFullname);
    2036         goto out;
    2037     }
    2038     /* The image must be a multiple of a sector in size. If not, it means the
    2039      * image is at least truncated, or even seriously garbled. */
    2040     rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
    2041     if (RT_FAILURE(rc))
    2042     {
    2043         rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    20442044        goto out;
    20452045    }
     
    20532053        goto out;
    20542054    }
    2055     pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     2055    pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */
    20562056    pExtent->cSectors = RT_LE2H_U64(Header.capacity);
    20572057    pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize);
     2058    pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset);
     2059    pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize);
     2060    if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
     2061    {
     2062        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
     2063        goto out;
     2064    }
     2065    pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
     2066    if (RT_LE2H_U32(Header.flags) & 2)
     2067    {
     2068        pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
     2069        pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
     2070    }
     2071    else
     2072    {
     2073        /** @todo this is just guesswork, the spec doesn't document this
     2074         * properly and I don't have a vmdk without RGD. */
     2075        pExtent->uSectorGD = RT_LE2H_U64(Header.rgdOffset);
     2076        pExtent->uSectorRGD = 0;
     2077    }
     2078    pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
     2079    pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
     2080    cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     2081    if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
     2082    {
     2083        rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
     2084        goto out;
     2085    }
     2086    pExtent->cSectorsPerGDE = cSectorsPerGDE;
     2087    pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     2088
     2089    /* Fix up the number of descriptor sectors, as some flat images have
     2090     * really just one, and this causes failures when inserting the UUID
     2091     * values and other extra information. */
     2092    if (pExtent->cDescriptorSectors != 0 && pExtent->cDescriptorSectors < 4)
     2093    {
     2094        /* Do it the easy way - just fix it for flat images which have no
     2095         * other complicated metadata which needs space too. */
     2096        if (    pExtent->uDescriptorSector + 4 < pExtent->cOverheadSectors
     2097            &&  pExtent->cGTEntries * pExtent->cGDEntries == 0)
     2098            pExtent->cDescriptorSectors = 4;
     2099    }
     2100
     2101out:
     2102    if (RT_FAILURE(rc))
     2103        vmdkFreeExtentData(pImage, pExtent, false);
     2104
     2105    return rc;
     2106}
     2107
     2108/**
     2109 * Internal: read additional metadata belonging to an extent. For those
     2110 * extents which have no additional metadata just verify the information.
     2111 */
     2112static int vmdkReadMetaExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
     2113{
     2114    int rc = VINF_SUCCESS;
     2115    uint64_t cbExtentSize;
     2116
     2117    /* The image must be a multiple of a sector in size and contain the data
     2118     * area (flat images only). If not, it means the image is at least
     2119     * truncated, or even seriously garbled. */
     2120    rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
     2121    if (RT_FAILURE(rc))
     2122    {
     2123        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     2124        goto out;
     2125    }
     2126    if (    cbExtentSize != RT_ALIGN_64(cbExtentSize, 512)
     2127        &&  (pExtent->enmType != VMDKETYPE_FLAT || pExtent->cNominalSectors + pExtent->uSectorOffset > VMDK_BYTE2SECTOR(cbExtentSize)))
     2128    {
     2129        rc = vmdkError(pExtent->pImage, VERR_VDI_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);
     2130        goto out;
     2131    }
     2132    if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE)
     2133        goto out;
     2134
    20582135    /* The spec says that this must be a power of two and greater than 8,
    20592136     * but probably they meant not less than 8. */
     
    20642141        goto out;
    20652142    }
    2066     pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset);
    2067     pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize);
    2068     if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
    2069     {
    2070         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
    2071         goto out;
    2072     }
    2073     pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
     2143
    20742144    /* This code requires that a grain table must hold a power of two multiple
    20752145     * of the number of entries per GT cache entry. */
     
    20802150        goto out;
    20812151    }
    2082     if (RT_LE2H_U32(Header.flags) & 2)
    2083     {
    2084         pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
    2085         pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
    2086     }
    2087     else
    2088     {
    2089         /** @todo this is just guesswork, the spec doesn't document this
    2090          * properly and I don't have a vmdk without RGD. */
    2091         pExtent->uSectorGD = RT_LE2H_U64(Header.rgdOffset);
    2092         pExtent->uSectorRGD = 0;
    2093     }
    2094     pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
    2095     pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
    2096     cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    2097     if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
    2098     {
    2099         rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
    2100         goto out;
    2101     }
    2102     pExtent->cSectorsPerGDE = cSectorsPerGDE;
    2103     pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    21042152
    21052153    rc = vmdkReadGrainDirectory(pExtent);
     
    23682416    if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
    23692417    {
    2370         /* It's a hosted sparse single-extent image. */
     2418        /* It's a hosted single-extent image. */
    23712419        rc = vmdkCreateExtents(pImage, 1);
    23722420        if (RT_FAILURE(rc))
     
    23832431            goto out;
    23842432        }
    2385         rc = vmdkReadMetaSparseExtent(pImage, pExtent);
     2433        rc = vmdkReadBinaryMetaExtent(pImage, pExtent);
    23862434        if (RT_FAILURE(rc))
    23872435            goto out;
    2388         /* As we're dealing with a monolithic sparse image here, there must
     2436        /* As we're dealing with a monolithic image here, there must
    23892437         * be a descriptor embedded in the image file. */
    23902438        if (!pExtent->uDescriptorSector || !pExtent->cDescriptorSectors)
     
    24132461        rc = vmdkParseDescriptor(pImage, pExtent->pDescData,
    24142462                                 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
     2463        if (RT_FAILURE(rc))
     2464            goto out;
     2465
     2466        rc = vmdkReadMetaExtent(pImage, pExtent);
    24152467        if (RT_FAILURE(rc))
    24162468            goto out;
     
    25352587                        goto out;
    25362588                    }
    2537                     rc = vmdkReadMetaSparseExtent(pImage, pExtent);
     2589                    rc = vmdkReadBinaryMetaExtent(pImage, pExtent);
     2590                    if (RT_FAILURE(rc))
     2591                        goto out;
     2592                    rc = vmdkReadMetaExtent(pImage, pExtent);
    25382593                    if (RT_FAILURE(rc))
    25392594                        goto out;
     
    35333588            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
    35343589        Assert(!(cbExtentSize % 512));
     3590        cbExtentSize = RT_ALIGN_64(cbExtentSize, 512);
    35353591        uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
    35363592        /* Normally the grain table is preallocated for hosted sparse extents
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