VirtualBox

Changeset 97854 in vbox for trunk/src/VBox/Storage/VMDK.cpp


Ignore:
Timestamp:
Dec 22, 2022 7:30:51 PM (2 years ago)
Author:
vboxsync
Message:

Storage: Add VMDK resize. bugref:8707

File:
1 edited

Legend:

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

    r97839 r97854  
    17921792}
    17931793
     1794static 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
    17941821static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
    17951822                             VMDKACCESS enmAccess, uint64_t cNominalSectors,
     
    18381865        || (  pDescriptor->aLines[pDescriptor->cLines]
    18391866            - 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    }
    18411877
    18421878    for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
     
    31073143
    31083144/**
    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.
    31113151 */
    31123152static int vmdkAddFileBackedExtent(PVMDKIMAGE pImage, uint64_t cbSize)
    31133153{
    31143154    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. */
    31153166    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    {
    31323195        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    {
    31643234        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. */
    31913263        rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, cbSize,
    31923264                                            0 /* fFlags */, NULL, 0, 0);
    3193 
    31943265        if (RT_FAILURE(rc))
    31953266            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++;
    31993267    }
    32003268    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
    32023291    return rc;
    32033292}
     3293
    32043294/**
    32053295 * Reads and processes the descriptor embedded in sparse images.
     
    82548344}
    82558345
    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 */
     8356static 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 */
     8384static 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))
    82698392        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))
    82858396        return VERR_BUFFER_OVERFLOW;
    8286     }
    8287 
    8288     char * szNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[line],
     8397
     8398    char *pszNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[uLine],
    82898399                                            szOldExtentSectors,
    82908400                                            szNewExtentSectors);
    82918401
    8292     RTMemFree(szOldExtentSectors);
    8293     szOldExtentSectors = NULL;
    8294 
    8295     RTMemFree(szNewExtentSectors);
    8296     szNewExtentSectors = NULL;
    8297 
    8298     if (!szNewExtentLine)
     8402    if (RT_UNLIKELY(!pszNewExtentLine))
    82998403        return VERR_INVALID_PARAMETER;
    83008404
    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;
    83028414
    83038415    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 */
     8427static 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 */
     8631static 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;
    83048867}
    83058868
     
    83188881    unsigned uImageFlags = pImage->uImageFlags;
    83198882    PVMDKEXTENT pExtent = &pImage->pExtents[0];
     8883    pExtent->fMetaDirty = true;
    83208884
    83218885    uint64_t cSectorsNew = cbSize / VMDK_SECTOR_SIZE;   /** < New number of sectors in the image after the resize */
     
    83388902     */
    83398903    /** @todo implement making the image smaller, it is the responsibility of
    8340      * the user to know what he's doing. */
     8904     * the user to know what they're doing. */
    83418905    if (cbSize < pImage->cbSize)
    83428906        rc = VERR_VD_SHRINK_NOT_SUPPORTED;
     
    83588922                return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    83598923
    8360             rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew);
     8924            rc = vmdkReplaceExtentSize(pImage, pExtent, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew);
    83618925            if (RT_FAILURE(rc))
    83628926                return rc;
     
    83758939
    83768940            uint64_t cSectorsNeeded = cSectorsNew - cSectorsOld;
     8941
     8942            /** Space remaining in current last extent file that we don't need to create another one. */
    83778943            if (fSpaceAvailible && cSectorsNeeded + cLastExtentRemSectors <= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE))
    83788944            {
     
    83848950                    return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
    83858951
    8386                 rc = vmdkRepaceExtentSize(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);
    83888954                if (RT_FAILURE(rc))
    83898955                    return rc;
    83908956            }
     8957            //** Need more extent files to handle all the requested space. */
    83918958            else
    83928959            {
     
    84028969                    cSectorsNeeded = cSectorsNeeded - VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE) + cLastExtentRemSectors;
    84038970
    8404                     rc = vmdkRepaceExtentSize(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));
    84068973                    if (RT_FAILURE(rc))
    84078974                        return rc;
     
    84359002        }
    84369003
     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
    84379122        /* Successful resize. Update metadata */
    84389123        if (RT_SUCCESS(rc))
     
    84409125            /* Update size and new block count. */
    84419126            pImage->cbSize = cbSize;
    8442             /** @todo r=jack: update cExtents if needed */
    8443             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     9127            pExtent->cNominalSectors = cSectorsNew;
     9128            pExtent->cSectors = cSectorsNew;
    84449129
    84459130            /* Update geometry. */
     
    84499134
    84509135        /* Update header information in base image file. */
     9136        pImage->Descriptor.fDirty = true;
    84519137        rc = vmdkWriteDescriptor(pImage, NULL);
    84529138
    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);
    84609141    }
    84619142    /* Same size doesn't change the image at all. */
     
    84649145    return rc;
    84659146}
    8466 
    84679147
    84689148const VDIMAGEBACKEND g_VmdkBackend =
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