- Timestamp:
- Sep 12, 2016 1:34:57 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VMDK.cpp
r63785 r63798 994 994 + 8 + sizeof(VMDKMARKER), 512); 995 995 pExtent->pvCompGrain = RTMemAlloc(pExtent->cbCompGrain); 996 if (!pExtent->pvCompGrain) 997 { 996 if (RT_LIKELY(pExtent->pvCompGrain)) 997 { 998 /* streamOptimized extents need a decompressed grain buffer. */ 999 pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 1000 if (!pExtent->pvGrain) 1001 rc = VERR_NO_MEMORY; 1002 } 1003 else 998 1004 rc = VERR_NO_MEMORY; 999 goto out; 1000 } 1001 1002 /* streamOptimized extents need a decompressed grain buffer. */ 1003 pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 1004 if (!pExtent->pvGrain) 1005 { 1006 rc = VERR_NO_MEMORY; 1007 goto out; 1008 } 1009 } 1010 1011 out: 1005 } 1006 1012 1007 if (RT_FAILURE(rc)) 1013 1008 vmdkFreeStreamBuffers(pExtent); … … 1023 1018 int rc = VINF_SUCCESS; 1024 1019 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t); 1025 /** @todo r=bird: This code is unnecessarily confusing pointer states with 1026 * (1) unnecessary initialization of locals, (2) unnecesarily wide 1027 * scoping of variables, (3) instance on goto code structure. Also, 1028 * having two initialized variables on one line decreases readability. */ 1029 uint32_t *pGD = NULL, *pRGD = NULL; 1030 1031 pGD = (uint32_t *)RTMemAllocZ(cbGD); 1032 if (!pGD) 1033 { 1020 1021 pExtent->pGD = (uint32_t *)RTMemAllocZ(cbGD); 1022 if (RT_LIKELY(pExtent->pGD)) 1023 { 1024 if (pExtent->uSectorRGD) 1025 { 1026 pExtent->pRGD = (uint32_t *)RTMemAllocZ(cbGD); 1027 if (RT_UNLIKELY(!pExtent->pRGD)) 1028 rc = VERR_NO_MEMORY; 1029 } 1030 } 1031 else 1034 1032 rc = VERR_NO_MEMORY; 1035 goto out; 1036 } 1037 pExtent->pGD = pGD; 1038 1039 if (pExtent->uSectorRGD) 1040 { 1041 pRGD = (uint32_t *)RTMemAllocZ(cbGD); 1042 if (!pRGD) 1043 { 1044 rc = VERR_NO_MEMORY; 1045 goto out; 1046 } 1047 pExtent->pRGD = pRGD; 1048 } 1049 1050 out: 1033 1051 1034 if (RT_FAILURE(rc)) 1052 1035 vmdkFreeGrainDirectory(pExtent); … … 1054 1037 } 1055 1038 1039 /** 1040 * Converts the grain directory from little to host endianess. 1041 * 1042 * @returns nothing. 1043 * @param pGD The grain directory. 1044 * @param cGDEntries Number of entries in the grain directory to convert. 1045 */ 1046 DECLINLINE(void) vmdkGrainDirectoryConvToHost(uint32_t *pGD, uint32_t cGDEntries) 1047 { 1048 uint32_t *pGDTmp = pGD; 1049 1050 for (uint32_t i = 0; i < cGDEntries; i++, pGDTmp++) 1051 *pGDTmp = RT_LE2H_U32(*pGDTmp); 1052 } 1053 1054 /** 1055 * Read the grain directory and allocated grain tables verifying them against 1056 * their back up copies if available. 1057 * 1058 * @returns VBox status code. 1059 * @param pImage Image instance data. 1060 * @param pExtent The VMDK extent. 1061 */ 1056 1062 static int vmdkReadGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent) 1057 1063 { 1058 1064 int rc = VINF_SUCCESS; 1059 size_t i;1060 uint32_t *pGDTmp, *pRGDTmp;1061 1065 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t); 1062 1066 1063 if (pExtent->enmType != VMDKETYPE_HOSTED_SPARSE) 1064 goto out; 1065 1066 if ( pExtent->uSectorGD == VMDK_GD_AT_END 1067 || pExtent->uSectorRGD == VMDK_GD_AT_END) 1068 { 1069 rc = VERR_INTERNAL_ERROR; 1070 goto out; 1071 } 1067 AssertReturn(( pExtent->enmType == VMDKETYPE_HOSTED_SPARSE 1068 && pExtent->uSectorGD != VMDK_GD_AT_END 1069 && pExtent->uSectorRGD != VMDK_GD_AT_END), VERR_INTERNAL_ERROR); 1072 1070 1073 1071 rc = vmdkAllocGrainDirectory(pImage, pExtent); 1074 if (RT_FAILURE(rc)) 1075 goto out; 1076 1077 /* The VMDK 1.1 spec seems to talk about compressed grain directories, 1078 * but in reality they are not compressed. */ 1079 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1080 VMDK_SECTOR2BYTE(pExtent->uSectorGD), 1081 pExtent->pGD, cbGD); 1082 AssertRC(rc); 1083 if (RT_FAILURE(rc)) 1084 { 1085 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1086 N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname, rc); 1087 goto out; 1088 } 1089 for (i = 0, pGDTmp = pExtent->pGD; i < pExtent->cGDEntries; i++, pGDTmp++) 1090 *pGDTmp = RT_LE2H_U32(*pGDTmp); 1091 1092 if ( pExtent->uSectorRGD 1093 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)) 1072 if (RT_SUCCESS(rc)) 1094 1073 { 1095 1074 /* The VMDK 1.1 spec seems to talk about compressed grain directories, 1096 1075 * but in reality they are not compressed. */ 1097 1076 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1098 VMDK_SECTOR2BYTE(pExtent->uSectorRGD), 1099 pExtent->pRGD, cbGD); 1100 AssertRC(rc); 1101 if (RT_FAILURE(rc)) 1102 { 1103 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1104 N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname); 1105 goto out; 1106 } 1107 for (i = 0, pRGDTmp = pExtent->pRGD; i < pExtent->cGDEntries; i++, pRGDTmp++) 1108 *pRGDTmp = RT_LE2H_U32(*pRGDTmp); 1109 1110 /* Check grain table and redundant grain table for consistency. */ 1111 size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t); 1112 size_t cbGTBuffers = cbGT; /* Start with space for one GT. */ 1113 size_t cbGTBuffersMax = _1M; 1114 1115 uint32_t *pTmpGT1 = (uint32_t *)RTMemAlloc(cbGTBuffers); 1116 uint32_t *pTmpGT2 = (uint32_t *)RTMemAlloc(cbGTBuffers); 1117 1118 if ( !pTmpGT1 1119 || !pTmpGT2) 1120 rc = VERR_NO_MEMORY; 1121 1122 i = 0; 1123 pGDTmp = pExtent->pGD; 1124 pRGDTmp = pExtent->pRGD; 1125 1126 /* Loop through all entries. */ 1127 while (i < pExtent->cGDEntries) 1128 { 1129 uint32_t uGTStart = *pGDTmp; 1130 uint32_t uRGTStart = *pRGDTmp; 1131 size_t cbGTRead = cbGT; 1132 1133 /* If no grain table is allocated skip the entry. */ 1134 if (*pGDTmp == 0 && *pRGDTmp == 0) 1077 VMDK_SECTOR2BYTE(pExtent->uSectorGD), 1078 pExtent->pGD, cbGD); 1079 if (RT_SUCCESS(rc)) 1080 { 1081 vmdkGrainDirectoryConvToHost(pExtent->pGD, pExtent->cGDEntries); 1082 1083 if ( pExtent->uSectorRGD 1084 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)) 1135 1085 { 1136 i++; 1137 continue; 1138 } 1139 1140 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp) 1141 { 1142 /* Just one grain directory entry refers to a not yet allocated 1143 * grain table or both grain directory copies refer to the same 1144 * grain table. Not allowed. */ 1145 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname); 1146 break; 1147 } 1148 1149 i++; 1150 pGDTmp++; 1151 pRGDTmp++; 1152 1153 /* 1154 * Read a few tables at once if adjacent to decrease the number 1155 * of I/O requests. Read at maximum 1MB at once. 1156 */ 1157 while ( i < pExtent->cGDEntries 1158 && cbGTRead < cbGTBuffersMax) 1159 { 1160 /* If no grain table is allocated skip the entry. */ 1161 if (*pGDTmp == 0 && *pRGDTmp == 0) 1086 /* The VMDK 1.1 spec seems to talk about compressed grain directories, 1087 * but in reality they are not compressed. */ 1088 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1089 VMDK_SECTOR2BYTE(pExtent->uSectorRGD), 1090 pExtent->pRGD, cbGD); 1091 if (RT_SUCCESS(rc)) 1162 1092 { 1163 i++; 1164 continue; 1165 } 1166 1167 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp) 1168 { 1169 /* Just one grain directory entry refers to a not yet allocated 1170 * grain table or both grain directory copies refer to the same 1171 * grain table. Not allowed. */ 1172 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname); 1173 break; 1174 } 1175 1176 /* Check that the start offsets are adjacent.*/ 1177 if ( VMDK_SECTOR2BYTE(uGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pGDTmp) 1178 || VMDK_SECTOR2BYTE(uRGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pRGDTmp)) 1179 break; 1180 1181 i++; 1182 pGDTmp++; 1183 pRGDTmp++; 1184 cbGTRead += cbGT; 1185 } 1186 1187 /* Increase buffers if required. */ 1188 if ( RT_SUCCESS(rc) 1189 && cbGTBuffers < cbGTRead) 1190 { 1191 uint32_t *pTmp; 1192 pTmp = (uint32_t *)RTMemRealloc(pTmpGT1, cbGTRead); 1193 if (pTmp) 1194 { 1195 pTmpGT1 = pTmp; 1196 pTmp = (uint32_t *)RTMemRealloc(pTmpGT2, cbGTRead); 1197 if (pTmp) 1198 pTmpGT2 = pTmp; 1199 else 1093 vmdkGrainDirectoryConvToHost(pExtent->pRGD, pExtent->cGDEntries); 1094 1095 /* Check grain table and redundant grain table for consistency. */ 1096 size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t); 1097 size_t cbGTBuffers = cbGT; /* Start with space for one GT. */ 1098 size_t cbGTBuffersMax = _1M; 1099 1100 uint32_t *pTmpGT1 = (uint32_t *)RTMemAlloc(cbGTBuffers); 1101 uint32_t *pTmpGT2 = (uint32_t *)RTMemAlloc(cbGTBuffers); 1102 1103 if ( !pTmpGT1 1104 || !pTmpGT2) 1200 1105 rc = VERR_NO_MEMORY; 1106 1107 uint32_t i = 0; 1108 uint32_t *pGDTmp = pExtent->pGD; 1109 uint32_t *pRGDTmp = pExtent->pRGD; 1110 1111 /* Loop through all entries. */ 1112 while (i < pExtent->cGDEntries) 1113 { 1114 uint32_t uGTStart = *pGDTmp; 1115 uint32_t uRGTStart = *pRGDTmp; 1116 size_t cbGTRead = cbGT; 1117 1118 /* If no grain table is allocated skip the entry. */ 1119 if (*pGDTmp == 0 && *pRGDTmp == 0) 1120 { 1121 i++; 1122 continue; 1123 } 1124 1125 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp) 1126 { 1127 /* Just one grain directory entry refers to a not yet allocated 1128 * grain table or both grain directory copies refer to the same 1129 * grain table. Not allowed. */ 1130 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1131 N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname); 1132 break; 1133 } 1134 1135 i++; 1136 pGDTmp++; 1137 pRGDTmp++; 1138 1139 /* 1140 * Read a few tables at once if adjacent to decrease the number 1141 * of I/O requests. Read at maximum 1MB at once. 1142 */ 1143 while ( i < pExtent->cGDEntries 1144 && cbGTRead < cbGTBuffersMax) 1145 { 1146 /* If no grain table is allocated skip the entry. */ 1147 if (*pGDTmp == 0 && *pRGDTmp == 0) 1148 { 1149 i++; 1150 continue; 1151 } 1152 1153 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp) 1154 { 1155 /* Just one grain directory entry refers to a not yet allocated 1156 * grain table or both grain directory copies refer to the same 1157 * grain table. Not allowed. */ 1158 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1159 N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname); 1160 break; 1161 } 1162 1163 /* Check that the start offsets are adjacent.*/ 1164 if ( VMDK_SECTOR2BYTE(uGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pGDTmp) 1165 || VMDK_SECTOR2BYTE(uRGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pRGDTmp)) 1166 break; 1167 1168 i++; 1169 pGDTmp++; 1170 pRGDTmp++; 1171 cbGTRead += cbGT; 1172 } 1173 1174 /* Increase buffers if required. */ 1175 if ( RT_SUCCESS(rc) 1176 && cbGTBuffers < cbGTRead) 1177 { 1178 uint32_t *pTmp; 1179 pTmp = (uint32_t *)RTMemRealloc(pTmpGT1, cbGTRead); 1180 if (pTmp) 1181 { 1182 pTmpGT1 = pTmp; 1183 pTmp = (uint32_t *)RTMemRealloc(pTmpGT2, cbGTRead); 1184 if (pTmp) 1185 pTmpGT2 = pTmp; 1186 else 1187 rc = VERR_NO_MEMORY; 1188 } 1189 else 1190 rc = VERR_NO_MEMORY; 1191 1192 if (rc == VERR_NO_MEMORY) 1193 { 1194 /* Reset to the old values. */ 1195 rc = VINF_SUCCESS; 1196 i -= cbGTRead / cbGT; 1197 cbGTRead = cbGT; 1198 1199 /* Don't try to increase the buffer again in the next run. */ 1200 cbGTBuffersMax = cbGTBuffers; 1201 } 1202 } 1203 1204 if (RT_SUCCESS(rc)) 1205 { 1206 /* The VMDK 1.1 spec seems to talk about compressed grain tables, 1207 * but in reality they are not compressed. */ 1208 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1209 VMDK_SECTOR2BYTE(uGTStart), 1210 pTmpGT1, cbGTRead); 1211 if (RT_FAILURE(rc)) 1212 { 1213 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1214 N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname); 1215 break; 1216 } 1217 /* The VMDK 1.1 spec seems to talk about compressed grain tables, 1218 * but in reality they are not compressed. */ 1219 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1220 VMDK_SECTOR2BYTE(uRGTStart), 1221 pTmpGT2, cbGTRead); 1222 if (RT_FAILURE(rc)) 1223 { 1224 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1225 N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname); 1226 break; 1227 } 1228 if (memcmp(pTmpGT1, pTmpGT2, cbGTRead)) 1229 { 1230 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1231 N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname); 1232 break; 1233 } 1234 } 1235 } /* while (i < pExtent->cGDEntries) */ 1236 1237 /** @todo figure out what to do for unclean VMDKs. */ 1238 if (pTmpGT1) 1239 RTMemFree(pTmpGT1); 1240 if (pTmpGT2) 1241 RTMemFree(pTmpGT2); 1201 1242 } 1202 1243 else 1203 rc = VERR_NO_MEMORY; 1204 1205 if (rc == VERR_NO_MEMORY) 1206 { 1207 /* Reset to the old values. */ 1208 rc = VINF_SUCCESS; 1209 i -= cbGTRead / cbGT; 1210 cbGTRead = cbGT; 1211 1212 /* Don't try to increase the buffer again in the next run. */ 1213 cbGTBuffersMax = cbGTBuffers; 1214 } 1244 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1245 N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname); 1215 1246 } 1216 1217 if (RT_SUCCESS(rc)) 1218 { 1219 /* The VMDK 1.1 spec seems to talk about compressed grain tables, 1220 * but in reality they are not compressed. */ 1221 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1222 VMDK_SECTOR2BYTE(uGTStart), 1223 pTmpGT1, cbGTRead); 1224 if (RT_FAILURE(rc)) 1225 { 1226 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1227 N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname); 1228 break; 1229 } 1230 /* The VMDK 1.1 spec seems to talk about compressed grain tables, 1231 * but in reality they are not compressed. */ 1232 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 1233 VMDK_SECTOR2BYTE(uRGTStart), 1234 pTmpGT2, cbGTRead); 1235 if (RT_FAILURE(rc)) 1236 { 1237 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1238 N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname); 1239 break; 1240 } 1241 if (memcmp(pTmpGT1, pTmpGT2, cbGTRead)) 1242 { 1243 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1244 N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname); 1245 break; 1246 } 1247 } 1248 } /* while (i < pExtent->cGDEntries) */ 1249 1250 /** @todo figure out what to do for unclean VMDKs. */ 1251 if (pTmpGT1) 1252 RTMemFree(pTmpGT1); 1253 if (pTmpGT2) 1254 RTMemFree(pTmpGT2); 1255 } 1256 1257 out: 1247 } 1248 else 1249 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, 1250 N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname, rc); 1251 } 1252 1258 1253 if (RT_FAILURE(rc)) 1259 1254 vmdkFreeGrainDirectory(pExtent); … … 1261 1256 } 1262 1257 1258 /** 1259 * Creates a new grain directory for the given extent at the given start sector. 1260 * 1261 * @returns VBox status code. 1262 * @param pImage Image instance data. 1263 * @param pExtent The VMDK extent. 1264 * @param uStartSector Where the grain directory should be stored in the image. 1265 * @param fPreAlloc Flag whether to pre allocate the grain tables at this point. 1266 */ 1263 1267 static int vmdkCreateGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 1264 1268 uint64_t uStartSector, bool fPreAlloc) … … 1274 1278 { 1275 1279 cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512); 1276 cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded 1277 + cbGTRounded; 1280 cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded + cbGTRounded; 1278 1281 } 1279 1282 else … … 1300 1303 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead); 1301 1304 } 1302 if (RT_FAILURE(rc)) 1303 goto out; 1304 pExtent->uAppendPosition = cbOverhead; 1305 pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead); 1306 1307 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 1308 { 1309 pExtent->uSectorRGD = 0; 1310 pExtent->uSectorGD = uStartSector; 1311 } 1312 else 1313 { 1314 pExtent->uSectorRGD = uStartSector; 1315 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded); 1316 } 1317 1318 rc = vmdkAllocStreamBuffers(pImage, pExtent); 1319 if (RT_FAILURE(rc)) 1320 goto out; 1321 1322 rc = vmdkAllocGrainDirectory(pImage, pExtent); 1323 if (RT_FAILURE(rc)) 1324 goto out; 1325 1326 if (fPreAlloc) 1327 { 1328 uint32_t uGTSectorLE; 1329 uint64_t uOffsetSectors; 1330 1331 if (pExtent->pRGD) 1332 { 1333 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded); 1334 for (i = 0; i < pExtent->cGDEntries; i++) 1305 1306 if (RT_SUCCESS(rc)) 1307 { 1308 pExtent->uAppendPosition = cbOverhead; 1309 pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead); 1310 1311 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 1312 { 1313 pExtent->uSectorRGD = 0; 1314 pExtent->uSectorGD = uStartSector; 1315 } 1316 else 1317 { 1318 pExtent->uSectorRGD = uStartSector; 1319 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded); 1320 } 1321 1322 rc = vmdkAllocStreamBuffers(pImage, pExtent); 1323 if (RT_SUCCESS(rc)) 1324 { 1325 rc = vmdkAllocGrainDirectory(pImage, pExtent); 1326 if ( RT_SUCCESS(rc) 1327 && fPreAlloc) 1335 1328 { 1336 pExtent->pRGD[i] = uOffsetSectors; 1337 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 1338 /* Write the redundant grain directory entry to disk. */ 1339 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 1340 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), 1341 &uGTSectorLE, sizeof(uGTSectorLE)); 1342 if (RT_FAILURE(rc)) 1329 uint32_t uGTSectorLE; 1330 uint64_t uOffsetSectors; 1331 1332 if (pExtent->pRGD) 1343 1333 { 1344 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname); 1345 goto out; 1334 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded); 1335 for (i = 0; i < pExtent->cGDEntries; i++) 1336 { 1337 pExtent->pRGD[i] = uOffsetSectors; 1338 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 1339 /* Write the redundant grain directory entry to disk. */ 1340 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 1341 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), 1342 &uGTSectorLE, sizeof(uGTSectorLE)); 1343 if (RT_FAILURE(rc)) 1344 { 1345 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname); 1346 break; 1347 } 1348 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)); 1349 } 1346 1350 } 1347 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)); 1351 1352 if (RT_SUCCESS(rc)) 1353 { 1354 uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded); 1355 for (i = 0; i < pExtent->cGDEntries; i++) 1356 { 1357 pExtent->pGD[i] = uOffsetSectors; 1358 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 1359 /* Write the grain directory entry to disk. */ 1360 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 1361 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), 1362 &uGTSectorLE, sizeof(uGTSectorLE)); 1363 if (RT_FAILURE(rc)) 1364 { 1365 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname); 1366 break; 1367 } 1368 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)); 1369 } 1370 } 1348 1371 } 1349 1372 } 1350 1351 uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded); 1352 for (i = 0; i < pExtent->cGDEntries; i++) 1353 { 1354 pExtent->pGD[i] = uOffsetSectors; 1355 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 1356 /* Write the grain directory entry to disk. */ 1357 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, 1358 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), 1359 &uGTSectorLE, sizeof(uGTSectorLE)); 1360 if (RT_FAILURE(rc)) 1361 { 1362 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname); 1363 goto out; 1364 } 1365 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)); 1366 } 1367 } 1368 1369 out: 1373 } 1374 1370 1375 if (RT_FAILURE(rc)) 1371 1376 vmdkFreeGrainDirectory(pExtent); … … 1825 1830 } 1826 1831 1827 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, 1828 size_t cbDescData, 1829 PVMDKDESCRIPTOR pDescriptor) 1830 { 1832 /** 1833 * Splits the descriptor data into individual lines checking for correct line 1834 * endings and descriptor size. 1835 * 1836 * @returns VBox status code. 1837 * @param pImage The image instance. 1838 * @param pDesc The descriptor. 1839 * @param pszTmp The raw descriptor data from the image. 1840 */ 1841 static int vmdkDescSplitLines(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDesc, char *pszTmp) 1842 { 1843 unsigned cLine = 0; 1831 1844 int rc = VINF_SUCCESS; 1832 unsigned cLine = 0, uLastNonEmptyLine = 0; 1833 char *pTmp = pDescData; 1834 1835 pDescriptor->cbDescAlloc = cbDescData; 1836 while (*pTmp != '\0') 1837 { 1838 pDescriptor->aLines[cLine++] = pTmp; 1845 1846 while ( RT_SUCCESS(rc) 1847 && *pszTmp != '\0') 1848 { 1849 pDesc->aLines[cLine++] = pszTmp; 1839 1850 if (cLine >= VMDK_DESCRIPTOR_LINES_MAX) 1840 1851 { 1841 1852 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename); 1842 goto out;1843 } 1844 1845 while (*p Tmp != '\0' && *pTmp != '\n')1846 { 1847 if (*p Tmp == '\r')1853 break; 1854 } 1855 1856 while (*pszTmp != '\0' && *pszTmp != '\n') 1857 { 1858 if (*pszTmp == '\r') 1848 1859 { 1849 if (*(p Tmp + 1) != '\n')1860 if (*(pszTmp + 1) != '\n') 1850 1861 { 1851 1862 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor in '%s'"), pImage->pszFilename); 1852 goto out;1863 break; 1853 1864 } 1854 1865 else 1855 1866 { 1856 1867 /* Get rid of CR character. */ 1857 *p Tmp = '\0';1868 *pszTmp = '\0'; 1858 1869 } 1859 1870 } 1860 p Tmp++;1871 pszTmp++; 1861 1872 } 1862 1873 /* Get rid of LF character. */ 1863 if (*pTmp == '\n') 1864 { 1865 *pTmp = '\0'; 1866 pTmp++; 1867 } 1868 } 1869 pDescriptor->cLines = cLine; 1870 /* Pointer right after the end of the used part of the buffer. */ 1871 pDescriptor->aLines[cLine] = pTmp; 1872 1873 if ( strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile") 1874 && strcmp(pDescriptor->aLines[0], "# Disk Descriptor File")) 1875 { 1876 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename); 1877 goto out; 1878 } 1879 1880 /* Initialize those, because we need to be able to reopen an image. */ 1881 pDescriptor->uFirstDesc = 0; 1882 pDescriptor->uFirstExtent = 0; 1883 pDescriptor->uFirstDDB = 0; 1884 for (unsigned i = 0; i < cLine; i++) 1885 { 1886 if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0') 1887 { 1888 if ( !strncmp(pDescriptor->aLines[i], "RW", 2) 1889 || !strncmp(pDescriptor->aLines[i], "RDONLY", 6) 1890 || !strncmp(pDescriptor->aLines[i], "NOACCESS", 8) ) 1874 if (*pszTmp == '\n') 1875 { 1876 *pszTmp = '\0'; 1877 pszTmp++; 1878 } 1879 } 1880 1881 if (RT_SUCCESS(rc)) 1882 { 1883 pDesc->cLines = cLine; 1884 /* Pointer right after the end of the used part of the buffer. */ 1885 pDesc->aLines[cLine] = pszTmp; 1886 } 1887 1888 return rc; 1889 } 1890 1891 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, 1892 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor) 1893 { 1894 pDescriptor->cbDescAlloc = cbDescData; 1895 int rc = vmdkDescSplitLines(pImage, pDescriptor, pDescData); 1896 if (RT_SUCCESS(rc)) 1897 { 1898 if ( strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile") 1899 && strcmp(pDescriptor->aLines[0], "# Disk Descriptor File")) 1900 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1901 N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename); 1902 else 1903 { 1904 unsigned uLastNonEmptyLine = 0; 1905 1906 /* Initialize those, because we need to be able to reopen an image. */ 1907 pDescriptor->uFirstDesc = 0; 1908 pDescriptor->uFirstExtent = 0; 1909 pDescriptor->uFirstDDB = 0; 1910 for (unsigned i = 0; i < pDescriptor->cLines; i++) 1891 1911 { 1892 /* An extent descriptor. */ 1893 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB) 1912 if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0') 1894 1913 { 1895 /* Incorrect ordering of entries. */ 1896 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename); 1897 goto out; 1898 } 1899 if (!pDescriptor->uFirstExtent) 1900 { 1901 pDescriptor->uFirstExtent = i; 1902 uLastNonEmptyLine = 0; 1914 if ( !strncmp(pDescriptor->aLines[i], "RW", 2) 1915 || !strncmp(pDescriptor->aLines[i], "RDONLY", 6) 1916 || !strncmp(pDescriptor->aLines[i], "NOACCESS", 8) ) 1917 { 1918 /* An extent descriptor. */ 1919 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB) 1920 { 1921 /* Incorrect ordering of entries. */ 1922 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1923 N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename); 1924 break; 1925 } 1926 if (!pDescriptor->uFirstExtent) 1927 { 1928 pDescriptor->uFirstExtent = i; 1929 uLastNonEmptyLine = 0; 1930 } 1931 } 1932 else if (!strncmp(pDescriptor->aLines[i], "ddb.", 4)) 1933 { 1934 /* A disk database entry. */ 1935 if (!pDescriptor->uFirstDesc || !pDescriptor->uFirstExtent) 1936 { 1937 /* Incorrect ordering of entries. */ 1938 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1939 N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename); 1940 break; 1941 } 1942 if (!pDescriptor->uFirstDDB) 1943 { 1944 pDescriptor->uFirstDDB = i; 1945 uLastNonEmptyLine = 0; 1946 } 1947 } 1948 else 1949 { 1950 /* A normal entry. */ 1951 if (pDescriptor->uFirstExtent || pDescriptor->uFirstDDB) 1952 { 1953 /* Incorrect ordering of entries. */ 1954 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 1955 N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename); 1956 break; 1957 } 1958 if (!pDescriptor->uFirstDesc) 1959 { 1960 pDescriptor->uFirstDesc = i; 1961 uLastNonEmptyLine = 0; 1962 } 1963 } 1964 if (uLastNonEmptyLine) 1965 pDescriptor->aNextLines[uLastNonEmptyLine] = i; 1966 uLastNonEmptyLine = i; 1903 1967 } 1904 1968 } 1905 else if (!strncmp(pDescriptor->aLines[i], "ddb.", 4)) 1906 { 1907 /* A disk database entry. */ 1908 if (!pDescriptor->uFirstDesc || !pDescriptor->uFirstExtent) 1909 { 1910 /* Incorrect ordering of entries. */ 1911 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename); 1912 goto out; 1913 } 1914 if (!pDescriptor->uFirstDDB) 1915 { 1916 pDescriptor->uFirstDDB = i; 1917 uLastNonEmptyLine = 0; 1918 } 1919 } 1920 else 1921 { 1922 /* A normal entry. */ 1923 if (pDescriptor->uFirstExtent || pDescriptor->uFirstDDB) 1924 { 1925 /* Incorrect ordering of entries. */ 1926 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename); 1927 goto out; 1928 } 1929 if (!pDescriptor->uFirstDesc) 1930 { 1931 pDescriptor->uFirstDesc = i; 1932 uLastNonEmptyLine = 0; 1933 } 1934 } 1935 if (uLastNonEmptyLine) 1936 pDescriptor->aNextLines[uLastNonEmptyLine] = i; 1937 uLastNonEmptyLine = i; 1938 } 1939 } 1940 1941 out: 1969 } 1970 } 1971 1942 1972 return rc; 1943 1973 } … … 1985 2015 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor) 1986 2016 { 1987 int rc;1988 1989 2017 pDescriptor->uFirstDesc = 0; 1990 2018 pDescriptor->uFirstExtent = 0; … … 1996 2024 memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines)); 1997 2025 1998 rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile"); 1999 if (RT_FAILURE(rc)) 2000 goto out; 2001 rc = vmdkDescInitStr(pImage, pDescriptor, "version=1"); 2002 if (RT_FAILURE(rc)) 2003 goto out; 2004 pDescriptor->uFirstDesc = pDescriptor->cLines - 1; 2005 rc = vmdkDescInitStr(pImage, pDescriptor, ""); 2006 if (RT_FAILURE(rc)) 2007 goto out; 2008 rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description"); 2009 if (RT_FAILURE(rc)) 2010 goto out; 2011 rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO "); 2012 if (RT_FAILURE(rc)) 2013 goto out; 2014 pDescriptor->uFirstExtent = pDescriptor->cLines - 1; 2015 rc = vmdkDescInitStr(pImage, pDescriptor, ""); 2016 if (RT_FAILURE(rc)) 2017 goto out; 2018 /* The trailing space is created by VMware, too. */ 2019 rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base "); 2020 if (RT_FAILURE(rc)) 2021 goto out; 2022 rc = vmdkDescInitStr(pImage, pDescriptor, "#DDB"); 2023 if (RT_FAILURE(rc)) 2024 goto out; 2025 rc = vmdkDescInitStr(pImage, pDescriptor, ""); 2026 if (RT_FAILURE(rc)) 2027 goto out; 2028 rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\""); 2029 if (RT_FAILURE(rc)) 2030 goto out; 2031 pDescriptor->uFirstDDB = pDescriptor->cLines - 1; 2032 2033 /* Now that the framework is in place, use the normal functions to insert 2034 * the remaining keys. */ 2035 char szBuf[9]; 2036 RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32()); 2037 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, 2038 "CID", szBuf); 2039 if (RT_FAILURE(rc)) 2040 goto out; 2041 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, 2042 "parentCID", "ffffffff"); 2043 if (RT_FAILURE(rc)) 2044 goto out; 2045 2046 rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide"); 2047 if (RT_FAILURE(rc)) 2048 goto out; 2049 2050 out: 2026 int rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile"); 2027 if (RT_SUCCESS(rc)) 2028 rc = vmdkDescInitStr(pImage, pDescriptor, "version=1"); 2029 if (RT_SUCCESS(rc)) 2030 { 2031 pDescriptor->uFirstDesc = pDescriptor->cLines - 1; 2032 rc = vmdkDescInitStr(pImage, pDescriptor, ""); 2033 } 2034 if (RT_SUCCESS(rc)) 2035 rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description"); 2036 if (RT_SUCCESS(rc)) 2037 rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO "); 2038 if (RT_SUCCESS(rc)) 2039 { 2040 pDescriptor->uFirstExtent = pDescriptor->cLines - 1; 2041 rc = vmdkDescInitStr(pImage, pDescriptor, ""); 2042 } 2043 if (RT_SUCCESS(rc)) 2044 { 2045 /* The trailing space is created by VMware, too. */ 2046 rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base "); 2047 } 2048 if (RT_SUCCESS(rc)) 2049 rc = vmdkDescInitStr(pImage, pDescriptor, "#DDB"); 2050 if (RT_SUCCESS(rc)) 2051 rc = vmdkDescInitStr(pImage, pDescriptor, ""); 2052 if (RT_SUCCESS(rc)) 2053 rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\""); 2054 if (RT_SUCCESS(rc)) 2055 { 2056 pDescriptor->uFirstDDB = pDescriptor->cLines - 1; 2057 2058 /* Now that the framework is in place, use the normal functions to insert 2059 * the remaining keys. */ 2060 char szBuf[9]; 2061 RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32()); 2062 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, 2063 "CID", szBuf); 2064 } 2065 if (RT_SUCCESS(rc)) 2066 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, 2067 "parentCID", "ffffffff"); 2068 if (RT_SUCCESS(rc)) 2069 rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide"); 2070 2051 2071 return rc; 2052 2072 } 2053 2073 2054 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, 2055 size_t cbDescData) 2074 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData) 2056 2075 { 2057 2076 int rc; … … 2547 2566 { 2548 2567 SparseExtentHeader Header; 2549 uint64_t cSectorsPerGDE;2550 uint64_t cbFile = 0;2551 2568 int rc; 2552 2569 … … 2563 2580 - RT_OFFSETOF(SparseExtentHeader, version)); 2564 2581 } 2565 AssertRC(rc); 2566 if (RT_FAILURE(rc)) 2582 2583 if (RT_SUCCESS(rc)) 2584 { 2585 rc = vmdkValidateHeader(pImage, pExtent, &Header); 2586 if (RT_SUCCESS(rc)) 2587 { 2588 uint64_t cbFile = 0; 2589 2590 if ( (RT_LE2H_U32(Header.flags) & RT_BIT(17)) 2591 && RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END) 2592 pExtent->fFooter = true; 2593 2594 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2595 || ( pExtent->fFooter 2596 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))) 2597 { 2598 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbFile); 2599 if (RT_FAILURE(rc)) 2600 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname); 2601 } 2602 2603 if (RT_SUCCESS(rc)) 2604 { 2605 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 2606 pExtent->uAppendPosition = RT_ALIGN_64(cbFile, 512); 2607 2608 if ( pExtent->fFooter 2609 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2610 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))) 2611 { 2612 /* Read the footer, which comes before the end-of-stream marker. */ 2613 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 2614 cbFile - 2*512, &Header, 2615 sizeof(Header)); 2616 if (RT_FAILURE(rc)) 2617 { 2618 vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading extent footer in '%s'"), pExtent->pszFullname); 2619 rc = VERR_VD_VMDK_INVALID_HEADER; 2620 } 2621 2622 if (RT_SUCCESS(rc)) 2623 rc = vmdkValidateHeader(pImage, pExtent, &Header); 2624 /* Prohibit any writes to this extent. */ 2625 pExtent->uAppendPosition = 0; 2626 } 2627 2628 if (RT_SUCCESS(rc)) 2629 { 2630 pExtent->uVersion = RT_LE2H_U32(Header.version); 2631 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */ 2632 pExtent->cSectors = RT_LE2H_U64(Header.capacity); 2633 pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize); 2634 pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset); 2635 pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize); 2636 pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT); 2637 pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead); 2638 pExtent->fUncleanShutdown = !!Header.uncleanShutdown; 2639 pExtent->uCompression = RT_LE2H_U16(Header.compressAlgorithm); 2640 if (RT_LE2H_U32(Header.flags) & RT_BIT(1)) 2641 { 2642 pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset); 2643 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset); 2644 } 2645 else 2646 { 2647 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset); 2648 pExtent->uSectorRGD = 0; 2649 } 2650 2651 if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors) 2652 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 2653 N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname); 2654 2655 if ( RT_SUCCESS(rc) 2656 && ( pExtent->uSectorGD == VMDK_GD_AT_END 2657 || pExtent->uSectorRGD == VMDK_GD_AT_END) 2658 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2659 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))) 2660 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 2661 N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname); 2662 2663 if (RT_SUCCESS(rc)) 2664 { 2665 uint64_t cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2666 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX) 2667 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 2668 N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname); 2669 else 2670 { 2671 pExtent->cSectorsPerGDE = cSectorsPerGDE; 2672 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 2673 2674 /* Fix up the number of descriptor sectors, as some flat images have 2675 * really just one, and this causes failures when inserting the UUID 2676 * values and other extra information. */ 2677 if (pExtent->cDescriptorSectors != 0 && pExtent->cDescriptorSectors < 4) 2678 { 2679 /* Do it the easy way - just fix it for flat images which have no 2680 * other complicated metadata which needs space too. */ 2681 if ( pExtent->uDescriptorSector + 4 < pExtent->cOverheadSectors 2682 && pExtent->cGTEntries * pExtent->cGDEntries == 0) 2683 pExtent->cDescriptorSectors = 4; 2684 } 2685 } 2686 } 2687 } 2688 } 2689 } 2690 } 2691 else 2567 2692 { 2568 2693 vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname); 2569 2694 rc = VERR_VD_VMDK_INVALID_HEADER; 2570 goto out; 2571 } 2572 rc = vmdkValidateHeader(pImage, pExtent, &Header); 2573 if (RT_FAILURE(rc)) 2574 goto out; 2575 2576 if ( (RT_LE2H_U32(Header.flags) & RT_BIT(17)) 2577 && RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END) 2578 pExtent->fFooter = true; 2579 2580 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2581 || ( pExtent->fFooter 2582 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))) 2583 { 2584 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbFile); 2585 AssertRC(rc); 2586 if (RT_FAILURE(rc)) 2587 { 2588 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname); 2589 goto out; 2590 } 2591 } 2592 2593 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 2594 pExtent->uAppendPosition = RT_ALIGN_64(cbFile, 512); 2595 2596 if ( pExtent->fFooter 2597 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2598 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))) 2599 { 2600 /* Read the footer, which comes before the end-of-stream marker. */ 2601 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 2602 cbFile - 2*512, &Header, 2603 sizeof(Header)); 2604 AssertRC(rc); 2605 if (RT_FAILURE(rc)) 2606 { 2607 vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading extent footer in '%s'"), pExtent->pszFullname); 2608 rc = VERR_VD_VMDK_INVALID_HEADER; 2609 goto out; 2610 } 2611 rc = vmdkValidateHeader(pImage, pExtent, &Header); 2612 if (RT_FAILURE(rc)) 2613 goto out; 2614 /* Prohibit any writes to this extent. */ 2615 pExtent->uAppendPosition = 0; 2616 } 2617 2618 pExtent->uVersion = RT_LE2H_U32(Header.version); 2619 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */ 2620 pExtent->cSectors = RT_LE2H_U64(Header.capacity); 2621 pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize); 2622 pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset); 2623 pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize); 2624 if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors) 2625 { 2626 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname); 2627 goto out; 2628 } 2629 pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT); 2630 if (RT_LE2H_U32(Header.flags) & RT_BIT(1)) 2631 { 2632 pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset); 2633 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset); 2634 } 2635 else 2636 { 2637 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset); 2638 pExtent->uSectorRGD = 0; 2639 } 2640 if ( ( pExtent->uSectorGD == VMDK_GD_AT_END 2641 || pExtent->uSectorRGD == VMDK_GD_AT_END) 2642 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2643 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))) 2644 { 2645 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname); 2646 goto out; 2647 } 2648 pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead); 2649 pExtent->fUncleanShutdown = !!Header.uncleanShutdown; 2650 pExtent->uCompression = RT_LE2H_U16(Header.compressAlgorithm); 2651 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2652 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX) 2653 { 2654 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname); 2655 goto out; 2656 } 2657 pExtent->cSectorsPerGDE = cSectorsPerGDE; 2658 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 2659 2660 /* Fix up the number of descriptor sectors, as some flat images have 2661 * really just one, and this causes failures when inserting the UUID 2662 * values and other extra information. */ 2663 if (pExtent->cDescriptorSectors != 0 && pExtent->cDescriptorSectors < 4) 2664 { 2665 /* Do it the easy way - just fix it for flat images which have no 2666 * other complicated metadata which needs space too. */ 2667 if ( pExtent->uDescriptorSector + 4 < pExtent->cOverheadSectors 2668 && pExtent->cGTEntries * pExtent->cGDEntries == 0) 2669 pExtent->cDescriptorSectors = 4; 2670 } 2671 2672 out: 2695 } 2696 2673 2697 if (RT_FAILURE(rc)) 2674 2698 vmdkFreeExtentData(pImage, pExtent, false); … … 2693 2717 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbExtentSize); 2694 2718 if (RT_FAILURE(rc)) 2695 {2696 2719 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); 2697 goto out; 2698 } 2699 if ( cbExtentSize != RT_ALIGN_64(cbExtentSize, 512) 2720 else if ( cbExtentSize != RT_ALIGN_64(cbExtentSize, 512) 2700 2721 && (pExtent->enmType != VMDKETYPE_FLAT || pExtent->cNominalSectors + pExtent->uSectorOffset > VMDK_BYTE2SECTOR(cbExtentSize))) 2701 { 2702 rc = vdIfError(pImage->pIfError, 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); 2703 goto out; 2704 } 2722 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 2723 N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname); 2705 2724 #endif /* VBOX_WITH_VMDK_STRICT_SIZE_CHECK */ 2706 if ( pExtent->enmType != VMDKETYPE_HOSTED_SPARSE)2707 goto out;2708 2709 /* The spec says that this must be a power of two and greater than 8,2710 * but probably they meant not less than 8. */2711 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))2712 || pExtent->cSectorsPerGrain < 8)2713 {2714 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);2715 goto out;2716 }2717 2718 /* This code requires that a grain table must hold a power of two multiple2719 * of the number of entries per GT cache entry. */2720 if ( (pExtent->cGTEntries & (pExtent->cGTEntries - 1))2721 || pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)2722 {2723 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);2724 goto out;2725 }2726 2727 rc = vmdkAllocStreamBuffers(pImage, pExtent);2728 if (RT_FAILURE(rc))2729 goto out;2730 2731 /* Prohibit any writes to this streamOptimized extent. */ 2732 if(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)2733 pExtent->uAppendPosition = 0;2734 2735 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)2736 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)2737 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))2738 rc = vmdkReadGrainDirectory(pImage, pExtent);2739 else2740 {2741 pExtent->uGrainSectorAbs = pExtent->cOverheadSectors;2742 pExtent->cbGrainStreamRead = 0;2743 }2744 2745 out: 2725 if ( RT_SUCCESS(rc) 2726 && pExtent->enmType == VMDKETYPE_HOSTED_SPARSE) 2727 { 2728 /* The spec says that this must be a power of two and greater than 8, 2729 * but probably they meant not less than 8. */ 2730 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1)) 2731 || pExtent->cSectorsPerGrain < 8) 2732 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 2733 N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname); 2734 else 2735 { 2736 /* This code requires that a grain table must hold a power of two multiple 2737 * of the number of entries per GT cache entry. */ 2738 if ( (pExtent->cGTEntries & (pExtent->cGTEntries - 1)) 2739 || pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE) 2740 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, 2741 N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname); 2742 else 2743 { 2744 rc = vmdkAllocStreamBuffers(pImage, pExtent); 2745 if (RT_SUCCESS(rc)) 2746 { 2747 /* Prohibit any writes to this streamOptimized extent. */ 2748 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 2749 pExtent->uAppendPosition = 0; 2750 2751 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 2752 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 2753 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)) 2754 rc = vmdkReadGrainDirectory(pImage, pExtent); 2755 else 2756 { 2757 pExtent->uGrainSectorAbs = pExtent->cOverheadSectors; 2758 pExtent->cbGrainStreamRead = 0; 2759 } 2760 } 2761 } 2762 } 2763 } 2764 2746 2765 if (RT_FAILURE(rc)) 2747 2766 vmdkFreeExtentData(pImage, pExtent, false); … … 2780 2799 } 2781 2800 else 2782 {2783 2801 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END); 2784 }2785 2802 } 2786 2803 else … … 2793 2810 } 2794 2811 else 2795 {2796 2812 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD); 2797 }2798 2813 } 2799 2814 Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors); … … 2822 2837 { 2823 2838 COWDisk_Header Header; 2824 uint64_t cSectorsPerGDE;2825 2839 2826 2840 int rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 0, 2827 2841 &Header, sizeof(Header)); 2828 AssertRC(rc); 2829 if (RT_FAILURE(rc)) 2842 if (RT_SUCCESS(rc)) 2843 { 2844 if ( RT_LE2H_U32(Header.magicNumber) == VMDK_ESX_SPARSE_MAGICNUMBER 2845 && RT_LE2H_U32(Header.version) == 1 2846 && RT_LE2H_U32(Header.flags) == 3) 2847 { 2848 pExtent->enmType = VMDKETYPE_ESX_SPARSE; 2849 pExtent->cSectors = RT_LE2H_U32(Header.numSectors); 2850 pExtent->cSectorsPerGrain = RT_LE2H_U32(Header.grainSize); 2851 pExtent->uDescriptorSector = 0; 2852 pExtent->cDescriptorSectors = 0; 2853 pExtent->uSectorGD = RT_LE2H_U32(Header.gdOffset); 2854 pExtent->uSectorRGD = 0; 2855 pExtent->cOverheadSectors = 0; 2856 pExtent->cGTEntries = 4096; 2857 pExtent->cSectorsPerGDE = cSectorsPerGDE; 2858 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 2859 pExtent->uFreeSector = RT_LE2H_U32(Header.freeSector); 2860 pExtent->fUncleanShutdown = !!Header.uncleanShutdown; 2861 2862 uint64_t cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2863 2864 /* 2865 * The spec says that this must be between 1 sector and 1MB. This code 2866 * assumes it's a power of two, so check that requirement, too. 2867 * 2868 * Check that the number of computed GD entries matches the 2869 * stored value. Better be safe than sorry. 2870 */ 2871 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1)) 2872 || pExtent->cSectorsPerGrain == 0 2873 || pExtent->cSectorsPerGrain > 2048 2874 || !cSectorsPerGDE 2875 || cSectorsPerGDE > UINT32_MAX) 2876 || pExtent->cGDEntries != RT_LE2H_U32(Header.numGDEntries)) 2877 rc = VERR_VD_VMDK_INVALID_HEADER; 2878 else 2879 rc = vmdkReadGrainDirectory(pImage, pExtent); 2880 } 2881 else 2882 rc = VERR_VD_VMDK_INVALID_HEADER; 2883 } 2884 else 2830 2885 { 2831 2886 vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading ESX sparse extent header in '%s'"), pExtent->pszFullname); 2832 2887 rc = VERR_VD_VMDK_INVALID_HEADER; 2833 goto out; 2834 } 2835 if ( RT_LE2H_U32(Header.magicNumber) != VMDK_ESX_SPARSE_MAGICNUMBER 2836 || RT_LE2H_U32(Header.version) != 1 2837 || RT_LE2H_U32(Header.flags) != 3) 2838 { 2839 rc = VERR_VD_VMDK_INVALID_HEADER; 2840 goto out; 2841 } 2842 pExtent->enmType = VMDKETYPE_ESX_SPARSE; 2843 pExtent->cSectors = RT_LE2H_U32(Header.numSectors); 2844 pExtent->cSectorsPerGrain = RT_LE2H_U32(Header.grainSize); 2845 /* The spec says that this must be between 1 sector and 1MB. This code 2846 * assumes it's a power of two, so check that requirement, too. */ 2847 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1)) 2848 || pExtent->cSectorsPerGrain == 0 2849 || pExtent->cSectorsPerGrain > 2048) 2850 { 2851 rc = VERR_VD_VMDK_INVALID_HEADER; 2852 goto out; 2853 } 2854 pExtent->uDescriptorSector = 0; 2855 pExtent->cDescriptorSectors = 0; 2856 pExtent->uSectorGD = RT_LE2H_U32(Header.gdOffset); 2857 pExtent->uSectorRGD = 0; 2858 pExtent->cOverheadSectors = 0; 2859 pExtent->cGTEntries = 4096; 2860 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain; 2861 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX) 2862 { 2863 rc = VERR_VD_VMDK_INVALID_HEADER; 2864 goto out; 2865 } 2866 pExtent->cSectorsPerGDE = cSectorsPerGDE; 2867 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE; 2868 if (pExtent->cGDEntries != RT_LE2H_U32(Header.numGDEntries)) 2869 { 2870 /* Inconsistency detected. Computed number of GD entries doesn't match 2871 * stored value. Better be safe than sorry. */ 2872 rc = VERR_VD_VMDK_INVALID_HEADER; 2873 goto out; 2874 } 2875 pExtent->uFreeSector = RT_LE2H_U32(Header.freeSector); 2876 pExtent->fUncleanShutdown = !!Header.uncleanShutdown; 2877 2878 rc = vmdkReadGrainDirectory(pImage, pExtent); 2879 2880 out: 2888 } 2889 2881 2890 if (RT_FAILURE(rc)) 2882 2891 vmdkFreeExtentData(pImage, pExtent, false);
Note:
See TracChangeset
for help on using the changeset viewer.