Changeset 17775 in vbox for trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
- Timestamp:
- Mar 12, 2009 6:41:34 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r16873 r17775 294 294 /** Pointer to the redundant grain directory. */ 295 295 uint32_t *pRGD; 296 /** VMDK version of this extent. 1=1.0 , 3=1.1 */296 /** VMDK version of this extent. 1=1.0/1.1 */ 297 297 uint32_t uVersion; 298 298 /** Type of this extent. */ … … 306 306 /** Compression type for this extent. */ 307 307 uint16_t uCompression; 308 /** Last grain which has been written to. Only for streamOptimized extents. */ 309 uint32_t uLastGrainWritten; 310 /** Sector number of last grain which has been written to. Only for 311 * streamOptimized extents. */ 312 uint32_t uLastGrainSector; 313 /** Data size of last grain which has been written to. Only for 314 * streamOptimized extents. */ 315 uint32_t cbLastGrainWritten; 308 316 /** Starting sector of the decompressed grain buffer. */ 309 uint 64_t uGrainSector;317 uint32_t uGrainSector; 310 318 /** Decompressed grain buffer for streamOptimized extents. */ 311 319 void *pvGrain; … … 405 413 const char *pszFilename; 406 414 /** Descriptor file if applicable. */ 407 PVMDKFILE 415 PVMDKFILE pFile; 408 416 409 417 /** Pointer to the per-disk VD interface list. */ 410 PVDINTERFACE 418 PVDINTERFACE pVDIfsDisk; 411 419 412 420 /** Error interface. */ 413 PVDINTERFACE 421 PVDINTERFACE pInterfaceError; 414 422 /** Error interface callbacks. */ 415 423 PVDINTERFACEERROR pInterfaceErrorCallbacks; 416 424 417 425 /** Async I/O interface. */ 418 PVDINTERFACE 426 PVDINTERFACE pInterfaceAsyncIO; 419 427 /** Async I/O interface callbacks. */ 420 428 PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks; … … 425 433 * is too expensive. 426 434 */ 427 void 435 void **apTask; 428 436 /** Entries available in the task handle array. */ 429 unsigned 437 unsigned cTask; 430 438 431 439 /** Open flags passed by VBoxHD layer. */ … … 474 482 } VMDKINFLATESTATE; 475 483 484 /** State for the output callout of the deflate writer. */ 485 typedef struct VMDKDEFLATESTATE 486 { 487 /* File where the data is to be stored. */ 488 RTFILE File; 489 /* Offset in the file to write at. */ 490 uint64_t uFileOffset; 491 /* Current write position. */ 492 ssize_t iOffset; 493 } VMDKDEFLATESTATE; 494 476 495 /******************************************************************************* 477 496 * Static Variables * … … 748 767 uint64_t uOffset, void *pvBuf, 749 768 size_t cbToRead, unsigned uMarker, 750 uint64_t *puLBA )769 uint64_t *puLBA, uint32_t *pcbMarkerData) 751 770 { 752 771 if (pVmdkFile->fAsyncIO) … … 780 799 if (puLBA) 781 800 *puLBA = Marker.uSector; 801 if (pcbMarkerData) 802 *pcbMarkerData = cbComp + 12; 782 803 } 783 804 else … … 795 816 uCompOffset = uOffset + 512; 796 817 cbComp = VMDK_SECTOR2BYTE(Marker.uSector); 818 if (pcbMarkerData) 819 *pcbMarkerData = cbComp + 512; 797 820 } 798 821 else … … 820 843 if (cbActuallyRead != cbToRead) 821 844 rc = VERR_VD_VMDK_INVALID_FORMAT; 845 return rc; 846 } 847 } 848 849 static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf) 850 { 851 VMDKDEFLATESTATE *pDeflateState = (VMDKDEFLATESTATE *)pvUser; 852 853 Assert(cbBuf); 854 if (pDeflateState->iOffset < 0) 855 { 856 pvBuf = (const uint8_t *)pvBuf + 1; 857 cbBuf--; 858 pDeflateState->iOffset = 0; 859 } 860 if (!cbBuf) 861 return VINF_SUCCESS; 862 int rc = RTFileWriteAt(pDeflateState->File, pDeflateState->uFileOffset, pvBuf, cbBuf, NULL); 863 if (RT_FAILURE(rc)) 864 return rc; 865 pDeflateState->uFileOffset += cbBuf; 866 pDeflateState->iOffset += cbBuf; 867 return VINF_SUCCESS; 868 } 869 870 /** 871 * Internal: deflate the uncompressed data and write to a file, 872 * distinguishing between async and normal operation 873 */ 874 DECLINLINE(int) vmdkFileDeflateAt(PVMDKFILE pVmdkFile, 875 uint64_t uOffset, const void *pvBuf, 876 size_t cbToWrite, unsigned uMarker, 877 uint64_t uLBA, uint32_t *pcbMarkerData) 878 { 879 if (pVmdkFile->fAsyncIO) 880 { 881 AssertMsgFailed(("TODO\n")); 882 return VERR_NOT_SUPPORTED; 883 } 884 else 885 { 886 int rc; 887 PRTZIPCOMP pZip = NULL; 888 VMDKMARKER Marker; 889 uint64_t uCompOffset, cbDecomp; 890 VMDKDEFLATESTATE DeflateState; 891 892 Marker.uSector = RT_H2LE_U64(uLBA); 893 Marker.cbSize = RT_H2LE_U32(cbToWrite); 894 if (uMarker == VMDK_MARKER_IGNORE) 895 { 896 /* Compressed grain marker. Data follows immediately. */ 897 uCompOffset = uOffset + 12; 898 cbDecomp = cbToWrite; 899 rc = RTFileWriteAt(pVmdkFile->File, uOffset, &Marker, 12, NULL); 900 if (RT_FAILURE(rc)) 901 return rc; 902 } 903 else 904 { 905 /** @todo implement creating the other marker types */ 906 return VERR_NOT_IMPLEMENTED; 907 } 908 DeflateState.File = pVmdkFile->File; 909 DeflateState.uFileOffset = uCompOffset; 910 DeflateState.iOffset = -1; 911 912 rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper, RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT); 913 if (RT_FAILURE(rc)) 914 return rc; 915 rc = RTZipCompress(pZip, pvBuf, cbDecomp); 916 if (RT_SUCCESS(rc)) 917 rc = RTZipCompFinish(pZip); 918 RTZipCompDestroy(pZip); 919 if (RT_SUCCESS(rc)) 920 { 921 if (pcbMarkerData) 922 *pcbMarkerData = 12 + DeflateState.iOffset; 923 /* Set the file size to remove old garbage in case the block is 924 * rewritten. Cannot cause data loss as the code calling this 925 * guarantees that data gets only appended. */ 926 rc = RTFileSetSize(pVmdkFile->File, DeflateState.uFileOffset); 927 } 822 928 return rc; 823 929 } … … 1001 1107 1002 1108 /* Check grain table and redundant grain table for consistency. */ 1003 size_t cbGT = pExtent->cGTEntries ;1109 size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t); 1004 1110 uint32_t *pTmpGT1 = (uint32_t *)RTMemTmpAlloc(cbGT); 1005 1111 if (!pTmpGT1) … … 1070 1176 } 1071 1177 1178 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 1179 { 1180 uint32_t uLastGrainWritten = 0; 1181 uint32_t uLastGrainSector = 0; 1182 size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t); 1183 uint32_t *pTmpGT = (uint32_t *)RTMemTmpAlloc(cbGT); 1184 if (!pTmpGT) 1185 { 1186 rc = VERR_NO_MEMORY; 1187 goto out; 1188 } 1189 for (i = 0, pGDTmp = pGD; i < pExtent->cGDEntries; i++, pGDTmp++) 1190 { 1191 /* If no grain table is allocated skip the entry. */ 1192 if (*pGDTmp == 0) 1193 continue; 1194 1195 /* The VMDK 1.1 spec talks about compressed grain tables, but real 1196 * life files don't have them. The spec is wrong in creative ways. */ 1197 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp), 1198 pTmpGT, cbGT, NULL); 1199 if (RT_FAILURE(rc)) 1200 { 1201 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname); 1202 RTMemTmpFree(pTmpGT); 1203 goto out; 1204 } 1205 uint32_t j; 1206 uint32_t *pGTTmp; 1207 for (j = 0, pGTTmp = pTmpGT; j < pExtent->cGTEntries; j++, pGTTmp++) 1208 { 1209 uint32_t uGTTmp = RT_LE2H_U32(*pGTTmp); 1210 1211 /* If no grain is allocated skip the entry. */ 1212 if (uGTTmp == 0) 1213 continue; 1214 1215 if (uLastGrainSector && uLastGrainSector >= uGTTmp) 1216 { 1217 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: grain table in '%s' contains a violation of the ordering assumptions"), pExtent->pszFullname); 1218 RTMemTmpFree(pTmpGT); 1219 goto out; 1220 } 1221 uLastGrainSector = uGTTmp; 1222 uLastGrainWritten = i * pExtent->cGTEntries + j; 1223 } 1224 } 1225 RTMemTmpFree(pTmpGT); 1226 1227 if (uLastGrainSector) 1228 { 1229 uint64_t uLBA = 0; 1230 uint32_t cbMarker = 0; 1231 rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uLastGrainSector), 1232 pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA, &cbMarker); 1233 if (RT_FAILURE(rc)) 1234 goto out; 1235 1236 Assert(uLBA == uLastGrainWritten * pExtent->cSectorsPerGrain); 1237 pExtent->uGrainSector = uLastGrainSector; 1238 pExtent->cbLastGrainWritten = RT_ALIGN(cbMarker, 512); 1239 } 1240 pExtent->uLastGrainWritten = uLastGrainWritten; 1241 pExtent->uLastGrainSector = uLastGrainSector; 1242 } 1243 1072 1244 out: 1073 1245 if (RT_FAILURE(rc)) … … 1108 1280 1109 1281 cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 1110 rc = vmdkFileSetSize(pExtent->pFile, cbOverhead); 1282 /* For streamOptimized extents put the end-of-stream marker at the end. */ 1283 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 1284 rc = vmdkFileSetSize(pExtent->pFile, cbOverhead + 512); 1285 else 1286 rc = vmdkFileSetSize(pExtent->pFile, cbOverhead); 1111 1287 if (RT_FAILURE(rc)) 1112 1288 goto out; … … 2137 2313 return rc; 2138 2314 2139 /* Stream optimized images are always readonly. Nevertheless we opened the2140 * file as read/write to allow us to sneak in the UUID info. */2141 if (pImage->uImageFlags == VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)2142 pImage->uOpenFlags |= VD_OPEN_FLAGS_READONLY;2143 2144 2315 return VINF_SUCCESS; 2145 2316 } … … 2268 2439 } 2269 2440 cbSize = RT_ALIGN_64(cbSize, 512); 2270 rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL );2441 rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL, NULL); 2271 2442 AssertRC(rc); 2272 2443 if (RT_FAILURE(rc)) … … 2331 2502 2332 2503 /* streamOptimized extents need a grain decryption buffer. */ 2333 if (pExtent-> uVersion == 3)2504 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 2334 2505 { 2335 2506 pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); … … 2339 2510 goto out; 2340 2511 } 2341 pExtent->uGrainSector = 0 xffffffffffffffffULL;2512 pExtent->uGrainSector = 0; 2342 2513 } 2343 2514 … … 2603 2774 pExtents[i].pRGD = NULL; 2604 2775 pExtents[i].pDescData = NULL; 2776 pExtents[i].uCompression = VMDK_COMPRESSION_NONE; 2605 2777 pExtents[i].uExtent = i; 2606 2778 pExtents[i].pImage = pImage; … … 3331 3503 if (pfnProgress) 3332 3504 { 3333 rc = pfnProgress(NULL /* WARNING! pVM=NULL 3505 rc = pfnProgress(NULL /* WARNING! pVM=NULL */, 3334 3506 uPercentStart + uOff * uPercentSpan / cbExtent, 3335 3507 pvUser); … … 3365 3537 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 3366 3538 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t)); 3539 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 3540 pExtent->uCompression = VMDK_COMPRESSION_DEFLATE; 3367 3541 } 3368 3542 else … … 3387 3561 3388 3562 if (RT_SUCCESS(rc) && pfnProgress) 3389 pfnProgress(NULL /* WARNING! pVM=NULL 3563 pfnProgress(NULL /* WARNING! pVM=NULL */, 3390 3564 uPercentStart + i * uPercentSpan / cExtents, 3391 3565 pvUser); … … 3403 3577 else if (enmType == VD_IMAGE_TYPE_NORMAL) 3404 3578 { 3405 pszDescType = (cExtents == 1) 3406 ? "monolithicSparse" : "twoGbMaxExtentSparse"; 3579 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 3580 pszDescType = "streamOptimized"; 3581 else 3582 { 3583 pszDescType = (cExtents == 1) 3584 ? "monolithicSparse" : "twoGbMaxExtentSparse"; 3585 } 3407 3586 } 3408 3587 else … … 3477 3656 3478 3657 if (RT_SUCCESS(rc) && pfnProgress) 3479 pfnProgress(NULL /* WARNING! pVM=NULL 3658 pfnProgress(NULL /* WARNING! pVM=NULL */, 3480 3659 uPercentStart + uPercentSpan * 98 / 100, pvUser); 3481 3660 … … 3565 3744 3566 3745 if (RT_SUCCESS(rc) && pfnProgress) 3567 pfnProgress(NULL /* WARNING! pVM=NULL 3746 pfnProgress(NULL /* WARNING! pVM=NULL */, 3568 3747 uPercentStart + uPercentSpan * 99 / 100, pvUser); 3569 3748 … … 3572 3751 out: 3573 3752 if (RT_SUCCESS(rc) && pfnProgress) 3574 pfnProgress(NULL /* WARNING! pVM=NULL 3753 pfnProgress(NULL /* WARNING! pVM=NULL */, 3575 3754 uPercentStart + uPercentSpan, pvUser); 3576 3755 … … 3806 3985 } 3807 3986 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE; 3808 uint 64_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];3987 uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex]; 3809 3988 if (uGrainSector) 3810 3989 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain; … … 3850 4029 cbExtentSize = RT_ALIGN_64(cbExtentSize, 512); 3851 4030 uGTSector = VMDK_BYTE2SECTOR(cbExtentSize); 4031 /* For writable streamOptimized extents the final sector is the 4032 * end-of-stream marker. Will be re-added after the grain table. */ 4033 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4034 { 4035 uGTSector--; 4036 pExtent->uLastGrainSector = 0; 4037 uint8_t aEOS[512]; 4038 memset(aEOS, '\0', sizeof(aEOS)); 4039 rc = vmdkFileWriteAt(pExtent->pFile, 4040 VMDK_SECTOR2BYTE(uGTSector) + pExtent->cGTEntries * sizeof(uint32_t), 4041 aEOS, sizeof(aEOS), NULL); 4042 if (RT_FAILURE(rc)) 4043 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after grain table in '%s'"), pExtent->pszFullname); 4044 } 3852 4045 /* Normally the grain table is preallocated for hosted sparse extents 3853 4046 * that support more than 32 bit sector numbers. So this shouldn't … … 3878 4071 Assert(!(cbExtentSize % 512)); 3879 4072 uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize); 4073 /* For writable streamOptimized extents the final sector is the 4074 * end-of-stream marker. Will be re-added after the grain table. */ 4075 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4076 { 4077 uRGTSector--; 4078 pExtent->uLastGrainSector = 0; 4079 uint8_t aEOS[512]; 4080 memset(aEOS, '\0', sizeof(aEOS)); 4081 rc = vmdkFileWriteAt(pExtent->pFile, 4082 VMDK_SECTOR2BYTE(uRGTSector) + pExtent->cGTEntries * sizeof(uint32_t), 4083 aEOS, sizeof(aEOS), NULL); 4084 if (RT_FAILURE(rc)) 4085 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after redundant grain table in '%s'"), pExtent->pszFullname); 4086 } 3880 4087 /* Normally the redundant grain table is preallocated for hosted 3881 4088 * sparse extents that support more than 32 bit sector numbers. So … … 3930 4137 Assert(!(cbExtentSize % 512)); 3931 4138 3932 /* Write the data. */ 3933 rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL); 3934 if (RT_FAILURE(rc)) 3935 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname); 4139 /* Write the data. Always a full grain, or we're in big trouble. */ 4140 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4141 { 4142 /* For streamOptimized extents this is a little more difficult, as the 4143 * cached data also needs to be updated, to handle updating the last 4144 * written block properly. Also we're trying to avoid unnecessary gaps. 4145 * Additionally the end-of-stream marker needs to be written. */ 4146 if (!pExtent->uLastGrainSector) 4147 cbExtentSize -= 512; 4148 else 4149 cbExtentSize = VMDK_SECTOR2BYTE(pExtent->uLastGrainSector) + pExtent->cbLastGrainWritten; 4150 Assert(cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 4151 uint32_t cbGrain = 0; 4152 rc = vmdkFileDeflateAt(pExtent->pFile, cbExtentSize, 4153 pvBuf, cbWrite, VMDK_MARKER_IGNORE, uSector, &cbGrain); 4154 if (RT_FAILURE(rc)) 4155 { 4156 pExtent->uGrainSector = 0; 4157 pExtent->uLastGrainSector = 0; 4158 AssertRC(rc); 4159 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname); 4160 } 4161 cbGrain = RT_ALIGN(cbGrain, 512); 4162 pExtent->uLastGrainSector = VMDK_BYTE2SECTOR(cbExtentSize); 4163 pExtent->uLastGrainWritten = uSector / pExtent->cSectorsPerGrain; 4164 pExtent->cbLastGrainWritten = cbGrain; 4165 memcpy(pExtent->pvGrain, pvBuf, cbWrite); 4166 pExtent->uGrainSector = uSector; 4167 4168 uint8_t aEOS[512]; 4169 memset(aEOS, '\0', sizeof(aEOS)); 4170 rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize + RT_ALIGN(cbGrain, 512), 4171 aEOS, sizeof(aEOS), NULL); 4172 if (RT_FAILURE(rc)) 4173 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after allocated data block in '%s'"), pExtent->pszFullname); 4174 } 4175 else 4176 { 4177 rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL); 4178 if (RT_FAILURE(rc)) 4179 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname); 4180 } 3936 4181 3937 4182 /* Update the grain table (and the cache). */ … … 4121 4366 || (enmType != VD_IMAGE_TYPE_NORMAL && enmType != VD_IMAGE_TYPE_FIXED) 4122 4367 || !VALID_PTR(pPCHSGeometry) 4123 || !VALID_PTR(pLCHSGeometry)) 4368 || !VALID_PTR(pLCHSGeometry) 4369 || ( (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4370 && ( (uImageFlags & ~VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4371 || (enmType != VD_IMAGE_TYPE_NORMAL)))) 4124 4372 { 4125 4373 rc = VERR_INVALID_PARAMETER; … … 4226 4474 unsigned i, line; 4227 4475 VMDKDESCRIPTOR DescriptorCopy; 4228 VMDKEXTENT 4476 VMDKEXTENT ExtentCopy; 4229 4477 4230 4478 memset(&DescriptorCopy, 0, sizeof(DescriptorCopy)); … … 4245 4493 * with zeros. We actually save stuff when and if we change it. 4246 4494 */ 4247 apszOldName 4248 apszNewName 4495 apszOldName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*)); 4496 apszNewName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*)); 4249 4497 apszNewLines = (char **)RTMemTmpAllocZ((cExtents) * sizeof(char*)); 4250 4498 if (!apszOldName || !apszNewName || !apszNewLines) … … 4263 4511 { 4264 4512 /* Embedded descriptor file. */ 4265 ExtentCopy 4513 ExtentCopy = pImage->pExtents[0]; 4266 4514 fEmbeddedDesc = true; 4267 4515 } … … 4389 4637 if (fEmbeddedDesc) 4390 4638 { 4391 ExtentCopy.pFile 4639 ExtentCopy.pFile = pFile; 4392 4640 pImage->pExtents = &ExtentCopy; 4393 4641 } … … 4534 4782 { 4535 4783 rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uSectorExtentAbs), 4536 pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA );4784 pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA, NULL); 4537 4785 if (RT_FAILURE(rc)) 4538 4786 { 4539 pExtent->uGrainSector = 0 xffffffffffffffffULL;4787 pExtent->uGrainSector = 0; 4540 4788 AssertRC(rc); 4541 4789 goto out; … … 4631 4879 /* Clip write range to at most the rest of the grain. */ 4632 4880 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain)); 4881 if ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED 4882 && uSectorExtentRel < (uint64_t)pExtent->uLastGrainWritten * pExtent->cSectorsPerGrain) 4883 { 4884 rc = VERR_VD_VMDK_INVALID_WRITE; 4885 goto out; 4886 } 4633 4887 if (uSectorExtentAbs == 0) 4634 4888 { … … 4636 4890 { 4637 4891 /* Full block write to a previously unallocated block. 4638 * Check if the caller wants to avoid th is. */4892 * Check if the caller wants to avoid the automatic alloc. */ 4639 4893 if (!(fWrite & VD_WRITE_NO_ALLOC)) 4640 4894 { … … 4658 4912 } 4659 4913 else 4660 rc = vmdkFileWriteAt(pExtent->pFile, 4661 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4662 pvBuf, cbToWrite, NULL); 4914 { 4915 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4916 { 4917 uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain; 4918 uSectorExtentAbs -= uSectorInGrain; 4919 uint64_t uLBA; 4920 if ( pExtent->uGrainSector != uSectorExtentAbs 4921 || pExtent->uGrainSector != pExtent->uLastGrainSector) 4922 { 4923 rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uSectorExtentAbs), 4924 pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA, NULL); 4925 if (RT_FAILURE(rc)) 4926 { 4927 pExtent->uGrainSector = 0; 4928 pExtent->uLastGrainSector = 0; 4929 AssertRC(rc); 4930 goto out; 4931 } 4932 pExtent->uGrainSector = uSectorExtentAbs; 4933 pExtent->uLastGrainSector = uSectorExtentAbs; 4934 Assert(uLBA == uSectorExtentRel); 4935 } 4936 memcpy((uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), pvBuf, cbToWrite); 4937 uint32_t cbGrain = 0; 4938 rc = vmdkFileDeflateAt(pExtent->pFile, 4939 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4940 pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), 4941 VMDK_MARKER_IGNORE, uLBA, &cbGrain); 4942 if (RT_FAILURE(rc)) 4943 { 4944 pExtent->uGrainSector = 0; 4945 pExtent->uLastGrainSector = 0; 4946 AssertRC(rc); 4947 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname); 4948 } 4949 cbGrain = RT_ALIGN(cbGrain, 512); 4950 pExtent->uLastGrainSector = uSectorExtentAbs; 4951 pExtent->uLastGrainWritten = uSectorExtentRel / pExtent->cSectorsPerGrain; 4952 pExtent->cbLastGrainWritten = cbGrain; 4953 4954 uint8_t aEOS[512]; 4955 memset(aEOS, '\0', sizeof(aEOS)); 4956 rc = vmdkFileWriteAt(pExtent->pFile, 4957 VMDK_SECTOR2BYTE(uSectorExtentAbs) + RT_ALIGN(cbGrain, 512), 4958 aEOS, sizeof(aEOS), NULL); 4959 if (RT_FAILURE(rc)) 4960 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write end-of stream marker after data block in '%s'"), pExtent->pszFullname); 4961 } 4962 else 4963 { 4964 rc = vmdkFileWriteAt(pExtent->pFile, 4965 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4966 pvBuf, cbToWrite, NULL); 4967 } 4968 } 4663 4969 break; 4664 4970 case VMDKETYPE_FLAT: … … 5309 5615 unsigned cTasksToSubmit = 0; 5310 5616 PPDMDATASEG paSegCurrent = paSeg; 5311 unsigned 5312 unsigned 5617 unsigned cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5618 unsigned uOffsetInCurrentSegment = 0; 5313 5619 5314 5620 AssertPtr(pImage); … … 5401 5707 } 5402 5708 5403 cbRead 5709 cbRead -= cbToRead; 5404 5710 uOffset += cbToRead; 5405 5711 cbLeftInCurrentSegment -= cbToRead; … … 5445 5751 unsigned cTasksToSubmit = 0; 5446 5752 PPDMDATASEG paSegCurrent = paSeg; 5447 unsigned 5448 unsigned 5753 unsigned cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5754 unsigned uOffsetInCurrentSegment = 0; 5449 5755 5450 5756 AssertPtr(pImage); … … 5537 5843 } 5538 5844 5539 cbWrite 5540 uOffset 5845 cbWrite -= cbToWrite; 5846 uOffset += cbToWrite; 5541 5847 cbLeftInCurrentSegment -= cbToWrite; 5542 5848 uOffsetInCurrentSegment += cbToWrite;
Note:
See TracChangeset
for help on using the changeset viewer.