- Timestamp:
- Dec 16, 2019 5:58:40 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 135480
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/QCOW.cpp
r79965 r82595 31 31 #include <iprt/path.h> 32 32 #include <iprt/list.h> 33 #include <iprt/zip.h> 33 34 34 35 #include "VDBackends.h" … … 250 251 /** Cluster size in bytes. */ 251 252 uint32_t cbCluster; 253 /** Number of bits in the virtual offset used as the cluster offset. */ 254 uint32_t cClusterBits; 255 /** Bitmask to extract the offset from a compressed cluster descriptor. */ 256 uint64_t fMaskCompressedClusterOffset; 257 /** Bitmask to extract the sector count from a compressed cluster descriptor. */ 258 uint64_t fMaskCompressedClusterSectors; 259 /** Number of bits to shift the sector count to the right to get the final value. */ 260 uint32_t cBitsShiftRCompressedClusterSectors; 252 261 /** Number of entries in the L1 table. */ 253 262 uint32_t cL1TableEntries; … … 287 296 /** Number of bits to shift to get the L2 index. */ 288 297 uint32_t cL2Shift; 298 299 /** Size of compressed cluster buffer. */ 300 size_t cbCompCluster; 301 /** Compressed cluster buffer. */ 302 void *pvCompCluster; 303 /** Buffer to hold the uncompressed data. */ 304 void *pvCluster; 289 305 290 306 /** Pointer to the L2 table we are currently allocating … … 860 876 static int qcowConvertToImageOffset(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, 861 877 uint32_t idxL1, uint32_t idxL2, 862 uint32_t offCluster, uint64_t *poffImage) 878 uint32_t offCluster, uint64_t *poffImage, 879 bool *pfCompressed, size_t *pcbCompressed) 863 880 { 864 881 int rc = VERR_VD_BLOCK_FREE; … … 886 903 { 887 904 if (RT_UNLIKELY(off & QCOW_V2_COMPRESSED_FLAG)) 888 rc = VERR_NOT_SUPPORTED; 905 { 906 size_t cCompressedClusterSectors = ((off & pImage->fMaskCompressedClusterSectors) >> pImage->cBitsShiftRCompressedClusterSectors); 907 uint64_t offImage = off & pImage->fMaskCompressedClusterOffset; 908 909 *pfCompressed = true; 910 *poffImage = offImage; 911 *pcbCompressed = (cCompressedClusterSectors + 1) * 512 - (offImage & 511ULL); 912 } 889 913 else 914 { 890 915 off &= QCOW_V2_TBL_OFFSET_MASK; 916 917 *pfCompressed = false; 918 *poffImage = off + offCluster; 919 } 891 920 } 892 921 else 893 922 { 894 923 if (RT_UNLIKELY(off & QCOW_V1_COMPRESSED_FLAG)) 895 rc = VERR_NOT_SUPPORTED; 924 { 925 size_t cCompressedClusterSectors = (off & pImage->fMaskCompressedClusterSectors) >> pImage->cBitsShiftRCompressedClusterSectors; 926 927 *pfCompressed = true; 928 *poffImage = off & pImage->fMaskCompressedClusterOffset; 929 *pcbCompressed = cCompressedClusterSectors * 512; /* Only additional sectors */ 930 /* Add remaining bytes of the sector the offset starts in. */ 931 *pcbCompressed += 512 - RT_ALIGN_64(*poffImage, 512) - *poffImage; 932 } 896 933 else 934 { 897 935 off &= ~QCOW_V1_COMPRESSED_FLAG; 936 937 *pfCompressed = false; 938 *poffImage = off + offCluster; 939 } 898 940 } 899 900 *poffImage = off + offCluster;901 941 } 902 942 else … … 1031 1071 RTStrFree(pImage->pszBackingFilename); 1032 1072 pImage->pszBackingFilename = NULL; 1073 } 1074 1075 if (pImage->pvCompCluster) 1076 { 1077 RTMemFree(pImage->pvCompCluster); 1078 pImage->pvCompCluster = NULL; 1079 pImage->cbCompCluster = 0; 1080 } 1081 1082 if (pImage->pvCluster) 1083 { 1084 RTMemFree(pImage->pvCluster); 1085 pImage->pvCluster = NULL; 1033 1086 } 1034 1087 … … 1156 1209 pImage->MTime = Header.Version.v1.u32MTime; 1157 1210 pImage->cbSize = Header.Version.v1.u64Size; 1211 pImage->cClusterBits = Header.Version.v1.u8ClusterBits; 1158 1212 pImage->cbCluster = RT_BIT_32(Header.Version.v1.u8ClusterBits); 1159 1213 pImage->cL2TableEntries = RT_BIT_32(Header.Version.v1.u8L2Bits); … … 1185 1239 pImage->cbBackingFilename = Header.Version.v2.u32BackingFileSize; 1186 1240 pImage->cbSize = Header.Version.v2.u64Size; 1241 pImage->cClusterBits = Header.Version.v2.u32ClusterBits; 1187 1242 pImage->cbCluster = RT_BIT_32(Header.Version.v2.u32ClusterBits); 1188 1243 pImage->cL2TableEntries = pImage->cbCluster / sizeof(uint64_t); … … 1193 1248 pImage->cbRefcountTable = qcowCluster2Byte(pImage, Header.Version.v2.u32RefcountTableClusters); 1194 1249 pImage->cRefcountTableEntries = pImage->cbRefcountTable / sizeof(uint64_t); 1250 1251 /* Init the masks to extract offset and sector count from a compressed cluster descriptor. */ 1252 uint32_t cBitsCompressedClusterOffset = 62 - (pImage->cClusterBits - 8); 1253 pImage->fMaskCompressedClusterOffset = RT_BIT_64(cBitsCompressedClusterOffset) - 1; 1254 pImage->fMaskCompressedClusterSectors = (RT_BIT_64(62) - 1) & ~pImage->fMaskCompressedClusterOffset; 1255 pImage->cBitsShiftRCompressedClusterSectors = cBitsCompressedClusterOffset; 1195 1256 1196 1257 if (Header.u32Version == 3) … … 1575 1636 } 1576 1637 1638 /** 1639 * Reads a compressed cluster, inflates it and copies the amount of data requested 1640 * into the given I/O context. 1641 * 1642 * @returns VBox status code. 1643 * @param pImage The image instance data. 1644 * @param pIoCtx The I/O context. 1645 * @param offCluster Where to start reading in the uncompressed cluster. 1646 * @param cbToRead How much to read in the uncomrpessed cluster. 1647 * @param offFile Offset where the compressed cluster is stored in the image. 1648 * @param cbCompressedCluster Size of the comrpessed cluster in bytes. 1649 */ 1650 static int qcowReadCompressedCluster(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, 1651 uint32_t offCluster, size_t cbToRead, 1652 uint64_t offFile, size_t cbCompressedCluster) 1653 { 1654 int rc = VINF_SUCCESS; 1655 1656 AssertReturn(!(pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO), VERR_NOT_SUPPORTED); /* Only synchronous I/O supported so far. */ 1657 1658 if (cbCompressedCluster > pImage->cbCompCluster) 1659 { 1660 void *pvCompClusterNew = RTMemRealloc(pImage->pvCompCluster, cbCompressedCluster); 1661 if (RT_LIKELY(pvCompClusterNew)) 1662 { 1663 pImage->pvCompCluster = pvCompClusterNew; 1664 pImage->cbCompCluster = cbCompressedCluster; 1665 } 1666 else 1667 rc = VERR_NO_MEMORY; 1668 } 1669 1670 if (RT_SUCCESS(rc)) 1671 { 1672 rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage, 1673 offFile, pImage->pvCompCluster, 1674 cbCompressedCluster, NULL, 1675 NULL, NULL, NULL); 1676 if (RT_SUCCESS(rc)) 1677 { 1678 if (!pImage->pvCluster) 1679 { 1680 pImage->pvCluster = RTMemAllocZ(pImage->cbCluster); 1681 if (!pImage->pvCluster) 1682 rc = VERR_NO_MEMORY; 1683 } 1684 1685 if (RT_SUCCESS(rc)) 1686 { 1687 size_t cbDecomp = 0; 1688 1689 rc = RTZipBlockDecompress(RTZIPTYPE_ZLIB_NO_HEADER, 0 /*fFlags*/, 1690 pImage->pvCompCluster, cbCompressedCluster, NULL, 1691 pImage->pvCluster, pImage->cbCluster, &cbDecomp); 1692 if (RT_SUCCESS(rc)) 1693 { 1694 Assert(cbDecomp == pImage->cbCluster); 1695 vdIfIoIntIoCtxCopyTo(pImage->pIfIo, pIoCtx, 1696 (uint8_t *)pImage->pvCluster + offCluster, 1697 cbToRead); 1698 } 1699 } 1700 } 1701 } 1702 1703 return rc; 1704 } 1705 1577 1706 /** @copydoc VDIMAGEBACKEND::pfnProbe */ 1578 1707 static DECLCALLBACK(int) qcowProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk, … … 1773 1902 1774 1903 static DECLCALLBACK(int) qcowRead(void *pBackendData, uint64_t uOffset, size_t cbToRead, 1775 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)1904 PVDIOCTX pIoCtx, size_t *pcbActuallyRead) 1776 1905 { 1777 1906 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n", … … 1796 1925 1797 1926 /* Get offset in image. */ 1798 rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offFile); 1927 bool fCompressedCluster = false; 1928 size_t cbCompressedCluster = 0; 1929 rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, 1930 &offFile, &fCompressedCluster, &cbCompressedCluster); 1799 1931 if (RT_SUCCESS(rc)) 1800 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile, 1801 pIoCtx, cbToRead); 1932 { 1933 if (!fCompressedCluster) 1934 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile, 1935 pIoCtx, cbToRead); 1936 else 1937 rc = qcowReadCompressedCluster(pImage, pIoCtx, offCluster, cbToRead, offFile, cbCompressedCluster); 1938 } 1802 1939 1803 1940 if ( ( RT_SUCCESS(rc) … … 1812 1949 1813 1950 static DECLCALLBACK(int) qcowWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite, 1814 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,1815 size_t *pcbPostRead, unsigned fWrite)1951 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead, 1952 size_t *pcbPostRead, unsigned fWrite) 1816 1953 { 1817 1954 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", … … 1840 1977 1841 1978 /* Get offset in image. */ 1842 rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, &offImage); 1979 bool fCompressedCluster = false; 1980 size_t cbCompressedCluster = 0; 1981 rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster, 1982 &offImage, &fCompressedCluster, &cbCompressedCluster); 1843 1983 if (RT_SUCCESS(rc)) 1844 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, 1845 offImage, pIoCtx, cbToWrite, NULL, NULL); 1984 { 1985 if (!fCompressedCluster) 1986 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, 1987 offImage, pIoCtx, cbToWrite, NULL, NULL); 1988 else 1989 rc = VERR_NOT_SUPPORTED; /** @todo Support writing compressed clusters */ 1990 } 1846 1991 else if (rc == VERR_VD_BLOCK_FREE) 1847 1992 {
Note:
See TracChangeset
for help on using the changeset viewer.