Changeset 16827 in vbox for trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
- Timestamp:
- Feb 17, 2009 11:01:43 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r15565 r16827 35 35 #include <iprt/string.h> 36 36 #include <iprt/rand.h> 37 #include <iprt/zip.h> 37 38 38 39 … … 74 75 /** VMDK descriptor DDB entry for parent image modification UUID. */ 75 76 #define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification" 77 78 /** No compression for streamOptimized files. */ 79 #define VMDK_COMPRESSION_NONE 0 80 81 /** Deflate compression for streamOptimized files. */ 82 #define VMDK_COMPRESSION_DEFLATE 1 83 84 /** Marker that the actual GD value is stored in the footer. */ 85 #define VMDK_GD_AT_END 0xffffffffffffffffULL 86 87 /** Marker for end-of-stream in streamOptimized images. */ 88 #define VMDK_MARKER_EOS 0 89 90 /** Marker for grain table block in streamOptimized images. */ 91 #define VMDK_MARKER_GT 1 92 93 /** Marker for grain directory block in streamOptimized images. */ 94 #define VMDK_MARKER_GD 2 95 96 /** Marker for footer in streamOptimized images. */ 97 #define VMDK_MARKER_FOOTER 3 98 99 /** Dummy marker for "don't check the marker value". */ 100 #define VMDK_MARKER_IGNORE 0xffffffffU 76 101 77 102 /** … … 104 129 char doubleEndLineChar1; 105 130 char doubleEndLineChar2; 106 uint8_t pad[435]; 131 uint16_t compressAlgorithm; 132 uint8_t pad[433]; 107 133 } SparseExtentHeader; 108 134 #pragma pack() … … 111 137 * divisible by the default grain size (64K) */ 112 138 #define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024) 139 140 /** VMDK streamOptimized file format marker. The type field may or may not 141 * be actually valid, but there's always data to read there. */ 142 #pragma pack(1) 143 typedef struct VMDKMARKER 144 { 145 uint64_t uSector; 146 uint32_t cbSize; 147 uint32_t uType; 148 } VMDKMARKER; 149 #pragma pack() 113 150 114 151 … … 256 293 uint32_t *pGD; 257 294 /** Pointer to the redundant grain directory. */ 258 uint32_t *pRGD; 295 uint32_t *pRGD; 296 /** VMDK version of this extent. 1=1.0, 3=1.1 */ 297 uint32_t uVersion; 259 298 /** Type of this extent. */ 260 299 VMDKETYPE enmType; … … 265 304 /** Flag whether the metadata in the extent header needs to be updated. */ 266 305 bool fMetaDirty; 306 /** Compression type for this extent. */ 307 uint16_t uCompression; 308 /** Starting sector of the decompressed grain buffer. */ 309 uint64_t uGrainSector; 310 /** Decompressed grain buffer for streamOptimized extents. */ 311 void *pvGrain; 267 312 /** Reference to the image in which this extent is used. Do not use this 268 313 * on a regular basis to avoid passing pImage references to functions … … 415 460 } VMDKIMAGE; 416 461 462 463 /** State for the input callout of the inflate reader. */ 464 typedef struct VMDKINFLATESTATE 465 { 466 /* File where the data is stored. */ 467 RTFILE File; 468 /* Total size of the data to read. */ 469 size_t cbSize; 470 /* Offset in the file to read. */ 471 uint64_t uFileOffset; 472 /* Current read position. */ 473 ssize_t iOffset; 474 } VMDKINFLATESTATE; 475 417 476 /******************************************************************************* 418 477 * Static Variables * … … 654 713 else 655 714 return RTFileFlush(pVmdkFile->File); 715 } 716 717 718 static DECLCALLBACK(int) vmdkFileInflateHelper(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf) 719 { 720 VMDKINFLATESTATE *pInflateState = (VMDKINFLATESTATE *)pvUser; 721 722 Assert(cbBuf); 723 if (pInflateState->iOffset < 0) 724 { 725 *(uint8_t *)pvBuf = RTZIPTYPE_ZLIB; 726 if (pcbBuf) 727 *pcbBuf = 1; 728 pInflateState->iOffset = 0; 729 return VINF_SUCCESS; 730 } 731 cbBuf = RT_MIN(cbBuf, pInflateState->cbSize); 732 int rc = RTFileReadAt(pInflateState->File, pInflateState->uFileOffset, pvBuf, cbBuf, NULL); 733 if (RT_FAILURE(rc)) 734 return rc; 735 pInflateState->uFileOffset += cbBuf; 736 pInflateState->iOffset += cbBuf; 737 pInflateState->cbSize -= cbBuf; 738 Assert(pcbBuf); 739 *pcbBuf = cbBuf; 740 return VINF_SUCCESS; 741 } 742 743 /** 744 * Internal: read from a file and inflate the compressed data, 745 * distinguishing between async and normal operation 746 */ 747 DECLINLINE(int) vmdkFileInflateAt(PVMDKFILE pVmdkFile, 748 uint64_t uOffset, void *pvBuf, 749 size_t cbToRead, unsigned uMarker, 750 uint64_t *puLBA) 751 { 752 if (pVmdkFile->fAsyncIO) 753 { 754 AssertMsgFailed(("TODO\n")); 755 return VERR_NOT_SUPPORTED; 756 } 757 else 758 { 759 int rc; 760 PRTZIPDECOMP pZip = NULL; 761 VMDKMARKER Marker; 762 uint64_t uCompOffset, cbComp; 763 VMDKINFLATESTATE InflateState; 764 size_t cbActuallyRead; 765 766 rc = RTFileReadAt(pVmdkFile->File, uOffset, &Marker, sizeof(Marker), NULL); 767 if (RT_FAILURE(rc)) 768 return rc; 769 Marker.uSector = RT_LE2H_U64(Marker.uSector); 770 Marker.cbSize = RT_LE2H_U32(Marker.cbSize); 771 if ( uMarker != VMDK_MARKER_IGNORE 772 && ( RT_LE2H_U32(Marker.uType) != uMarker 773 || Marker.cbSize != 0)) 774 return VERR_VD_VMDK_INVALID_FORMAT; 775 if (Marker.cbSize != 0) 776 { 777 /* Compressed grain marker. Data follows immediately. */ 778 uCompOffset = uOffset + 12; 779 cbComp = Marker.cbSize; 780 if (puLBA) 781 *puLBA = Marker.uSector; 782 } 783 else 784 { 785 Marker.uType = RT_LE2H_U32(Marker.uType); 786 if (Marker.uType == VMDK_MARKER_EOS) 787 { 788 Assert(uMarker != VMDK_MARKER_EOS); 789 return VERR_VD_VMDK_INVALID_FORMAT; 790 } 791 else if ( Marker.uType == VMDK_MARKER_GT 792 || Marker.uType == VMDK_MARKER_GD 793 || Marker.uType == VMDK_MARKER_FOOTER) 794 { 795 uCompOffset = uOffset + 512; 796 cbComp = VMDK_SECTOR2BYTE(Marker.uSector); 797 } 798 else 799 { 800 AssertMsgFailed(("VMDK: unknown marker type %u\n", Marker.uType)); 801 return VERR_VD_VMDK_INVALID_FORMAT; 802 } 803 } 804 InflateState.File = pVmdkFile->File; 805 InflateState.cbSize = cbComp; 806 InflateState.uFileOffset = uCompOffset; 807 InflateState.iOffset = -1; 808 /* Sanity check - the expansion ratio should be much less than 2. */ 809 Assert(cbComp < 2 * cbToRead); 810 if (cbComp >= 2 * cbToRead) 811 return VERR_VD_VMDK_INVALID_FORMAT; 812 813 rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper); 814 if (RT_FAILURE(rc)) 815 return rc; 816 rc = RTZipDecompress(pZip, pvBuf, cbToRead, &cbActuallyRead); 817 RTZipDecompDestroy(pZip); 818 if (RT_FAILURE(rc)) 819 return rc; 820 if (cbActuallyRead != cbToRead) 821 rc = VERR_VD_VMDK_INVALID_FORMAT; 822 return rc; 823 } 656 824 } 657 825 … … 797 965 } 798 966 pExtent->pGD = pGD; 967 /* The VMDK 1.1 spec talks about compressed grain directories, but real 968 * life files don't have them. The spec is wrong in creative ways. */ 799 969 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorGD), 800 970 pGD, cbGD, NULL); … … 802 972 if (RT_FAILURE(rc)) 803 973 { 804 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s' "), pExtent->pszFullname);974 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname); 805 975 goto out; 806 976 } … … 817 987 } 818 988 pExtent->pRGD = pRGD; 989 /* The VMDK 1.1 spec talks about compressed grain directories, but real 990 * life files don't have them. The spec is wrong in creative ways. */ 819 991 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorRGD), 820 992 pRGD, cbGD, NULL); … … 862 1034 goto out; 863 1035 } 1036 /* The VMDK 1.1 spec talks about compressed grain tables, but real 1037 * life files don't have them. The spec is wrong in creative ways. */ 864 1038 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp), 865 1039 pTmpGT1, cbGT, NULL); … … 871 1045 goto out; 872 1046 } 1047 /* The VMDK 1.1 spec talks about compressed grain tables, but real 1048 * life files don't have them. The spec is wrong in creative ways. */ 873 1049 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pRGDTmp), 874 1050 pTmpGT2, cbGT, NULL); … … 1670 1846 || !strcmp(pszCreateType, "twoGbMaxExtentFlat")) 1671 1847 pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_SPLIT_2G; 1672 if (!strcmp(pszCreateType, "partitionedDevice")1673 ||!strcmp(pszCreateType, "fullDevice"))1848 else if ( !strcmp(pszCreateType, "partitionedDevice") 1849 || !strcmp(pszCreateType, "fullDevice")) 1674 1850 pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_RAWDISK; 1851 else if (!strcmp(pszCreateType, "streamOptimized")) 1852 pImage->uImageFlags = VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED; 1675 1853 else 1676 1854 pImage->uImageFlags = 0; … … 1959 2137 return rc; 1960 2138 2139 /* Stream optimized images are always readonly. Nevertheless we opened the 2140 * 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 1961 2144 return VINF_SUCCESS; 1962 2145 } … … 2025 2208 2026 2209 /** 2210 * Internal: validate the consistency check values in a binary header. 2211 */ 2212 static int vmdkValidateHeader(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, const SparseExtentHeader *pHeader) 2213 { 2214 int rc = VINF_SUCCESS; 2215 if (RT_LE2H_U32(pHeader->magicNumber) != VMDK_SPARSE_MAGICNUMBER) 2216 { 2217 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic in sparse extent header in '%s'"), pExtent->pszFullname); 2218 return rc; 2219 } 2220 if (RT_LE2H_U32(pHeader->version) != 1 && RT_LE2H_U32(pHeader->version) != 3) 2221 { 2222 rc = vmdkError(pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: incorrect version in sparse extent header in '%s', not a VMDK 1.0/1.1 conforming file"), pExtent->pszFullname); 2223 return rc; 2224 } 2225 if ( (RT_LE2H_U32(pHeader->flags) & 1) 2226 && ( pHeader->singleEndLineChar != '\n' 2227 || pHeader->nonEndLineChar != ' ' 2228 || pHeader->doubleEndLineChar1 != '\r' 2229 || pHeader->doubleEndLineChar2 != '\n') ) 2230 { 2231 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname); 2232 return rc; 2233 } 2234 return rc; 2235 } 2236 2237 /** 2027 2238 * Internal: read metadata belonging to an extent with binary header, i.e. 2028 2239 * as found in monolithic files. … … 2037 2248 if (RT_FAILURE(rc)) 2038 2249 { 2039 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname); 2040 goto out; 2041 } 2042 if (RT_LE2H_U32(Header.magicNumber) != VMDK_SPARSE_MAGICNUMBER) 2043 { 2044 rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic in sparse extent header in '%s'"), pExtent->pszFullname); 2045 goto out; 2046 } 2047 if (RT_LE2H_U32(Header.version) != 1) 2048 { 2049 rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: incorrect version in sparse extent header in '%s', not a VMDK 1.0 conforming file"), pExtent->pszFullname); 2050 goto out; 2051 } 2052 if ( (RT_LE2H_U32(Header.flags) & 1) 2053 && ( Header.singleEndLineChar != '\n' 2054 || Header.nonEndLineChar != ' ' 2055 || Header.doubleEndLineChar1 != '\r' 2056 || Header.doubleEndLineChar2 != '\n') ) 2057 { 2058 rc = vmdkError(pExtent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname); 2059 goto out; 2060 } 2250 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname); 2251 goto out; 2252 } 2253 rc = vmdkValidateHeader(pImage, pExtent, &Header); 2254 if (RT_FAILURE(rc)) 2255 goto out; 2256 if ( RT_LE2H_U32(Header.flags & RT_BIT(17)) 2257 && RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END) 2258 { 2259 /* Extent with markers. Use this as criteria to read the footer, as 2260 * the spec is as usual totally fuzzy what the criteria really is. */ 2261 uint64_t cbSize; 2262 rc = vmdkFileGetSize(pExtent->pFile, &cbSize); 2263 AssertRC(rc); 2264 if (RT_FAILURE(rc)) 2265 { 2266 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname); 2267 goto out; 2268 } 2269 cbSize = RT_ALIGN_64(cbSize, 512); 2270 rc = vmdkFileInflateAt(pExtent->pFile, cbSize - 2 * 512, &Header, sizeof(Header), VMDK_MARKER_FOOTER, NULL); 2271 AssertRC(rc); 2272 if (RT_FAILURE(rc)) 2273 { 2274 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent footer in '%s'"), pExtent->pszFullname); 2275 goto out; 2276 } 2277 rc = vmdkValidateHeader(pImage, pExtent, &Header); 2278 if (RT_FAILURE(rc)) 2279 goto out; 2280 } 2281 pExtent->uVersion = RT_LE2H_U32(Header.version); 2061 2282 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */ 2062 2283 pExtent->cSectors = RT_LE2H_U64(Header.capacity); … … 2066 2287 if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors) 2067 2288 { 2068 rc = vmdkError(p Extent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);2289 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname); 2069 2290 goto out; 2070 2291 } 2071 2292 pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT); 2072 if (RT_LE2H_U32(Header.flags) & 2)2293 if (RT_LE2H_U32(Header.flags) & RT_BIT(1)) 2073 2294 { 2074 2295 pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset); … … 2077 2298 else 2078 2299 { 2079 /** @todo this is just guesswork, the spec doesn't document this 2080 * properly and I don't have a vmdk without RGD. */ 2081 pExtent->uSectorGD = RT_LE2H_U64(Header.rgdOffset); 2300 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset); 2082 2301 pExtent->uSectorRGD = 0; 2302 } 2303 if (pExtent->uSectorGD == VMDK_GD_AT_END || pExtent->uSectorRGD == VMDK_GD_AT_END) 2304 { 2305 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname); 2306 goto out; 2083 2307 } 2084 2308 pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead); 2085 2309 pExtent->fUncleanShutdown = !!Header.uncleanShutdown; 2310 pExtent->uCompression = RT_LE2H_U16(Header.compressAlgorithm); 2086 2311 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2087 2312 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX) 2088 2313 { 2089 rc = vmdkError(p Extent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);2314 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname); 2090 2315 goto out; 2091 2316 } … … 2105 2330 } 2106 2331 2332 /* streamOptimized extents need a grain decryption buffer. */ 2333 if (pExtent->uVersion == 3) 2334 { 2335 pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 2336 if (!pExtent->pvGrain) 2337 { 2338 rc = VERR_NO_MEMORY; 2339 goto out; 2340 } 2341 pExtent->uGrainSector = 0xffffffffffffffffULL; 2342 } 2343 2107 2344 out: 2108 2345 if (RT_FAILURE(rc)) … … 2127 2364 if (RT_FAILURE(rc)) 2128 2365 { 2129 rc = vmdkError(p Extent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);2366 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); 2130 2367 goto out; 2131 2368 } … … 2135 2372 && (pExtent->enmType != VMDKETYPE_FLAT || pExtent->cNominalSectors + pExtent->uSectorOffset > VMDK_BYTE2SECTOR(cbExtentSize))) 2136 2373 { 2137 rc = vmdkError(p Extent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname);2374 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname); 2138 2375 goto out; 2139 2376 } … … 2147 2384 || pExtent->cSectorsPerGrain < 8) 2148 2385 { 2149 rc = vmdkError(p Extent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);2386 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname); 2150 2387 goto out; 2151 2388 } … … 2156 2393 || pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE) 2157 2394 { 2158 rc = vmdkError(p Extent->pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);2395 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname); 2159 2396 goto out; 2160 2397 } … … 2179 2416 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER); 2180 2417 Header.version = RT_H2LE_U32(1); 2181 Header.flags = RT_H2LE_U32(1 | ((pExtent->pRGD) ? 2 : 0)); 2418 Header.flags = RT_H2LE_U32(RT_BIT(0)); 2419 if (pExtent->pRGD) 2420 Header.flags |= RT_H2LE_U32(RT_BIT(1)); 2421 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 2422 Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17)); 2182 2423 Header.capacity = RT_H2LE_U64(pExtent->cSectors); 2183 2424 Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain); … … 2193 2434 else 2194 2435 { 2195 /** @todo this is just guesswork, the spec doesn't document this 2196 * properly and I don't have a vmdk without RGD. */ 2197 Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorGD); 2436 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD); 2198 2437 } 2199 2438 Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors); … … 2203 2442 Header.doubleEndLineChar1 = '\r'; 2204 2443 Header.doubleEndLineChar2 = '\n'; 2444 Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression); 2205 2445 2206 2446 int rc = vmdkFileWriteAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL); … … 2635 2875 /* Make sure this is not reached accidentally with an error status. */ 2636 2876 AssertRC(rc); 2877 2878 /* VMDK 1.0/1.1 version paranoia. */ 2879 for (unsigned i = 0; i < pImage->cExtents; i++) 2880 { 2881 pExtent = &pImage->pExtents[i]; 2882 if ( ( pExtent->uVersion != 3 2883 && (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)) 2884 || ( pExtent->uVersion != 1 2885 && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))) 2886 { 2887 rc = vmdkError(pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: inconsistent version in extent header in '%s', not a VMDK 1.0/1.1 conforming file"), pExtent->pszFullname); 2888 goto out; 2889 } 2890 } 2637 2891 2638 2892 /* Determine PCHS geometry if not set. */ … … 2985 3239 if (RT_FAILURE(rc)) 2986 3240 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename); 2987 // @todo Is there any sense in the following line I've commented out?2988 //pImage->pszFilename = RTStrDup(pImage->pszFilename);2989 3241 } 2990 3242 else … … 4287 4539 rc = VERR_VD_BLOCK_FREE; 4288 4540 else 4289 rc = vmdkFileReadAt(pExtent->pFile, 4290 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4291 pvBuf, cbToRead, NULL); 4541 { 4542 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 4543 { 4544 uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain; 4545 uSectorExtentAbs -= uSectorInGrain; 4546 uint64_t uLBA; 4547 if (pExtent->uGrainSector != uSectorExtentAbs) 4548 { 4549 rc = vmdkFileInflateAt(pExtent->pFile, VMDK_SECTOR2BYTE(uSectorExtentAbs), 4550 pExtent->pvGrain, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain), VMDK_MARKER_IGNORE, &uLBA); 4551 if (RT_FAILURE(rc)) 4552 { 4553 pExtent->uGrainSector = 0xffffffffffffffffULL; 4554 AssertRC(rc); 4555 goto out; 4556 } 4557 pExtent->uGrainSector = uSectorExtentAbs; 4558 Assert(uLBA == uSectorExtentRel); 4559 } 4560 memcpy(pvBuf, (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), cbToRead); 4561 } 4562 else 4563 { 4564 rc = vmdkFileReadAt(pExtent->pFile, 4565 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4566 pvBuf, cbToRead, NULL); 4567 } 4568 } 4292 4569 break; 4293 4570 case VMDKETYPE_FLAT:
Note:
See TracChangeset
for help on using the changeset viewer.