VirtualBox

Ignore:
Timestamp:
May 18, 2010 4:29:31 PM (15 years ago)
Author:
vboxsync
Message:

Frontends/VBoxManage: make partition table processing much more generic, solves the long-standing bugs with rejecting many partition tables (e.g. #688).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp

    r28800 r29649  
    496496}
    497497
     498static int handleVDMessage(void *pvUser, const char *pszFormat, ...)
     499{
     500    NOREF(pvUser);
     501    va_list args;
     502    va_start(args, pszFormat);
     503    int rc = RTPrintfV(pszFormat, args);
     504    va_end(args);
     505    return rc;
     506}
     507
    498508static int CmdSetHDUUID(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
    499509{
     
    525535    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
    526536    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
    527     vdInterfaceErrorCallbacks.pfnMessage   = NULL;
     537    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
    528538
    529539    rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
     
    557567}
    558568
    559 
    560 static int handleVDMessage(void *pvUser, const char *pszFormat, ...)
    561 {
    562     NOREF(pvUser);
    563     va_list args;
    564     va_start(args, pszFormat);
    565     int rc = RTPrintfV(pszFormat, args);
    566     va_end(args);
    567     return rc;
    568 }
    569569
    570570static int CmdDumpHDInfo(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
     
    769769    }
    770770
    771     /* Now do a lot of consistency checking. */
    772     uint64_t uPrevEnd = 0;
    773     for (unsigned i = 0; i < pPart->cPartitions-1; i++)
    774     {
    775         if (pPart->aPartitions[i].cPartDataSectors)
    776         {
    777             if (pPart->aPartitions[i].uPartDataStart < uPrevEnd)
    778             {
    779                 RTPrintf("Overlapping partition description areas. Aborting\n");
    780                 return VERR_INVALID_PARAMETER;
    781             }
    782             uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
    783         }
    784         if (pPart->aPartitions[i].uStart < uPrevEnd)
    785         {
    786             RTPrintf("Overlapping partitions. Aborting\n");
    787             return VERR_INVALID_PARAMETER;
    788         }
    789         if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
    790             uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
    791     }
    792 
    793771    /* Fill out partitioning location info for MBR. */
    794772    pPart->aPartitions[0].uPartDataStart = 0;
    795773    pPart->aPartitions[0].cPartDataSectors = pPart->aPartitions[0].uStart;
    796774
     775    /* Now do a some partition table consistency checking, to reject the most
     776     * obvious garbage which can lead to trouble later. */
     777    uint64_t uPrevEnd = 0;
     778    for (unsigned i = 0; i < pPart->cPartitions-1; i++)
     779    {
     780        if (pPart->aPartitions[i].cPartDataSectors)
     781            uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
     782        if (pPart->aPartitions[i].uStart < uPrevEnd)
     783        {
     784            RTPrintf("Overlapping partitions. Aborting\n");
     785            return VERR_INVALID_PARAMETER;
     786        }
     787        if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
     788            uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
     789    }
     790
    797791    return VINF_SUCCESS;
    798792}
     
    833827    HOSTPARTITIONS partitions;
    834828    vrc = partRead(RawFile, &partitions);
    835     if (RT_FAILURE(vrc))
    836         return vrc;
     829    /* Don't bail out on errors, print the table and return the result code. */
    837830
    838831    RTPrintf("Number  Type   StartCHS       EndCHS      Size (MiB)  Start (Sect)\n");
    839832    for (unsigned i = 0; i < partitions.cPartitions; i++)
    840833    {
    841         /* Suppress printing the extended partition. Otherwise people
    842          * might add it to the list of partitions for raw partition
    843          * access (which is not good). */
     834        /* Don't show the extended partition, otherwise users might think they
     835         * can add it to the list of partitions for raw partition access. */
    844836        if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
    845837            continue;
     
    858850    }
    859851
    860     return 0;
     852    return vrc;
     853}
     854
     855static PVBOXHDDRAWPARTDESC appendPartDesc(uint32_t *pcPartDescs, PVBOXHDDRAWPARTDESC *ppPartDescs)
     856{
     857    (*pcPartDescs)++;
     858    PVBOXHDDRAWPARTDESC p;
     859    p = (PVBOXHDDRAWPARTDESC)RTMemRealloc(*ppPartDescs,
     860                                          *pcPartDescs * sizeof(VBOXHDDRAWPARTDESC));
     861    *ppPartDescs = p;
     862    if (p)
     863    {
     864        p = p + *pcPartDescs - 1;
     865        memset(p, '\0', sizeof(VBOXHDDRAWPARTDESC));
     866    }
     867
     868    return p;
    861869}
    862870
     
    874882    PVBOXHDD pDisk = NULL;
    875883    VBOXHDDRAW RawDescriptor;
    876     HOSTPARTITIONS partitions;
    877     uint32_t uPartitions = 0;
    878884    PVDINTERFACE pVDIfs = NULL;
    879885
     
    11381144        RawDescriptor.fRawDisk = false;
    11391145        RawDescriptor.pszRawDisk = NULL;
    1140         RawDescriptor.cPartitions = 0;
     1146        RawDescriptor.cPartDescs = 0;
     1147        RawDescriptor.pPartDescs = NULL;
     1148
     1149        uint32_t uPartitions = 0;
    11411150
    11421151        const char *p = pszPartitions;
     
    11631172        }
    11641173
     1174        HOSTPARTITIONS partitions;
    11651175        vrc = partRead(RawFile, &partitions);
    11661176        if (RT_FAILURE(vrc))
     
    11861196        }
    11871197
    1188         RawDescriptor.cPartitions = partitions.cPartitions;
    1189         RawDescriptor.pPartitions = (PVBOXHDDRAWPART)RTMemAllocZ(partitions.cPartitions * sizeof(VBOXHDDRAWPART));
    1190         if (!RawDescriptor.pPartitions)
    1191         {
    1192             RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
    1193             vrc = VERR_NO_MEMORY;
    1194             goto out;
    1195         }
    11961198        for (unsigned i = 0; i < partitions.cPartitions; i++)
    11971199        {
    1198             if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
    1199             {
    1200                 if (fRelative)
     1200            PVBOXHDDRAWPARTDESC pPartDesc = NULL;
     1201
     1202            /* first dump the MBR/EPT data area */
     1203            if (partitions.aPartitions[i].cPartDataSectors)
     1204            {
     1205                pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
     1206                                           &RawDescriptor.pPartDescs);
     1207                if (!pPartDesc)
    12011208                {
    1202 #ifdef RT_OS_LINUX
    1203                     /* Refer to the correct partition and use offset 0. */
    1204                     char *pszRawName;
    1205                     vrc = RTStrAPrintf(&pszRawName, "%s%u", rawdisk.raw(),
    1206                                        partitions.aPartitions[i].uIndex);
    1207                     if (RT_FAILURE(vrc))
    1208                     {
    1209                         RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
    1210                                  partitions.aPartitions[i].uIndex, vrc);
    1211                         goto out;
    1212                     }
    1213                     RawDescriptor.pPartitions[i].pszRawDevice = pszRawName;
    1214                     RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
    1215                     RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
    1216 #elif defined(RT_OS_DARWIN)
    1217                     /* Refer to the correct partition and use offset 0. */
    1218                     char *pszRawName;
    1219                     vrc = RTStrAPrintf(&pszRawName, "%ss%u", rawdisk.raw(),
    1220                                        partitions.aPartitions[i].uIndex);
    1221                     if (RT_FAILURE(vrc))
    1222                     {
    1223                         RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
    1224                                  partitions.aPartitions[i].uIndex, vrc);
    1225                         goto out;
    1226                     }
    1227                     RawDescriptor.pPartitions[i].pszRawDevice = pszRawName;
    1228                     RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
    1229                     RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
    1230 #else
    1231                     /** @todo not implemented yet for Windows host. Treat just
    1232                      * like not specified (this code is actually never reached). */
    1233                     RawDescriptor.pPartitions[i].pszRawDevice = rawdisk.raw();
    1234                     RawDescriptor.pPartitions[i].uPartitionStartOffset = partitions.aPartitions[i].uStart * 512;
    1235                     RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
    1236 #endif
     1209                    RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
     1210                    vrc = VERR_NO_MEMORY;
     1211                    goto out;
    12371212                }
    1238                 else
    1239                 {
    1240                     /* This is the "everything refers to the base raw device"
    1241                      * variant. This requires opening the base device in RW
    1242                      * mode even for creation. */
    1243                     RawDescriptor.pPartitions[i].pszRawDevice = rawdisk.raw();
    1244                     RawDescriptor.pPartitions[i].uPartitionStartOffset = partitions.aPartitions[i].uStart * 512;
    1245                     RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
    1246                 }
    1247             }
    1248             else
    1249             {
    1250                 /* Suppress access to this partition. */
    1251                 RawDescriptor.pPartitions[i].pszRawDevice = NULL;
    1252                 RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
    1253                 /* This is used in the plausibility check in the creation
    1254                  * code. In theory it's a dummy, but I don't want to make
    1255                  * the VMDK creatiion any more complicated than what it needs
    1256                  * to be. */
    1257                 RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
    1258             }
    1259             if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
    1260             {
    1261                 /* Suppress exporting the actual extended partition. Only
    1262                  * logical partitions should be processed. However completely
    1263                  * ignoring it leads to leaving out the MBR data. */
    1264                 RawDescriptor.pPartitions[i].cbPartition = 0;
    1265             }
    1266             else
    1267                 RawDescriptor.pPartitions[i].cbPartition =  partitions.aPartitions[i].uSize * 512;
    1268             RawDescriptor.pPartitions[i].uPartitionDataStart = partitions.aPartitions[i].uPartDataStart * 512;
    1269             /** @todo the clipping below isn't 100% accurate, as it should
    1270              * actually clip to the track size. However that's easier said
    1271              * than done as figuring out the track size is heuristics. */
    1272             RawDescriptor.pPartitions[i].cbPartitionData = RT_MIN(partitions.aPartitions[i].cPartDataSectors, 63) * 512;
    1273             if (RawDescriptor.pPartitions[i].cbPartitionData)
    1274             {
    1275                 Assert (RawDescriptor.pPartitions[i].cbPartitionData -
    1276                         (size_t)RawDescriptor.pPartitions[i].cbPartitionData == 0);
    1277                 void *pPartData = RTMemAlloc((size_t)RawDescriptor.pPartitions[i].cbPartitionData);
     1213
     1214                /** @todo the clipping below isn't 100% accurate, as it should
     1215                 * actually clip to the track size. However that's easier said
     1216                 * than done as figuring out the track size is heuristics. In
     1217                 * any case the clipping is adjusted later after sorting, to
     1218                 * prevent overlapping data areas on the resulting image. */
     1219                pPartDesc->cbData = RT_MIN(partitions.aPartitions[i].cPartDataSectors, 63) * 512;
     1220                pPartDesc->uStart = partitions.aPartitions[i].uPartDataStart * 512;
     1221                Assert(pPartDesc->cbData - (size_t)pPartDesc->cbData == 0);
     1222                void *pPartData = RTMemAlloc((size_t)pPartDesc->cbData);
    12781223                if (!pPartData)
    12791224                {
     
    12821227                    goto out;
    12831228                }
    1284                 vrc = RTFileReadAt(RawFile, partitions.aPartitions[i].uPartDataStart * 512, pPartData, (size_t)RawDescriptor.pPartitions[i].cbPartitionData, NULL);
     1229                vrc = RTFileReadAt(RawFile, partitions.aPartitions[i].uPartDataStart * 512,
     1230                                   pPartData, (size_t)pPartDesc->cbData, NULL);
    12851231                if (RT_FAILURE(vrc))
    12861232                {
     
    13071253                    }
    13081254                }
    1309                 RawDescriptor.pPartitions[i].pvPartitionData = pPartData;
     1255                pPartDesc->pvPartitionData = pPartData;
     1256            }
     1257
     1258            if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
     1259            {
     1260                /* Suppress exporting the actual extended partition. Only
     1261                 * logical partitions should be processed. However completely
     1262                 * ignoring it leads to leaving out the EBR data. */
     1263                continue;
     1264            }
     1265
     1266            /* set up values for non-relative device names */
     1267            const char *pszRawName = rawdisk.raw();
     1268            uint64_t uStartOffset = partitions.aPartitions[i].uStart * 512;
     1269
     1270            pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
     1271                                       &RawDescriptor.pPartDescs);
     1272            if (!pPartDesc)
     1273            {
     1274                RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
     1275                vrc = VERR_NO_MEMORY;
     1276                goto out;
     1277            }
     1278
     1279            if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
     1280            {
     1281                if (fRelative)
     1282                {
     1283#ifdef RT_OS_LINUX
     1284                    /* Refer to the correct partition and use offset 0. */
     1285                    char *psz;
     1286                    vrc = RTStrAPrintf(&psz, "%s%u", rawdisk.raw(),
     1287                                       partitions.aPartitions[i].uIndex);
     1288                    if (RT_FAILURE(vrc))
     1289                    {
     1290                        RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
     1291                                 partitions.aPartitions[i].uIndex, vrc);
     1292                        goto out;
     1293                    }
     1294                    pszRawName = psz;
     1295                    uStartOffset = 0;
     1296#elif defined(RT_OS_DARWIN)
     1297                    /* Refer to the correct partition and use offset 0. */
     1298                    char *psz;
     1299                    vrc = RTStrAPrintf(&psz, "%ss%u", rawdisk.raw(),
     1300                                       partitions.aPartitions[i].uIndex);
     1301                    if (RT_FAILURE(vrc))
     1302                    {
     1303                        RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
     1304                                 partitions.aPartitions[i].uIndex, vrc);
     1305                        goto out;
     1306                    }
     1307                    pszRawName = psz;
     1308                    uStartOffset = 0;
     1309#else
     1310                    /** @todo not implemented for other hosts. Treat just like
     1311                     * not specified (this code is actually never reached). */
     1312#endif
     1313                }
     1314
     1315                pPartDesc->pszRawDevice = pszRawName;
     1316                pPartDesc->uStartOffset = uStartOffset;
     1317            }
     1318            else
     1319            {
     1320                pPartDesc->pszRawDevice = NULL;
     1321                pPartDesc->uStartOffset = 0;
     1322            }
     1323
     1324            pPartDesc->uStart = partitions.aPartitions[i].uStart * 512;
     1325            pPartDesc->cbData = partitions.aPartitions[i].uSize * 512;
     1326        }
     1327
     1328        /* Sort data areas in ascending order of start. */
     1329        for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
     1330        {
     1331            unsigned uMinIdx = i;
     1332            uint64_t uMinVal = RawDescriptor.pPartDescs[i].uStart;
     1333            for (unsigned j = i + 1; j < RawDescriptor.cPartDescs; j++)
     1334            {
     1335                if (RawDescriptor.pPartDescs[j].uStart < uMinVal)
     1336                {
     1337                    uMinIdx = j;
     1338                    uMinVal = RawDescriptor.pPartDescs[j].uStart;
     1339                }
     1340            }
     1341            if (uMinIdx != i)
     1342            {
     1343                /* Swap entries at index i and uMinIdx. */
     1344                VBOXHDDRAWPARTDESC tmp;
     1345                memcpy(&tmp, &RawDescriptor.pPartDescs[i], sizeof(tmp));
     1346                memcpy(&RawDescriptor.pPartDescs[i], &RawDescriptor.pPartDescs[uMinIdx], sizeof(tmp));
     1347                memcpy(&RawDescriptor.pPartDescs[uMinIdx], &tmp, sizeof(tmp));
     1348            }
     1349        }
     1350
     1351        /* Have a second go at MBR/EPT area clipping. Now that the data areas
     1352         * are sorted this is much easier to get 100% right. */
     1353        for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
     1354        {
     1355            if (RawDescriptor.pPartDescs[i].pvPartitionData)
     1356            {
     1357                RawDescriptor.pPartDescs[i].cbData = RT_MIN(RawDescriptor.pPartDescs[i+1].uStart - RawDescriptor.pPartDescs[i].uStart, RawDescriptor.pPartDescs[i].cbData);
     1358                if (!RawDescriptor.pPartDescs[i].cbData)
     1359                {
     1360                    RTPrintf("MBR/EPT overlaps with data area\n");
     1361                    vrc = VERR_INVALID_PARAMETER;
     1362                    goto out;
     1363                }
    13101364            }
    13111365        }
     
    13131367
    13141368    RTFileClose(RawFile);
     1369
     1370#ifdef DEBUG_klaus
     1371    RTPrintf("#            start         length    startoffset  partdataptr  device\n");
     1372    for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
     1373    {
     1374        RTPrintf("%2u  %14RU64 %14RU64 %14RU64 %#18p %s\n", i,
     1375                 RawDescriptor.pPartDescs[i].uStart,
     1376                 RawDescriptor.pPartDescs[i].cbData,
     1377                 RawDescriptor.pPartDescs[i].uStartOffset,
     1378                 RawDescriptor.pPartDescs[i].pvPartitionData,
     1379                 RawDescriptor.pPartDescs[i].pszRawDevice);
     1380    }
     1381#endif
    13151382
    13161383    VDINTERFACE      vdInterfaceError;
     
    13191386    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
    13201387    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
    1321     vdInterfaceErrorCallbacks.pfnMessage   = NULL;
     1388    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
    13221389
    13231390    vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
     
    13571424    if (pszPartitions)
    13581425    {
    1359         for (unsigned i = 0; i < partitions.cPartitions; i++)
    1360         {
    1361             if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
    1362             {
    1363                 if (fRelative)
    1364                 {
    1365 #ifdef RT_OS_LINUX
    1366                     /* Free memory allocated above. */
    1367                     RTStrFree((char *)(void *)RawDescriptor.pPartitions[i].pszRawDevice);
    1368 #endif /* RT_OS_LINUX */
    1369                 }
    1370             }
    1371         }
     1426        for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
     1427        {
     1428            /* Free memory allocated for relative device name. */
     1429            if (RawDescriptor.pPartDescs[i].pszRawDevice)
     1430                RTStrFree((char *)(void *)RawDescriptor.pPartDescs[i].pszRawDevice);
     1431            if (RawDescriptor.pPartDescs[i].pvPartitionData)
     1432                RTMemFree(RawDescriptor.pPartDescs[i].pvPartitionData);
     1433        }
     1434        if (RawDescriptor.pPartDescs)
     1435            RTMemFree(RawDescriptor.pPartDescs);
    13721436    }
    13731437
     
    14291493    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
    14301494    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
    1431     vdInterfaceErrorCallbacks.pfnMessage   = NULL;
     1495    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
    14321496
    14331497    int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
     
    15111575    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
    15121576    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
    1513     vdInterfaceErrorCallbacks.pfnMessage   = NULL;
     1577    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
    15141578
    15151579    int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
     
    16761740    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
    16771741    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
    1678     vdInterfaceErrorCallbacks.pfnMessage   = NULL;
     1742    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
    16791743
    16801744    vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
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