Changeset 97854 in vbox for trunk/src/VBox/Storage/VMDK.cpp
- Timestamp:
- Dec 22, 2022 7:30:51 PM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VMDK.cpp
r97839 r97854 1792 1792 } 1793 1793 1794 static void vmdkDescExtRemoveByLine(PVMDKIMAGE pImage, 1795 PVMDKDESCRIPTOR pDescriptor, unsigned uLine) 1796 { 1797 RT_NOREF1(pImage); 1798 unsigned uEntry = uLine; 1799 ssize_t cbDiff; 1800 if (!uEntry) 1801 return; 1802 cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1; 1803 /* Move everything including \0 in the entry marking the end of buffer. */ 1804 memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1], 1805 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1); 1806 for (unsigned i = uEntry; i <= pDescriptor->cLines; i++) 1807 { 1808 if (i != uEntry) 1809 pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff; 1810 if (pDescriptor->aNextLines[i]) 1811 pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1; 1812 else 1813 pDescriptor->aNextLines[i - 1] = 0; 1814 } 1815 pDescriptor->cLines--; 1816 if (pDescriptor->uFirstDDB) 1817 pDescriptor->uFirstDDB--; 1818 return; 1819 } 1820 1794 1821 static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, 1795 1822 VMDKACCESS enmAccess, uint64_t cNominalSectors, … … 1838 1865 || ( pDescriptor->aLines[pDescriptor->cLines] 1839 1866 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)) 1840 return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename); 1867 { 1868 if ((pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G) 1869 && !(pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)) 1870 { 1871 pImage->cbDescAlloc *= 2; 1872 pDescriptor->cbDescAlloc *= 2; 1873 } 1874 else 1875 return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename); 1876 } 1841 1877 1842 1878 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--) … … 3107 3143 3108 3144 /** 3109 * Internal: allocate and describes an additional, file-backed extent 3110 * for the given size. Preserves original extents. 3145 * Internal: Create an additional file backed extent in split images. 3146 * Supports split sparse and flat images. 3147 * 3148 * @returns VBox status code. 3149 * @param pImage VMDK image instance. 3150 * @param cbSize Desiried size in bytes of new extent. 3111 3151 */ 3112 3152 static int vmdkAddFileBackedExtent(PVMDKIMAGE pImage, uint64_t cbSize) 3113 3153 { 3114 3154 int rc = VINF_SUCCESS; 3155 unsigned uImageFlags = pImage->uImageFlags; 3156 3157 /* Check for unsupported image type. */ 3158 if ((uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX) 3159 || (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 3160 || (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)) 3161 { 3162 return VERR_NOT_SUPPORTED; 3163 } 3164 3165 /* Allocate array of extents and copy existing extents to it. */ 3115 3166 PVMDKEXTENT pNewExtents = (PVMDKEXTENT)RTMemAllocZ((pImage->cExtents + 1) * sizeof(VMDKEXTENT)); 3116 if (pNewExtents) 3117 { 3118 memcpy(pNewExtents, pImage->pExtents, pImage->cExtents * sizeof(VMDKEXTENT)); 3119 PVMDKEXTENT pExtent = &pNewExtents[pImage->cExtents]; 3120 3121 pExtent->pFile = NULL; 3122 pExtent->pszBasename = NULL; 3123 pExtent->pszFullname = NULL; 3124 pExtent->pGD = NULL; 3125 pExtent->pRGD = NULL; 3126 pExtent->pDescData = NULL; 3127 pExtent->uVersion = 1; 3128 pExtent->uCompression = VMDK_COMPRESSION_NONE; 3129 pExtent->uExtent = pImage->cExtents; 3130 pExtent->pImage = pImage; 3131 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize); 3167 if (!pNewExtents) 3168 { 3169 return VERR_NO_MEMORY; 3170 } 3171 3172 memcpy(pNewExtents, pImage->pExtents, pImage->cExtents * sizeof(VMDKEXTENT)); 3173 3174 /* Locate newly created extent and populate default metadata. */ 3175 PVMDKEXTENT pExtent = &pNewExtents[pImage->cExtents]; 3176 3177 pExtent->pFile = NULL; 3178 pExtent->pszBasename = NULL; 3179 pExtent->pszFullname = NULL; 3180 pExtent->pGD = NULL; 3181 pExtent->pRGD = NULL; 3182 pExtent->pDescData = NULL; 3183 pExtent->uVersion = 1; 3184 pExtent->uCompression = VMDK_COMPRESSION_NONE; 3185 pExtent->uExtent = pImage->cExtents; 3186 pExtent->pImage = pImage; 3187 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize); 3188 pExtent->enmAccess = VMDKACCESS_READWRITE; 3189 pExtent->uSectorOffset = 0; 3190 pExtent->fMetaDirty = true; 3191 3192 /* Apply image type specific meta data. */ 3193 if (uImageFlags & VD_IMAGE_FLAGS_FIXED) 3194 { 3132 3195 pExtent->enmType = VMDKETYPE_FLAT; 3133 pExtent->enmAccess = VMDKACCESS_READWRITE; 3134 pExtent->uSectorOffset = 0; 3135 3136 char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename); 3137 AssertPtr(pszBasenameSubstr); 3138 3139 char *pszBasenameSuff = RTPathSuffix(pszBasenameSubstr); 3140 char *pszBasenameBase = RTStrDup(pszBasenameSubstr); 3141 RTPathStripSuffix(pszBasenameBase); 3142 char *pszTmp; 3143 size_t cbTmp; 3144 3145 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED) 3146 RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase, 3147 pExtent->uExtent + 1, pszBasenameSuff); 3148 else 3149 RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, pExtent->uExtent + 1, 3150 pszBasenameSuff); 3151 3152 RTStrFree(pszBasenameBase); 3153 if (!pszTmp) 3154 return VERR_NO_STR_MEMORY; 3155 cbTmp = strlen(pszTmp) + 1; 3156 char *pszBasename = (char *)RTMemTmpAlloc(cbTmp); 3157 if (!pszBasename) 3158 { 3159 RTStrFree(pszTmp); 3160 return VERR_NO_MEMORY; 3161 } 3162 3163 memcpy(pszBasename, pszTmp, cbTmp); 3196 } 3197 else 3198 { 3199 uint64_t cSectorsPerGDE, cSectorsPerGD; 3200 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; 3201 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K)); 3202 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K); 3203 pExtent->cGTEntries = 512; 3204 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 3205 pExtent->cSectorsPerGDE = cSectorsPerGDE; 3206 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 3207 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t)); 3208 } 3209 3210 /* Allocate and set file name for extent. */ 3211 char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename); 3212 AssertPtr(pszBasenameSubstr); 3213 3214 char *pszBasenameSuff = RTPathSuffix(pszBasenameSubstr); 3215 char *pszBasenameBase = RTStrDup(pszBasenameSubstr); 3216 RTPathStripSuffix(pszBasenameBase); 3217 char *pszTmp; 3218 size_t cbTmp; 3219 3220 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED) 3221 RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase, 3222 pExtent->uExtent + 1, pszBasenameSuff); 3223 else 3224 RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, pExtent->uExtent + 1, 3225 pszBasenameSuff); 3226 3227 RTStrFree(pszBasenameBase); 3228 if (!pszTmp) 3229 return VERR_NO_STR_MEMORY; 3230 cbTmp = strlen(pszTmp) + 1; 3231 char *pszBasename = (char *)RTMemTmpAlloc(cbTmp); 3232 if (!pszBasename) 3233 { 3164 3234 RTStrFree(pszTmp); 3165 3166 pExtent->pszBasename = pszBasename; 3167 3168 char *pszBasedirectory = RTStrDup(pImage->pszFilename); 3169 if (!pszBasedirectory) 3170 return VERR_NO_STR_MEMORY; 3171 RTPathStripFilename(pszBasedirectory); 3172 char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename); 3173 RTStrFree(pszBasedirectory); 3174 if (!pszFullname) 3175 return VERR_NO_STR_MEMORY; 3176 pExtent->pszFullname = pszFullname; 3177 3178 /* Create file for extent. */ 3179 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname, 3180 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, 3181 true /* fCreate */)); 3182 if (RT_FAILURE(rc)) 3183 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname); 3184 3185 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess, 3186 pExtent->cNominalSectors, pExtent->enmType, 3187 pExtent->pszBasename, pExtent->uSectorOffset); 3188 if (RT_FAILURE(rc)) 3189 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename); 3190 3235 return VERR_NO_MEMORY; 3236 } 3237 3238 memcpy(pszBasename, pszTmp, cbTmp); 3239 RTStrFree(pszTmp); 3240 3241 pExtent->pszBasename = pszBasename; 3242 3243 char *pszBasedirectory = RTStrDup(pImage->pszFilename); 3244 if (!pszBasedirectory) 3245 return VERR_NO_STR_MEMORY; 3246 RTPathStripFilename(pszBasedirectory); 3247 char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename); 3248 RTStrFree(pszBasedirectory); 3249 if (!pszFullname) 3250 return VERR_NO_STR_MEMORY; 3251 pExtent->pszFullname = pszFullname; 3252 3253 /* Create file for extent. */ 3254 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname, 3255 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, 3256 true /* fCreate */)); 3257 if (RT_FAILURE(rc)) 3258 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname); 3259 3260 if (uImageFlags & VD_IMAGE_FLAGS_FIXED) 3261 { 3262 /* For flat images: Pre allocate file space. */ 3191 3263 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, cbSize, 3192 3264 0 /* fFlags */, NULL, 0, 0); 3193 3194 3265 if (RT_FAILURE(rc)) 3195 3266 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 3196 3197 pImage->pExtents = pNewExtents;3198 pImage->cExtents++;3199 3267 } 3200 3268 else 3201 rc = VERR_NO_MEMORY; 3269 { 3270 /* For sparse images: Allocate new grain directories/tables. */ 3271 /* fPreAlloc should never be false because VMware can't use such images. */ 3272 rc = vmdkCreateGrainDirectory(pImage, pExtent, 3273 RT_MAX( pExtent->uDescriptorSector 3274 + pExtent->cDescriptorSectors, 3275 1), 3276 true /* fPreAlloc */); 3277 if (RT_FAILURE(rc)) 3278 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname); 3279 } 3280 3281 /* Insert new extent into descriptor file. */ 3282 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess, 3283 pExtent->cNominalSectors, pExtent->enmType, 3284 pExtent->pszBasename, pExtent->uSectorOffset); 3285 if (RT_FAILURE(rc)) 3286 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename); 3287 3288 pImage->pExtents = pNewExtents; 3289 pImage->cExtents++; 3290 3202 3291 return rc; 3203 3292 } 3293 3204 3294 /** 3205 3295 * Reads and processes the descriptor embedded in sparse images. … … 8254 8344 } 8255 8345 8256 static int vmdkRepaceExtentSize(PVMDKIMAGE pImage, unsigned line, uint64_t cSectorsOld, 8257 uint64_t cSectorsNew) 8258 { 8259 char * szOldExtentSectors = (char *)RTMemAlloc(UINT64_MAX_BUFF_SIZE); 8260 if (!szOldExtentSectors) 8261 return VERR_NO_MEMORY; 8262 8263 int cbWritten = RTStrPrintf2(szOldExtentSectors, UINT64_MAX_BUFF_SIZE, "%llu", cSectorsOld); 8264 if (cbWritten <= 0 || cbWritten > UINT64_MAX_BUFF_SIZE) 8265 { 8266 RTMemFree(szOldExtentSectors); 8267 szOldExtentSectors = NULL; 8268 8346 8347 /** 8348 * Returns the size, in bytes, of the sparse extent overhead for 8349 * the number of desired total sectors and based on the current 8350 * sectors of the extent. 8351 * 8352 * @returns uint64_t size of new overhead in bytes. 8353 * @param pExtent VMDK extent instance. 8354 * @param cSectorsNew Number of desired total sectors. 8355 */ 8356 static uint64_t vmdkGetNewOverhead(PVMDKEXTENT pExtent, uint64_t cSectorsNew) 8357 { 8358 uint64_t cNewDirEntries = cSectorsNew / pExtent->cSectorsPerGDE; 8359 if (cSectorsNew % pExtent->cSectorsPerGDE) 8360 cNewDirEntries++; 8361 8362 size_t cbNewGD = cNewDirEntries * sizeof(uint32_t); 8363 uint64_t cbNewDirSize = RT_ALIGN_64(cbNewGD, 512); 8364 uint64_t cbNewAllTablesSize = RT_ALIGN_64(cNewDirEntries * pExtent->cGTEntries * sizeof(uint32_t), 512); 8365 uint64_t cbNewOverhead = RT_ALIGN_Z(RT_MAX(pExtent->uDescriptorSector 8366 + pExtent->cDescriptorSectors, 1) 8367 + cbNewDirSize + cbNewAllTablesSize, 512); 8368 cbNewOverhead += cbNewDirSize + cbNewAllTablesSize; 8369 cbNewOverhead = RT_ALIGN_64(cbNewOverhead, 8370 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 8371 8372 return cbNewOverhead; 8373 } 8374 8375 /** 8376 * Internal: Replaces the size (in sectors) of an extent in the descriptor file. 8377 * 8378 * @returns VBox status code. 8379 * @param pImage VMDK image instance. 8380 * @param uLine Line number of descriptor to change. 8381 * @param cSectorsOld Existing number of sectors. 8382 * @param cSectorsNew New number of sectors. 8383 */ 8384 static int vmdkReplaceExtentSize(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, unsigned uLine, uint64_t cSectorsOld, 8385 uint64_t cSectorsNew) 8386 { 8387 char szOldExtentSectors[UINT64_MAX_BUFF_SIZE]; 8388 char szNewExtentSectors[UINT64_MAX_BUFF_SIZE]; 8389 8390 ssize_t cbWritten = RTStrPrintf2(szOldExtentSectors, sizeof(szOldExtentSectors), "%llu", cSectorsOld); 8391 if (cbWritten <= 0 || cbWritten > (ssize_t)sizeof(szOldExtentSectors)) 8269 8392 return VERR_BUFFER_OVERFLOW; 8270 } 8271 8272 char * szNewExtentSectors = (char *)RTMemAlloc(UINT64_MAX_BUFF_SIZE); 8273 if (!szNewExtentSectors) 8274 return VERR_NO_MEMORY; 8275 8276 cbWritten = RTStrPrintf2(szNewExtentSectors, UINT64_MAX_BUFF_SIZE, "%llu", cSectorsNew); 8277 if (cbWritten <= 0 || cbWritten > UINT64_MAX_BUFF_SIZE) 8278 { 8279 RTMemFree(szOldExtentSectors); 8280 szOldExtentSectors = NULL; 8281 8282 RTMemFree(szNewExtentSectors); 8283 szNewExtentSectors = NULL; 8284 8393 8394 cbWritten = RTStrPrintf2(szNewExtentSectors, sizeof(szNewExtentSectors), "%llu", cSectorsNew); 8395 if (cbWritten <= 0 || cbWritten > (ssize_t)sizeof(szNewExtentSectors)) 8285 8396 return VERR_BUFFER_OVERFLOW; 8286 } 8287 8288 char * szNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[line], 8397 8398 char *pszNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[uLine], 8289 8399 szOldExtentSectors, 8290 8400 szNewExtentSectors); 8291 8401 8292 RTMemFree(szOldExtentSectors); 8293 szOldExtentSectors = NULL; 8294 8295 RTMemFree(szNewExtentSectors); 8296 szNewExtentSectors = NULL; 8297 8298 if (!szNewExtentLine) 8402 if (RT_UNLIKELY(!pszNewExtentLine)) 8299 8403 return VERR_INVALID_PARAMETER; 8300 8404 8301 pImage->Descriptor.aLines[line] = szNewExtentLine; 8405 vmdkDescExtRemoveByLine(pImage, &pImage->Descriptor, uLine); 8406 vmdkDescExtInsert(pImage, &pImage->Descriptor, 8407 pExtent->enmAccess, cSectorsNew, 8408 pExtent->enmType, pExtent->pszBasename, pExtent->uSectorOffset); 8409 8410 RTStrFree(pszNewExtentLine); 8411 pszNewExtentLine = NULL; 8412 8413 pImage->Descriptor.fDirty = true; 8302 8414 8303 8415 return VINF_SUCCESS; 8416 } 8417 8418 /** 8419 * Moves sectors down to make room for new overhead. 8420 * Used for sparse extent resize. 8421 * 8422 * @returns VBox status code. 8423 * @param pImage VMDK image instance. 8424 * @param pExtent VMDK extent instance. 8425 * @param cSectorsNew Number of sectors after resize. 8426 */ 8427 static int vmdkRelocateSectorsForSparseResize(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 8428 uint64_t cSectorsNew) 8429 { 8430 int rc = VINF_SUCCESS; 8431 8432 uint64_t cbNewOverhead = vmdkGetNewOverhead(pExtent, cSectorsNew); 8433 8434 uint64_t cNewOverheadSectors = VMDK_BYTE2SECTOR(cbNewOverhead); 8435 uint64_t cOverheadSectorDiff = cNewOverheadSectors - pExtent->cOverheadSectors; 8436 8437 uint64_t cbFile = 0; 8438 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbFile); 8439 8440 uint64_t uNewAppendPosition; 8441 8442 /* Calculate how many sectors need to be relocated. */ 8443 unsigned cSectorsReloc = cOverheadSectorDiff; 8444 if (cbNewOverhead % VMDK_SECTOR_SIZE) 8445 cSectorsReloc++; 8446 8447 if (cSectorsReloc < pExtent->cSectors) 8448 uNewAppendPosition = RT_ALIGN_Z(cbFile + VMDK_SECTOR2BYTE(cOverheadSectorDiff), 512); 8449 else 8450 uNewAppendPosition = cbFile; 8451 8452 /* 8453 * Get the blocks we need to relocate first, they are appended to the end 8454 * of the image. 8455 */ 8456 void *pvBuf = NULL, *pvZero = NULL; 8457 do 8458 { 8459 /* Allocate data buffer. */ 8460 pvBuf = RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 8461 if (!pvBuf) 8462 { 8463 rc = VERR_NO_MEMORY; 8464 break; 8465 } 8466 8467 /* Allocate buffer for overwriting with zeroes. */ 8468 pvZero = RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 8469 if (!pvZero) 8470 { 8471 RTMemFree(pvBuf); 8472 pvBuf = NULL; 8473 8474 rc = VERR_NO_MEMORY; 8475 break; 8476 } 8477 8478 uint32_t *aGTDataTmp = (uint32_t *)RTMemAllocZ(sizeof(uint32_t) * pExtent->cGTEntries); 8479 if(!aGTDataTmp) 8480 { 8481 RTMemFree(pvBuf); 8482 pvBuf = NULL; 8483 8484 RTMemFree(pvZero); 8485 pvZero = NULL; 8486 8487 rc = VERR_NO_MEMORY; 8488 break; 8489 } 8490 8491 uint32_t *aRGTDataTmp = (uint32_t *)RTMemAllocZ(sizeof(uint32_t) * pExtent->cGTEntries); 8492 if(!aRGTDataTmp) 8493 { 8494 RTMemFree(pvBuf); 8495 pvBuf = NULL; 8496 8497 RTMemFree(pvZero); 8498 pvZero = NULL; 8499 8500 RTMemFree(aGTDataTmp); 8501 aGTDataTmp = NULL; 8502 8503 rc = VERR_NO_MEMORY; 8504 break; 8505 } 8506 8507 /* Search for overlap sector in the grain table. */ 8508 for (uint32_t idxGD = 0; idxGD < pExtent->cGDEntries; idxGD++) 8509 { 8510 uint64_t uGTSector = pExtent->pGD[idxGD]; 8511 uint64_t uRGTSector = pExtent->pRGD[idxGD]; 8512 8513 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8514 VMDK_SECTOR2BYTE(uGTSector), 8515 aGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries); 8516 8517 if (RT_FAILURE(rc)) 8518 break; 8519 8520 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8521 VMDK_SECTOR2BYTE(uRGTSector), 8522 aRGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries); 8523 8524 if (RT_FAILURE(rc)) 8525 break; 8526 8527 for (uint32_t idxGT = 0; idxGT < pExtent->cGTEntries; idxGT++) 8528 { 8529 uint64_t aGTEntryLE = RT_LE2H_U64(aGTDataTmp[idxGT]); 8530 uint64_t aRGTEntryLE = RT_LE2H_U64(aRGTDataTmp[idxGT]); 8531 8532 /** 8533 * Check if grain table is valid. If not dump out with an error. 8534 * Shoudln't ever get here (given other checks) but good sanity check. 8535 */ 8536 if (aGTEntryLE != aRGTEntryLE) 8537 { 8538 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 8539 N_("VMDK: inconsistent references within grain table in '%s'"), pExtent->pszFullname); 8540 break; 8541 } 8542 8543 if (aGTEntryLE < cNewOverheadSectors 8544 && aGTEntryLE != 0) 8545 { 8546 /* Read data and append grain to the end of the image. */ 8547 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8548 VMDK_SECTOR2BYTE(aGTEntryLE), pvBuf, 8549 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 8550 if (RT_FAILURE(rc)) 8551 break; 8552 8553 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8554 uNewAppendPosition, pvBuf, 8555 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 8556 if (RT_FAILURE(rc)) 8557 break; 8558 8559 /* Zero out the old block area. */ 8560 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8561 VMDK_SECTOR2BYTE(aGTEntryLE), pvZero, 8562 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 8563 if (RT_FAILURE(rc)) 8564 break; 8565 8566 /* Write updated grain tables to file */ 8567 aGTDataTmp[idxGT] = VMDK_BYTE2SECTOR(uNewAppendPosition); 8568 aRGTDataTmp[idxGT] = VMDK_BYTE2SECTOR(uNewAppendPosition); 8569 8570 if (memcmp(aGTDataTmp, aRGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries)) 8571 { 8572 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 8573 N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname); 8574 break; 8575 } 8576 8577 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8578 VMDK_SECTOR2BYTE(uGTSector), 8579 aGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries); 8580 8581 if (RT_FAILURE(rc)) 8582 break; 8583 8584 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8585 VMDK_SECTOR2BYTE(uRGTSector), 8586 aRGTDataTmp, sizeof(uint32_t) * pExtent->cGTEntries); 8587 8588 break; 8589 } 8590 } 8591 } 8592 8593 RTMemFree(aGTDataTmp); 8594 aGTDataTmp = NULL; 8595 8596 RTMemFree(aRGTDataTmp); 8597 aRGTDataTmp = NULL; 8598 8599 if (RT_FAILURE(rc)) 8600 break; 8601 8602 uNewAppendPosition += VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain); 8603 } while (0); 8604 8605 if (pvBuf) 8606 { 8607 RTMemFree(pvBuf); 8608 pvBuf = NULL; 8609 } 8610 8611 if (pvZero) 8612 { 8613 RTMemFree(pvZero); 8614 pvZero = NULL; 8615 } 8616 8617 // Update append position for extent 8618 pExtent->uAppendPosition = uNewAppendPosition; 8619 8620 return rc; 8621 } 8622 8623 /** 8624 * Resizes meta/overhead for sparse extent resize. 8625 * 8626 * @returns VBox status code. 8627 * @param pImage VMDK image instance. 8628 * @param pExtent VMDK extent instance. 8629 * @param cSectorsNew Number of sectors after resize. 8630 */ 8631 static int vmdkResizeSparseMeta(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 8632 uint64_t cSectorsNew) 8633 { 8634 int rc = VINF_SUCCESS; 8635 uint32_t cOldGDEntries = pExtent->cGDEntries; 8636 8637 uint64_t cNewDirEntries = cSectorsNew / pExtent->cSectorsPerGDE; 8638 if (cSectorsNew % pExtent->cSectorsPerGDE) 8639 cNewDirEntries++; 8640 8641 size_t cbNewGD = cNewDirEntries * sizeof(uint32_t); 8642 8643 uint64_t cbNewDirSize = RT_ALIGN_64(cbNewGD, 512); 8644 uint64_t cbCurrDirSize = RT_ALIGN_64(pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE, 512); 8645 uint64_t cDirSectorDiff = VMDK_BYTE2SECTOR(cbNewDirSize - cbCurrDirSize); 8646 8647 uint64_t cbNewAllTablesSize = RT_ALIGN_64(cNewDirEntries * pExtent->cGTEntries * sizeof(uint32_t), 512); 8648 uint64_t cbCurrAllTablesSize = RT_ALIGN_64(pExtent->cGDEntries * VMDK_GRAIN_TABLE_SIZE, 512); 8649 uint64_t cTableSectorDiff = VMDK_BYTE2SECTOR(cbNewAllTablesSize - cbCurrAllTablesSize); 8650 8651 uint64_t cbNewOverhead = vmdkGetNewOverhead(pExtent, cSectorsNew); 8652 uint64_t cNewOverheadSectors = VMDK_BYTE2SECTOR(cbNewOverhead); 8653 uint64_t cOverheadSectorDiff = cNewOverheadSectors - pExtent->cOverheadSectors; 8654 8655 /* 8656 * Get the blocks we need to relocate first, they are appended to the end 8657 * of the image. 8658 */ 8659 void *pvBuf = NULL, *pvZero = NULL; 8660 8661 do 8662 { 8663 /* Allocate data buffer. */ 8664 pvBuf = RTMemAllocZ(VMDK_GRAIN_TABLE_SIZE); 8665 if (!pvBuf) 8666 { 8667 rc = VERR_NO_MEMORY; 8668 break; 8669 } 8670 8671 /* Allocate buffer for overwriting with zeroes. */ 8672 pvZero = RTMemAllocZ(VMDK_GRAIN_TABLE_SIZE); 8673 if (!pvZero) 8674 { 8675 RTMemFree(pvBuf); 8676 pvBuf = NULL; 8677 8678 rc = VERR_NO_MEMORY; 8679 break; 8680 } 8681 8682 uint32_t uGTStart = VMDK_SECTOR2BYTE(pExtent->uSectorGD) + (cOldGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8683 8684 // points to last element in the grain table 8685 uint32_t uGTTail = uGTStart + (pExtent->cGDEntries * VMDK_GRAIN_TABLE_SIZE) - VMDK_GRAIN_TABLE_SIZE; 8686 uint32_t cbGTOff = RT_ALIGN_Z(VMDK_SECTOR2BYTE(cDirSectorDiff + cTableSectorDiff + cDirSectorDiff), 512); 8687 8688 for (int i = pExtent->cGDEntries - 1; i >= 0; i--) 8689 { 8690 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8691 uGTTail, pvBuf, 8692 VMDK_GRAIN_TABLE_SIZE); 8693 if (RT_FAILURE(rc)) 8694 break; 8695 8696 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8697 RT_ALIGN_Z(uGTTail + cbGTOff, 512), pvBuf, 8698 VMDK_GRAIN_TABLE_SIZE); 8699 if (RT_FAILURE(rc)) 8700 break; 8701 8702 // This overshoots when i == 0, but we don't need it anymore. 8703 uGTTail -= VMDK_GRAIN_TABLE_SIZE; 8704 } 8705 8706 8707 /* Find the end of the grain directory and start bumping everything down. Update locations of GT entries. */ 8708 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8709 VMDK_SECTOR2BYTE(pExtent->uSectorGD), pvBuf, 8710 pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8711 if (RT_FAILURE(rc)) 8712 break; 8713 8714 int * tmpBuf = (int *)pvBuf; 8715 8716 for (uint32_t i = 0; i < pExtent->cGDEntries; i++) 8717 { 8718 tmpBuf[i] = tmpBuf[i] + VMDK_BYTE2SECTOR(cbGTOff); 8719 pExtent->pGD[i] = pExtent->pGD[i] + VMDK_BYTE2SECTOR(cbGTOff); 8720 } 8721 8722 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8723 RT_ALIGN_Z(VMDK_SECTOR2BYTE(pExtent->uSectorGD + cTableSectorDiff + cDirSectorDiff), 512), pvBuf, 8724 pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8725 if (RT_FAILURE(rc)) 8726 break; 8727 8728 pExtent->uSectorGD = pExtent->uSectorGD + cDirSectorDiff + cTableSectorDiff; 8729 8730 /* Repeat both steps with the redundant grain table/directory. */ 8731 8732 uint32_t uRGTStart = VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + (cOldGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8733 8734 // points to last element in the grain table 8735 uint32_t uRGTTail = uRGTStart + (pExtent->cGDEntries * VMDK_GRAIN_TABLE_SIZE) - VMDK_GRAIN_TABLE_SIZE; 8736 uint32_t cbRGTOff = RT_ALIGN_Z(VMDK_SECTOR2BYTE(cDirSectorDiff), 512); 8737 8738 for (int i = pExtent->cGDEntries - 1; i >= 0; i--) 8739 { 8740 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8741 uRGTTail, pvBuf, 8742 VMDK_GRAIN_TABLE_SIZE); 8743 if (RT_FAILURE(rc)) 8744 break; 8745 8746 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8747 RT_ALIGN_Z(uRGTTail + cbRGTOff, 512), pvBuf, 8748 VMDK_GRAIN_TABLE_SIZE); 8749 if (RT_FAILURE(rc)) 8750 break; 8751 8752 // This overshoots when i == 0, but we don't need it anymore. 8753 uRGTTail -= VMDK_GRAIN_TABLE_SIZE; 8754 } 8755 8756 /* Update locations of GT entries. */ 8757 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 8758 VMDK_SECTOR2BYTE(pExtent->uSectorRGD), pvBuf, 8759 pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8760 if (RT_FAILURE(rc)) 8761 break; 8762 8763 tmpBuf = (int *)pvBuf; 8764 8765 for (uint32_t i = 0; i < pExtent->cGDEntries; i++) 8766 { 8767 tmpBuf[i] = tmpBuf[i] + cDirSectorDiff; 8768 pExtent->pRGD[i] = pExtent->pRGD[i] + cDirSectorDiff; 8769 } 8770 8771 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8772 VMDK_SECTOR2BYTE(pExtent->uSectorRGD), pvBuf, 8773 pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8774 if (RT_FAILURE(rc)) 8775 break; 8776 8777 pExtent->uSectorRGD = pExtent->uSectorRGD; 8778 pExtent->cOverheadSectors += cOverheadSectorDiff; 8779 8780 } while (0); 8781 8782 if (pvBuf) 8783 { 8784 RTMemFree(pvBuf); 8785 pvBuf = NULL; 8786 } 8787 8788 if (pvZero) 8789 { 8790 RTMemFree(pvZero); 8791 pvZero = NULL; 8792 } 8793 8794 pExtent->cGDEntries = cNewDirEntries; 8795 8796 /* Allocate buffer for overwriting with zeroes. */ 8797 pvZero = RTMemAllocZ(VMDK_GRAIN_TABLE_SIZE); 8798 if (!pvZero) 8799 return VERR_NO_MEMORY; 8800 8801 // Allocate additional grain dir 8802 pExtent->pGD = (uint32_t *) RTMemReallocZ(pExtent->pGD, pExtent->cGDEntries * sizeof(uint32_t), cbNewGD); 8803 if (RT_LIKELY(pExtent->pGD)) 8804 { 8805 if (pExtent->uSectorRGD) 8806 { 8807 pExtent->pRGD = (uint32_t *)RTMemReallocZ(pExtent->pRGD, pExtent->cGDEntries * sizeof(uint32_t), cbNewGD); 8808 if (RT_UNLIKELY(!pExtent->pRGD)) 8809 rc = VERR_NO_MEMORY; 8810 } 8811 } 8812 else 8813 return VERR_NO_MEMORY; 8814 8815 8816 uint32_t uTmpDirVal = pExtent->pGD[cOldGDEntries - 1] + VMDK_GRAIN_DIR_ENTRY_SIZE; 8817 for (uint32_t i = cOldGDEntries; i < pExtent->cGDEntries; i++) 8818 { 8819 pExtent->pGD[i] = uTmpDirVal; 8820 8821 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8822 VMDK_SECTOR2BYTE(uTmpDirVal), pvZero, 8823 VMDK_GRAIN_TABLE_SIZE); 8824 8825 if (RT_FAILURE(rc)) 8826 return rc; 8827 8828 uTmpDirVal += VMDK_GRAIN_DIR_ENTRY_SIZE; 8829 } 8830 8831 uint32_t uRTmpDirVal = pExtent->pRGD[cOldGDEntries - 1] + VMDK_GRAIN_DIR_ENTRY_SIZE; 8832 for (uint32_t i = cOldGDEntries; i < pExtent->cGDEntries; i++) 8833 { 8834 pExtent->pRGD[i] = uRTmpDirVal; 8835 8836 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8837 VMDK_SECTOR2BYTE(uRTmpDirVal), pvZero, 8838 VMDK_GRAIN_TABLE_SIZE); 8839 8840 if (RT_FAILURE(rc)) 8841 return rc; 8842 8843 uRTmpDirVal += VMDK_GRAIN_DIR_ENTRY_SIZE; 8844 } 8845 8846 RTMemFree(pvZero); 8847 pvZero = NULL; 8848 8849 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8850 VMDK_SECTOR2BYTE(pExtent->uSectorGD), pExtent->pGD, 8851 pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8852 if (RT_FAILURE(rc)) 8853 return rc; 8854 8855 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 8856 VMDK_SECTOR2BYTE(pExtent->uSectorRGD), pExtent->pRGD, 8857 pExtent->cGDEntries * VMDK_GRAIN_DIR_ENTRY_SIZE); 8858 if (RT_FAILURE(rc)) 8859 return rc; 8860 8861 rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent + pExtent->uExtent, 8862 pExtent->cNominalSectors, cSectorsNew); 8863 if (RT_FAILURE(rc)) 8864 return rc; 8865 8866 return rc; 8304 8867 } 8305 8868 … … 8318 8881 unsigned uImageFlags = pImage->uImageFlags; 8319 8882 PVMDKEXTENT pExtent = &pImage->pExtents[0]; 8883 pExtent->fMetaDirty = true; 8320 8884 8321 8885 uint64_t cSectorsNew = cbSize / VMDK_SECTOR_SIZE; /** < New number of sectors in the image after the resize */ … … 8338 8902 */ 8339 8903 /** @todo implement making the image smaller, it is the responsibility of 8340 * the user to know what he'sdoing. */8904 * the user to know what they're doing. */ 8341 8905 if (cbSize < pImage->cbSize) 8342 8906 rc = VERR_VD_SHRINK_NOT_SUPPORTED; … … 8358 8922 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 8359 8923 8360 rc = vmdkRep aceExtentSize(pImage, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew);8924 rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew); 8361 8925 if (RT_FAILURE(rc)) 8362 8926 return rc; … … 8375 8939 8376 8940 uint64_t cSectorsNeeded = cSectorsNew - cSectorsOld; 8941 8942 /** Space remaining in current last extent file that we don't need to create another one. */ 8377 8943 if (fSpaceAvailible && cSectorsNeeded + cLastExtentRemSectors <= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)) 8378 8944 { … … 8384 8950 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 8385 8951 8386 rc = vmdkRep aceExtentSize(pImage, pImage->Descriptor.uFirstExtent + cExtents - 1,8387 pExtent->cNominalSectors, cSectorsNeeded + cLastExtentRemSectors);8952 rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent + cExtents - 1, 8953 pExtent->cNominalSectors, cSectorsNeeded + cLastExtentRemSectors); 8388 8954 if (RT_FAILURE(rc)) 8389 8955 return rc; 8390 8956 } 8957 //** Need more extent files to handle all the requested space. */ 8391 8958 else 8392 8959 { … … 8402 8969 cSectorsNeeded = cSectorsNeeded - VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE) + cLastExtentRemSectors; 8403 8970 8404 rc = vmdkRep aceExtentSize(pImage, pImage->Descriptor.uFirstExtent + cExtents - 1,8405 pExtent->cNominalSectors, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE));8971 rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent + cExtents - 1, 8972 pExtent->cNominalSectors, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)); 8406 8973 if (RT_FAILURE(rc)) 8407 8974 return rc; … … 8435 9002 } 8436 9003 9004 /** 9005 * monolithicSparse. 9006 */ 9007 if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE && !(uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)) 9008 { 9009 // 1. Calculate sectors needed for new overhead. 9010 9011 uint64_t cbNewOverhead = vmdkGetNewOverhead(pExtent, cSectorsNew); 9012 uint64_t cNewOverheadSectors = VMDK_BYTE2SECTOR(cbNewOverhead); 9013 uint64_t cOverheadSectorDiff = cNewOverheadSectors - pExtent->cOverheadSectors; 9014 9015 // 2. Relocate sectors to make room for new GD/GT, update entries in GD/GT 9016 if (cOverheadSectorDiff > 0) 9017 { 9018 if (pExtent->cSectors > 0) 9019 { 9020 /* Do the relocation. */ 9021 LogFlow(("Relocating VMDK sectors\n")); 9022 rc = vmdkRelocateSectorsForSparseResize(pImage, pExtent, cSectorsNew); 9023 if (RT_FAILURE(rc)) 9024 return rc; 9025 9026 rc = vmdkFlushImage(pImage, NULL); 9027 if (RT_FAILURE(rc)) 9028 return rc; 9029 } 9030 9031 rc = vmdkResizeSparseMeta(pImage, pExtent, cSectorsNew); 9032 if (RT_FAILURE(rc)) 9033 return rc; 9034 } 9035 } 9036 9037 /** 9038 * twoGbSparseExtent 9039 */ 9040 if (pExtent->enmType == VMDKETYPE_HOSTED_SPARSE && (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)) 9041 { 9042 /* Check to see how much space remains in last extent */ 9043 bool fSpaceAvailible = false; 9044 uint64_t cLastExtentRemSectors = cSectorsOld % VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 9045 if (cLastExtentRemSectors) 9046 fSpaceAvailible = true; 9047 9048 uint64_t cSectorsNeeded = cSectorsNew - cSectorsOld; 9049 9050 if (fSpaceAvailible && cSectorsNeeded + cLastExtentRemSectors <= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)) 9051 { 9052 pExtent = &pImage->pExtents[cExtents - 1]; 9053 rc = vmdkRelocateSectorsForSparseResize(pImage, pExtent, cSectorsNeeded + cLastExtentRemSectors); 9054 if (RT_FAILURE(rc)) 9055 return rc; 9056 9057 rc = vmdkFlushImage(pImage, NULL); 9058 if (RT_FAILURE(rc)) 9059 return rc; 9060 9061 rc = vmdkResizeSparseMeta(pImage, pExtent, cSectorsNeeded + cLastExtentRemSectors); 9062 if (RT_FAILURE(rc)) 9063 return rc; 9064 } 9065 else 9066 { 9067 if (fSpaceAvailible) 9068 { 9069 pExtent = &pImage->pExtents[cExtents - 1]; 9070 rc = vmdkRelocateSectorsForSparseResize(pImage, pExtent, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)); 9071 if (RT_FAILURE(rc)) 9072 return rc; 9073 9074 rc = vmdkFlushImage(pImage, NULL); 9075 if (RT_FAILURE(rc)) 9076 return rc; 9077 9078 rc = vmdkResizeSparseMeta(pImage, pExtent, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)); 9079 if (RT_FAILURE(rc)) 9080 return rc; 9081 9082 cSectorsNeeded = cSectorsNeeded - VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE) + cLastExtentRemSectors; 9083 } 9084 9085 unsigned cNewExtents = VMDK_SECTOR2BYTE(cSectorsNeeded) / VMDK_2G_SPLIT_SIZE; 9086 if (cNewExtents % VMDK_2G_SPLIT_SIZE || cNewExtents < VMDK_2G_SPLIT_SIZE) 9087 cNewExtents++; 9088 9089 for (unsigned i = cExtents; 9090 i < cExtents + cNewExtents && cSectorsNeeded >= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 9091 i++) 9092 { 9093 rc = vmdkAddFileBackedExtent(pImage, VMDK_2G_SPLIT_SIZE); 9094 if (RT_FAILURE(rc)) 9095 return rc; 9096 9097 pExtent = &pImage->pExtents[i]; 9098 9099 rc = vmdkFlushImage(pImage, NULL); 9100 if (RT_FAILURE(rc)) 9101 return rc; 9102 9103 pExtent->cSectors = VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 9104 cSectorsNeeded -= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 9105 } 9106 9107 if (cSectorsNeeded) 9108 { 9109 rc = vmdkAddFileBackedExtent(pImage, VMDK_SECTOR2BYTE(cSectorsNeeded)); 9110 if (RT_FAILURE(rc)) 9111 return rc; 9112 9113 pExtent = &pImage->pExtents[pImage->cExtents]; 9114 9115 rc = vmdkFlushImage(pImage, NULL); 9116 if (RT_FAILURE(rc)) 9117 return rc; 9118 } 9119 } 9120 } 9121 8437 9122 /* Successful resize. Update metadata */ 8438 9123 if (RT_SUCCESS(rc)) … … 8440 9125 /* Update size and new block count. */ 8441 9126 pImage->cbSize = cbSize; 8442 /** @todo r=jack: update cExtents if needed */8443 pExtent->c NominalSectors = VMDK_BYTE2SECTOR(cbSize);9127 pExtent->cNominalSectors = cSectorsNew; 9128 pExtent->cSectors = cSectorsNew; 8444 9129 8445 9130 /* Update geometry. */ … … 8449 9134 8450 9135 /* Update header information in base image file. */ 9136 pImage->Descriptor.fDirty = true; 8451 9137 rc = vmdkWriteDescriptor(pImage, NULL); 8452 9138 8453 if (RT_FAILURE(rc)) 8454 return rc; 8455 8456 rc = vmdkFlushImage(pImage, NULL); 8457 8458 if (RT_FAILURE(rc)) 8459 return rc; 9139 if (RT_SUCCESS(rc)) 9140 rc = vmdkFlushImage(pImage, NULL); 8460 9141 } 8461 9142 /* Same size doesn't change the image at all. */ … … 8464 9145 return rc; 8465 9146 } 8466 8467 9147 8468 9148 const VDIMAGEBACKEND g_VmdkBackend =
Note:
See TracChangeset
for help on using the changeset viewer.