Changeset 96832 in vbox for trunk/src/VBox/Storage/VMDK.cpp
- Timestamp:
- Sep 22, 2022 7:02:09 PM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VMDK.cpp
r96407 r96832 146 146 */ 147 147 #define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */ 148 /** VMDK sector size in bytes. */ 149 #define VMDK_SECTOR_SIZE 512 150 /** Max string buffer size for uint64_t with null term */ 151 #define UINT64_MAX_BUFF_SIZE 21 152 /** Grain directory entry size in bytes */ 153 #define VMDK_GRAIN_DIR_ENTRY_SIZE 4 154 /** Grain table size in bytes */ 155 #define VMDK_GRAIN_TABLE_SIZE 2048 148 156 /** 149 157 * VMDK hosted binary extent header. The "Sparse" is a total misnomer, as … … 1238 1246 */ 1239 1247 static int vmdkCreateGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 1240 uint64_t uStartSector, bool fPreAlloc) 1248 uint64_t uStartSector, bool fPreAlloc, 1249 bool fExisting = false) 1241 1250 { 1242 1251 int rc = VINF_SUCCESS; … … 1271 1280 cbOverhead = RT_ALIGN_64(cbOverhead, 1272 1281 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 1273 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead); 1282 1283 if (!fExisting) 1284 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead); 1274 1285 } 1275 1286 if (RT_SUCCESS(rc)) … … 2806 2817 pImage->pExtents = pExtents; 2807 2818 pImage->cExtents = cExtents; 2819 } 2820 else 2821 rc = VERR_NO_MEMORY; 2822 return rc; 2823 } 2824 /** 2825 * Internal: allocate and describes an additional, file-backed extent 2826 * for the given size. Preserves original extents. 2827 */ 2828 static int vmdkAddFileBackedExtent(PVMDKIMAGE pImage, uint64_t cbSize) 2829 { 2830 int rc = VINF_SUCCESS; 2831 PVMDKEXTENT pNewExtents = (PVMDKEXTENT)RTMemAllocZ((pImage->cExtents + 1) * sizeof(VMDKEXTENT)); 2832 if (pNewExtents) 2833 { 2834 memcpy(pNewExtents, pImage->pExtents, pImage->cExtents * sizeof(VMDKEXTENT)); 2835 PVMDKEXTENT pExtent = &pNewExtents[pImage->cExtents]; 2836 2837 pExtent->pFile = NULL; 2838 pExtent->pszBasename = NULL; 2839 pExtent->pszFullname = NULL; 2840 pExtent->pGD = NULL; 2841 pExtent->pRGD = NULL; 2842 pExtent->pDescData = NULL; 2843 pExtent->uVersion = 1; 2844 pExtent->uCompression = VMDK_COMPRESSION_NONE; 2845 pExtent->uExtent = pImage->cExtents; 2846 pExtent->pImage = pImage; 2847 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize); 2848 pExtent->enmType = VMDKETYPE_FLAT; 2849 pExtent->enmAccess = VMDKACCESS_READWRITE; 2850 pExtent->uSectorOffset = 0; 2851 2852 char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename); 2853 AssertPtr(pszBasenameSubstr); 2854 2855 char *pszBasenameSuff = RTPathSuffix(pszBasenameSubstr); 2856 char *pszBasenameBase = RTStrDup(pszBasenameSubstr); 2857 RTPathStripSuffix(pszBasenameBase); 2858 char *pszTmp; 2859 size_t cbTmp; 2860 2861 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED) 2862 RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase, 2863 pExtent->uExtent + 1, pszBasenameSuff); 2864 else 2865 RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, pExtent->uExtent + 1, 2866 pszBasenameSuff); 2867 2868 RTStrFree(pszBasenameBase); 2869 if (!pszTmp) 2870 return VERR_NO_STR_MEMORY; 2871 cbTmp = strlen(pszTmp) + 1; 2872 char *pszBasename = (char *)RTMemTmpAlloc(cbTmp); 2873 if (!pszBasename) 2874 { 2875 RTStrFree(pszTmp); 2876 return VERR_NO_MEMORY; 2877 } 2878 2879 memcpy(pszBasename, pszTmp, cbTmp); 2880 RTStrFree(pszTmp); 2881 2882 pExtent->pszBasename = pszBasename; 2883 2884 char *pszBasedirectory = RTStrDup(pImage->pszFilename); 2885 if (!pszBasedirectory) 2886 return VERR_NO_STR_MEMORY; 2887 RTPathStripFilename(pszBasedirectory); 2888 char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename); 2889 RTStrFree(pszBasedirectory); 2890 if (!pszFullname) 2891 return VERR_NO_STR_MEMORY; 2892 pExtent->pszFullname = pszFullname; 2893 2894 /* Create file for extent. */ 2895 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszBasename, pExtent->pszFullname, 2896 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, 2897 true /* fCreate */)); 2898 if (RT_FAILURE(rc)) 2899 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname); 2900 2901 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess, 2902 pExtent->cNominalSectors, pExtent->enmType, 2903 pExtent->pszBasename, pExtent->uSectorOffset); 2904 if (RT_FAILURE(rc)) 2905 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename); 2906 2907 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, cbSize, 2908 0 /* fFlags */, NULL, 0, 0); 2909 2910 if (RT_FAILURE(rc)) 2911 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 2912 2913 pImage->pExtents = pNewExtents; 2914 pImage->cExtents++; 2808 2915 } 2809 2916 else … … 7400 7507 vdIfErrorMessage(pImage->pIfError, "Header: uuidParentModification={%RTuuid}\n", &pImage->ParentModificationUuid); 7401 7508 } 7509 7510 static int vmdkRepaceExtentSize(PVMDKIMAGE pImage, unsigned line, uint64_t cSectorsOld, 7511 uint64_t cSectorsNew) 7512 { 7513 char * szOldExtentSectors = (char *)RTMemAlloc(UINT64_MAX_BUFF_SIZE); 7514 if (!szOldExtentSectors) 7515 return VERR_NO_MEMORY; 7516 7517 int cbWritten = RTStrPrintf2(szOldExtentSectors, UINT64_MAX_BUFF_SIZE, "%llu", cSectorsOld); 7518 if (cbWritten <= 0 || cbWritten > UINT64_MAX_BUFF_SIZE) 7519 { 7520 RTMemFree(szOldExtentSectors); 7521 szOldExtentSectors = NULL; 7522 7523 return VERR_BUFFER_OVERFLOW; 7524 } 7525 7526 char * szNewExtentSectors = (char *)RTMemAlloc(UINT64_MAX_BUFF_SIZE); 7527 if (!szNewExtentSectors) 7528 return VERR_NO_MEMORY; 7529 7530 cbWritten = RTStrPrintf2(szNewExtentSectors, UINT64_MAX_BUFF_SIZE, "%llu", cSectorsNew); 7531 if (cbWritten <= 0 || cbWritten > UINT64_MAX_BUFF_SIZE) 7532 { 7533 RTMemFree(szOldExtentSectors); 7534 szOldExtentSectors = NULL; 7535 7536 RTMemFree(szNewExtentSectors); 7537 szNewExtentSectors = NULL; 7538 7539 return VERR_BUFFER_OVERFLOW; 7540 } 7541 7542 char * szNewExtentLine = vmdkStrReplace(pImage->Descriptor.aLines[line], 7543 szOldExtentSectors, 7544 szNewExtentSectors); 7545 7546 RTMemFree(szOldExtentSectors); 7547 szOldExtentSectors = NULL; 7548 7549 RTMemFree(szNewExtentSectors); 7550 szNewExtentSectors = NULL; 7551 7552 if (!szNewExtentLine) 7553 return VERR_INVALID_PARAMETER; 7554 7555 pImage->Descriptor.aLines[line] = szNewExtentLine; 7556 7557 return VINF_SUCCESS; 7558 } 7559 7560 /** @copydoc VDIMAGEBACKEND::pfnResize */ 7561 static DECLCALLBACK(int) vmdkResize(void *pBackendData, uint64_t cbSize, 7562 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry, 7563 unsigned uPercentStart, unsigned uPercentSpan, 7564 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, 7565 PVDINTERFACE pVDIfsOperation) 7566 { 7567 // Establish variables and objects needed 7568 int rc = VINF_SUCCESS; 7569 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 7570 unsigned uImageFlags = pImage->uImageFlags; 7571 PVMDKEXTENT pExtent = &pImage->pExtents[0]; 7572 7573 uint64_t cSectorsNew = cbSize / VMDK_SECTOR_SIZE; /** < New number of sectors in the image after the resize */ 7574 if (cbSize % VMDK_SECTOR_SIZE) 7575 cSectorsNew++; 7576 7577 uint64_t cSectorsOld = pImage->cbSize / VMDK_SECTOR_SIZE; /** < Number of sectors before the resize. Only for FLAT images. */ 7578 if (pImage->cbSize % VMDK_SECTOR_SIZE) 7579 cSectorsOld++; 7580 unsigned cExtents = pImage->cExtents; 7581 7582 /* Check size is within min/max bounds. */ 7583 if ( !(uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK) 7584 && ( !cbSize 7585 || (!(uImageFlags & VD_IMAGE_FLAGS_FIXED) && cbSize >= _1T * 256 - _64K)) ) 7586 return VERR_VD_INVALID_SIZE; 7587 7588 /* 7589 * Making the image smaller is not supported at the moment. 7590 */ 7591 /** @todo implement making the image smaller, it is the responsibility of 7592 * the user to know what he's doing. */ 7593 if (cbSize < pImage->cbSize) 7594 rc = VERR_VD_SHRINK_NOT_SUPPORTED; 7595 else if (cbSize > pImage->cbSize) 7596 { 7597 /** 7598 * monolithicFlat. FIXED flag and not split up into 2 GB parts. 7599 */ 7600 if ((uImageFlags & VD_IMAGE_FLAGS_FIXED) && !(uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)) 7601 { 7602 /** Required space in bytes for the extent after the resize. */ 7603 uint64_t cbSectorSpaceNew = cSectorsNew * VMDK_SECTOR_SIZE; 7604 pExtent = &pImage->pExtents[0]; 7605 7606 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, cbSectorSpaceNew, 7607 0 /* fFlags */, NULL, 7608 uPercentStart, uPercentSpan); 7609 if (RT_FAILURE(rc)) 7610 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 7611 7612 rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent, cSectorsOld, cSectorsNew); 7613 if (RT_FAILURE(rc)) 7614 return rc; 7615 } 7616 7617 /** 7618 * twoGbMaxExtentFlat. FIXED flag and SPLIT into 2 GB parts. 7619 */ 7620 if ((uImageFlags & VD_IMAGE_FLAGS_FIXED) && (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)) 7621 { 7622 /* Check to see how much space remains in last extent */ 7623 bool fSpaceAvailible = false; 7624 uint64_t cLastExtentRemSectors = cSectorsOld % VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 7625 if (cLastExtentRemSectors) 7626 fSpaceAvailible = true; 7627 7628 uint64_t cSectorsNeeded = cSectorsNew - cSectorsOld; 7629 if (fSpaceAvailible && cSectorsNeeded + cLastExtentRemSectors <= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)) 7630 { 7631 pExtent = &pImage->pExtents[cExtents - 1]; 7632 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, 7633 VMDK_SECTOR2BYTE(cSectorsNeeded + cLastExtentRemSectors), 7634 0 /* fFlags */, NULL, uPercentStart, uPercentSpan); 7635 if (RT_FAILURE(rc)) 7636 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 7637 7638 rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent + cExtents - 1, 7639 pExtent->cNominalSectors, cSectorsNeeded + cLastExtentRemSectors); 7640 if (RT_FAILURE(rc)) 7641 return rc; 7642 } 7643 else 7644 { 7645 if (fSpaceAvailible) 7646 { 7647 pExtent = &pImage->pExtents[cExtents - 1]; 7648 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pExtent->pFile->pStorage, VMDK_2G_SPLIT_SIZE, 7649 0 /* fFlags */, NULL, 7650 uPercentStart, uPercentSpan); 7651 if (RT_FAILURE(rc)) 7652 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 7653 7654 cSectorsNeeded = cSectorsNeeded - VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE) + cLastExtentRemSectors; 7655 7656 rc = vmdkRepaceExtentSize(pImage, pImage->Descriptor.uFirstExtent + cExtents - 1, 7657 pExtent->cNominalSectors, VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE)); 7658 if (RT_FAILURE(rc)) 7659 return rc; 7660 } 7661 7662 unsigned cNewExtents = VMDK_SECTOR2BYTE(cSectorsNeeded) / VMDK_2G_SPLIT_SIZE; 7663 if (cNewExtents % VMDK_2G_SPLIT_SIZE || cNewExtents < VMDK_2G_SPLIT_SIZE) 7664 cNewExtents++; 7665 7666 for (unsigned i = cExtents; 7667 i < cExtents + cNewExtents && cSectorsNeeded >= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 7668 i++) 7669 { 7670 rc = vmdkAddFileBackedExtent(pImage, VMDK_2G_SPLIT_SIZE); 7671 if (RT_FAILURE(rc)) 7672 return rc; 7673 7674 pExtent = &pImage->pExtents[i]; 7675 7676 pExtent->cSectors = VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 7677 cSectorsNeeded -= VMDK_BYTE2SECTOR(VMDK_2G_SPLIT_SIZE); 7678 } 7679 7680 if (cSectorsNeeded) 7681 { 7682 rc = vmdkAddFileBackedExtent(pImage, VMDK_SECTOR2BYTE(cSectorsNeeded)); 7683 if (RT_FAILURE(rc)) 7684 return rc; 7685 } 7686 } 7687 } 7688 7689 /* Successful resize. Update metadata */ 7690 if (RT_SUCCESS(rc)) 7691 { 7692 /* Update size and new block count. */ 7693 pImage->cbSize = cbSize; 7694 /** @todo r=jack: update cExtents if needed */ 7695 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize); 7696 7697 /* Update geometry. */ 7698 pImage->PCHSGeometry = *pPCHSGeometry; 7699 pImage->LCHSGeometry = *pLCHSGeometry; 7700 } 7701 7702 /* Update header information in base image file. */ 7703 rc = vmdkWriteDescriptor(pImage, NULL); 7704 7705 if (RT_FAILURE(rc)) 7706 return rc; 7707 7708 rc = vmdkFlushImage(pImage, NULL); 7709 7710 if (RT_FAILURE(rc)) 7711 return rc; 7712 } 7713 /* Same size doesn't change the image at all. */ 7714 7715 LogFlowFunc(("returns %Rrc\n", rc)); 7716 return rc; 7717 } 7718 7402 7719 const VDIMAGEBACKEND g_VmdkBackend = 7403 7720 { … … 7493 7810 NULL, 7494 7811 /* pfnResize */ 7495 NULL,7812 vmdkResize, 7496 7813 /* pfnRepair */ 7497 7814 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.