VirtualBox

Changeset 63825 in vbox for trunk


Ignore:
Timestamp:
Sep 14, 2016 7:59:21 AM (8 years ago)
Author:
vboxsync
Message:

Storage/VMDK: Cleanup (part 4, get rid of goto in vmdkOpenImage)

File:
1 edited

Legend:

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

    r63811 r63825  
    29142914
    29152915/**
    2916  * Internal: Open an image, constructing all necessary data structures.
    2917  */
    2918 static int vmdkOpenImage(PVMDKIMAGE pImage, unsigned uOpenFlags)
    2919 {
    2920     int rc;
    2921     uint32_t u32Magic;
    2922     PVMDKFILE pFile;
    2923     PVMDKEXTENT pExtent;
    2924 
    2925     pImage->uOpenFlags = uOpenFlags;
    2926 
    2927     pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
    2928     pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
    2929     AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
    2930 
    2931     /*
    2932      * Open the image.
    2933      * We don't have to check for asynchronous access because
    2934      * we only support raw access and the opened file is a description
    2935      * file were no data is stored.
    2936      */
    2937 
    2938     rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename,
    2939                       VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
    2940     if (RT_FAILURE(rc))
    2941     {
    2942         /* Do NOT signal an appropriate error here, as the VD layer has the
    2943          * choice of retrying the open if it failed. */
    2944         goto out;
    2945     }
    2946     pImage->pFile = pFile;
    2947 
    2948     /* Read magic (if present). */
    2949     rc = vdIfIoIntFileReadSync(pImage->pIfIo, pFile->pStorage, 0,
    2950                                &u32Magic, sizeof(u32Magic));
    2951     if (RT_FAILURE(rc))
    2952     {
    2953         vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading the magic number in '%s'"), pImage->pszFilename);
    2954         rc = VERR_VD_VMDK_INVALID_HEADER;
    2955         goto out;
    2956     }
    2957 
    2958     /* Handle the file according to its magic number. */
    2959     if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
    2960     {
    2961         /* It's a hosted single-extent image. */
    2962         rc = vmdkCreateExtents(pImage, 1);
    2963         if (RT_FAILURE(rc))
    2964             goto out;
     2916 * Reads and processes the descriptor embedded in sparse images.
     2917 *
     2918 * @returns VBox status code.
     2919 * @param   pImage         VMDK image instance.
     2920 * @param   pFile          The sparse file handle.
     2921 */
     2922static int vmdkDescriptorReadSparse(PVMDKIMAGE pImage, PVMDKFILE pFile)
     2923{
     2924    /* It's a hosted single-extent image. */
     2925    int rc = vmdkCreateExtents(pImage, 1);
     2926    if (RT_SUCCESS(rc))
     2927    {
    29652928        /* The opened file is passed to the extent. No separate descriptor
    29662929         * file, so no need to keep anything open for the image. */
    2967         pExtent = &pImage->pExtents[0];
     2930        PVMDKEXTENT pExtent = &pImage->pExtents[0];
    29682931        pExtent->pFile = pFile;
    29692932        pImage->pFile = NULL;
    29702933        pExtent->pszFullname = RTPathAbsDup(pImage->pszFilename);
    2971         if (!pExtent->pszFullname)
    2972         {
     2934        if (RT_LIKELY(pExtent->pszFullname))
     2935        {
     2936            /* As we're dealing with a monolithic image here, there must
     2937             * be a descriptor embedded in the image file. */
     2938            rc = vmdkReadBinaryMetaExtent(pImage, pExtent, true /* fMagicAlreadyRead */);
     2939            if (   RT_SUCCESS(rc)
     2940                && pExtent->uDescriptorSector
     2941                && pExtent->cDescriptorSectors)
     2942            {
     2943                /* HACK: extend the descriptor if it is unusually small and it fits in
     2944                 * the unused space after the image header. Allows opening VMDK files
     2945                 * with extremely small descriptor in read/write mode.
     2946                 *
     2947                 * The previous version introduced a possible regression for VMDK stream
     2948                 * optimized images from VMware which tend to have only a single sector sized
     2949                 * descriptor. Increasing the descriptor size resulted in adding the various uuid
     2950                 * entries required to make it work with VBox but for stream optimized images
     2951                 * the updated binary header wasn't written to the disk creating a mismatch
     2952                 * between advertised and real descriptor size.
     2953                 *
     2954                 * The descriptor size will be increased even if opened readonly now if there
     2955                 * enough room but the new value will not be written back to the image.
     2956                 */
     2957                if (    pExtent->cDescriptorSectors < 3
     2958                    &&  (int64_t)pExtent->uSectorGD - pExtent->uDescriptorSector >= 4
     2959                    &&  (!pExtent->uSectorRGD || (int64_t)pExtent->uSectorRGD - pExtent->uDescriptorSector >= 4))
     2960                {
     2961                    uint64_t cDescriptorSectorsOld = pExtent->cDescriptorSectors;
     2962
     2963                    pExtent->cDescriptorSectors = 4;
     2964                    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     2965                    {
     2966                        /*
     2967                         * Update the on disk number now to make sure we don't introduce inconsistencies
     2968                         * in case of stream optimized images from VMware where the descriptor is just
     2969                         * one sector big (the binary header is not written to disk for complete
     2970                         * stream optimized images in vmdkFlushImage()).
     2971                         */
     2972                        uint64_t u64DescSizeNew = RT_H2LE_U64(pExtent->cDescriptorSectors);
     2973                        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pFile->pStorage, RT_OFFSETOF(SparseExtentHeader, descriptorSize),
     2974                                                    &u64DescSizeNew, sizeof(u64DescSizeNew));
     2975                        if (RT_FAILURE(rc))
     2976                        {
     2977                            LogFlowFunc(("Increasing the descriptor size failed with %Rrc\n", rc));
     2978                            /* Restore the old size and carry on. */
     2979                            pExtent->cDescriptorSectors = cDescriptorSectorsOld;
     2980                        }
     2981                    }
     2982                }
     2983                /* Read the descriptor from the extent. */
     2984                pExtent->pDescData = (char *)RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
     2985                if (RT_LIKELY(pExtent->pDescData))
     2986                {
     2987                    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
     2988                                               VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
     2989                                               pExtent->pDescData,
     2990                                               VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
     2991                    if (RT_SUCCESS(rc))
     2992                    {
     2993                        rc = vmdkParseDescriptor(pImage, pExtent->pDescData,
     2994                                                 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
     2995                        if (   RT_SUCCESS(rc)
     2996                            && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     2997                            && !(pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO))
     2998                        {
     2999                            rc = vmdkReadMetaExtent(pImage, pExtent);
     3000                            if (RT_SUCCESS(rc))
     3001                            {
     3002                                /* Mark the extent as unclean if opened in read-write mode. */
     3003                                if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3004                                    && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     3005                                {
     3006                                    pExtent->fUncleanShutdown = true;
     3007                                    pExtent->fMetaDirty = true;
     3008                                }
     3009                            }
     3010                        }
     3011                        else if (RT_SUCCESS(rc))
     3012                            rc = VERR_NOT_SUPPORTED;
     3013                    }
     3014                    else
     3015                        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pExtent->pszFullname);
     3016                }
     3017                else
     3018                    rc = VERR_NO_MEMORY;
     3019            }
     3020            else if (RT_SUCCESS(rc))
     3021                rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in '%s'"), pImage->pszFilename);
     3022        }
     3023        else
    29733024            rc = VERR_NO_MEMORY;
    2974             goto out;
    2975         }
    2976         rc = vmdkReadBinaryMetaExtent(pImage, pExtent, true /* fMagicAlreadyRead */);
    2977         if (RT_FAILURE(rc))
    2978             goto out;
    2979 
    2980         /* As we're dealing with a monolithic image here, there must
    2981          * be a descriptor embedded in the image file. */
    2982         if (!pExtent->uDescriptorSector || !pExtent->cDescriptorSectors)
    2983         {
    2984             rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in '%s'"), pImage->pszFilename);
    2985             goto out;
    2986         }
    2987         /* HACK: extend the descriptor if it is unusually small and it fits in
    2988          * the unused space after the image header. Allows opening VMDK files
    2989          * with extremely small descriptor in read/write mode.
    2990          *
    2991          * The previous version introduced a possible regression for VMDK stream
    2992          * optimized images from VMware which tend to have only a single sector sized
    2993          * descriptor. Increasing the descriptor size resulted in adding the various uuid
    2994          * entries required to make it work with VBox but for stream optimized images
    2995          * the updated binary header wasn't written to the disk creating a mismatch
    2996          * between advertised and real descriptor size.
    2997          *
    2998          * The descriptor size will be increased even if opened readonly now if there
    2999          * enough room but the new value will not be written back to the image.
    3000          */
    3001         if (    pExtent->cDescriptorSectors < 3
    3002             &&  (int64_t)pExtent->uSectorGD - pExtent->uDescriptorSector >= 4
    3003             &&  (!pExtent->uSectorRGD || (int64_t)pExtent->uSectorRGD - pExtent->uDescriptorSector >= 4))
    3004         {
    3005             uint64_t cDescriptorSectorsOld = pExtent->cDescriptorSectors;
    3006 
    3007             pExtent->cDescriptorSectors = 4;
    3008             if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    3009             {
    3010                 /*
    3011                  * Update the on disk number now to make sure we don't introduce inconsistencies
    3012                  * in case of stream optimized images from VMware where the descriptor is just
    3013                  * one sector big (the binary header is not written to disk for complete
    3014                  * stream optimized images in vmdkFlushImage()).
    3015                  */
    3016                 uint64_t u64DescSizeNew = RT_H2LE_U64(pExtent->cDescriptorSectors);
    3017                 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pFile->pStorage, RT_OFFSETOF(SparseExtentHeader, descriptorSize),
    3018                                             &u64DescSizeNew, sizeof(u64DescSizeNew));
    3019                 if (RT_FAILURE(rc))
    3020                 {
    3021                     LogFlowFunc(("Increasing the descriptor size failed with %Rrc\n", rc));
    3022                     /* Restore the old size and carry on. */
    3023                     pExtent->cDescriptorSectors = cDescriptorSectorsOld;
    3024                 }
    3025             }
    3026         }
    3027         /* Read the descriptor from the extent. */
    3028         pExtent->pDescData = (char *)RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
    3029         if (!pExtent->pDescData)
    3030         {
    3031             rc = VERR_NO_MEMORY;
    3032             goto out;
    3033         }
    3034         rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
    3035                                    VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
    3036                                    pExtent->pDescData,
    3037                                    VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
    3038         AssertRC(rc);
    3039         if (RT_FAILURE(rc))
    3040         {
    3041             rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pExtent->pszFullname);
    3042             goto out;
    3043         }
    3044 
    3045         rc = vmdkParseDescriptor(pImage, pExtent->pDescData,
    3046                                  VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
    3047         if (RT_FAILURE(rc))
    3048             goto out;
    3049 
    3050         if (   pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
    3051             && uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
    3052         {
    3053             rc = VERR_NOT_SUPPORTED;
    3054             goto out;
    3055         }
    3056 
    3057         rc = vmdkReadMetaExtent(pImage, pExtent);
    3058         if (RT_FAILURE(rc))
    3059             goto out;
    3060 
    3061         /* Mark the extent as unclean if opened in read-write mode. */
    3062         if (   !(uOpenFlags & VD_OPEN_FLAGS_READONLY)
    3063             && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
    3064         {
    3065             pExtent->fUncleanShutdown = true;
    3066             pExtent->fMetaDirty = true;
    3067         }
    3068     }
    3069     else
    3070     {
    3071         /* Allocate at least 10K, and make sure that there is 5K free space
    3072          * in case new entries need to be added to the descriptor. Never
    3073          * allocate more than 128K, because that's no valid descriptor file
    3074          * and will result in the correct "truncated read" error handling. */
    3075         uint64_t cbFileSize;
    3076         rc = vdIfIoIntFileGetSize(pImage->pIfIo, pFile->pStorage, &cbFileSize);
    3077         if (RT_FAILURE(rc))
    3078             goto out;
    3079 
    3080         /* If the descriptor file is shorter than 50 bytes it can't be valid. */
    3081         if (cbFileSize < 50)
    3082         {
    3083             rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor in '%s' is too short"), pImage->pszFilename);
    3084             goto out;
    3085         }
    3086 
     3025    }
     3026
     3027    return rc;
     3028}
     3029
     3030/**
     3031 * Reads the descriptor from a pure text file.
     3032 *
     3033 * @returns VBox status code.
     3034 * @param   pImage          VMDK image instance.
     3035 * @param   pFile           The descriptor file handle.
     3036 */
     3037static int vmdkDescriptorReadAscii(PVMDKIMAGE pImage, PVMDKFILE pFile)
     3038{
     3039    /* Allocate at least 10K, and make sure that there is 5K free space
     3040     * in case new entries need to be added to the descriptor. Never
     3041     * allocate more than 128K, because that's no valid descriptor file
     3042     * and will result in the correct "truncated read" error handling. */
     3043    uint64_t cbFileSize;
     3044    int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pFile->pStorage, &cbFileSize);
     3045    if (   RT_SUCCESS(rc)
     3046        && cbFileSize >= 50)
     3047    {
    30873048        uint64_t cbSize = cbFileSize;
    30883049        if (cbSize % VMDK_SECTOR2BYTE(10))
     
    30933054        pImage->cbDescAlloc = RT_MAX(VMDK_SECTOR2BYTE(20), cbSize);
    30943055        pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
    3095         if (!pImage->pDescData)
    3096         {
    3097             rc = VERR_NO_MEMORY;
    3098             goto out;
    3099         }
    3100 
    3101         /* Don't reread the place where the magic would live in a sparse
    3102          * image if it's a descriptor based one. */
    3103         memcpy(pImage->pDescData, &u32Magic, sizeof(u32Magic));
    3104         rc = vdIfIoIntFileReadSync(pImage->pIfIo, pFile->pStorage, sizeof(u32Magic),
    3105                                    pImage->pDescData + sizeof(u32Magic),
    3106                                    RT_MIN(pImage->cbDescAlloc - sizeof(u32Magic),
    3107                                           cbFileSize - sizeof(u32Magic)));
    3108         if (RT_FAILURE(rc))
    3109         {
    3110             rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pImage->pszFilename);
    3111             goto out;
    3112         }
    3113 
     3056        if (RT_LIKELY(pImage->pDescData))
     3057        {
     3058            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pFile->pStorage, 0, pImage->pDescData,
     3059                                       RT_MIN(pImage->cbDescAlloc, cbFileSize));
     3060            if (RT_SUCCESS(rc))
     3061            {
    31143062#if 0 /** @todo Revisit */
    3115         cbRead += sizeof(u32Magic);
    3116         if (cbRead == pImage->cbDescAlloc)
    3117         {
    3118             /* Likely the read is truncated. Better fail a bit too early
    3119              * (normally the descriptor is much smaller than our buffer). */
    3120             rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in '%s'"), pImage->pszFilename);
    3121             goto out;
    3122         }
     3063                cbRead += sizeof(u32Magic);
     3064                if (cbRead == pImage->cbDescAlloc)
     3065                {
     3066                    /* Likely the read is truncated. Better fail a bit too early
     3067                     * (normally the descriptor is much smaller than our buffer). */
     3068                    rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in '%s'"), pImage->pszFilename);
     3069                    goto out;
     3070                }
    31233071#endif
    3124 
    3125         rc = vmdkParseDescriptor(pImage, pImage->pDescData,
    3126                                  pImage->cbDescAlloc);
    3127         if (RT_FAILURE(rc))
    3128             goto out;
    3129 
    3130         for (unsigned i = 0; i < pImage->cExtents; i++)
    3131         {
    3132             pExtent = &pImage->pExtents[i];
    3133 
    3134             if (pExtent->pszBasename)
    3135             {
    3136                 /* Hack to figure out whether the specified name in the
    3137                  * extent descriptor is absolute. Doesn't always work, but
    3138                  * should be good enough for now. */
    3139                 char *pszFullname;
    3140                 /** @todo implement proper path absolute check. */
    3141                 if (pExtent->pszBasename[0] == RTPATH_SLASH)
     3072                rc = vmdkParseDescriptor(pImage, pImage->pDescData,
     3073                                         pImage->cbDescAlloc);
     3074                if (RT_SUCCESS(rc))
    31423075                {
    3143                     pszFullname = RTStrDup(pExtent->pszBasename);
    3144                     if (!pszFullname)
     3076                    for (unsigned i = 0; i < pImage->cExtents && RT_SUCCESS(rc); i++)
    31453077                    {
    3146                         rc = VERR_NO_MEMORY;
    3147                         goto out;
     3078                        PVMDKEXTENT pExtent = &pImage->pExtents[i];
     3079                        if (pExtent->pszBasename)
     3080                        {
     3081                            /* Hack to figure out whether the specified name in the
     3082                             * extent descriptor is absolute. Doesn't always work, but
     3083                             * should be good enough for now. */
     3084                            char *pszFullname;
     3085                            /** @todo implement proper path absolute check. */
     3086                            if (pExtent->pszBasename[0] == RTPATH_SLASH)
     3087                            {
     3088                                pszFullname = RTStrDup(pExtent->pszBasename);
     3089                                if (!pszFullname)
     3090                                {
     3091                                    rc = VERR_NO_MEMORY;
     3092                                    break;
     3093                                }
     3094                            }
     3095                            else
     3096                            {
     3097                                char *pszDirname = RTStrDup(pImage->pszFilename);
     3098                                if (!pszDirname)
     3099                                {
     3100                                    rc = VERR_NO_MEMORY;
     3101                                    break;
     3102                                }
     3103                                RTPathStripFilename(pszDirname);
     3104                                pszFullname = RTPathJoinA(pszDirname, pExtent->pszBasename);
     3105                                RTStrFree(pszDirname);
     3106                                if (!pszFullname)
     3107                                {
     3108                                    rc = VERR_NO_STR_MEMORY;
     3109                                    break;
     3110                                }
     3111                            }
     3112                            pExtent->pszFullname = pszFullname;
     3113                        }
     3114                        else
     3115                            pExtent->pszFullname = NULL;
     3116
     3117                        unsigned uOpenFlags = pImage->uOpenFlags | ((pExtent->enmAccess == VMDKACCESS_READONLY) ? VD_OPEN_FLAGS_READONLY : 0);
     3118                        switch (pExtent->enmType)
     3119                        {
     3120                            case VMDKETYPE_HOSTED_SPARSE:
     3121                                rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     3122                                                  VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
     3123                                if (RT_FAILURE(rc))
     3124                                {
     3125                                    /* Do NOT signal an appropriate error here, as the VD
     3126                                     * layer has the choice of retrying the open if it
     3127                                     * failed. */
     3128                                    break;
     3129                                }
     3130                                rc = vmdkReadBinaryMetaExtent(pImage, pExtent,
     3131                                                              false /* fMagicAlreadyRead */);
     3132                                if (RT_FAILURE(rc))
     3133                                    break;
     3134                                rc = vmdkReadMetaExtent(pImage, pExtent);
     3135                                if (RT_FAILURE(rc))
     3136                                    break;
     3137
     3138                                /* Mark extent as unclean if opened in read-write mode. */
     3139                                if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     3140                                {
     3141                                    pExtent->fUncleanShutdown = true;
     3142                                    pExtent->fMetaDirty = true;
     3143                                }
     3144                                break;
     3145                            case VMDKETYPE_VMFS:
     3146                            case VMDKETYPE_FLAT:
     3147                                rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     3148                                                  VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
     3149                                if (RT_FAILURE(rc))
     3150                                {
     3151                                    /* Do NOT signal an appropriate error here, as the VD
     3152                                     * layer has the choice of retrying the open if it
     3153                                     * failed. */
     3154                                    break;
     3155                                }
     3156                                break;
     3157                            case VMDKETYPE_ZERO:
     3158                                /* Nothing to do. */
     3159                                break;
     3160                            default:
     3161                                AssertMsgFailed(("unknown vmdk extent type %d\n", pExtent->enmType));
     3162                        }
    31483163                    }
    31493164                }
    3150                 else
    3151                 {
    3152                     char *pszDirname = RTStrDup(pImage->pszFilename);
    3153                     if (!pszDirname)
    3154                     {
    3155                         rc = VERR_NO_MEMORY;
    3156                         goto out;
    3157                     }
    3158                     RTPathStripFilename(pszDirname);
    3159                     pszFullname = RTPathJoinA(pszDirname, pExtent->pszBasename);
    3160                     RTStrFree(pszDirname);
    3161                     if (!pszFullname)
    3162                     {
    3163                         rc = VERR_NO_STR_MEMORY;
    3164                         goto out;
    3165                     }
    3166                 }
    3167                 pExtent->pszFullname = pszFullname;
    31683165            }
    31693166            else
    3170                 pExtent->pszFullname = NULL;
    3171 
    3172             switch (pExtent->enmType)
     3167                rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pImage->pszFilename);
     3168        }
     3169        else
     3170            rc = VERR_NO_MEMORY;
     3171    }
     3172    else if (RT_SUCCESS(rc))
     3173        rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor in '%s' is too short"), pImage->pszFilename);
     3174
     3175    return rc;
     3176}
     3177
     3178/**
     3179 * Read and process the descriptor based on the image type.
     3180 *
     3181 * @returns VBox status code.
     3182 * @param   pImage    VMDK image instance.
     3183 * @param   pFile     VMDK file handle.
     3184 */
     3185static int vmdkDescriptorRead(PVMDKIMAGE pImage, PVMDKFILE pFile)
     3186{
     3187    uint32_t u32Magic;
     3188
     3189    /* Read magic (if present). */
     3190    int rc = vdIfIoIntFileReadSync(pImage->pIfIo, pFile->pStorage, 0,
     3191                                   &u32Magic, sizeof(u32Magic));
     3192    if (RT_SUCCESS(rc))
     3193    {
     3194        /* Handle the file according to its magic number. */
     3195        if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
     3196            rc = vmdkDescriptorReadSparse(pImage, pFile);
     3197        else
     3198            rc = vmdkDescriptorReadAscii(pImage, pFile);
     3199    }
     3200    else
     3201    {
     3202        vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading the magic number in '%s'"), pImage->pszFilename);   
     3203        rc = VERR_VD_VMDK_INVALID_HEADER;
     3204    }
     3205
     3206    return rc;
     3207}
     3208
     3209/**
     3210 * Internal: Open an image, constructing all necessary data structures.
     3211 */
     3212static int vmdkOpenImage(PVMDKIMAGE pImage, unsigned uOpenFlags)
     3213{
     3214    pImage->uOpenFlags = uOpenFlags;
     3215    pImage->pIfError   = VDIfErrorGet(pImage->pVDIfsDisk);
     3216    pImage->pIfIo      = VDIfIoIntGet(pImage->pVDIfsImage);
     3217    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
     3218
     3219    /*
     3220     * Open the image.
     3221     * We don't have to check for asynchronous access because
     3222     * we only support raw access and the opened file is a description
     3223     * file were no data is stored.
     3224     */
     3225    PVMDKFILE pFile;
     3226    int rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename,
     3227                          VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */));
     3228    if (RT_SUCCESS(rc))
     3229    {
     3230        pImage->pFile = pFile;
     3231
     3232        rc = vmdkDescriptorRead(pImage, pFile);
     3233        if (RT_SUCCESS(rc))
     3234        {
     3235            /* Determine PCHS geometry if not set. */
     3236            if (pImage->PCHSGeometry.cCylinders == 0)
    31733237            {
    3174                 case VMDKETYPE_HOSTED_SPARSE:
    3175                     rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
    3176                                       VDOpenFlagsToFileOpenFlags(uOpenFlags | ((pExtent->enmAccess == VMDKACCESS_READONLY) ? VD_OPEN_FLAGS_READONLY : 0),
    3177                                                                  false /* fCreate */));
    3178                     if (RT_FAILURE(rc))
     3238                uint64_t cCylinders =   VMDK_BYTE2SECTOR(pImage->cbSize)
     3239                                      / pImage->PCHSGeometry.cHeads
     3240                                      / pImage->PCHSGeometry.cSectors;
     3241                pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
     3242                if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3243                    && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
     3244                {
     3245                    rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
     3246                    AssertRC(rc);
     3247                }
     3248            }
     3249
     3250            /* Update the image metadata now in case has changed. */
     3251            rc = vmdkFlushImage(pImage, NULL);
     3252            if (RT_SUCCESS(rc))
     3253            {
     3254                /* Figure out a few per-image constants from the extents. */
     3255                pImage->cbSize = 0;
     3256                for (unsigned i = 0; i < pImage->cExtents; i++)
     3257                {
     3258                    PVMDKEXTENT pExtent = &pImage->pExtents[i];
     3259                    if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE)
    31793260                    {
    3180                         /* Do NOT signal an appropriate error here, as the VD
    3181                          * layer has the choice of retrying the open if it
    3182                          * failed. */
    3183                         goto out;
     3261                        /* Here used to be a check whether the nominal size of an extent
     3262                         * is a multiple of the grain size. The spec says that this is
     3263                         * always the case, but unfortunately some files out there in the
     3264                         * wild violate the spec (e.g. ReactOS 0.3.1). */
    31843265                    }
    3185                     rc = vmdkReadBinaryMetaExtent(pImage, pExtent,
    3186                                                   false /* fMagicAlreadyRead */);
    3187                     if (RT_FAILURE(rc))
    3188                         goto out;
    3189                     rc = vmdkReadMetaExtent(pImage, pExtent);
    3190                     if (RT_FAILURE(rc))
    3191                         goto out;
    3192 
    3193                     /* Mark extent as unclean if opened in read-write mode. */
    3194                     if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
    3195                     {
    3196                         pExtent->fUncleanShutdown = true;
    3197                         pExtent->fMetaDirty = true;
    3198                     }
    3199                     break;
    3200                 case VMDKETYPE_VMFS:
    3201                 case VMDKETYPE_FLAT:
    3202                     rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
    3203                                       VDOpenFlagsToFileOpenFlags(uOpenFlags | ((pExtent->enmAccess == VMDKACCESS_READONLY) ? VD_OPEN_FLAGS_READONLY : 0),
    3204                                                                  false /* fCreate */));
    3205                     if (RT_FAILURE(rc))
    3206                     {
    3207                         /* Do NOT signal an appropriate error here, as the VD
    3208                          * layer has the choice of retrying the open if it
    3209                          * failed. */
    3210                         goto out;
    3211                     }
    3212                     break;
    3213                 case VMDKETYPE_ZERO:
    3214                     /* Nothing to do. */
    3215                     break;
    3216                 default:
    3217                     AssertMsgFailed(("unknown vmdk extent type %d\n", pExtent->enmType));
     3266                    else if (    pExtent->enmType == VMDKETYPE_FLAT
     3267                             ||  pExtent->enmType == VMDKETYPE_ZERO)
     3268                        pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
     3269
     3270                    pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
     3271                }
     3272
     3273                if (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     3274                    || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3275                    || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
     3276                    rc = vmdkAllocateGrainTableCache(pImage);
    32183277            }
    32193278        }
    32203279    }
    3221 
    3222     /* Make sure this is not reached accidentally with an error status. */
    3223     AssertRC(rc);
    3224 
    3225     /* Determine PCHS geometry if not set. */
    3226     if (pImage->PCHSGeometry.cCylinders == 0)
    3227     {
    3228         uint64_t cCylinders =   VMDK_BYTE2SECTOR(pImage->cbSize)
    3229                               / pImage->PCHSGeometry.cHeads
    3230                               / pImage->PCHSGeometry.cSectors;
    3231         pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
    3232         if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    3233             && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
    3234         {
    3235             rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
    3236             AssertRC(rc);
    3237         }
    3238     }
    3239 
    3240     /* Update the image metadata now in case has changed. */
    3241     rc = vmdkFlushImage(pImage, NULL);
    3242     if (RT_FAILURE(rc))
    3243         goto out;
    3244 
    3245     /* Figure out a few per-image constants from the extents. */
    3246     pImage->cbSize = 0;
    3247     for (unsigned i = 0; i < pImage->cExtents; i++)
    3248     {
    3249         pExtent = &pImage->pExtents[i];
    3250         if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE)
    3251         {
    3252             /* Here used to be a check whether the nominal size of an extent
    3253              * is a multiple of the grain size. The spec says that this is
    3254              * always the case, but unfortunately some files out there in the
    3255              * wild violate the spec (e.g. ReactOS 0.3.1). */
    3256         }
    3257         pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
    3258     }
    3259 
    3260     for (unsigned i = 0; i < pImage->cExtents; i++)
    3261     {
    3262         pExtent = &pImage->pExtents[i];
    3263         if (    pImage->pExtents[i].enmType == VMDKETYPE_FLAT
    3264             ||  pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
    3265         {
    3266             pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
    3267             break;
    3268         }
    3269     }
    3270 
    3271     if (   !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
    3272         || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    3273         || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
    3274         rc = vmdkAllocateGrainTableCache(pImage);
    3275 
    3276 out:
     3280    /* else: Do NOT signal an appropriate error here, as the VD layer has the
     3281     *       choice of retrying the open if it failed. */
     3282
    32773283    if (RT_FAILURE(rc))
    32783284        vmdkFreeImage(pImage, false);
     
    33433349            PVBOXHDDRAWPARTDESC pPart = &pRaw->pPartDescs[i];
    33443350            if (uStart > pPart->uStart)
    3345                 return vdIfError(pImage->pIfError, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: incorrect partition data area ordering set up by the caller in '%s'"), pImage->pszFilename);
     3351                return vdIfError(pImage->pIfError, VERR_INVALID_PARAMETER, RT_SRC_POS,
     3352                                 N_("VMDK: incorrect partition data area ordering set up by the caller in '%s'"), pImage->pszFilename);
    33463353
    33473354            if (uStart < pPart->uStart)
     
    56375644    Assert(cbToWrite % 512 == 0);
    56385645    AssertReturn((VALID_PTR(pIoCtx) && cbToWrite), VERR_INVALID_PARAMETER);
    5639     AssertReturn(uOffset + cbToWrite <= pImage->cbSize, VERR_INVALID_PARAMETER);
    56405646
    56415647    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
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