Changeset 38203 in vbox for trunk/src/VBox/Storage
- Timestamp:
- Jul 27, 2011 4:13:43 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 73171
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VD.cpp
r37329 r38203 809 809 810 810 /** 811 * internal: read the specified amount of data in whatever blocks the backend 812 * will give us. 813 */ 814 static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 815 uint64_t uOffset, void *pvBuf, size_t cbRead, 816 bool fZeroFreeBlocks, bool fUpdateCache) 811 * Extended version of vdReadHelper(), implementing certain optimizations 812 * for image cloning. 813 * 814 * @returns VBox status code. 815 * @param pDisk The disk to read from. 816 * @param pImage The image to start reading from. 817 * @param pImageParentOverride The parent image to read from 818 * if the starting image returns a free block. 819 * If NULL is passed the real parent of the image 820 * in the chain is used. 821 * @param uOffset Offset in the disk to start reading from. 822 * @param pvBuf Where to store the read data. 823 * @param cbRead How much to read. 824 * @param fZeroFreeBlocks Flag whether free blocks should be zeroed. 825 * If false and no image has data for sepcified 826 * range VERR_VD_BLOCK_FREE is returned. 827 * Note that unallocated blocks are still zeroed 828 * if at least one image has valid data for a part 829 * of the range. 830 * @param fUpdateCache Flag whether to update the attached cache if 831 * available. 832 * @param cImagesRead Number of images in the chain to read until 833 * the read is cut off. A value of 0 disables the cut off. 834 */ 835 static int vdReadHelperEx(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 836 uint64_t uOffset, void *pvBuf, size_t cbRead, 837 bool fZeroFreeBlocks, bool fUpdateCache, unsigned cImagesRead) 817 838 { 818 839 int rc = VINF_SUCCESS; … … 837 858 if (rc == VERR_VD_BLOCK_FREE) 838 859 { 839 rc = vdDiskReadHelper(pDisk, pImage, pImageParentOverride,840 uOffset, pvBuf, cbThisRead,&cbThisRead);860 rc = vdDiskReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbThisRead, 861 &cbThisRead); 841 862 842 863 /* If the read was successful, write the data back into the cache. */ … … 862 883 &cbThisRead); 863 884 864 if (rc == VERR_VD_BLOCK_FREE) 885 if ( rc == VERR_VD_BLOCK_FREE 886 && cImagesRead != 1) 865 887 { 888 unsigned cImagesToProcess = cImagesRead; 889 866 890 for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev; 867 891 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; … … 871 895 uOffset, pvBuf, cbThisRead, 872 896 &cbThisRead); 897 if (cImagesToProcess == 1) 898 break; 899 else if (cImagesToProcess > 0) 900 cImagesToProcess--; 873 901 } 874 902 } … … 904 932 905 933 return (!fZeroFreeBlocks && fAllFree) ? VERR_VD_BLOCK_FREE : rc; 934 } 935 936 /** 937 * internal: read the specified amount of data in whatever blocks the backend 938 * will give us. 939 */ 940 static int vdReadHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset, 941 void *pvBuf, size_t cbRead, bool fUpdateCache) 942 { 943 return vdReadHelperEx(pDisk, pImage, NULL, uOffset, pvBuf, cbRead, 944 true /* fZeroFreeBlocks */, fUpdateCache, 0); 906 945 } 907 946 … … 1377 1416 { 1378 1417 PVDPARENTSTATEDESC pParentState = (PVDPARENTSTATEDESC)pvUser; 1379 return vdReadHelper(pParentState->pDisk, pParentState->pImage, NULL, uOffset, 1380 pvBuf, cbRead, true /* fZeroFreeBlocks */, 1381 false /* fUpdateCache */); 1418 return vdReadHelper(pParentState->pDisk, pParentState->pImage, uOffset, 1419 pvBuf, cbRead, false /* fUpdateCache */); 1382 1420 } 1383 1421 … … 1447 1485 * this will be done after the complete block was written. 1448 1486 */ 1449 rc = vdReadHelper (pDisk, pImage, pImageParentOverride,1450 uOffset - cbPreRead, pvTmp, cbPreRead,1451 true /* fZeroFreeBlocks*/,1452 false /* fUpdateCache */);1487 rc = vdReadHelperEx(pDisk, pImage, pImageParentOverride, 1488 uOffset - cbPreRead, pvTmp, cbPreRead, 1489 true /* fZeroFreeBlocks*/, 1490 false /* fUpdateCache */, 0); 1453 1491 if (RT_FAILURE(rc)) 1454 1492 return rc; … … 1484 1522 (char *)pvBuf + cbThisWrite, cbWriteCopy); 1485 1523 if (cbReadImage) 1486 rc = vdReadHelper (pDisk, pImage, pImageParentOverride,1487 uOffset + cbThisWrite + cbWriteCopy,1488 (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy,1489 cbReadImage, true /* fZeroFreeBlocks */,1490 false /* fUpdateCache */);1524 rc = vdReadHelperEx(pDisk, pImage, pImageParentOverride, 1525 uOffset + cbThisWrite + cbWriteCopy, 1526 (char *)pvTmp + cbPreRead + cbThisWrite + cbWriteCopy, 1527 cbReadImage, true /* fZeroFreeBlocks */, 1528 false /* fUpdateCache */, 0); 1491 1529 if (RT_FAILURE(rc)) 1492 1530 return rc; … … 1521 1559 size_t cbThisWrite, size_t cbPreRead, 1522 1560 size_t cbPostRead, const void *pvBuf, 1523 void *pvTmp )1561 void *pvTmp, unsigned cImagesRead) 1524 1562 { 1525 1563 size_t cbFill = 0; … … 1547 1585 /* Read the entire data of the block so that we can compare whether it will 1548 1586 * be modified by the write or not. */ 1549 rc = vdReadHelper (pDisk, pImage, pImageParentOverride, uOffset - cbPreRead, pvTmp,1550 cbPreRead + cbThisWrite + cbPostRead - cbFill,1551 true /* fZeroFreeBlocks*/,1552 false /* fUpdateCache */);1587 rc = vdReadHelperEx(pDisk, pImage, pImageParentOverride, uOffset - cbPreRead, pvTmp, 1588 cbPreRead + cbThisWrite + cbPostRead - cbFill, 1589 true /* fZeroFreeBlocks */, false /* fUpdateCache */, 1590 cImagesRead); 1553 1591 if (RT_FAILURE(rc)) 1554 1592 return rc; … … 1596 1634 * write optimizations. 1597 1635 */ 1598 static int vdWriteHelper (PVBOXHDD pDisk, PVDIMAGE pImage,1599 PVDIMAGE pImageParentOverride, uint64_t uOffset,1600 const void *pvBuf, size_t cbWrite,1601 bool fUpdateCache)1636 static int vdWriteHelperEx(PVBOXHDD pDisk, PVDIMAGE pImage, 1637 PVDIMAGE pImageParentOverride, uint64_t uOffset, 1638 const void *pvBuf, size_t cbWrite, 1639 bool fUpdateCache, unsigned cImagesRead) 1602 1640 { 1603 1641 int rc; … … 1636 1674 uOffsetCur, cbWriteCur, 1637 1675 cbThisWrite, cbPreRead, cbPostRead, 1638 pcvBufCur, pvTmp );1676 pcvBufCur, pvTmp, cImagesRead); 1639 1677 } 1640 1678 else … … 1665 1703 rc = vdCacheWriteHelper(pDisk->pCache, uOffset, pvBuf, cbWrite, NULL); 1666 1704 1705 return rc; 1706 } 1707 1708 /** 1709 * internal: write buffer to the image, taking care of block boundaries and 1710 * write optimizations. 1711 */ 1712 static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset, 1713 const void *pvBuf, size_t cbWrite, bool fUpdateCache) 1714 { 1715 return vdWriteHelperEx(pDisk, pImage, NULL, uOffset, pvBuf, cbWrite, 1716 fUpdateCache, 0); 1717 } 1718 1719 /** 1720 * Internal: Copies the content of one disk to another one applying optimizations 1721 * to speed up the copy process if possible. 1722 */ 1723 static int vdCopyHelper(PVBOXHDD pDiskFrom, PVDIMAGE pImageFrom, PVBOXHDD pDiskTo, 1724 uint64_t cbSize, unsigned cImagesFromRead, unsigned cImagesToRead, 1725 bool fSuppressRedundantIo, 1726 PVDINTERFACE pIfProgress, PVDINTERFACEPROGRESS pCbProgress, 1727 PVDINTERFACE pDstIfProgress, PVDINTERFACEPROGRESS pDstCbProgress) 1728 { 1729 int rc = VINF_SUCCESS; 1730 int rc2; 1731 uint64_t uOffset = 0; 1732 uint64_t cbRemaining = cbSize; 1733 void *pvBuf = NULL; 1734 bool fLockReadFrom = false; 1735 bool fLockWriteTo = false; 1736 bool fBlockwiseCopy = fSuppressRedundantIo || (cImagesFromRead > 0); 1737 unsigned uProgressOld = 0; 1738 1739 LogFlowFunc(("pDiskFrom=%#p pImageFrom=%#p pDiskTo=%#p cbSize=%llu cImagesFromRead=%u cImagesToRead=%u fSuppressRedundantIo=%RTbool pIfProgress=%#p pCbProgress=%#p pDstIfProgress=%#p pDstCbProgress=%#p\n", 1740 pDiskFrom, pImageFrom, pDiskTo, cbSize, cImagesFromRead, cImagesToRead, fSuppressRedundantIo, pIfProgress, pCbProgress, pDstIfProgress, pDstCbProgress)); 1741 1742 /* Allocate tmp buffer. */ 1743 pvBuf = RTMemTmpAlloc(VD_MERGE_BUFFER_SIZE); 1744 if (!pvBuf) 1745 return rc; 1746 1747 do 1748 { 1749 size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining); 1750 1751 /* Note that we don't attempt to synchronize cross-disk accesses. 1752 * It wouldn't be very difficult to do, just the lock order would 1753 * need to be defined somehow to prevent deadlocks. Postpone such 1754 * magic as there is no use case for this. */ 1755 1756 rc2 = vdThreadStartRead(pDiskFrom); 1757 AssertRC(rc2); 1758 fLockReadFrom = true; 1759 1760 if (fBlockwiseCopy) 1761 { 1762 /* Read the source data. */ 1763 rc = pImageFrom->Backend->pfnRead(pImageFrom->pBackendData, 1764 uOffset, pvBuf, cbThisRead, 1765 &cbThisRead); 1766 1767 if ( rc == VERR_VD_BLOCK_FREE 1768 && cImagesFromRead != 1) 1769 { 1770 unsigned cImagesToProcess = cImagesFromRead; 1771 1772 for (PVDIMAGE pCurrImage = pImageFrom->pPrev; 1773 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; 1774 pCurrImage = pCurrImage->pPrev) 1775 { 1776 rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData, 1777 uOffset, pvBuf, cbThisRead, 1778 &cbThisRead); 1779 if (cImagesToProcess == 1) 1780 break; 1781 else if (cImagesToProcess > 0) 1782 cImagesToProcess--; 1783 } 1784 } 1785 } 1786 else 1787 rc = vdReadHelper(pDiskFrom, pImageFrom, uOffset, pvBuf, cbThisRead, 1788 false /* fUpdateCache */); 1789 1790 if (RT_FAILURE(rc) && rc != VERR_VD_BLOCK_FREE) 1791 break; 1792 1793 rc2 = vdThreadFinishRead(pDiskFrom); 1794 AssertRC(rc2); 1795 fLockReadFrom = false; 1796 1797 if (rc != VERR_VD_BLOCK_FREE) 1798 { 1799 rc2 = vdThreadStartWrite(pDiskTo); 1800 AssertRC(rc2); 1801 fLockWriteTo = true; 1802 1803 /* Only do collapsed I/O if we are copying the data blockwise. */ 1804 rc = vdWriteHelperEx(pDiskTo, pDiskTo->pLast, NULL, uOffset, pvBuf, 1805 cbThisRead, false /* fUpdateCache */, 1806 fBlockwiseCopy ? cImagesToRead : 0); 1807 if (RT_FAILURE(rc)) 1808 break; 1809 1810 rc2 = vdThreadFinishWrite(pDiskTo); 1811 AssertRC(rc2); 1812 fLockWriteTo = false; 1813 } 1814 else /* Don't propagate the error to the outside */ 1815 rc = VINF_SUCCESS; 1816 1817 uOffset += cbThisRead; 1818 cbRemaining -= cbThisRead; 1819 1820 unsigned uProgressNew = uOffset * 99 / cbSize; 1821 if (uProgressNew != uProgressOld) 1822 { 1823 uProgressOld = uProgressNew; 1824 1825 if (pCbProgress && pCbProgress->pfnProgress) 1826 { 1827 rc = pCbProgress->pfnProgress(pIfProgress->pvUser, 1828 uProgressOld); 1829 if (RT_FAILURE(rc)) 1830 break; 1831 } 1832 if (pDstCbProgress && pDstCbProgress->pfnProgress) 1833 { 1834 rc = pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 1835 uProgressOld); 1836 if (RT_FAILURE(rc)) 1837 break; 1838 } 1839 } 1840 } while (uOffset < cbSize); 1841 1842 RTMemFree(pvBuf); 1843 1844 if (fLockReadFrom) 1845 { 1846 rc2 = vdThreadFinishRead(pDiskFrom); 1847 AssertRC(rc2); 1848 } 1849 1850 if (fLockWriteTo) 1851 { 1852 rc2 = vdThreadFinishWrite(pDiskTo); 1853 AssertRC(rc2); 1854 } 1855 1856 LogFlowFunc(("returns rc=%Rrc\n", rc)); 1667 1857 return rc; 1668 1858 } … … 5503 5693 break; 5504 5694 /* Updating the cache is required because this might be a live merge. */ 5505 rc = vdWriteHelper (pDisk, pImageTo, pImageFrom->pPrev,5506 uOffset, pvBuf, cbThisRead,5507 true /* fUpdateCache */);5695 rc = vdWriteHelperEx(pDisk, pImageTo, pImageFrom->pPrev, 5696 uOffset, pvBuf, cbThisRead, 5697 true /* fUpdateCache */, 0); 5508 5698 if (RT_FAILURE(rc)) 5509 5699 break; … … 5618 5808 if (RT_FAILURE(rc)) 5619 5809 break; 5620 rc = vdWriteHelper(pDisk, pImageTo, NULL,uOffset, pvBuf,5810 rc = vdWriteHelper(pDisk, pImageTo, uOffset, pvBuf, 5621 5811 cbThisRead, true /* fUpdateCache */); 5622 5812 if (RT_FAILURE(rc)) … … 5768 5958 if (RT_SUCCESS(rc) && pCbProgress && pCbProgress->pfnProgress) 5769 5959 pCbProgress->pfnProgress(pIfProgress->pvUser, 100); 5960 5961 LogFlowFunc(("returns %Rrc\n", rc)); 5962 return rc; 5963 } 5964 5965 /** 5966 * Copies an image from one HDD container to another - extended version. 5967 * The copy is opened in the target HDD container. 5968 * It is possible to convert between different image formats, because the 5969 * backend for the destination may be different from the source. 5970 * If both the source and destination reference the same HDD container, 5971 * then the image is moved (by copying/deleting or renaming) to the new location. 5972 * The source container is unchanged if the move operation fails, otherwise 5973 * the image at the new location is opened in the same way as the old one was. 5974 * 5975 * @note The read/write accesses across disks are not synchronized, just the 5976 * accesses to each disk. Once there is a use case which requires a defined 5977 * read/write behavior in this situation this needs to be extended. 5978 * 5979 * @return VBox status code. 5980 * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. 5981 * @param pDiskFrom Pointer to source HDD container. 5982 * @param nImage Image number, counts from 0. 0 is always base image of container. 5983 * @param pDiskTo Pointer to destination HDD container. 5984 * @param pszBackend Name of the image file backend to use (may be NULL to use the same as the source, case insensitive). 5985 * @param pszFilename New name of the image (may be NULL to specify that the 5986 * copy destination is the destination container, or 5987 * if pDiskFrom == pDiskTo, i.e. when moving). 5988 * @param fMoveByRename If true, attempt to perform a move by renaming (if successful the new size is ignored). 5989 * @param cbSize New image size (0 means leave unchanged). 5990 * @param nImageSameFrom todo 5991 * @param nImageSameTo todo 5992 * @param uImageFlags Flags specifying special destination image features. 5993 * @param pDstUuid New UUID of the destination image. If NULL, a new UUID is created. 5994 * This parameter is used if and only if a true copy is created. 5995 * In all rename/move cases or copy to existing image cases the modification UUIDs are copied over. 5996 * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. 5997 * Only used if the destination image is created. 5998 * @param pVDIfsOperation Pointer to the per-operation VD interface list. 5999 * @param pDstVDIfsImage Pointer to the per-image VD interface list, for the 6000 * destination image. 6001 * @param pDstVDIfsOperation Pointer to the per-operation VD interface list, 6002 * for the destination operation. 6003 */ 6004 VBOXDDU_DECL(int) VDCopyEx(PVBOXHDD pDiskFrom, unsigned nImage, PVBOXHDD pDiskTo, 6005 const char *pszBackend, const char *pszFilename, 6006 bool fMoveByRename, uint64_t cbSize, 6007 unsigned nImageFromSame, unsigned nImageToSame, 6008 unsigned uImageFlags, PCRTUUID pDstUuid, 6009 unsigned uOpenFlags, PVDINTERFACE pVDIfsOperation, 6010 PVDINTERFACE pDstVDIfsImage, 6011 PVDINTERFACE pDstVDIfsOperation) 6012 { 6013 int rc = VINF_SUCCESS; 6014 int rc2; 6015 bool fLockReadFrom = false, fLockWriteFrom = false, fLockWriteTo = false; 6016 PVDIMAGE pImageTo = NULL; 6017 6018 LogFlowFunc(("pDiskFrom=%#p nImage=%u pDiskTo=%#p pszBackend=\"%s\" pszFilename=\"%s\" fMoveByRename=%d cbSize=%llu uImageFlags=%#x pDstUuid=%#p uOpenFlags=%#x pVDIfsOperation=%#p pDstVDIfsImage=%#p pDstVDIfsOperation=%#p\n", 6019 pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename, cbSize, uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation, pDstVDIfsImage, pDstVDIfsOperation)); 6020 6021 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation, 6022 VDINTERFACETYPE_PROGRESS); 6023 PVDINTERFACEPROGRESS pCbProgress = NULL; 6024 if (pIfProgress) 6025 pCbProgress = VDGetInterfaceProgress(pIfProgress); 6026 6027 PVDINTERFACE pDstIfProgress = VDInterfaceGet(pDstVDIfsOperation, 6028 VDINTERFACETYPE_PROGRESS); 6029 PVDINTERFACEPROGRESS pDstCbProgress = NULL; 6030 if (pDstIfProgress) 6031 pDstCbProgress = VDGetInterfaceProgress(pDstIfProgress); 6032 6033 do { 6034 /* Check arguments. */ 6035 AssertMsgBreakStmt(VALID_PTR(pDiskFrom), ("pDiskFrom=%#p\n", pDiskFrom), 6036 rc = VERR_INVALID_PARAMETER); 6037 AssertMsg(pDiskFrom->u32Signature == VBOXHDDDISK_SIGNATURE, 6038 ("u32Signature=%08x\n", pDiskFrom->u32Signature)); 6039 6040 rc2 = vdThreadStartRead(pDiskFrom); 6041 AssertRC(rc2); 6042 fLockReadFrom = true; 6043 PVDIMAGE pImageFrom = vdGetImageByNumber(pDiskFrom, nImage); 6044 AssertPtrBreakStmt(pImageFrom, rc = VERR_VD_IMAGE_NOT_FOUND); 6045 AssertMsgBreakStmt(VALID_PTR(pDiskTo), ("pDiskTo=%#p\n", pDiskTo), 6046 rc = VERR_INVALID_PARAMETER); 6047 AssertMsg(pDiskTo->u32Signature == VBOXHDDDISK_SIGNATURE, 6048 ("u32Signature=%08x\n", pDiskTo->u32Signature)); 6049 AssertMsgBreakStmt( (nImageFromSame < nImage || nImageFromSame == VD_IMAGE_CONTENT_UNKNOWN) 6050 && (nImageToSame < pDiskTo->cImages || nImageToSame == VD_IMAGE_CONTENT_UNKNOWN) 6051 && ( (nImageFromSame == VD_IMAGE_CONTENT_UNKNOWN && nImageToSame == VD_IMAGE_CONTENT_UNKNOWN) 6052 || (nImageFromSame != VD_IMAGE_CONTENT_UNKNOWN && nImageToSame != VD_IMAGE_CONTENT_UNKNOWN)), 6053 ("nImageFromSame=%u nImageToSame=%u\n", nImageFromSame, nImageToSame), 6054 rc = VERR_INVALID_PARAMETER); 6055 6056 /* Move the image. */ 6057 if (pDiskFrom == pDiskTo) 6058 { 6059 /* Rename only works when backends are the same, are file based 6060 * and the rename method is implemented. */ 6061 if ( fMoveByRename 6062 && !RTStrICmp(pszBackend, pImageFrom->Backend->pszBackendName) 6063 && pImageFrom->Backend->uBackendCaps & VD_CAP_FILE 6064 && pImageFrom->Backend->pfnRename) 6065 { 6066 rc2 = vdThreadFinishRead(pDiskFrom); 6067 AssertRC(rc2); 6068 fLockReadFrom = false; 6069 6070 rc2 = vdThreadStartWrite(pDiskFrom); 6071 AssertRC(rc2); 6072 fLockWriteFrom = true; 6073 rc = pImageFrom->Backend->pfnRename(pImageFrom->pBackendData, pszFilename ? pszFilename : pImageFrom->pszFilename); 6074 break; 6075 } 6076 6077 /** @todo Moving (including shrinking/growing) of the image is 6078 * requested, but the rename attempt failed or it wasn't possible. 6079 * Must now copy image to temp location. */ 6080 AssertReleaseMsgFailed(("VDCopy: moving by copy/delete not implemented\n")); 6081 } 6082 6083 /* pszFilename is allowed to be NULL, as this indicates copy to the existing image. */ 6084 AssertMsgBreakStmt(pszFilename == NULL || (VALID_PTR(pszFilename) && *pszFilename), 6085 ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename), 6086 rc = VERR_INVALID_PARAMETER); 6087 6088 uint64_t cbSizeFrom; 6089 cbSizeFrom = pImageFrom->Backend->pfnGetSize(pImageFrom->pBackendData); 6090 if (cbSizeFrom == 0) 6091 { 6092 rc = VERR_VD_VALUE_NOT_FOUND; 6093 break; 6094 } 6095 6096 VDGEOMETRY PCHSGeometryFrom = {0, 0, 0}; 6097 VDGEOMETRY LCHSGeometryFrom = {0, 0, 0}; 6098 pImageFrom->Backend->pfnGetPCHSGeometry(pImageFrom->pBackendData, &PCHSGeometryFrom); 6099 pImageFrom->Backend->pfnGetLCHSGeometry(pImageFrom->pBackendData, &LCHSGeometryFrom); 6100 6101 RTUUID ImageUuid, ImageModificationUuid; 6102 if (pDiskFrom != pDiskTo) 6103 { 6104 if (pDstUuid) 6105 ImageUuid = *pDstUuid; 6106 else 6107 RTUuidCreate(&ImageUuid); 6108 } 6109 else 6110 { 6111 rc = pImageFrom->Backend->pfnGetUuid(pImageFrom->pBackendData, &ImageUuid); 6112 if (RT_FAILURE(rc)) 6113 RTUuidCreate(&ImageUuid); 6114 } 6115 rc = pImageFrom->Backend->pfnGetModificationUuid(pImageFrom->pBackendData, &ImageModificationUuid); 6116 if (RT_FAILURE(rc)) 6117 RTUuidClear(&ImageModificationUuid); 6118 6119 char szComment[1024]; 6120 rc = pImageFrom->Backend->pfnGetComment(pImageFrom->pBackendData, szComment, sizeof(szComment)); 6121 if (RT_FAILURE(rc)) 6122 szComment[0] = '\0'; 6123 else 6124 szComment[sizeof(szComment) - 1] = '\0'; 6125 6126 rc2 = vdThreadFinishRead(pDiskFrom); 6127 AssertRC(rc2); 6128 fLockReadFrom = false; 6129 6130 rc2 = vdThreadStartRead(pDiskTo); 6131 AssertRC(rc2); 6132 unsigned cImagesTo = pDiskTo->cImages; 6133 rc2 = vdThreadFinishRead(pDiskTo); 6134 AssertRC(rc2); 6135 6136 if (pszFilename) 6137 { 6138 if (cbSize == 0) 6139 cbSize = cbSizeFrom; 6140 6141 /* Create destination image with the properties of source image. */ 6142 /** @todo replace the VDCreateDiff/VDCreateBase calls by direct 6143 * calls to the backend. Unifies the code and reduces the API 6144 * dependencies. Would also make the synchronization explicit. */ 6145 if (cImagesTo > 0) 6146 { 6147 rc = VDCreateDiff(pDiskTo, pszBackend, pszFilename, 6148 uImageFlags, szComment, &ImageUuid, 6149 NULL /* pParentUuid */, 6150 uOpenFlags & ~VD_OPEN_FLAGS_READONLY, 6151 pDstVDIfsImage, NULL); 6152 6153 rc2 = vdThreadStartWrite(pDiskTo); 6154 AssertRC(rc2); 6155 fLockWriteTo = true; 6156 } else { 6157 /** @todo hack to force creation of a fixed image for 6158 * the RAW backend, which can't handle anything else. */ 6159 if (!RTStrICmp(pszBackend, "RAW")) 6160 uImageFlags |= VD_IMAGE_FLAGS_FIXED; 6161 6162 vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize); 6163 vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize); 6164 6165 rc = VDCreateBase(pDiskTo, pszBackend, pszFilename, cbSize, 6166 uImageFlags, szComment, 6167 &PCHSGeometryFrom, &LCHSGeometryFrom, 6168 NULL, uOpenFlags & ~VD_OPEN_FLAGS_READONLY, 6169 pDstVDIfsImage, NULL); 6170 6171 rc2 = vdThreadStartWrite(pDiskTo); 6172 AssertRC(rc2); 6173 fLockWriteTo = true; 6174 6175 if (RT_SUCCESS(rc) && !RTUuidIsNull(&ImageUuid)) 6176 pDiskTo->pLast->Backend->pfnSetUuid(pDiskTo->pLast->pBackendData, &ImageUuid); 6177 } 6178 if (RT_FAILURE(rc)) 6179 break; 6180 6181 pImageTo = pDiskTo->pLast; 6182 AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND); 6183 6184 cbSize = RT_MIN(cbSize, cbSizeFrom); 6185 } 6186 else 6187 { 6188 pImageTo = pDiskTo->pLast; 6189 AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND); 6190 6191 uint64_t cbSizeTo; 6192 cbSizeTo = pImageTo->Backend->pfnGetSize(pImageTo->pBackendData); 6193 if (cbSizeTo == 0) 6194 { 6195 rc = VERR_VD_VALUE_NOT_FOUND; 6196 break; 6197 } 6198 6199 if (cbSize == 0) 6200 cbSize = RT_MIN(cbSizeFrom, cbSizeTo); 6201 6202 vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize); 6203 vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize); 6204 6205 /* Update the geometry in the destination image. */ 6206 pImageTo->Backend->pfnSetPCHSGeometry(pImageTo->pBackendData, &PCHSGeometryFrom); 6207 pImageTo->Backend->pfnSetLCHSGeometry(pImageTo->pBackendData, &LCHSGeometryFrom); 6208 } 6209 6210 rc2 = vdThreadFinishWrite(pDiskTo); 6211 AssertRC(rc2); 6212 fLockWriteTo = false; 6213 6214 /* Whether we can take the optimized copy path (false) or not. 6215 * Don't optimize if the image existed or if it is a child image. */ 6216 bool fSuppressRedundantIo = ( !(pszFilename == NULL || cImagesTo > 0) 6217 || (nImageToSame != UINT32_MAX)); 6218 6219 /* Copy the data. */ 6220 rc = vdCopyHelper(pDiskFrom, pImageFrom, pDiskTo, cbSize, 6221 nImageFromSame == VD_IMAGE_CONTENT_UNKNOWN ? 0 : nImage - nImageFromSame, 6222 nImageToSame == VD_IMAGE_CONTENT_UNKNOWN ? 0 : pDiskTo->cImages - nImageToSame + 1, 6223 fSuppressRedundantIo, pIfProgress, pCbProgress, 6224 pDstIfProgress, pDstCbProgress); 6225 6226 if (RT_SUCCESS(rc)) 6227 { 6228 rc2 = vdThreadStartWrite(pDiskTo); 6229 AssertRC(rc2); 6230 fLockWriteTo = true; 6231 6232 /* Only set modification UUID if it is non-null, since the source 6233 * backend might not provide a valid modification UUID. */ 6234 if (!RTUuidIsNull(&ImageModificationUuid)) 6235 pImageTo->Backend->pfnSetModificationUuid(pImageTo->pBackendData, &ImageModificationUuid); 6236 6237 /* Set the requested open flags if they differ from the value 6238 * required for creating the image and copying the contents. */ 6239 if ( pImageTo && pszFilename 6240 && uOpenFlags != (uOpenFlags & ~VD_OPEN_FLAGS_READONLY)) 6241 rc = pImageTo->Backend->pfnSetOpenFlags(pImageTo->pBackendData, 6242 uOpenFlags); 6243 } 6244 } while (0); 6245 6246 if (RT_FAILURE(rc) && pImageTo && pszFilename) 6247 { 6248 /* Take the write lock only if it is not taken. Not worth making the 6249 * above code even more complicated. */ 6250 if (RT_UNLIKELY(!fLockWriteTo)) 6251 { 6252 rc2 = vdThreadStartWrite(pDiskTo); 6253 AssertRC(rc2); 6254 fLockWriteTo = true; 6255 } 6256 /* Error detected, but new image created. Remove image from list. */ 6257 vdRemoveImageFromList(pDiskTo, pImageTo); 6258 6259 /* Close and delete image. */ 6260 rc2 = pImageTo->Backend->pfnClose(pImageTo->pBackendData, true); 6261 AssertRC(rc2); 6262 pImageTo->pBackendData = NULL; 6263 6264 /* Free remaining resources. */ 6265 if (pImageTo->pszFilename) 6266 RTStrFree(pImageTo->pszFilename); 6267 6268 RTMemFree(pImageTo); 6269 } 6270 6271 if (RT_UNLIKELY(fLockWriteTo)) 6272 { 6273 rc2 = vdThreadFinishWrite(pDiskTo); 6274 AssertRC(rc2); 6275 } 6276 if (RT_UNLIKELY(fLockWriteFrom)) 6277 { 6278 rc2 = vdThreadFinishWrite(pDiskFrom); 6279 AssertRC(rc2); 6280 } 6281 else if (RT_UNLIKELY(fLockReadFrom)) 6282 { 6283 rc2 = vdThreadFinishRead(pDiskFrom); 6284 AssertRC(rc2); 6285 } 6286 6287 if (RT_SUCCESS(rc)) 6288 { 6289 if (pCbProgress && pCbProgress->pfnProgress) 6290 pCbProgress->pfnProgress(pIfProgress->pvUser, 100); 6291 if (pDstCbProgress && pDstCbProgress->pfnProgress) 6292 pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 100); 6293 } 5770 6294 5771 6295 LogFlowFunc(("returns %Rrc\n", rc)); … … 5812 6336 PVDINTERFACE pDstVDIfsOperation) 5813 6337 { 5814 int rc = VINF_SUCCESS; 5815 int rc2; 5816 bool fLockReadFrom = false, fLockWriteFrom = false, fLockWriteTo = false; 5817 void *pvBuf = NULL; 5818 PVDIMAGE pImageTo = NULL; 5819 5820 LogFlowFunc(("pDiskFrom=%#p nImage=%u pDiskTo=%#p pszBackend=\"%s\" pszFilename=\"%s\" fMoveByRename=%d cbSize=%llu uImageFlags=%#x pDstUuid=%#p uOpenFlags=%#x pVDIfsOperation=%#p pDstVDIfsImage=%#p pDstVDIfsOperation=%#p\n", 5821 pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename, cbSize, uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation, pDstVDIfsImage, pDstVDIfsOperation)); 5822 5823 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation, 5824 VDINTERFACETYPE_PROGRESS); 5825 PVDINTERFACEPROGRESS pCbProgress = NULL; 5826 if (pIfProgress) 5827 pCbProgress = VDGetInterfaceProgress(pIfProgress); 5828 5829 PVDINTERFACE pDstIfProgress = VDInterfaceGet(pDstVDIfsOperation, 5830 VDINTERFACETYPE_PROGRESS); 5831 PVDINTERFACEPROGRESS pDstCbProgress = NULL; 5832 if (pDstIfProgress) 5833 pDstCbProgress = VDGetInterfaceProgress(pDstIfProgress); 5834 5835 do { 5836 /* Check arguments. */ 5837 AssertMsgBreakStmt(VALID_PTR(pDiskFrom), ("pDiskFrom=%#p\n", pDiskFrom), 5838 rc = VERR_INVALID_PARAMETER); 5839 AssertMsg(pDiskFrom->u32Signature == VBOXHDDDISK_SIGNATURE, 5840 ("u32Signature=%08x\n", pDiskFrom->u32Signature)); 5841 5842 rc2 = vdThreadStartRead(pDiskFrom); 5843 AssertRC(rc2); 5844 fLockReadFrom = true; 5845 PVDIMAGE pImageFrom = vdGetImageByNumber(pDiskFrom, nImage); 5846 AssertPtrBreakStmt(pImageFrom, rc = VERR_VD_IMAGE_NOT_FOUND); 5847 AssertMsgBreakStmt(VALID_PTR(pDiskTo), ("pDiskTo=%#p\n", pDiskTo), 5848 rc = VERR_INVALID_PARAMETER); 5849 AssertMsg(pDiskTo->u32Signature == VBOXHDDDISK_SIGNATURE, 5850 ("u32Signature=%08x\n", pDiskTo->u32Signature)); 5851 5852 /* Move the image. */ 5853 if (pDiskFrom == pDiskTo) 5854 { 5855 /* Rename only works when backends are the same, are file based 5856 * and the rename method is implemented. */ 5857 if ( fMoveByRename 5858 && !RTStrICmp(pszBackend, pImageFrom->Backend->pszBackendName) 5859 && pImageFrom->Backend->uBackendCaps & VD_CAP_FILE 5860 && pImageFrom->Backend->pfnRename) 5861 { 5862 rc2 = vdThreadFinishRead(pDiskFrom); 5863 AssertRC(rc2); 5864 fLockReadFrom = false; 5865 5866 rc2 = vdThreadStartWrite(pDiskFrom); 5867 AssertRC(rc2); 5868 fLockWriteFrom = true; 5869 rc = pImageFrom->Backend->pfnRename(pImageFrom->pBackendData, pszFilename ? pszFilename : pImageFrom->pszFilename); 5870 break; 5871 } 5872 5873 /** @todo Moving (including shrinking/growing) of the image is 5874 * requested, but the rename attempt failed or it wasn't possible. 5875 * Must now copy image to temp location. */ 5876 AssertReleaseMsgFailed(("VDCopy: moving by copy/delete not implemented\n")); 5877 } 5878 5879 /* pszFilename is allowed to be NULL, as this indicates copy to the existing image. */ 5880 AssertMsgBreakStmt(pszFilename == NULL || (VALID_PTR(pszFilename) && *pszFilename), 5881 ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename), 5882 rc = VERR_INVALID_PARAMETER); 5883 5884 uint64_t cbSizeFrom; 5885 cbSizeFrom = pImageFrom->Backend->pfnGetSize(pImageFrom->pBackendData); 5886 if (cbSizeFrom == 0) 5887 { 5888 rc = VERR_VD_VALUE_NOT_FOUND; 5889 break; 5890 } 5891 5892 VDGEOMETRY PCHSGeometryFrom = {0, 0, 0}; 5893 VDGEOMETRY LCHSGeometryFrom = {0, 0, 0}; 5894 pImageFrom->Backend->pfnGetPCHSGeometry(pImageFrom->pBackendData, &PCHSGeometryFrom); 5895 pImageFrom->Backend->pfnGetLCHSGeometry(pImageFrom->pBackendData, &LCHSGeometryFrom); 5896 5897 RTUUID ImageUuid, ImageModificationUuid; 5898 if (pDiskFrom != pDiskTo) 5899 { 5900 if (pDstUuid) 5901 ImageUuid = *pDstUuid; 5902 else 5903 RTUuidCreate(&ImageUuid); 5904 } 5905 else 5906 { 5907 rc = pImageFrom->Backend->pfnGetUuid(pImageFrom->pBackendData, &ImageUuid); 5908 if (RT_FAILURE(rc)) 5909 RTUuidCreate(&ImageUuid); 5910 } 5911 rc = pImageFrom->Backend->pfnGetModificationUuid(pImageFrom->pBackendData, &ImageModificationUuid); 5912 if (RT_FAILURE(rc)) 5913 RTUuidClear(&ImageModificationUuid); 5914 5915 char szComment[1024]; 5916 rc = pImageFrom->Backend->pfnGetComment(pImageFrom->pBackendData, szComment, sizeof(szComment)); 5917 if (RT_FAILURE(rc)) 5918 szComment[0] = '\0'; 5919 else 5920 szComment[sizeof(szComment) - 1] = '\0'; 5921 5922 rc2 = vdThreadFinishRead(pDiskFrom); 5923 AssertRC(rc2); 5924 fLockReadFrom = false; 5925 5926 rc2 = vdThreadStartRead(pDiskTo); 5927 AssertRC(rc2); 5928 unsigned cImagesTo = pDiskTo->cImages; 5929 rc2 = vdThreadFinishRead(pDiskTo); 5930 AssertRC(rc2); 5931 5932 if (pszFilename) 5933 { 5934 if (cbSize == 0) 5935 cbSize = cbSizeFrom; 5936 5937 /* Create destination image with the properties of source image. */ 5938 /** @todo replace the VDCreateDiff/VDCreateBase calls by direct 5939 * calls to the backend. Unifies the code and reduces the API 5940 * dependencies. Would also make the synchronization explicit. */ 5941 if (cImagesTo > 0) 5942 { 5943 rc = VDCreateDiff(pDiskTo, pszBackend, pszFilename, 5944 uImageFlags, szComment, &ImageUuid, 5945 NULL /* pParentUuid */, 5946 uOpenFlags & ~VD_OPEN_FLAGS_READONLY, 5947 pDstVDIfsImage, NULL); 5948 5949 rc2 = vdThreadStartWrite(pDiskTo); 5950 AssertRC(rc2); 5951 fLockWriteTo = true; 5952 } else { 5953 /** @todo hack to force creation of a fixed image for 5954 * the RAW backend, which can't handle anything else. */ 5955 if (!RTStrICmp(pszBackend, "RAW")) 5956 uImageFlags |= VD_IMAGE_FLAGS_FIXED; 5957 5958 vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize); 5959 vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize); 5960 5961 rc = VDCreateBase(pDiskTo, pszBackend, pszFilename, cbSize, 5962 uImageFlags, szComment, 5963 &PCHSGeometryFrom, &LCHSGeometryFrom, 5964 NULL, uOpenFlags & ~VD_OPEN_FLAGS_READONLY, 5965 pDstVDIfsImage, NULL); 5966 5967 rc2 = vdThreadStartWrite(pDiskTo); 5968 AssertRC(rc2); 5969 fLockWriteTo = true; 5970 5971 if (RT_SUCCESS(rc) && !RTUuidIsNull(&ImageUuid)) 5972 pDiskTo->pLast->Backend->pfnSetUuid(pDiskTo->pLast->pBackendData, &ImageUuid); 5973 } 5974 if (RT_FAILURE(rc)) 5975 break; 5976 5977 pImageTo = pDiskTo->pLast; 5978 AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND); 5979 5980 cbSize = RT_MIN(cbSize, cbSizeFrom); 5981 } 5982 else 5983 { 5984 pImageTo = pDiskTo->pLast; 5985 AssertPtrBreakStmt(pImageTo, rc = VERR_VD_IMAGE_NOT_FOUND); 5986 5987 uint64_t cbSizeTo; 5988 cbSizeTo = pImageTo->Backend->pfnGetSize(pImageTo->pBackendData); 5989 if (cbSizeTo == 0) 5990 { 5991 rc = VERR_VD_VALUE_NOT_FOUND; 5992 break; 5993 } 5994 5995 if (cbSize == 0) 5996 cbSize = RT_MIN(cbSizeFrom, cbSizeTo); 5997 5998 vdFixupPCHSGeometry(&PCHSGeometryFrom, cbSize); 5999 vdFixupLCHSGeometry(&LCHSGeometryFrom, cbSize); 6000 6001 /* Update the geometry in the destination image. */ 6002 pImageTo->Backend->pfnSetPCHSGeometry(pImageTo->pBackendData, &PCHSGeometryFrom); 6003 pImageTo->Backend->pfnSetLCHSGeometry(pImageTo->pBackendData, &LCHSGeometryFrom); 6004 } 6005 6006 rc2 = vdThreadFinishWrite(pDiskTo); 6007 AssertRC(rc2); 6008 fLockWriteTo = false; 6009 6010 /* Allocate tmp buffer. */ 6011 pvBuf = RTMemTmpAlloc(VD_MERGE_BUFFER_SIZE); 6012 if (!pvBuf) 6013 { 6014 rc = VERR_NO_MEMORY; 6015 break; 6016 } 6017 6018 /* Whether we can take the optimized copy path (false) or not. 6019 * Don't optimize if the image existed or if it is a child image. */ 6020 bool fRegularRead = (pszFilename == NULL) || (cImagesTo > 0); 6021 6022 /* Copy the data. */ 6023 uint64_t uOffset = 0; 6024 uint64_t cbRemaining = cbSize; 6025 6026 do 6027 { 6028 size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining); 6029 6030 /* Note that we don't attempt to synchronize cross-disk accesses. 6031 * It wouldn't be very difficult to do, just the lock order would 6032 * need to be defined somehow to prevent deadlocks. Postpone such 6033 * magic as there is no use case for this. */ 6034 6035 rc2 = vdThreadStartRead(pDiskFrom); 6036 AssertRC(rc2); 6037 fLockReadFrom = true; 6038 6039 /* 6040 * Updating the cache doesn't make any sense 6041 * as we are looping once through the image. 6042 */ 6043 rc = vdReadHelper(pDiskFrom, pImageFrom, NULL, uOffset, pvBuf, 6044 cbThisRead, fRegularRead, 6045 false /* fUpdateCache */); 6046 if (RT_FAILURE(rc) && rc != VERR_VD_BLOCK_FREE) 6047 break; 6048 6049 rc2 = vdThreadFinishRead(pDiskFrom); 6050 AssertRC(rc2); 6051 fLockReadFrom = false; 6052 6053 if (rc != VERR_VD_BLOCK_FREE) 6054 { 6055 rc2 = vdThreadStartWrite(pDiskTo); 6056 AssertRC(rc2); 6057 fLockWriteTo = true; 6058 6059 rc = vdWriteHelper(pDiskTo, pImageTo, NULL, uOffset, pvBuf, 6060 cbThisRead, false /* fUpdateCache */); 6061 if (RT_FAILURE(rc)) 6062 break; 6063 6064 rc2 = vdThreadFinishWrite(pDiskTo); 6065 AssertRC(rc2); 6066 fLockWriteTo = false; 6067 } 6068 else /* Don't propagate the error to the outside */ 6069 rc = VINF_SUCCESS; 6070 6071 uOffset += cbThisRead; 6072 cbRemaining -= cbThisRead; 6073 6074 if (pCbProgress && pCbProgress->pfnProgress) 6075 { 6076 /** @todo r=klaus: this can update the progress to the same 6077 * percentage over and over again if the image format makes 6078 * relatively small increments. */ 6079 rc = pCbProgress->pfnProgress(pIfProgress->pvUser, 6080 uOffset * 99 / cbSize); 6081 if (RT_FAILURE(rc)) 6082 break; 6083 } 6084 if (pDstCbProgress && pDstCbProgress->pfnProgress) 6085 { 6086 /** @todo r=klaus: this can update the progress to the same 6087 * percentage over and over again if the image format makes 6088 * relatively small increments. */ 6089 rc = pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 6090 uOffset * 99 / cbSize); 6091 if (RT_FAILURE(rc)) 6092 break; 6093 } 6094 } while (uOffset < cbSize); 6095 6096 if (RT_SUCCESS(rc)) 6097 { 6098 rc2 = vdThreadStartWrite(pDiskTo); 6099 AssertRC(rc2); 6100 fLockWriteTo = true; 6101 6102 /* Only set modification UUID if it is non-null, since the source 6103 * backend might not provide a valid modification UUID. */ 6104 if (!RTUuidIsNull(&ImageModificationUuid)) 6105 pImageTo->Backend->pfnSetModificationUuid(pImageTo->pBackendData, &ImageModificationUuid); 6106 6107 /* Set the requested open flags if they differ from the value 6108 * required for creating the image and copying the contents. */ 6109 if ( pImageTo && pszFilename 6110 && uOpenFlags != (uOpenFlags & ~VD_OPEN_FLAGS_READONLY)) 6111 rc = pImageTo->Backend->pfnSetOpenFlags(pImageTo->pBackendData, 6112 uOpenFlags); 6113 } 6114 } while (0); 6115 6116 if (RT_FAILURE(rc) && pImageTo && pszFilename) 6117 { 6118 /* Take the write lock only if it is not taken. Not worth making the 6119 * above code even more complicated. */ 6120 if (RT_UNLIKELY(!fLockWriteTo)) 6121 { 6122 rc2 = vdThreadStartWrite(pDiskTo); 6123 AssertRC(rc2); 6124 fLockWriteTo = true; 6125 } 6126 /* Error detected, but new image created. Remove image from list. */ 6127 vdRemoveImageFromList(pDiskTo, pImageTo); 6128 6129 /* Close and delete image. */ 6130 rc2 = pImageTo->Backend->pfnClose(pImageTo->pBackendData, true); 6131 AssertRC(rc2); 6132 pImageTo->pBackendData = NULL; 6133 6134 /* Free remaining resources. */ 6135 if (pImageTo->pszFilename) 6136 RTStrFree(pImageTo->pszFilename); 6137 6138 RTMemFree(pImageTo); 6139 } 6140 6141 if (RT_UNLIKELY(fLockWriteTo)) 6142 { 6143 rc2 = vdThreadFinishWrite(pDiskTo); 6144 AssertRC(rc2); 6145 } 6146 if (RT_UNLIKELY(fLockWriteFrom)) 6147 { 6148 rc2 = vdThreadFinishWrite(pDiskFrom); 6149 AssertRC(rc2); 6150 } 6151 else if (RT_UNLIKELY(fLockReadFrom)) 6152 { 6153 rc2 = vdThreadFinishRead(pDiskFrom); 6154 AssertRC(rc2); 6155 } 6156 6157 if (pvBuf) 6158 RTMemTmpFree(pvBuf); 6159 6160 if (RT_SUCCESS(rc)) 6161 { 6162 if (pCbProgress && pCbProgress->pfnProgress) 6163 pCbProgress->pfnProgress(pIfProgress->pvUser, 100); 6164 if (pDstCbProgress && pDstCbProgress->pfnProgress) 6165 pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 100); 6166 } 6167 6168 LogFlowFunc(("returns %Rrc\n", rc)); 6169 return rc; 6338 return VDCopyEx(pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename, 6339 cbSize, VD_IMAGE_CONTENT_UNKNOWN, VD_IMAGE_CONTENT_UNKNOWN, 6340 uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation, 6341 pDstVDIfsImage, pDstVDIfsOperation); 6170 6342 } 6171 6343 … … 6686 6858 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 6687 6859 6688 rc = vdReadHelper(pDisk, pImage, NULL, uOffset, pvBuf, cbRead, 6689 true /* fZeroFreeBlocks */, 6860 rc = vdReadHelper(pDisk, pImage, uOffset, pvBuf, cbRead, 6690 6861 true /* fUpdateCache */); 6691 6862 } while (0); … … 6748 6919 6749 6920 vdSetModifiedFlag(pDisk); 6750 rc = vdWriteHelper(pDisk, pImage, NULL,uOffset, pvBuf, cbWrite,6921 rc = vdWriteHelper(pDisk, pImage, uOffset, pvBuf, cbWrite, 6751 6922 true /* fUpdateCache */); 6752 6923 if (RT_FAILURE(rc)) … … 6762 6933 * as this write is covered by the previous one. */ 6763 6934 if (RT_UNLIKELY(pDisk->pImageRelay)) 6764 rc = vdWriteHelper(pDisk, pDisk->pImageRelay, NULL,uOffset,6935 rc = vdWriteHelper(pDisk, pDisk->pImageRelay, uOffset, 6765 6936 pvBuf, cbWrite, false /* fUpdateCache */); 6766 6937 } while (0);
Note:
See TracChangeset
for help on using the changeset viewer.