Changeset 39577 in vbox for trunk/src/VBox
- Timestamp:
- Dec 10, 2011 8:35:11 PM (13 years ago)
- svn:sync-xref-src-repo-rev:
- 75337
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VHD.cpp
r39519 r39577 3036 3036 } 3037 3037 /* Same size doesn't change the image at all. */ 3038 3039 LogFlowFunc(("returns %Rrc\n", rc)); 3040 return rc; 3041 } 3042 3043 /** @copydoc VBOXHDDBACKEND::pfnRepair */ 3044 static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsDisk, 3045 PVDINTERFACE pVDIfsImage, uint32_t fFlags) 3046 { 3047 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage)); 3048 int rc; 3049 PVDINTERFACEERROR pIfError; 3050 PVDINTERFACEIOINT pIfIo; 3051 PVDIOSTORAGE pStorage; 3052 uint64_t cbFile; 3053 VHDFooter vhdFooter; 3054 VHDDynamicDiskHeader dynamicDiskHeader; 3055 uint32_t *paBat = NULL; 3056 uint32_t *pu32BlockBitmap = NULL; 3057 3058 pIfIo = VDIfIoIntGet(pVDIfsImage); 3059 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER); 3060 3061 pIfError = VDIfErrorGet(pVDIfsDisk); 3062 3063 do 3064 { 3065 uint64_t offDynamicDiskHeader = 0; 3066 uint64_t offBat = 0; 3067 uint64_t offFooter = 0; 3068 uint32_t cBatEntries = 0; 3069 bool fDynamic = false; 3070 bool fRepairFooter = false; 3071 bool fRepairBat = false; 3072 bool fRepairDynHeader = false; 3073 3074 rc = vdIfIoIntFileOpen(pIfIo, pszFilename, 3075 VDOpenFlagsToFileOpenFlags( fFlags & VD_REPAIR_DRY_RUN 3076 ? VD_OPEN_FLAGS_READONLY 3077 : 0, 3078 false /* fCreate */), 3079 &pStorage); 3080 if (RT_FAILURE(rc)) 3081 { 3082 rc = vdIfError(pIfError, rc, RT_SRC_POS, "Failed to open image \"%s\"", pszFilename); 3083 break; 3084 } 3085 3086 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile); 3087 if (RT_FAILURE(rc)) 3088 { 3089 rc = vdIfError(pIfError, rc, RT_SRC_POS, "Failed to query image size"); 3090 break; 3091 } 3092 3093 if (cbFile < sizeof(VHDFooter)) 3094 { 3095 rc = vdIfError(pIfError, VERR_VD_INVALID_SIZE, RT_SRC_POS, 3096 "Image must be at least %u bytes (got %llu)", 3097 sizeof(VHDFooter), cbFile); 3098 break; 3099 } 3100 3101 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, cbFile - sizeof(VHDFooter), 3102 &vhdFooter, sizeof(VHDFooter), NULL); 3103 if (RT_FAILURE(rc)) 3104 { 3105 rc = vdIfError(pIfError, rc, RT_SRC_POS, "Failed to read footer of image"); 3106 break; 3107 } 3108 3109 if (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0) 3110 { 3111 /* Dynamic images have a backup at the beginning of the image. */ 3112 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, 3113 &vhdFooter, sizeof(VHDFooter), NULL); 3114 if (RT_FAILURE(rc)) 3115 { 3116 rc = vdIfError(pIfError, rc, RT_SRC_POS, "Failed to read header of image"); 3117 break; 3118 } 3119 3120 /* 3121 * Check for the header, if this fails the image is either completely corrupted 3122 * and impossible to repair or in another format. 3123 */ 3124 if (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0) 3125 { 3126 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3127 "No valid VHD structures found"); 3128 break; 3129 } 3130 else 3131 vdIfErrorMessage(pIfError, "Missing footer structure, using backup"); 3132 3133 /* Remember to fix the footer structure. */ 3134 fRepairFooter = true; 3135 } 3136 3137 offFooter = cbFile - sizeof(VHDFooter); 3138 3139 /* Verify that checksums match. */ 3140 uint32_t u32ChkSumOld = RT_BE2H_U32(vhdFooter.Checksum); 3141 vhdFooter.Checksum = 0; 3142 uint32_t u32ChkSum = vhdChecksum(&vhdFooter, sizeof(VHDFooter)); 3143 3144 vhdFooter.Checksum = RT_H2BE_U32(u32ChkSum); 3145 3146 if (u32ChkSumOld != u32ChkSum) 3147 { 3148 vdIfErrorMessage(pIfError, "Checksum is invalid (should be %u got %u), repairing", 3149 u32ChkSum, u32ChkSumOld); 3150 fRepairFooter = true; 3151 break; 3152 } 3153 3154 switch (RT_BE2H_U32(vhdFooter.DiskType)) 3155 { 3156 case VHD_FOOTER_DISK_TYPE_FIXED: 3157 fDynamic = false; 3158 break; 3159 case VHD_FOOTER_DISK_TYPE_DYNAMIC: 3160 fDynamic = true; 3161 break; 3162 case VHD_FOOTER_DISK_TYPE_DIFFERENCING: 3163 fDynamic = true; 3164 break; 3165 default: 3166 { 3167 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3168 "VHD image type %u is not supported", 3169 RT_BE2H_U32(vhdFooter.DiskType)); 3170 break; 3171 } 3172 } 3173 3174 /* Load and check dynamic disk header if required. */ 3175 if (fDynamic) 3176 { 3177 size_t cbBlock; 3178 3179 offDynamicDiskHeader = RT_BE2H_U64(vhdFooter.DataOffset); 3180 if (offDynamicDiskHeader + sizeof(VHDDynamicDiskHeader) > cbFile) 3181 { 3182 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3183 "VHD image type is not supported"); 3184 break; 3185 } 3186 3187 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, offDynamicDiskHeader, 3188 &dynamicDiskHeader, sizeof(VHDDynamicDiskHeader), NULL); 3189 if (RT_FAILURE(rc)) 3190 { 3191 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3192 "Failed to read dynamic disk header (at %llu), %Rrc", 3193 offDynamicDiskHeader, rc); 3194 break; 3195 } 3196 3197 /* Verify that checksums match. */ 3198 u32ChkSumOld = RT_BE2H_U32(dynamicDiskHeader.Checksum); 3199 dynamicDiskHeader.Checksum = 0; 3200 u32ChkSum = vhdChecksum(&dynamicDiskHeader, sizeof(VHDDynamicDiskHeader)); 3201 3202 dynamicDiskHeader.Checksum = RT_H2BE_U32(u32ChkSum); 3203 3204 if (u32ChkSumOld != u32ChkSum) 3205 { 3206 vdIfErrorMessage(pIfError, "Checksum of dynamic disk header is invalid (should be %u got %u), repairing", 3207 u32ChkSum, u32ChkSumOld); 3208 fRepairDynHeader = true; 3209 break; 3210 } 3211 3212 /* Read the block allocation table and fix any inconsistencies. */ 3213 offBat = RT_BE2H_U64(dynamicDiskHeader.TableOffset); 3214 cBatEntries = RT_BE2H_U32(dynamicDiskHeader.MaxTableEntries); 3215 cbBlock = RT_BE2H_U32(dynamicDiskHeader.BlockSize); 3216 cbBlock += cbBlock / VHD_SECTOR_SIZE / 8; 3217 3218 if (offBat + cBatEntries * sizeof(uint32_t) > cbFile) 3219 { 3220 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3221 "Block allocation table is not inside the image"); 3222 break; 3223 } 3224 3225 paBat = (uint32_t *)RTMemAllocZ(cBatEntries * sizeof(uint32_t)); 3226 if (!paBat) 3227 { 3228 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3229 "Could not allocate memory for the block allocation table (%u bytes)", 3230 cBatEntries * sizeof(uint32_t)); 3231 break; 3232 } 3233 3234 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, offBat, paBat, 3235 cBatEntries * sizeof(uint32_t), NULL); 3236 if (RT_FAILURE(rc)) 3237 { 3238 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3239 "Could not read block allocation table (at %llu), %Rrc", 3240 offBat, rc); 3241 break; 3242 } 3243 3244 pu32BlockBitmap = (uint32_t *)RTMemAllocZ(RT_ALIGN_Z(cBatEntries, 4)); 3245 if (!pu32BlockBitmap) 3246 { 3247 rc = vdIfError(pIfError, VERR_NO_MEMORY, RT_SRC_POS, 3248 "Failed to allocate memory for block bitmap"); 3249 break; 3250 } 3251 3252 uint32_t idxMinBlock = UINT32_C(0xffffffff); 3253 for (uint32_t i = 0; i < cBatEntries; i++) 3254 { 3255 paBat[i] = RT_BE2H_U32(paBat[i]); 3256 if (paBat[i] < idxMinBlock) 3257 idxMinBlock = paBat[i]; 3258 } 3259 3260 vdIfErrorMessage(pIfError, "First data block at sector %u", idxMinBlock); 3261 3262 for (uint32_t i = 0; i < cBatEntries; i++) 3263 { 3264 if (paBat[i] != UINT32_C(0xffffffff)) 3265 { 3266 uint64_t offBlock =(uint64_t)paBat[i] * VHD_SECTOR_SIZE; 3267 3268 /* 3269 * Check that the offsets are valid (inside of the image) and 3270 * that there are no double references. 3271 */ 3272 if (offBlock + cbBlock > cbFile) 3273 { 3274 vdIfErrorMessage(pIfError, "Entry %u points to invalid offset %llu, clearing", 3275 i, offBlock); 3276 paBat[i] = 0; 3277 fRepairBat = true; 3278 } 3279 else if (offBlock + cbBlock > offFooter) 3280 { 3281 vdIfErrorMessage(pIfError, "Entry %u intersects with footer, aligning footer", 3282 i); 3283 offFooter = offBlock + cbBlock; 3284 fRepairBat = true; 3285 } 3286 3287 if (ASMBitTestAndSet(pu32BlockBitmap, (paBat[i] - idxMinBlock) / (cbBlock / VHD_SECTOR_SIZE))) 3288 { 3289 vdIfErrorMessage(pIfError, "Entry %u points to an already referenced data block, clearing", 3290 i); 3291 paBat[i] = 0; 3292 fRepairBat = true; 3293 } 3294 } 3295 } 3296 } 3297 3298 /* Write repaired structures now. */ 3299 if (!(fRepairBat || fRepairDynHeader || fRepairFooter)) 3300 vdIfErrorMessage(pIfError, "VHD image is in a consistent state, no repair required"); 3301 else if (!(fFlags & VD_REPAIR_DRY_RUN)) 3302 { 3303 if (fRepairBat) 3304 { 3305 for (uint32_t i = 0; i < cBatEntries; i++) 3306 paBat[i] = RT_H2BE_U32(paBat[i]); 3307 3308 vdIfErrorMessage(pIfError, "Writing repaired block allocation table..."); 3309 3310 rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offBat, paBat, 3311 cBatEntries * sizeof(uint32_t), NULL); 3312 if (RT_FAILURE(rc)) 3313 { 3314 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3315 "Could not write repaired block allocation table (at %llu), %Rrc", 3316 offBat, rc); 3317 break; 3318 } 3319 } 3320 3321 if (fRepairDynHeader) 3322 { 3323 Assert(fDynamic); 3324 3325 vdIfErrorMessage(pIfError, "Writing repaired dynamic disk header..."); 3326 rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offDynamicDiskHeader, &dynamicDiskHeader, 3327 sizeof(VHDDynamicDiskHeader), NULL); 3328 if (RT_FAILURE(rc)) 3329 { 3330 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3331 "Could not write repaired dynamic disk header (at %llu), %Rrc", 3332 offDynamicDiskHeader, rc); 3333 break; 3334 } 3335 } 3336 3337 if (fRepairFooter) 3338 { 3339 vdIfErrorMessage(pIfError, "Writing repaired Footer..."); 3340 3341 if (fDynamic) 3342 { 3343 /* Write backup at image beginning. */ 3344 rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, 0, &vhdFooter, 3345 sizeof(VHDFooter), NULL); 3346 if (RT_FAILURE(rc)) 3347 { 3348 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3349 "Could not write repaired backup footer (at %llu), %Rrc", 3350 0, rc); 3351 break; 3352 } 3353 } 3354 3355 rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offFooter, &vhdFooter, 3356 sizeof(VHDFooter), NULL); 3357 if (RT_FAILURE(rc)) 3358 { 3359 rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS, 3360 "Could not write repaired footer (at %llu), %Rrc", 3361 cbFile - sizeof(VHDFooter), rc); 3362 break; 3363 } 3364 } 3365 3366 vdIfErrorMessage(pIfError, "Corrupted VHD image repaired successfully"); 3367 } 3368 } while(0); 3369 3370 if (paBat) 3371 RTMemFree(paBat); 3372 3373 if (pu32BlockBitmap) 3374 RTMemFree(pu32BlockBitmap); 3375 3376 if (pStorage) 3377 vdIfIoIntFileClose(pIfIo, pStorage); 3038 3378 3039 3379 LogFlowFunc(("returns %Rrc\n", rc)); … … 3145 3485 NULL, 3146 3486 /* pfnRepair */ 3147 NULL3487 vhdRepair 3148 3488 };
Note:
See TracChangeset
for help on using the changeset viewer.