Changeset 32642 in vbox
- Timestamp:
- Sep 20, 2010 2:30:08 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r32625 r32642 31 31 #include <iprt/rand.h> 32 32 #include <iprt/zip.h> 33 #include <iprt/asm.h> 33 34 34 35 … … 921 922 { 922 923 Marker.uType = RT_LE2H_U32(Marker.uType); 923 if (Marker.uType == VMDK_MARKER_EOS) 924 { 925 Assert(uMarker != VMDK_MARKER_EOS); 926 return VERR_VD_VMDK_INVALID_FORMAT; 927 } 928 else if ( Marker.uType == VMDK_MARKER_GT 929 || Marker.uType == VMDK_MARKER_GD 930 || Marker.uType == VMDK_MARKER_FOOTER) 931 { 932 uCompOffset = uOffset + 512; 933 cbComp = VMDK_SECTOR2BYTE(Marker.uSector); 934 if (pcbMarkerData) 935 *pcbMarkerData = cbComp + 512; 936 } 937 else 938 { 939 AssertMsgFailed(("VMDK: unknown marker type %u\n", Marker.uType)); 940 return VERR_VD_VMDK_INVALID_FORMAT; 941 } 924 AssertMsgFailed(("VMDK: unexpected marker type %u\n", Marker.uType)); 925 return VERR_VD_VMDK_INVALID_FORMAT; 942 926 } 943 927 InflateState.pImage = pImage; … … 1018 1002 else 1019 1003 { 1020 /* * @todo implement creating the other marker types*/1004 /* The other markers don't contain compressed data. */ 1021 1005 return VERR_NOT_IMPLEMENTED; 1022 1006 } … … 1065 1049 else 1066 1050 { 1067 /* * @todo implement creating the other marker types*/1051 /* The other markers don't contain compressed data. */ 1068 1052 return VERR_NOT_IMPLEMENTED; 1069 1053 } … … 1455 1439 if (RT_FAILURE(rc)) 1456 1440 goto out; 1457 pExtent->uSectorRGD = uStartSector; 1458 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded); 1441 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 1442 { 1443 pExtent->uSectorRGD = 0; 1444 pExtent->uSectorGD = uStartSector; 1445 } 1446 else 1447 { 1448 pExtent->uSectorRGD = uStartSector; 1449 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded); 1450 } 1459 1451 } 1460 1452 else … … 1469 1461 uint64_t uOffsetSectors; 1470 1462 1471 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded); 1472 for (i = 0; i < pExtent->cGDEntries; i++) 1473 { 1474 pRGD[i] = uOffsetSectors; 1475 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 1476 /* Write the redundant grain directory entry to disk. */ 1477 rc = vmdkFileWriteSync(pImage, pExtent->pFile, 1478 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), 1479 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 1480 if (RT_FAILURE(rc)) 1463 if (pRGD) 1464 { 1465 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded); 1466 for (i = 0; i < pExtent->cGDEntries; i++) 1481 1467 { 1482 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname); 1483 goto out; 1468 pRGD[i] = uOffsetSectors; 1469 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 1470 /* Write the redundant grain directory entry to disk. */ 1471 rc = vmdkFileWriteSync(pImage, pExtent->pFile, 1472 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), 1473 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 1474 if (RT_FAILURE(rc)) 1475 { 1476 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname); 1477 goto out; 1478 } 1479 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)); 1484 1480 } 1485 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));1486 1481 } 1487 1482 … … 2785 2780 && RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END) 2786 2781 { 2787 /* Read the footer, which isn't compressed and comes before the 2788 * end-of-stream marker. This is bending the VMDK 1.1 spec, but that's 2789 * VMware reality. Theory and practice have very little in common. */ 2782 /* Read the footer, which comes before the end-of-stream marker. */ 2790 2783 uint64_t cbSize; 2791 2784 rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbSize); … … 4086 4079 uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE; 4087 4080 4081 /* VMware does not write out completely empty grain tables in the case 4082 * of streamOptimized images, which according to my interpretation of 4083 * the VMDK 1.1 spec is bending the rules. Since they do it and we can 4084 * handle it without problems do it the same way and save some bytes. */ 4085 bool fAllZero = true; 4086 for (uint32_t i = 0; i < cCacheLines; i++) 4087 { 4088 /* Convert the grain table to little endian in place, as it will not 4089 * be used at all after this function has been called. */ 4090 uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0]; 4091 for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++) 4092 if (*pGTTmp) 4093 { 4094 fAllZero = false; 4095 break; 4096 } 4097 if (!fAllZero) 4098 break; 4099 } 4100 if (fAllZero) 4101 return VINF_SUCCESS; 4102 4088 4103 uint64_t uFileOffset; 4089 4104 rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset); … … 4093 4108 4094 4109 /* Grain table marker. */ 4095 /** @todo check me! */4096 4110 uint8_t aMarker[512]; 4097 memset(aMarker, '\0', sizeof(aMarker));4098 4111 PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0]; 4099 pMarker->cbSize = RT_H2LE_U32(pExtent->cGTEntries * sizeof(uint32_t)); 4112 memset(pMarker, '\0', sizeof(aMarker)); 4113 pMarker->uSector = RT_H2LE_U64(VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t))); 4100 4114 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GT); 4101 4115 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset, … … 4121 4135 VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t), 4122 4136 NULL); 4123 } 4137 uFileOffset += VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t); 4138 if (RT_FAILURE(rc)) 4139 break; 4140 } 4141 Assert(!(uFileOffset % 512)); 4124 4142 return rc; 4125 4143 } … … 4146 4164 } 4147 4165 4148 /* No need to write any pending data if the file will be deleted. */ 4149 if (!fDelete && pImage->pExtents) 4166 /* No need to write any pending data if the file will be deleted or if 4167 * the new file wasn't successfully created. */ 4168 if (!fDelete && pImage->pExtents && pImage->pExtents[0].cGTEntries) 4150 4169 { 4151 4170 PVMDKEXTENT pExtent = &pImage->pExtents[0]; 4152 4171 uint32_t uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries; 4153 if (uLastGDEntry != pExtent->cGDEntries )4172 if (uLastGDEntry != pExtent->cGDEntries - 1) 4154 4173 { 4155 4174 rc = vmdksFlushGT(pImage, pExtent, uLastGDEntry); … … 4169 4188 4170 4189 /* Grain directory marker. */ 4171 /** @todo check me! */4172 4190 uint8_t aMarker[512]; 4173 memset(aMarker, '\0', sizeof(aMarker));4174 4191 PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0]; 4175 pMarker->cbSize = RT_H2LE_U32(pExtent->cGDEntries * sizeof(uint32_t)); 4192 memset(pMarker, '\0', sizeof(aMarker)); 4193 pMarker->uSector = VMDK_BYTE2SECTOR(RT_ALIGN_64(RT_H2LE_U64(pExtent->cGDEntries * sizeof(uint32_t)), 512)); 4176 4194 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD); 4177 4195 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset, … … 4195 4213 uFileOffset = RT_ALIGN_64(uFileOffset + pExtent->cGDEntries * sizeof(uint32_t), 512); 4196 4214 4197 /* End of stream marker. */ 4198 memset(aMarker, '\0', sizeof(aMarker)); 4199 /** @todo check me! */ 4215 /* Footer marker. */ 4216 memset(pMarker, '\0', sizeof(aMarker)); 4217 pMarker->uSector = VMDK_BYTE2SECTOR(512); 4218 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_FOOTER); 4200 4219 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset, 4201 4220 aMarker, sizeof(aMarker), NULL); … … 4204 4223 uFileOffset += 512; 4205 4224 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset); 4225 AssertRC(rc); 4226 4227 uFileOffset += 512; 4228 /* End-of-stream marker. */ 4229 memset(pMarker, '\0', sizeof(aMarker)); 4230 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset, 4231 aMarker, sizeof(aMarker), NULL); 4206 4232 AssertRC(rc); 4207 4233 } … … 4998 5024 return VINF_SUCCESS; 4999 5025 } 5000 5001 LogFlowFunc(("uGTSector=%llu\n", uGTSector));5002 5026 5003 5027 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE); … … 5858 5882 /* Do not allow to go back. */ 5859 5883 uGrain = VMDK_BYTE2SECTOR(uOffset) / pExtent->cSectorsPerGrain; 5860 uCacheLine = uGrain / VMDK_GT_CACHELINE_SIZE % VMDK_GT_CACHE_SIZE;5884 uCacheLine = uGrain % pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; 5861 5885 uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE; 5862 5886 uGDEntry = uGrain / pExtent->cGTEntries; … … 5865 5889 { 5866 5890 rc = VERR_VD_VMDK_INVALID_WRITE; 5891 goto out; 5892 } 5893 5894 /* Zero byte write optimization. Since we don't tell VBoxHDD that we need 5895 * to allocate something, we also need to detect the situation ourself. */ 5896 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES) 5897 && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbToWrite * 8) == -1) 5898 { 5899 rc = VINF_SUCCESS; 5900 if (pcbWriteProcess) 5901 *pcbWriteProcess = cbToWrite; 5867 5902 goto out; 5868 5903 }
Note:
See TracChangeset
for help on using the changeset viewer.