Changeset 6291 in vbox for trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
- Timestamp:
- Jan 9, 2008 10:57:05 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r5999 r6291 36 36 * Constants And Macros, Structures and Typedefs * 37 37 *******************************************************************************/ 38 39 /** VMDK descriptor DDB entry for PCHS cylinders. */ 40 #define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders" 41 42 /** VMDK descriptor DDB entry for PCHS heads. */ 43 #define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads" 44 45 /** VMDK descriptor DDB entry for PCHS sectors. */ 46 #define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors" 47 48 /** VMDK descriptor DDB entry for LCHS cylinders. */ 49 #define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders" 50 51 /** VMDK descriptor DDB entry for LCHS heads. */ 52 #define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads" 53 54 /** VMDK descriptor DDB entry for LCHS sectors. */ 55 #define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors" 38 56 39 57 /** … … 67 85 #pragma pack() 68 86 87 /** VMDK capacity for a single chunk when 2G splitting is turned on. Should be 88 * divisible by the default grain size (64K) */ 89 #define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024) 90 69 91 70 92 #ifdef VBOX_WITH_VMDK_ESX … … 89 111 uint32_t freeSector; 90 112 /* The spec incompletely documents quite a few further fields, but states 91 * that they are notused by the current format. Replace them by padding. */113 * that they are unused by the current format. Replace them by padding. */ 92 114 char reserved1[1604]; 93 115 uint32_t savedGeneration; … … 274 296 typedef struct VMDKIMAGE 275 297 { 298 /** Pointer to the image extents. */ 276 299 PVMDKEXTENT pExtents; 300 /** Number of image extents. */ 277 301 unsigned cExtents; 278 302 … … 295 319 /** Total size of the image. */ 296 320 uint64_t cbSize; 297 /** BIOS translation mode. */ 298 PDMBIOSTRANSLATION enmTranslation; 299 /** Physical geometry of this image, cylinders. */ 300 uint32_t cCylinders; 301 /** Physical geometry of this image, heads. */ 302 uint32_t cHeads; 303 /** Physical geometry of this image, sectors. */ 304 uint32_t cSectors; 321 /** Physical geometry of this image. */ 322 PDMMEDIAGEOMETRY PCHSGeometry; 323 /** Logical geometry of this image. */ 324 PDMMEDIAGEOMETRY LCHSGeometry; 305 325 /** Image UUID. */ 306 326 RTUUID ImageUuid; … … 310 330 RTUUID ParentUuid; 311 331 312 /** Pointer to thegrain table cache, if this image contains sparse extents. */332 /** Pointer to grain table cache, if this image contains sparse extents. */ 313 333 PVMDKGTCACHE pGTCache; 314 334 /** Pointer to the descriptor (NULL if no separate descriptor file). */ … … 342 362 static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete); 343 363 344 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData);345 static int vmdkClose(void *pBackendData, bool fDelete);346 347 364 348 365 DECLINLINE(int) vmdkError(PVMDKIMAGE pImage, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) … … 350 367 va_list va; 351 368 va_start(va, pszFormat); 352 pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va); 369 if (pImage->pfnError) 370 pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va); 353 371 va_end(va); 354 372 return rc; … … 439 457 } 440 458 441 for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD; i < pExtent->cGDEntries; i++, pGDTmp++, pRGDTmp++) 459 for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD; 460 i < pExtent->cGDEntries; 461 i++, pGDTmp++, pRGDTmp++) 442 462 { 443 463 /* If no grain table is allocated skip the entry. */ … … 491 511 } 492 512 493 static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector, bool fPreAlloc) 513 static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector, 514 bool fPreAlloc) 494 515 { 495 516 int rc = VINF_SUCCESS; … … 539 560 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 540 561 /* Write the redundant grain directory entry to disk. */ 541 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL); 562 rc = RTFileWriteAt(pExtent->File, 563 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), 564 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 542 565 if (VBOX_FAILURE(rc)) 543 566 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname); … … 551 574 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 552 575 /* Write the grain directory entry to disk. */ 553 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL); 576 rc = RTFileWriteAt(pExtent->File, 577 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), 578 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 554 579 if (VBOX_FAILURE(rc)) 555 580 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname); … … 579 604 } 580 605 581 static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr, char **ppszUnquoted, char **ppszNext) 606 static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr, 607 char **ppszUnquoted, char **ppszNext) 582 608 { 583 609 char *pszQ; … … 632 658 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey)) 633 659 { 634 /* Key matches, check if there isa '=' (preceded by whitespace). */660 /* Key matches, check for a '=' (preceded by whitespace). */ 635 661 pszValue = pDescriptor->aLines[uStart] + cbKey; 636 662 while (*pszValue == ' ' || *pszValue == '\t') … … 659 685 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey)) 660 686 { 661 /* Key matches, check if there isa '=' (preceded by whitespace). */687 /* Key matches, check for a '=' (preceded by whitespace). */ 662 688 pszTmp = pDescriptor->aLines[uStart] + cbKey; 663 689 while (*pszTmp == ' ' || *pszTmp == '\t') … … 715 741 else 716 742 { 717 /* Key doesn't exist, append itafter the last entry in this category. */743 /* Key doesn't exist, append after the last entry in this category. */ 718 744 if (!pszValue) 719 745 { … … 765 791 const char *pszValue; 766 792 767 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue)) 793 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, 794 &pszValue)) 768 795 return VERR_VDI_VALUE_NOT_FOUND; 769 796 return RTStrToUInt32Ex(pszValue, NULL, 10, puValue); … … 776 803 char *pszValueUnquoted; 777 804 778 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue)) 805 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, 806 &pszValue)) 779 807 return VERR_VDI_VALUE_NOT_FOUND; 780 808 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL); … … 793 821 if (VBOX_FAILURE(rc)) 794 822 return rc; 795 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey, pszValueQuoted); 823 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey, 824 pszValueQuoted); 796 825 RTStrFree(pszValueQuoted); 797 826 return rc; 798 827 } 799 828 800 static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor) 829 static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage, 830 PVMDKDESCRIPTOR pDescriptor) 801 831 { 802 832 unsigned uEntry = pDescriptor->uFirstExtent; … … 807 837 808 838 cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1; 809 /* Move everything including the\0 in the entry marking the end of buffer. */839 /* Move everything including \0 in the entry marking the end of buffer. */ 810 840 memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1], 811 841 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1); … … 902 932 char *pszValueUnquoted; 903 933 904 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue)) 934 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, 935 &pszValue)) 905 936 return VERR_VDI_VALUE_NOT_FOUND; 906 937 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL); … … 917 948 char *pszValueUnquoted; 918 949 919 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue)) 950 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, 951 &pszValue)) 920 952 return VERR_VDI_VALUE_NOT_FOUND; 921 953 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL); … … 933 965 char *pszValueUnquoted; 934 966 935 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue)) 967 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, 968 &pszValue)) 936 969 return VERR_VDI_VALUE_NOT_FOUND; 937 970 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL); … … 943 976 } 944 977 945 static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, const char *pszVal) 978 static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, 979 const char *pszKey, const char *pszVal) 946 980 { 947 981 int rc; … … 956 990 else 957 991 pszValQuoted = NULL; 958 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValQuoted); 992 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, 993 pszValQuoted); 959 994 if (pszValQuoted) 960 995 RTStrFree(pszValQuoted); … … 962 997 } 963 998 964 static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, PCRTUUID pUuid) 999 static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, 1000 const char *pszKey, PCRTUUID pUuid) 965 1001 { 966 1002 char *pszUuid; … … 969 1005 if (VBOX_FAILURE(rc)) 970 1006 return rc; 971 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszUuid); 1007 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, 1008 pszUuid); 972 1009 RTStrFree(pszUuid); 973 1010 return rc; 974 1011 } 975 1012 976 int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, uint32_t uValue) 1013 int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, 1014 const char *pszKey, uint32_t uValue) 977 1015 { 978 1016 char *pszValue; … … 981 1019 if (VBOX_FAILURE(rc)) 982 1020 return rc; 983 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValue); 1021 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, 1022 pszValue); 984 1023 RTStrFree(pszValue); 985 1024 return rc; 986 1025 } 987 1026 988 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor) 1027 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, 1028 size_t cbDescData, 1029 PVMDKDESCRIPTOR pDescriptor) 989 1030 { 990 1031 int rc = VINF_SUCCESS; … … 1101 1142 } 1102 1143 1103 static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor) 1144 static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage, 1145 PCPDMMEDIAGEOMETRY pPCHSGeometry) 1146 { 1147 int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 1148 VMDK_DDB_GEO_PCHS_CYLINDERS, 1149 pPCHSGeometry->cCylinders); 1150 if (VBOX_FAILURE(rc)) 1151 return rc; 1152 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 1153 VMDK_DDB_GEO_PCHS_HEADS, 1154 pPCHSGeometry->cHeads); 1155 if (VBOX_FAILURE(rc)) 1156 return rc; 1157 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 1158 VMDK_DDB_GEO_PCHS_SECTORS, 1159 pPCHSGeometry->cSectors); 1160 return rc; 1161 } 1162 1163 static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage, 1164 PCPDMMEDIAGEOMETRY pLCHSGeometry) 1165 { 1166 int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 1167 VMDK_DDB_GEO_LCHS_CYLINDERS, 1168 pLCHSGeometry->cCylinders); 1169 if (VBOX_FAILURE(rc)) 1170 return rc; 1171 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 1172 VMDK_DDB_GEO_LCHS_HEADS, 1173 pLCHSGeometry->cHeads); 1174 if (VBOX_FAILURE(rc)) 1175 return rc; 1176 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 1177 VMDK_DDB_GEO_LCHS_SECTORS, 1178 pLCHSGeometry->cSectors); 1179 return rc; 1180 } 1181 1182 static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData, 1183 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor) 1104 1184 { 1105 1185 int rc; … … 1153 1233 char szBuf[9]; 1154 1234 RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32()); 1155 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "CID", szBuf); 1156 if (VBOX_FAILURE(rc)) 1157 goto out; 1158 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "parentCID", "ffffffff"); 1235 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, 1236 "CID", szBuf); 1237 if (VBOX_FAILURE(rc)) 1238 goto out; 1239 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, 1240 "parentCID", "ffffffff"); 1159 1241 if (VBOX_FAILURE(rc)) 1160 1242 goto out; … … 1168 1250 } 1169 1251 1170 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData) 1252 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, 1253 size_t cbDescData) 1171 1254 { 1172 1255 int rc; … … 1174 1257 unsigned uLine; 1175 1258 1176 rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData, &pImage->Descriptor); 1259 rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData, 1260 &pImage->Descriptor); 1177 1261 if (VBOX_FAILURE(rc)) 1178 1262 return rc; … … 1318 1402 } 1319 1403 1404 /* Determine PCHS geometry (autogenerate if necessary). */ 1320 1405 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor, 1321 "ddb.geometry.cylinders", &pImage->cCylinders); 1322 if (VBOX_FAILURE(rc)) 1323 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename); 1406 VMDK_DDB_GEO_PCHS_CYLINDERS, 1407 &pImage->PCHSGeometry.cCylinders); 1408 if (rc == VERR_VDI_VALUE_NOT_FOUND) 1409 pImage->PCHSGeometry.cCylinders = 0; 1410 else if (VBOX_FAILURE(rc)) 1411 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename); 1324 1412 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor, 1325 "ddb.geometry.heads", &pImage->cHeads); 1326 if (VBOX_FAILURE(rc)) 1327 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename); 1413 VMDK_DDB_GEO_PCHS_HEADS, 1414 &pImage->PCHSGeometry.cHeads); 1415 if (rc == VERR_VDI_VALUE_NOT_FOUND) 1416 pImage->PCHSGeometry.cHeads = 0; 1417 else if (VBOX_FAILURE(rc)) 1418 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename); 1328 1419 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor, 1329 "ddb.geometry.sectors", &pImage->cSectors); 1330 if (VBOX_FAILURE(rc)) 1331 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename); 1332 if (pImage->cCylinders >= 1024 || pImage->cHeads != 16) 1333 pImage->enmTranslation = PDMBIOSTRANSLATION_LBA; 1334 else 1335 pImage->enmTranslation = PDMBIOSTRANSLATION_NONE; 1420 VMDK_DDB_GEO_PCHS_SECTORS, 1421 &pImage->PCHSGeometry.cSectors); 1422 if (rc == VERR_VDI_VALUE_NOT_FOUND) 1423 pImage->PCHSGeometry.cSectors = 0; 1424 else if (VBOX_FAILURE(rc)) 1425 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename); 1426 if ( pImage->PCHSGeometry.cCylinders == 0 1427 || pImage->PCHSGeometry.cHeads == 0 1428 || pImage->PCHSGeometry.cHeads > 16 1429 || pImage->PCHSGeometry.cSectors == 0 1430 || pImage->PCHSGeometry.cSectors > 63) 1431 { 1432 /* Mark PCHS geometry as not yet valid (can't do the calculation here 1433 * as the total image size isn't known yet). */ 1434 pImage->PCHSGeometry.cCylinders = 0; 1435 pImage->PCHSGeometry.cHeads = 16; 1436 pImage->PCHSGeometry.cSectors = 63; 1437 } 1438 1439 /* Determine LCHS geometry (set to 0 if not specified). */ 1440 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor, 1441 VMDK_DDB_GEO_LCHS_CYLINDERS, 1442 &pImage->LCHSGeometry.cCylinders); 1443 if (rc == VERR_VDI_VALUE_NOT_FOUND) 1444 pImage->LCHSGeometry.cCylinders = 0; 1445 else if (VBOX_FAILURE(rc)) 1446 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename); 1447 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor, 1448 VMDK_DDB_GEO_LCHS_HEADS, 1449 &pImage->LCHSGeometry.cHeads); 1450 if (rc == VERR_VDI_VALUE_NOT_FOUND) 1451 pImage->LCHSGeometry.cHeads = 0; 1452 else if (VBOX_FAILURE(rc)) 1453 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename); 1454 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor, 1455 VMDK_DDB_GEO_LCHS_SECTORS, 1456 &pImage->LCHSGeometry.cSectors); 1457 if (rc == VERR_VDI_VALUE_NOT_FOUND) 1458 pImage->LCHSGeometry.cSectors = 0; 1459 else if (VBOX_FAILURE(rc)) 1460 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename); 1461 if ( pImage->LCHSGeometry.cCylinders == 0 1462 || pImage->LCHSGeometry.cHeads == 0 1463 || pImage->LCHSGeometry.cSectors == 0) 1464 { 1465 pImage->LCHSGeometry.cCylinders = 0; 1466 pImage->LCHSGeometry.cHeads = 0; 1467 pImage->LCHSGeometry.cSectors = 0; 1468 } 1336 1469 1337 1470 /* Get image UUID. */ … … 1360 1493 1361 1494 /* Get image modification UUID. */ 1362 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, "ddb.uuid.modification", 1495 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, 1496 "ddb.uuid.modification", 1363 1497 &pImage->ModificationUuid); 1364 1498 if (rc == VERR_VDI_VALUE_NOT_FOUND) … … 1375 1509 return rc; 1376 1510 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor, 1377 "ddb.uuid.modification", &pImage->ModificationUuid); 1511 "ddb.uuid.modification", 1512 &pImage->ModificationUuid); 1378 1513 if (VBOX_FAILURE(rc)) 1379 1514 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename); … … 1750 1885 } 1751 1886 1752 static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, unsigned uOpenFlags) 1887 static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, 1888 unsigned uOpenFlags) 1753 1889 { 1754 1890 int rc = VINF_SUCCESS; … … 1860 1996 } 1861 1997 1862 rc = vmdkParseDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc); 1998 rc = vmdkParseDescriptor(pImage, pImage->pDescData, 1999 pImage->cbDescAlloc); 1863 2000 if (VBOX_FAILURE(rc)) 1864 2001 goto out; … … 1924 2061 goto out; 1925 2062 1926 /* Mark theextent as unclean if opened in read-write mode. */2063 /* Mark extent as unclean if opened in read-write mode. */ 1927 2064 if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY)) 1928 2065 { … … 1956 2093 AssertRC(rc); 1957 2094 2095 /* Determine PCHS geometry if not set. */ 2096 if (pImage->PCHSGeometry.cCylinders == 0) 2097 { 2098 uint64_t cCylinders = VMDK_BYTE2SECTOR(pImage->cbSize) 2099 / pImage->PCHSGeometry.cHeads 2100 / pImage->PCHSGeometry.cSectors; 2101 pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383); 2102 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 2103 { 2104 rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry); 2105 AssertRC(rc); 2106 } 2107 } 2108 1958 2109 /* Update the image metadata now in case has changed. */ 1959 2110 rc = vmdkFlushImage(pImage); … … 2002 2153 } 2003 2154 2004 static int vmdkCreate Image(PVMDKIMAGE pImage, const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)2005 { 2006 int rc; 2007 uint64_t cSectorsPerGDE, cSectorsPerGD;2155 static int vmdkCreateRawImage(PVMDKIMAGE pImage, const char *pszFilename, 2156 const PVBOXHDDRAW pRaw, uint64_t cbSize) 2157 { 2158 int rc = VINF_SUCCESS; 2008 2159 PVMDKEXTENT pExtent; 2009 2160 2010 pImage->uImageFlags = uImageFlags; 2011 rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc, &pImage->Descriptor); 2012 if (VBOX_FAILURE(rc)) 2013 { 2014 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename); 2015 goto out; 2016 } 2017 2018 if ( enmType == VD_IMAGE_TYPE_FIXED 2019 || (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G) 2020 || (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)) 2021 { 2022 /* Fixed images and split images in general have a separate descriptor 2023 * file. This is the more complicated case, as it requires setting up 2024 * potentially more than one extent, including filename generation. */ 2025 2026 if ( enmType == VD_IMAGE_TYPE_FIXED 2027 && (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)) 2028 { 2029 PVBOXHDDRAW pRaw = (PVBOXHDDRAW)(void *)pszComment; 2030 /* As the comment is misused, zap it so that no garbage comment 2031 * is set below. */ 2032 pszComment = NULL; 2033 if (pRaw->fRawDisk) 2161 if (pRaw->fRawDisk) 2162 { 2163 /* Full raw disk access. This requires setting up a descriptor 2164 * file and open the (flat) raw disk. */ 2165 rc = vmdkCreateExtents(pImage, 1); 2166 if (VBOX_FAILURE(rc)) 2167 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename); 2168 pExtent = &pImage->pExtents[0]; 2169 rc = RTFileOpen(&pImage->File, pszFilename, 2170 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE); 2171 if (VBOX_FAILURE(rc)) 2172 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename); 2173 2174 /* Set up basename for extent description. Cannot use StrDup. */ 2175 size_t cbBasename = strlen(pRaw->pszRawDisk) + 1; 2176 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename); 2177 if (!pszBasename) 2178 return VERR_NO_MEMORY; 2179 memcpy(pszBasename, pRaw->pszRawDisk, cbBasename); 2180 pExtent->pszBasename = pszBasename; 2181 /* For raw disks the full name is identical to the base name. */ 2182 pExtent->pszFullname = RTStrDup(pszBasename); 2183 if (!pExtent->pszFullname) 2184 return VERR_NO_MEMORY; 2185 pExtent->enmType = VMDKETYPE_FLAT; 2186 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize); 2187 pExtent->uSectorOffset = 0; 2188 pExtent->enmAccess = VMDKACCESS_READWRITE; 2189 pExtent->fMetaDirty = false; 2190 2191 /* Open flat image, the raw disk. */ 2192 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2193 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2194 if (VBOX_FAILURE(rc)) 2195 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname); 2196 } 2197 else 2198 { 2199 /* Raw partition access. This requires setting up a descriptor 2200 * file, write the partition information to a flat extent and 2201 * open all the (flat) raw disk partitions. */ 2202 2203 /* First pass over the partitions to determine how many 2204 * extents we need. One partition can require up to 4 extents. 2205 * One to skip over unpartitioned space, one for the 2206 * partitioning data, one to skip over unpartitioned space 2207 * and one for the partition data. */ 2208 unsigned cExtents = 0; 2209 uint64_t uStart = 0; 2210 for (unsigned i = 0; i < pRaw->cPartitions; i++) 2211 { 2212 PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i]; 2213 if (pPart->cbPartitionData) 2034 2214 { 2035 /* Full raw disk access. This requires setting up a descriptor 2036 * file and open the (flat) raw disk. */ 2037 rc = vmdkCreateExtents(pImage, 1); 2038 if (VBOX_FAILURE(rc)) 2039 { 2040 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename); 2041 goto out; 2042 } 2043 pExtent = &pImage->pExtents[0]; 2044 rc = RTFileOpen(&pImage->File, pszFilename, 2045 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE); 2046 if (VBOX_FAILURE(rc)) 2047 { 2048 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename); 2049 goto out; 2050 } 2051 2052 /* Set up basename for extent description. Cannot use StrDup. */ 2053 size_t cbBasename = strlen(pRaw->pszRawDisk) + 1; 2054 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename); 2055 if (!pszBasename) 2056 { 2057 rc = VERR_NO_MEMORY; 2058 goto out; 2059 } 2060 memcpy(pszBasename, pRaw->pszRawDisk, cbBasename); 2061 pExtent->pszBasename = pszBasename; 2062 /* For raw disks the full name is identical to the base name. */ 2063 pExtent->pszFullname = RTStrDup(pszBasename); 2064 if (!pExtent->pszFullname) 2065 { 2066 rc = VERR_NO_MEMORY; 2067 goto out; 2068 } 2069 pExtent->enmType = VMDKETYPE_FLAT; 2070 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize); 2071 pExtent->uSectorOffset = 0; 2072 pExtent->enmAccess = VMDKACCESS_READWRITE; 2073 pExtent->fMetaDirty = false; 2074 2075 pImage->enmImageType = enmType; 2076 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "fullDevice"); 2077 if (VBOX_FAILURE(rc)) 2078 { 2079 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename); 2080 goto out; 2081 } 2082 2083 /* Open flat image, the raw disk. */ 2084 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2085 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2086 if (VBOX_FAILURE(rc)) 2087 { 2088 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname); 2089 goto out; 2090 } 2215 if (uStart > pPart->uPartitionDataStart) 2216 return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pszFilename); 2217 else if (uStart != pPart->uPartitionDataStart) 2218 cExtents++; 2219 uStart = pPart->uPartitionDataStart + pPart->cbPartitionData; 2220 cExtents++; 2091 2221 } 2092 else2222 if (pPart->cbPartition) 2093 2223 { 2094 /* Raw partition access. This requires setting up a descriptor 2095 * file, write the partition information to a flat extent and 2096 * open all the (flat) raw disk partitions. */ 2097 2098 /* First pass over the partitions to determine how many 2099 * extents we need. One partition can require up to 4 extents. 2100 * One to skip over unpartitioned space, one for the 2101 * partitioning data, one to skip over unpartitioned space 2102 * and one for the partition data. */ 2103 unsigned cExtents = 0; 2104 uint64_t uStart = 0; 2105 for (unsigned i = 0; i < pRaw->cPartitions; i++) 2106 { 2107 PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i]; 2108 if (pPart->cbPartitionData) 2109 { 2110 if (uStart > pPart->uPartitionDataStart) 2111 { 2112 rc = vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pszFilename); 2113 goto out; 2114 } else if (uStart != pPart->uPartitionDataStart) 2115 cExtents++; 2116 uStart = pPart->uPartitionDataStart + pPart->cbPartitionData; 2117 cExtents++; 2118 } 2119 if (pPart->cbPartition) 2120 { 2121 if (uStart > pPart->uPartitionStart) 2122 { 2123 rc = vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pszFilename); 2124 goto out; 2125 } else if (uStart != pPart->uPartitionStart) 2126 cExtents++; 2127 uStart = pPart->uPartitionStart + pPart->cbPartition; 2128 cExtents++; 2129 } 2130 } 2131 /* Another extent for filling up the rest of the image. */ 2132 if (uStart != cbSize) 2224 if (uStart > pPart->uPartitionStart) 2225 return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pszFilename); 2226 else if (uStart != pPart->uPartitionStart) 2133 2227 cExtents++; 2134 2135 rc = vmdkCreateExtents(pImage, cExtents); 2136 if (VBOX_FAILURE(rc)) 2137 { 2138 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename); 2139 goto out; 2140 } 2141 2142 rc = RTFileOpen(&pImage->File, pszFilename, 2143 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE); 2144 if (VBOX_FAILURE(rc)) 2145 { 2146 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename); 2147 goto out; 2148 } 2149 2150 /* Create base filename for the partition table extent. */ 2151 /** @todo remove fixed buffer. */ 2152 char pszPartition[1024]; 2153 const char *pszBase = RTPathFilename(pszFilename); 2154 const char *pszExt = RTPathExt(pszBase); 2155 if (pszExt == NULL) 2156 { 2157 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pszFilename); 2158 goto out; 2159 } 2160 memcpy(pszPartition, pszBase, pszExt - pszBase); 2161 memcpy(pszPartition + (pszExt - pszBase), "-pt", 3); 2162 memcpy(pszPartition + (pszExt - pszBase) + 3, pszExt, strlen(pszExt) + 1); 2163 2164 /* Second pass over the partitions, now define all extents. */ 2165 uint64_t uPartOffset = 0; 2166 cExtents = 0; 2167 uStart = 0; 2168 for (unsigned i = 0; i < pRaw->cPartitions; i++) 2169 { 2170 PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i]; 2171 if (pPart->cbPartitionData) 2172 { 2173 if (uStart != pPart->uPartitionDataStart) 2174 { 2175 pExtent = &pImage->pExtents[cExtents++]; 2176 pExtent->pszBasename = NULL; 2177 pExtent->pszFullname = NULL; 2178 pExtent->enmType = VMDKETYPE_ZERO; 2179 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart); 2180 pExtent->uSectorOffset = 0; 2181 pExtent->enmAccess = VMDKACCESS_READWRITE; 2182 pExtent->fMetaDirty = false; 2183 } 2184 uStart = pPart->uPartitionDataStart + pPart->cbPartitionData; 2185 pExtent = &pImage->pExtents[cExtents++]; 2186 /* Set up basename for extent description. Cannot use StrDup. */ 2187 size_t cbBasename = strlen(pszPartition) + 1; 2188 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename); 2189 if (!pszBasename) 2190 { 2191 rc = VERR_NO_MEMORY; 2192 goto out; 2193 } 2194 memcpy(pszBasename, pszPartition, cbBasename); 2195 pExtent->pszBasename = pszBasename; 2196 2197 /* Set up full name for partition extent. */ 2198 size_t cbDirname; 2199 char *pszDirname = RTStrDup(pImage->pszFilename); 2200 if (!pszDirname) 2201 { 2202 rc = VERR_NO_MEMORY; 2203 goto out; 2204 } 2205 RTPathStripFilename(pszDirname); 2206 cbDirname = strlen(pszDirname); 2207 char *pszFullname; 2208 rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname, 2209 RTPATH_SLASH, pExtent->pszBasename); 2210 RTStrFree(pszDirname); 2211 if (VBOX_FAILURE(rc)) 2212 goto out; 2213 pExtent->pszFullname = pszFullname; 2214 pExtent->enmType = VMDKETYPE_FLAT; 2215 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData); 2216 pExtent->uSectorOffset = uPartOffset; 2217 pExtent->enmAccess = VMDKACCESS_READWRITE; 2218 pExtent->fMetaDirty = false; 2219 2220 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2221 RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); 2222 if (VBOX_FAILURE(rc)) 2223 { 2224 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname); 2225 goto out; 2226 } 2227 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uPartOffset), pPart->pvPartitionData, pPart->cbPartitionData, NULL); 2228 if (VBOX_FAILURE(rc)) 2229 { 2230 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname); 2231 goto out; 2232 } 2233 uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData); 2234 } 2235 if (pPart->cbPartition) 2236 { 2237 if (uStart != pPart->uPartitionStart) 2238 { 2239 pExtent = &pImage->pExtents[cExtents++]; 2240 pExtent->pszBasename = NULL; 2241 pExtent->pszFullname = NULL; 2242 pExtent->enmType = VMDKETYPE_ZERO; 2243 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart); 2244 pExtent->uSectorOffset = 0; 2245 pExtent->enmAccess = VMDKACCESS_READWRITE; 2246 pExtent->fMetaDirty = false; 2247 } 2248 uStart = pPart->uPartitionStart + pPart->cbPartition; 2249 pExtent = &pImage->pExtents[cExtents++]; 2250 if (pPart->pszRawDevice) 2251 { 2252 /* Set up basename for extent description. Cannot use StrDup. */ 2253 size_t cbBasename = strlen(pPart->pszRawDevice) + 1; 2254 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename); 2255 if (!pszBasename) 2256 { 2257 rc = VERR_NO_MEMORY; 2258 goto out; 2259 } 2260 memcpy(pszBasename, pPart->pszRawDevice, cbBasename); 2261 pExtent->pszBasename = pszBasename; 2262 /* For raw disks the full name is identical to the base name. */ 2263 pExtent->pszFullname = RTStrDup(pszBasename); 2264 if (!pExtent->pszFullname) 2265 { 2266 rc = VERR_NO_MEMORY; 2267 goto out; 2268 } 2269 pExtent->enmType = VMDKETYPE_FLAT; 2270 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition); 2271 pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset); 2272 pExtent->enmAccess = VMDKACCESS_READWRITE; 2273 pExtent->fMetaDirty = false; 2274 2275 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2276 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2277 if (VBOX_FAILURE(rc)) 2278 { 2279 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname); 2280 goto out; 2281 } 2282 } 2283 else 2284 { 2285 pExtent->pszBasename = NULL; 2286 pExtent->pszFullname = NULL; 2287 pExtent->enmType = VMDKETYPE_ZERO; 2288 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition); 2289 pExtent->uSectorOffset = 0; 2290 pExtent->enmAccess = VMDKACCESS_READWRITE; 2291 pExtent->fMetaDirty = false; 2292 } 2293 } 2294 } 2295 /* Another extent for filling up the rest of the image. */ 2296 if (uStart != cbSize) 2228 uStart = pPart->uPartitionStart + pPart->cbPartition; 2229 cExtents++; 2230 } 2231 } 2232 /* Another extent for filling up the rest of the image. */ 2233 if (uStart != cbSize) 2234 cExtents++; 2235 2236 rc = vmdkCreateExtents(pImage, cExtents); 2237 if (VBOX_FAILURE(rc)) 2238 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename); 2239 2240 rc = RTFileOpen(&pImage->File, pszFilename, 2241 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE); 2242 if (VBOX_FAILURE(rc)) 2243 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename); 2244 2245 /* Create base filename for the partition table extent. */ 2246 /** @todo remove fixed buffer without creating memory leaks. */ 2247 char pszPartition[1024]; 2248 const char *pszBase = RTPathFilename(pszFilename); 2249 const char *pszExt = RTPathExt(pszBase); 2250 if (pszExt == NULL) 2251 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pszFilename); 2252 char *pszBaseBase = RTStrDup(pszBase); 2253 if (!pszBaseBase) 2254 return VERR_NO_MEMORY; 2255 RTPathStripExt(pszBaseBase); 2256 RTStrPrintf(pszPartition, sizeof(pszPartition), "%s-pt%s", 2257 pszBaseBase, pszExt); 2258 RTStrFree(pszBaseBase); 2259 2260 /* Second pass over the partitions, now define all extents. */ 2261 uint64_t uPartOffset = 0; 2262 cExtents = 0; 2263 uStart = 0; 2264 for (unsigned i = 0; i < pRaw->cPartitions; i++) 2265 { 2266 PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i]; 2267 if (pPart->cbPartitionData) 2268 { 2269 if (uStart != pPart->uPartitionDataStart) 2297 2270 { 2298 2271 pExtent = &pImage->pExtents[cExtents++]; … … 2300 2273 pExtent->pszFullname = NULL; 2301 2274 pExtent->enmType = VMDKETYPE_ZERO; 2302 pExtent->cNominalSectors = VMDK_BYTE2SECTOR( cbSize- uStart);2275 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart); 2303 2276 pExtent->uSectorOffset = 0; 2304 2277 pExtent->enmAccess = VMDKACCESS_READWRITE; 2305 2278 pExtent->fMetaDirty = false; 2306 2279 } 2307 2308 pImage->enmImageType = enmType; 2309 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "partitionedDevice"); 2280 uStart = pPart->uPartitionDataStart + pPart->cbPartitionData; 2281 pExtent = &pImage->pExtents[cExtents++]; 2282 /* Set up basename for extent description. Can't use StrDup. */ 2283 size_t cbBasename = strlen(pszPartition) + 1; 2284 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename); 2285 if (!pszBasename) 2286 return VERR_NO_MEMORY; 2287 memcpy(pszBasename, pszPartition, cbBasename); 2288 pExtent->pszBasename = pszBasename; 2289 2290 /* Set up full name for partition extent. */ 2291 size_t cbDirname; 2292 char *pszDirname = RTStrDup(pImage->pszFilename); 2293 if (!pszDirname) 2294 return VERR_NO_MEMORY; 2295 RTPathStripFilename(pszDirname); 2296 cbDirname = strlen(pszDirname); 2297 char *pszFullname; 2298 rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname, 2299 RTPATH_SLASH, pExtent->pszBasename); 2300 RTStrFree(pszDirname); 2310 2301 if (VBOX_FAILURE(rc)) 2302 return rc; 2303 pExtent->pszFullname = pszFullname; 2304 pExtent->enmType = VMDKETYPE_FLAT; 2305 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData); 2306 pExtent->uSectorOffset = uPartOffset; 2307 pExtent->enmAccess = VMDKACCESS_READWRITE; 2308 pExtent->fMetaDirty = false; 2309 2310 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2311 RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); 2312 if (VBOX_FAILURE(rc)) 2313 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname); 2314 rc = RTFileWriteAt(pExtent->File, 2315 VMDK_SECTOR2BYTE(uPartOffset), 2316 pPart->pvPartitionData, 2317 pPart->cbPartitionData, NULL); 2318 if (VBOX_FAILURE(rc)) 2319 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname); 2320 uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData); 2321 } 2322 if (pPart->cbPartition) 2323 { 2324 if (uStart != pPart->uPartitionStart) 2311 2325 { 2312 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename); 2313 goto out; 2326 pExtent = &pImage->pExtents[cExtents++]; 2327 pExtent->pszBasename = NULL; 2328 pExtent->pszFullname = NULL; 2329 pExtent->enmType = VMDKETYPE_ZERO; 2330 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart); 2331 pExtent->uSectorOffset = 0; 2332 pExtent->enmAccess = VMDKACCESS_READWRITE; 2333 pExtent->fMetaDirty = false; 2334 } 2335 uStart = pPart->uPartitionStart + pPart->cbPartition; 2336 pExtent = &pImage->pExtents[cExtents++]; 2337 if (pPart->pszRawDevice) 2338 { 2339 /* Set up basename for extent descr. Can't use StrDup. */ 2340 size_t cbBasename = strlen(pPart->pszRawDevice) + 1; 2341 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename); 2342 if (!pszBasename) 2343 return VERR_NO_MEMORY; 2344 memcpy(pszBasename, pPart->pszRawDevice, cbBasename); 2345 pExtent->pszBasename = pszBasename; 2346 /* For raw disks full name is identical to base name. */ 2347 pExtent->pszFullname = RTStrDup(pszBasename); 2348 if (!pExtent->pszFullname) 2349 return VERR_NO_MEMORY; 2350 pExtent->enmType = VMDKETYPE_FLAT; 2351 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition); 2352 pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset); 2353 pExtent->enmAccess = VMDKACCESS_READWRITE; 2354 pExtent->fMetaDirty = false; 2355 2356 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2357 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2358 if (VBOX_FAILURE(rc)) 2359 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname); 2360 } 2361 else 2362 { 2363 pExtent->pszBasename = NULL; 2364 pExtent->pszFullname = NULL; 2365 pExtent->enmType = VMDKETYPE_ZERO; 2366 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition); 2367 pExtent->uSectorOffset = 0; 2368 pExtent->enmAccess = VMDKACCESS_READWRITE; 2369 pExtent->fMetaDirty = false; 2314 2370 } 2315 2371 } 2316 2372 } 2317 else 2318 { 2319 rc = VERR_NOT_IMPLEMENTED; 2320 goto out; 2321 } 2322 } 2323 else 2324 { 2325 /* Normal (growing) image which is not split into pieces. */ 2326 rc = vmdkCreateExtents(pImage, 1); 2327 if (VBOX_FAILURE(rc)) 2328 { 2329 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename); 2330 goto out; 2331 } 2332 pExtent = &pImage->pExtents[0]; 2333 pImage->File = NIL_RTFILE; 2334 rc = RTFileOpen(&pExtent->File, pszFilename, 2373 /* Another extent for filling up the rest of the image. */ 2374 if (uStart != cbSize) 2375 { 2376 pExtent = &pImage->pExtents[cExtents++]; 2377 pExtent->pszBasename = NULL; 2378 pExtent->pszFullname = NULL; 2379 pExtent->enmType = VMDKETYPE_ZERO; 2380 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart); 2381 pExtent->uSectorOffset = 0; 2382 pExtent->enmAccess = VMDKACCESS_READWRITE; 2383 pExtent->fMetaDirty = false; 2384 } 2385 } 2386 2387 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", 2388 pRaw->fRawDisk ? 2389 "fullDevice" : "partitionedDevice"); 2390 if (VBOX_FAILURE(rc)) 2391 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename); 2392 return rc; 2393 } 2394 2395 static int vmdkCreateRegularImage(PVMDKIMAGE pImage, const char *pszFilename, 2396 VDIMAGETYPE enmType, uint64_t cbSize, 2397 unsigned uImageFlags, 2398 PFNVMPROGRESS pfnProgress, void *pvUser, 2399 unsigned uPercentStart, 2400 unsigned uPercentSpan) 2401 { 2402 int rc = VINF_SUCCESS; 2403 unsigned cExtents = 1; 2404 uint64_t cbOffset = 0; 2405 uint64_t cbRemaining = cbSize; 2406 2407 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G) 2408 { 2409 cExtents = cbSize / VMDK_2G_SPLIT_SIZE; 2410 /* Do proper extent computation: need one smaller extent if the total 2411 * size isn't evenly divisible by the split size. */ 2412 if (cbSize % VMDK_2G_SPLIT_SIZE) 2413 cExtents++; 2414 } 2415 rc = vmdkCreateExtents(pImage, cExtents); 2416 if (VBOX_FAILURE(rc)) 2417 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename); 2418 2419 /* Basename strings needed for constructing the extent names. */ 2420 char *pszBasenameSubstr = RTPathFilename(pszFilename); 2421 Assert(pszBasenameSubstr); 2422 size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1; 2423 2424 /* Create searate descriptor file if necessary. */ 2425 if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED) 2426 { 2427 rc = RTFileOpen(&pImage->File, pszFilename, 2335 2428 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE); 2336 2429 if (VBOX_FAILURE(rc)) 2337 { 2338 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename); 2339 goto out; 2340 } 2341 2342 /* Set up basename for extent description. Cannot use StrDup, as it is 2343 * not guaranteed that the memory can be freed with RTMemTmpFree, which 2344 * must be used as in other code paths StrDup is not usable. */ 2345 char *pszBasenameSubstr = RTPathFilename(pszFilename); 2346 Assert(pszBasenameSubstr); 2347 size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1; 2348 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr); 2349 if (!pszBasename) 2350 { 2351 rc = VERR_NO_MEMORY; 2352 goto out; 2353 } 2354 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr); 2355 pExtent->pszBasename = pszBasename; 2356 pExtent->pszFullname = RTStrDup(pszFilename); 2357 if (!pExtent->pszFullname) 2358 { 2359 rc = VERR_NO_MEMORY; 2360 goto out; 2361 } 2362 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; 2363 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, 65536)); 2364 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536); 2365 pExtent->uDescriptorSector = 1; 2366 pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc); 2367 pExtent->cGTEntries = 512; 2368 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2369 pExtent->cSectorsPerGDE = cSectorsPerGDE; 2370 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 2371 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t)); 2430 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pszFilename); 2431 pImage->pszFilename = RTStrDup(pszFilename); 2432 } 2433 else 2434 pImage->File = NIL_RTFILE; 2435 2436 /* Set up all extents. */ 2437 for (unsigned i = 0; i < cExtents; i++) 2438 { 2439 PVMDKEXTENT pExtent = &pImage->pExtents[i]; 2440 uint64_t cbExtent = cbRemaining; 2441 2442 /* Set up fullname/basename for extent description. Cannot use StrDup 2443 * for basename, as it is not guaranteed that the memory can be freed 2444 * with RTMemTmpFree, which must be used as in other code paths 2445 * StrDup is not usable. */ 2446 if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED) 2447 { 2448 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr); 2449 if (!pszBasename) 2450 return VERR_NO_MEMORY; 2451 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr); 2452 pExtent->pszBasename = pszBasename; 2453 } 2454 else 2455 { 2456 char *pszBasenameExt = RTPathExt(pszBasenameSubstr); 2457 char *pszBasenameBase = RTStrDup(pszBasenameSubstr); 2458 RTPathStripExt(pszBasenameBase); 2459 char *pszTmp; 2460 size_t cbTmp; 2461 if (enmType == VD_IMAGE_TYPE_FIXED) 2462 { 2463 if (cExtents == 1) 2464 rc = RTStrAPrintf(&pszTmp, "%s-flat%s", pszBasenameBase, 2465 pszBasenameExt); 2466 else 2467 rc = RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase, 2468 i+1, pszBasenameExt); 2469 } 2470 else 2471 rc = RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, i+1, 2472 pszBasenameExt); 2473 RTStrFree(pszBasenameBase); 2474 if (VBOX_FAILURE(rc)) 2475 return rc; 2476 cbTmp = strlen(pszTmp) + 1; 2477 char *pszBasename = (char *)RTMemTmpAlloc(cbTmp); 2478 if (!pszBasename) 2479 return VERR_NO_MEMORY; 2480 memcpy(pszBasename, pszTmp, cbTmp); 2481 RTStrFree(pszTmp); 2482 pExtent->pszBasename = pszBasename; 2483 cbExtent = RT_MIN(cbRemaining, VMDK_2G_SPLIT_SIZE); 2484 } 2485 char *pszBasedirectory = RTStrDup(pszFilename); 2486 RTPathStripFilename(pszBasedirectory); 2487 char *pszFN; 2488 rc = RTStrAPrintf(&pszFN, "%s%c%s", pszBasedirectory, RTPATH_SLASH, 2489 pExtent->pszBasename); 2490 RTStrFree(pszBasedirectory); 2491 if (VBOX_FAILURE(rc)) 2492 return rc; 2493 pExtent->pszFullname = pszFN; 2494 2495 /* Create file for extent. */ 2496 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname, 2497 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE); 2498 if (VBOX_FAILURE(rc)) 2499 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname); 2500 if (enmType == VD_IMAGE_TYPE_FIXED) 2501 { 2502 rc = RTFileSetSize(pExtent->File, cbExtent); 2503 if (VBOX_FAILURE(rc)) 2504 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); 2505 } 2506 2507 /* Place descriptor file information (where integrated). */ 2508 if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED) 2509 { 2510 pExtent->uDescriptorSector = 1; 2511 pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc); 2512 /* The descriptor is part of the (only) extent. */ 2513 pExtent->pDescData = pImage->pDescData; 2514 pImage->pDescData = NULL; 2515 } 2516 2517 if (enmType == VD_IMAGE_TYPE_NORMAL) 2518 { 2519 uint64_t cSectorsPerGDE, cSectorsPerGD; 2520 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; 2521 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbExtent, 65536)); 2522 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536); 2523 pExtent->cGTEntries = 512; 2524 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2525 pExtent->cSectorsPerGDE = cSectorsPerGDE; 2526 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 2527 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t)); 2528 } 2529 else 2530 pExtent->enmType = VMDKETYPE_FLAT; 2531 2372 2532 pExtent->enmAccess = VMDKACCESS_READWRITE; 2373 2533 pExtent->fUncleanShutdown = true; 2374 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cb Size);2375 pExtent->uSectorOffset = 0;2534 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbExtent); 2535 pExtent->uSectorOffset = VMDK_BYTE2SECTOR(cbOffset); 2376 2536 pExtent->fMetaDirty = true; 2377 2537 2378 rc = vmdkCreateGrainDirectory(pExtent, pExtent->uDescriptorSector + pExtent->cDescriptorSectors, true); 2379 if (VBOX_FAILURE(rc)) 2380 { 2381 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pszFilename); 2382 goto out; 2383 } 2384 2385 pImage->enmImageType = enmType; 2386 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "monolithicSparse"); 2387 if (VBOX_FAILURE(rc)) 2388 { 2389 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename); 2390 goto out; 2391 } 2392 2393 /* The descriptor is part of the extent, move info to extent. */ 2394 pExtent->pDescData = pImage->pDescData; 2395 pImage->pDescData = NULL; 2396 } 2397 2538 if (enmType == VD_IMAGE_TYPE_NORMAL) 2539 { 2540 rc = vmdkCreateGrainDirectory(pExtent, 2541 pExtent->uDescriptorSector 2542 + pExtent->cDescriptorSectors, 2543 true); 2544 if (VBOX_FAILURE(rc)) 2545 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname); 2546 } 2547 2548 if (VBOX_SUCCESS(rc) && pfnProgress) 2549 pfnProgress(NULL /* WARNING! pVM=NULL */, 2550 i * uPercentSpan / cExtents + uPercentStart, 2551 pvUser); 2552 2553 cbRemaining -= cbExtent; 2554 cbOffset += cbExtent; 2555 } 2556 2557 const char *pszDescType = NULL; 2558 if (enmType == VD_IMAGE_TYPE_FIXED) 2559 { 2560 pszDescType = (cExtents == 1) 2561 ? "monolithicFlat" : "twoGbMaxExtentFlat"; 2562 } 2563 else if (enmType == VD_IMAGE_TYPE_NORMAL) 2564 { 2565 pszDescType = (cExtents == 1) 2566 ? "monolithicSparse" : "twoGbMaxExtentSparse"; 2567 } 2568 else 2569 AssertMsgFailed(("invalid image type %d\n", enmType)); 2570 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", 2571 pszDescType); 2572 if (VBOX_FAILURE(rc)) 2573 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename); 2574 return rc; 2575 } 2576 2577 static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename, 2578 VDIMAGETYPE enmType, uint64_t cbSize, 2579 unsigned uImageFlags, const char *pszComment, 2580 PCPDMMEDIAGEOMETRY pPCHSGeometry, 2581 PCPDMMEDIAGEOMETRY pLCHSGeometry, 2582 PFNVMPROGRESS pfnProgress, void *pvUser, 2583 unsigned uPercentStart, unsigned uPercentSpan) 2584 { 2585 int rc; 2586 2587 pImage->uImageFlags = uImageFlags; 2588 rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc, 2589 &pImage->Descriptor); 2590 if (VBOX_FAILURE(rc)) 2591 { 2592 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename); 2593 goto out; 2594 } 2595 2596 if ( enmType == VD_IMAGE_TYPE_FIXED 2597 && (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)) 2598 { 2599 /* Raw disk image (includes raw partition). */ 2600 const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment; 2601 /* As the comment is misused, zap it so that no garbage comment 2602 * is set below. */ 2603 pszComment = NULL; 2604 rc = vmdkCreateRawImage(pImage, pszFilename, pRaw, cbSize); 2605 } 2606 else if ( enmType == VD_IMAGE_TYPE_FIXED 2607 || enmType == VD_IMAGE_TYPE_NORMAL) 2608 { 2609 /* Regular fixed or sparse image (monolithic or split). */ 2610 rc = vmdkCreateRegularImage(pImage, pszFilename, enmType, cbSize, 2611 uImageFlags, pfnProgress, pvUser, 2612 uPercentStart, uPercentSpan * 95 / 100); 2613 } 2614 else 2615 { 2616 /* Unknown/invalid image type. */ 2617 rc = VERR_NOT_IMPLEMENTED; 2618 } 2619 2620 if (VBOX_FAILURE(rc)) 2621 goto out; 2622 2623 if (VBOX_SUCCESS(rc) && pfnProgress) 2624 pfnProgress(NULL /* WARNING! pVM=NULL */, 2625 uPercentStart + uPercentSpan * 98 / 100, pvUser); 2626 2627 pImage->enmImageType = enmType; 2398 2628 pImage->cbSize = cbSize; 2399 if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)2400 pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;2401 else2402 pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;2403 2629 2404 2630 for (unsigned i = 0; i < pImage->cExtents; i++) 2405 2631 { 2406 pExtent = &pImage->pExtents[i];2632 PVMDKEXTENT pExtent = &pImage->pExtents[i]; 2407 2633 2408 2634 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess, … … 2417 2643 vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor); 2418 2644 2419 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 2420 "ddb.geometry.cylinders", cCylinders); 2421 if (VBOX_FAILURE(rc)) 2422 goto out; 2423 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 2424 "ddb.geometry.heads", cHeads); 2425 if (VBOX_FAILURE(rc)) 2426 goto out; 2427 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 2428 "ddb.geometry.sectors", cSectors); 2429 if (VBOX_FAILURE(rc)) 2430 goto out; 2431 2432 pImage->cCylinders = cCylinders; 2433 pImage->cHeads = cHeads; 2434 pImage->cSectors = cSectors; 2645 if ( pPCHSGeometry->cCylinders == 0 2646 || pPCHSGeometry->cHeads == 0 2647 || pPCHSGeometry->cSectors == 0) 2648 { 2649 rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry); 2650 if (VBOX_FAILURE(rc)) 2651 goto out; 2652 } 2653 if ( pLCHSGeometry->cCylinders == 0 2654 || pLCHSGeometry->cHeads == 0 2655 || pLCHSGeometry->cSectors == 0) 2656 { 2657 rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry); 2658 if (VBOX_FAILURE(rc)) 2659 goto out; 2660 } 2661 2662 pImage->LCHSGeometry = *pLCHSGeometry; 2663 pImage->PCHSGeometry = *pPCHSGeometry; 2435 2664 2436 2665 rc = RTUuidCreate(&pImage->ImageUuid); … … 2454 2683 RTUuidClear(&pImage->ModificationUuid); 2455 2684 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor, 2456 "ddb.uuid.modification", &pImage->ModificationUuid); 2685 "ddb.uuid.modification", 2686 &pImage->ModificationUuid); 2457 2687 if (VBOX_FAILURE(rc)) 2458 2688 { … … 2472 2702 } 2473 2703 2704 if (VBOX_SUCCESS(rc) && pfnProgress) 2705 pfnProgress(NULL /* WARNING! pVM=NULL */, 2706 uPercentStart + uPercentSpan * 99 / 100, pvUser); 2707 2474 2708 rc = vmdkFlushImage(pImage); 2475 2709 2476 2710 out: 2711 if (VBOX_SUCCESS(rc) && pfnProgress) 2712 pfnProgress(NULL /* WARNING! pVM=NULL */, 2713 uPercentStart + uPercentSpan, pvUser); 2714 2477 2715 if (VBOX_FAILURE(rc)) 2478 2716 vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS); … … 2587 2825 case VMDKETYPE_FLAT: 2588 2826 /** @todo implement proper path absolute check. */ 2589 if (pExtent->File != NIL_RTFILE && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) && !(pExtent->pszBasename[0] == RTPATH_SLASH)) 2827 if ( pExtent->File != NIL_RTFILE 2828 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2829 && !(pExtent->pszBasename[0] == RTPATH_SLASH)) 2590 2830 rc = RTFileFlush(pExtent->File); 2591 2831 break; … … 2603 2843 } 2604 2844 2605 static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector, PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent) 2845 static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector, 2846 PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent) 2606 2847 { 2607 2848 PVMDKEXTENT pExtent = NULL; … … 2627 2868 } 2628 2869 2629 static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector, unsigned uExtent) 2870 static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector, 2871 unsigned uExtent) 2630 2872 { 2631 2873 /** @todo this hash function is quite simple, maybe use a better one which … … 2688 2930 */ 2689 2931 static int vmdkAllocGrain(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent, 2690 uint64_t uSector, const void *pvBuf, uint64_t cbWrite) 2932 uint64_t uSector, const void *pvBuf, 2933 uint64_t cbWrite) 2691 2934 { 2692 2935 uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock; … … 2722 2965 * should be acceptable. */ 2723 2966 memset(aGTDataTmp, '\0', sizeof(aGTDataTmp)); 2724 for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++) 2725 { 2726 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL); 2967 for (unsigned i = 0; 2968 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; 2969 i++) 2970 { 2971 rc = RTFileWriteAt(pExtent->File, 2972 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), 2973 aGTDataTmp, sizeof(aGTDataTmp), NULL); 2727 2974 if (VBOX_FAILURE(rc)) 2728 2975 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname); … … 2739 2986 * bit slower. But as this is a pretty infrequently occurring case 2740 2987 * it should be acceptable. */ 2741 for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++) 2988 for (unsigned i = 0; 2989 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; 2990 i++) 2742 2991 { 2743 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL); 2992 rc = RTFileWriteAt(pExtent->File, 2993 VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), 2994 aGTDataTmp, sizeof(aGTDataTmp), NULL); 2744 2995 if (VBOX_FAILURE(rc)) 2745 2996 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname); … … 2752 3003 * some unused sectors in the extent. */ 2753 3004 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector); 2754 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL); 3005 rc = RTFileWriteAt(pExtent->File, 3006 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), 3007 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 2755 3008 if (VBOX_FAILURE(rc)) 2756 3009 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname); … … 2758 3011 { 2759 3012 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector); 2760 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), &uRGTSectorLE, sizeof(uRGTSectorLE), NULL); 3013 rc = RTFileWriteAt(pExtent->File, 3014 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), 3015 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL); 2761 3016 if (VBOX_FAILURE(rc)) 2762 3017 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname); … … 2832 3087 } 2833 3088 2834 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData) 3089 3090 static int vmdkCheckIfValid(const char *pszFilename) 3091 { 3092 int rc = VINF_SUCCESS; 3093 PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE)); 3094 if (!pImage) 3095 { 3096 rc = VERR_NO_MEMORY; 3097 goto out; 3098 } 3099 pImage->pszFilename = pszFilename; 3100 pImage->File = NIL_RTFILE; 3101 pImage->pExtents = NULL; 3102 pImage->pGTCache = NULL; 3103 pImage->pDescData = NULL; 3104 pImage->pfnError = NULL; 3105 pImage->pvErrorUser = NULL; 3106 /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as 3107 * much as possible in vmdkOpenImage. */ 3108 rc = vmdkOpenImage(pImage, pszFilename, 3109 VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY); 3110 vmdkFreeImage(pImage, false); 3111 3112 out: 3113 return rc; 3114 } 3115 3116 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, 3117 PFNVDERROR pfnError, void *pvErrorUser, 3118 void **ppvBackendData) 2835 3119 { 2836 3120 int rc; … … 2871 3155 static int vmdkCreate(const char *pszFilename, VDIMAGETYPE enmType, 2872 3156 uint64_t cbSize, unsigned uImageFlags, 2873 const char *pszComment, uint32_t cCylinders, 2874 uint32_t cHeads, uint32_t cSectors, unsigned uOpenFlags, 2875 PFNVMPROGRESS pfnProgress, void *pvUser, 2876 PFNVDERROR pfnError, void *pvErrorUser, 2877 void **ppvBackendData) 3157 const char *pszComment, 3158 PCPDMMEDIAGEOMETRY pPCHSGeometry, 3159 PCPDMMEDIAGEOMETRY pLCHSGeometry, 3160 unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, 3161 void *pvUser, unsigned uPercentStart, 3162 unsigned uPercentSpan, PFNVDERROR pfnError, 3163 void *pvErrorUser, void **ppvBackendData) 2878 3164 { 2879 3165 int rc; … … 2911 3197 2912 3198 rc = vmdkCreateImage(pImage, pszFilename, enmType, cbSize, uImageFlags, 2913 pszComment, cCylinders, cHeads, cSectors); 3199 pszComment, pPCHSGeometry, pLCHSGeometry, 3200 pfnProgress, pvUser, uPercentStart, uPercentSpan); 2914 3201 if (VBOX_SUCCESS(rc)) 2915 3202 { … … 2927 3214 2928 3215 out: 2929 /** @todo implement meaningful progress stuff (especially for fixed images). */2930 if ( VBOX_SUCCESS(rc)2931 && pfnProgress)2932 pfnProgress(NULL /* WARNING! pVM=NULL */, 100, pvUser);2933 2934 3216 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 2935 3217 return rc; 3218 } 3219 3220 static int vmdkRename(void *pBackendData, const char *pszFilename) 3221 { 3222 return VERR_NOT_IMPLEMENTED; 2936 3223 } 2937 3224 … … 2950 3237 } 2951 3238 2952 static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf, size_t cbRead, size_t *pcbActuallyRead) 3239 static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf, 3240 size_t cbRead, size_t *pcbActuallyRead) 2953 3241 { 2954 3242 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; … … 3004 3292 break; 3005 3293 case VMDKETYPE_FLAT: 3006 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel), 3294 rc = RTFileReadAt(pExtent->File, 3295 VMDK_SECTOR2BYTE(uSectorExtentRel), 3007 3296 pvBuf, cbRead, NULL); 3008 3297 break; … … 3017 3306 } 3018 3307 3019 static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, size_t cbWrite, size_t *pcbWriteProcess, size_t *pcbPreRead, size_t *pcbPostRead) 3308 static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, 3309 size_t cbWrite, size_t *pcbWriteProcess, 3310 size_t *pcbPreRead, size_t *pcbPostRead) 3020 3311 { 3021 3312 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; … … 3100 3391 /* Clip write range to remain in this extent. */ 3101 3392 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 3102 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel), pvBuf, cbWrite, NULL); 3393 rc = RTFileWriteAt(pExtent->File, 3394 VMDK_SECTOR2BYTE(uSectorExtentRel), 3395 pvBuf, cbWrite, NULL); 3103 3396 break; 3104 3397 case VMDKETYPE_ZERO: … … 3123 3416 } 3124 3417 3418 static unsigned vmdkGetVersion(void *pBackendData) 3419 { 3420 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3421 3422 Assert(pImage); 3423 3424 if (pImage) 3425 return VMDK_IMAGE_VERSION; 3426 else 3427 return 0; 3428 } 3429 3125 3430 static int vmdkGetImageType(void *pBackendData, PVDIMAGETYPE penmImageType) 3126 3431 { … … 3151 3456 } 3152 3457 3153 static int vmdkGetGeometry(void *pBackendData, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors) 3458 static uint64_t vmdkGetFileSize(void *pBackendData) 3459 { 3460 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3461 3462 Assert(pImage); 3463 3464 if (pImage) 3465 { 3466 int rc; 3467 uint64_t cbFile, cb = 0; 3468 if (pImage->File != NIL_RTFILE) 3469 { 3470 rc = RTFileGetSize(pImage->File, &cbFile); 3471 if (VBOX_SUCCESS(rc)) 3472 cb += cbFile; 3473 for (unsigned i = 0; i <= pImage->cExtents; i++) 3474 { 3475 rc = RTFileGetSize(pImage->File, &cbFile); 3476 if (VBOX_SUCCESS(rc)) 3477 cb += cbFile; 3478 } 3479 } 3480 return cb; 3481 } 3482 else 3483 return 0; 3484 } 3485 3486 static int vmdkGetPCHSGeometry(void *pBackendData, 3487 PPDMMEDIAGEOMETRY pPCHSGeometry) 3154 3488 { 3155 3489 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; … … 3160 3494 if (pImage) 3161 3495 { 3162 if (pImage->cCylinders) 3163 { 3164 *pcCylinders = pImage->cCylinders; 3165 *pcHeads = pImage->cHeads; 3166 *pcSectors = pImage->cSectors; 3496 if (pImage->PCHSGeometry.cCylinders) 3497 { 3498 *pPCHSGeometry = pImage->PCHSGeometry; 3167 3499 rc = VINF_SUCCESS; 3168 3500 } … … 3173 3505 rc = VERR_VDI_NOT_OPENED; 3174 3506 LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc, 3175 pImage->cCylinders, pImage->cHeads, pImage->cSectors)); 3176 return rc; 3177 } 3178 3179 static int vmdkSetGeometry(void *pBackendData, unsigned cCylinders, unsigned cHeads, unsigned cSectors) 3507 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors)); 3508 return rc; 3509 } 3510 3511 static int vmdkSetPCHSGeometry(void *pBackendData, 3512 PCPDMMEDIAGEOMETRY pPCHSGeometry) 3180 3513 { 3181 3514 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; … … 3191 3524 goto out; 3192 3525 } 3193 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 3194 "ddb.geometry.cylinders", cCylinders); 3526 rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry); 3195 3527 if (VBOX_FAILURE(rc)) 3196 3528 goto out; 3197 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 3198 "ddb.geometry.heads", cHeads); 3529 3530 pImage->PCHSGeometry = *pPCHSGeometry; 3531 rc = VINF_SUCCESS; 3532 } 3533 else 3534 rc = VERR_VDI_NOT_OPENED; 3535 3536 out: 3537 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 3538 return rc; 3539 } 3540 3541 static int vmdkGetLCHSGeometry(void *pBackendData, 3542 PPDMMEDIAGEOMETRY pLCHSGeometry) 3543 { 3544 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3545 int rc; 3546 3547 Assert(pImage); 3548 3549 if (pImage) 3550 { 3551 if (pImage->LCHSGeometry.cCylinders) 3552 { 3553 *pLCHSGeometry = pImage->LCHSGeometry; 3554 rc = VINF_SUCCESS; 3555 } 3556 else 3557 rc = VERR_VDI_GEOMETRY_NOT_SET; 3558 } 3559 else 3560 rc = VERR_VDI_NOT_OPENED; 3561 LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc, 3562 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors)); 3563 return rc; 3564 } 3565 3566 static int vmdkSetLCHSGeometry(void *pBackendData, 3567 PCPDMMEDIAGEOMETRY pLCHSGeometry) 3568 { 3569 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3570 int rc; 3571 3572 Assert(pImage); 3573 3574 if (pImage) 3575 { 3576 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 3577 { 3578 rc = VERR_VDI_IMAGE_READ_ONLY; 3579 goto out; 3580 } 3581 rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry); 3199 3582 if (VBOX_FAILURE(rc)) 3200 3583 goto out; 3201 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor, 3202 "ddb.geometry.sectors", cSectors); 3203 if (VBOX_FAILURE(rc)) 3204 goto out; 3205 3206 pImage->cCylinders = cCylinders; 3207 pImage->cHeads = cHeads; 3208 pImage->cSectors = cSectors; 3584 3585 pImage->LCHSGeometry = *pLCHSGeometry; 3209 3586 rc = VINF_SUCCESS; 3210 3587 } … … 3217 3594 } 3218 3595 3219 static int vmdkGetTranslation(void *pBackendData, PPDMBIOSTRANSLATION penmTranslation)3596 static unsigned vmdkGetImageFlags(void *pBackendData) 3220 3597 { 3221 3598 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3222 int rc;3599 unsigned uImageFlags; 3223 3600 3224 3601 Assert(pImage); 3225 3602 3226 3603 if (pImage) 3227 { 3228 if (pImage->enmTranslation) 3229 { 3230 *penmTranslation = pImage->enmTranslation; 3231 rc = VINF_SUCCESS; 3232 } 3233 else 3234 rc = VERR_VDI_GEOMETRY_NOT_SET; 3235 } 3604 uImageFlags = pImage->uImageFlags; 3236 3605 else 3237 rc = VERR_VDI_NOT_OPENED; 3238 LogFlow(("%s: returned %Vrc (%d)\n", __FUNCTION__, rc, 3239 pImage->enmTranslation)); 3240 return rc; 3241 } 3242 3243 static int vmdkSetTranslation(void *pBackendData, PDMBIOSTRANSLATION enmTranslation) 3244 { 3245 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3246 int rc; 3247 3248 Assert(pImage); 3249 3250 if (pImage) 3251 { 3252 /** @todo maybe store this in the image descriptor */ 3253 pImage->enmTranslation = enmTranslation; 3254 rc = VINF_SUCCESS; 3255 } 3256 else 3257 rc = VERR_VDI_NOT_OPENED; 3258 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 3259 return rc; 3606 uImageFlags = 0; 3607 3608 LogFlow(("%s: returned %#x\n", __FUNCTION__, uImageFlags)); 3609 return uImageFlags; 3260 3610 } 3261 3611 … … 3300 3650 } 3301 3651 3302 static int vmdkGetComment(void *pBackendData, char *pszComment, size_t cbComment) 3652 static int vmdkGetComment(void *pBackendData, char *pszComment, 3653 size_t cbComment) 3303 3654 { 3304 3655 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; … … 3477 3828 } 3478 3829 3830 static void vmdkDump(void *pBackendData) 3831 { 3832 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData; 3833 3834 Assert(pImage); 3835 if (pImage) 3836 { 3837 RTLogPrintf("Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n", 3838 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors, 3839 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors, 3840 VMDK_BYTE2SECTOR(pImage->cbSize)); 3841 RTLogPrintf("Header: uuidCreation={%Vuuid}\n", pImage->ImageUuid); 3842 RTLogPrintf("Header: uuidModification={%Vuuid}\n", pImage->ModificationUuid); 3843 RTLogPrintf("Header: uuidParent={%Vuuid}\n", pImage->ParentUuid); 3844 } 3845 } 3846 3479 3847 3480 3848 VBOXHDDBACKEND g_VmdkBackend = 3481 3849 { 3850 /* pszBackendName */ 3851 "VMDK", 3482 3852 /* cbSize */ 3483 3853 sizeof(VBOXHDDBACKEND), 3484 3854 /* pfnCheckIfValid */ 3485 NULL,3855 vmdkCheckIfValid, 3486 3856 /* pfnOpen */ 3487 3857 vmdkOpen, 3488 3858 /* pfnCreate */ 3489 3859 vmdkCreate, 3860 /* pfnRename */ 3861 vmdkRename, 3490 3862 /* pfnClose */ 3491 3863 vmdkClose, … … 3496 3868 /* pfnFlush */ 3497 3869 vmdkFlush, 3870 /* pfnGetVersion */ 3871 vmdkGetVersion, 3498 3872 /* pfnGetImageType */ 3499 3873 vmdkGetImageType, 3500 3874 /* pfnGetSize */ 3501 3875 vmdkGetSize, 3502 /* pfnGetGeometry */ 3503 vmdkGetGeometry, 3504 /* pfnSetGeometry */ 3505 vmdkSetGeometry, 3506 /* pfnGetTranslation */ 3507 vmdkGetTranslation, 3508 /* pfnSetTranslation */ 3509 vmdkSetTranslation, 3876 /* pfnGetFileSize */ 3877 vmdkGetFileSize, 3878 /* pfnGetPCHSGeometry */ 3879 vmdkGetPCHSGeometry, 3880 /* pfnSetPCHSGeometry */ 3881 vmdkSetPCHSGeometry, 3882 /* pfnGetLCHSGeometry */ 3883 vmdkGetLCHSGeometry, 3884 /* pfnSetLCHSGeometry */ 3885 vmdkSetLCHSGeometry, 3886 /* pfnGetImageFlags */ 3887 vmdkGetImageFlags, 3510 3888 /* pfnGetOpenFlags */ 3511 3889 vmdkGetOpenFlags, … … 3527 3905 vmdkGetParentUuid, 3528 3906 /* pfnSetParentUuid */ 3529 vmdkSetParentUuid 3907 vmdkSetParentUuid, 3908 /* pfnDump */ 3909 vmdkDump 3530 3910 };
Note:
See TracChangeset
for help on using the changeset viewer.