- Timestamp:
- Sep 14, 2016 7:59:21 AM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VMDK.cpp
r63811 r63825 2914 2914 2915 2915 /** 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 */ 2922 static 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 { 2965 2928 /* The opened file is passed to the extent. No separate descriptor 2966 2929 * file, so no need to keep anything open for the image. */ 2967 pExtent = &pImage->pExtents[0];2930 PVMDKEXTENT pExtent = &pImage->pExtents[0]; 2968 2931 pExtent->pFile = pFile; 2969 2932 pImage->pFile = NULL; 2970 2933 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 2973 3024 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 */ 3037 static 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 { 3087 3048 uint64_t cbSize = cbFileSize; 3088 3049 if (cbSize % VMDK_SECTOR2BYTE(10)) … … 3093 3054 pImage->cbDescAlloc = RT_MAX(VMDK_SECTOR2BYTE(20), cbSize); 3094 3055 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 { 3114 3062 #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 early3119 * (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 } 3123 3071 #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)) 3142 3075 { 3143 pszFullname = RTStrDup(pExtent->pszBasename); 3144 if (!pszFullname) 3076 for (unsigned i = 0; i < pImage->cExtents && RT_SUCCESS(rc); i++) 3145 3077 { 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 } 3148 3163 } 3149 3164 } 3150 else3151 {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;3168 3165 } 3169 3166 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 */ 3185 static 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 */ 3212 static 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) 3173 3237 { 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) 3179 3260 { 3180 /* Do NOT signal an appropriate error here, as the VD3181 * layer has the choice of retrying the open if it3182 * 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). */ 3184 3265 } 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); 3218 3277 } 3219 3278 } 3220 3279 } 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 3277 3283 if (RT_FAILURE(rc)) 3278 3284 vmdkFreeImage(pImage, false); … … 3343 3349 PVBOXHDDRAWPARTDESC pPart = &pRaw->pPartDescs[i]; 3344 3350 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); 3346 3353 3347 3354 if (uStart < pPart->uStart) … … 5637 5644 Assert(cbToWrite % 512 == 0); 5638 5645 AssertReturn((VALID_PTR(pIoCtx) && cbToWrite), VERR_INVALID_PARAMETER); 5639 AssertReturn(uOffset + cbToWrite <= pImage->cbSize, VERR_INVALID_PARAMETER);5640 5646 5641 5647 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
Note:
See TracChangeset
for help on using the changeset viewer.