VirtualBox

Changeset 63798 in vbox for trunk


Ignore:
Timestamp:
Sep 12, 2016 1:34:57 PM (8 years ago)
Author:
vboxsync
Message:

Storage/VMDK: Cleanup, get rid of goto... (part 1)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/VMDK.cpp

    r63785 r63798  
    994994                                          + 8 + sizeof(VMDKMARKER), 512);
    995995        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
    9981004            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
    10121007    if (RT_FAILURE(rc))
    10131008        vmdkFreeStreamBuffers(pExtent);
     
    10231018    int rc = VINF_SUCCESS;
    10241019    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
    10341032        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
    10511034    if (RT_FAILURE(rc))
    10521035        vmdkFreeGrainDirectory(pExtent);
     
    10541037}
    10551038
     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 */
     1046DECLINLINE(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 */
    10561062static int vmdkReadGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
    10571063{
    10581064    int rc = VINF_SUCCESS;
    1059     size_t i;
    1060     uint32_t *pGDTmp, *pRGDTmp;
    10611065    size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
    10621066
    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);
    10721070
    10731071    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))
    10941073    {
    10951074        /* The VMDK 1.1 spec seems to talk about compressed grain directories,
    10961075         * but in reality they are not compressed. */
    10971076        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))
    11351085            {
    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))
    11621092                {
    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)
    12001105                        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);
    12011242                }
    12021243                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);
    12151246            }
    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
    12581253    if (RT_FAILURE(rc))
    12591254        vmdkFreeGrainDirectory(pExtent);
     
    12611256}
    12621257
     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 */
    12631267static int vmdkCreateGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
    12641268                                    uint64_t uStartSector, bool fPreAlloc)
     
    12741278    {
    12751279        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;
    12781281    }
    12791282    else
     
    13001303        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead);
    13011304    }
    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)
    13351328            {
    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)
    13431333                {
    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                    }
    13461350                }
    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                }
    13481371            }
    13491372        }
    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
    13701375    if (RT_FAILURE(rc))
    13711376        vmdkFreeGrainDirectory(pExtent);
     
    18251830}
    18261831
    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 */
     1841static int vmdkDescSplitLines(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDesc, char *pszTmp)
     1842{
     1843    unsigned cLine = 0;
    18311844    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;
    18391850        if (cLine >= VMDK_DESCRIPTOR_LINES_MAX)
    18401851        {
    18411852            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 (*pTmp != '\0' && *pTmp != '\n')
    1846         {
    1847             if (*pTmp == '\r')
     1853            break;
     1854        }
     1855
     1856        while (*pszTmp != '\0' && *pszTmp != '\n')
     1857        {
     1858            if (*pszTmp == '\r')
    18481859            {
    1849                 if (*(pTmp + 1) != '\n')
     1860                if (*(pszTmp + 1) != '\n')
    18501861                {
    18511862                    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;
    18531864                }
    18541865                else
    18551866                {
    18561867                    /* Get rid of CR character. */
    1857                     *pTmp = '\0';
     1868                    *pszTmp = '\0';
    18581869                }
    18591870            }
    1860             pTmp++;
     1871            pszTmp++;
    18611872        }
    18621873        /* 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
     1891static 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++)
    18911911            {
    1892                 /* An extent descriptor. */
    1893                 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB)
     1912                if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0')
    18941913                {
    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;
    19031967                }
    19041968            }
    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
    19421972    return rc;
    19431973}
     
    19852015                                size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
    19862016{
    1987     int rc;
    1988 
    19892017    pDescriptor->uFirstDesc = 0;
    19902018    pDescriptor->uFirstExtent = 0;
     
    19962024    memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
    19972025
    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
    20512071    return rc;
    20522072}
    20532073
    2054 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData,
    2055                                size_t cbDescData)
     2074static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
    20562075{
    20572076    int rc;
     
    25472566{
    25482567    SparseExtentHeader Header;
    2549     uint64_t cSectorsPerGDE;
    2550     uint64_t cbFile = 0;
    25512568    int rc;
    25522569
     
    25632580                                   - RT_OFFSETOF(SparseExtentHeader, version));
    25642581    }
    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
    25672692    {
    25682693        vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
    25692694        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
    26732697    if (RT_FAILURE(rc))
    26742698        vmdkFreeExtentData(pImage, pExtent, false);
     
    26932717    rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbExtentSize);
    26942718    if (RT_FAILURE(rc))
    2695     {
    26962719        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)
    27002721        &&  (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);
    27052724#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 multiple
    2719      * 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     else
    2740     {
    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
    27462765    if (RT_FAILURE(rc))
    27472766        vmdkFreeExtentData(pImage, pExtent, false);
     
    27802799        }
    27812800        else
    2782         {
    27832801            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
    2784         }
    27852802    }
    27862803    else
     
    27932810        }
    27942811        else
    2795         {
    27962812            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
    2797         }
    27982813    }
    27992814    Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
     
    28222837{
    28232838    COWDisk_Header Header;
    2824     uint64_t cSectorsPerGDE;
    28252839
    28262840    int rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 0,
    28272841                                   &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
    28302885    {
    28312886        vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading ESX sparse extent header in '%s'"), pExtent->pszFullname);
    28322887        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
    28812890    if (RT_FAILURE(rc))
    28822891        vmdkFreeExtentData(pImage, pExtent, false);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette