Index: trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp
===================================================================
--- trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp	(revision 29645)
+++ trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp	(revision 29649)
@@ -496,4 +496,14 @@
 }
 
+static int handleVDMessage(void *pvUser, const char *pszFormat, ...)
+{
+    NOREF(pvUser);
+    va_list args;
+    va_start(args, pszFormat);
+    int rc = RTPrintfV(pszFormat, args);
+    va_end(args);
+    return rc;
+}
+
 static int CmdSetHDUUID(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
 {
@@ -525,5 +535,5 @@
     vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     vdInterfaceErrorCallbacks.pfnError     = handleVDError;
-    vdInterfaceErrorCallbacks.pfnMessage   = NULL;
+    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
 
     rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
@@ -557,14 +567,4 @@
 }
 
-
-static int handleVDMessage(void *pvUser, const char *pszFormat, ...)
-{
-    NOREF(pvUser);
-    va_list args;
-    va_start(args, pszFormat);
-    int rc = RTPrintfV(pszFormat, args);
-    va_end(args);
-    return rc;
-}
 
 static int CmdDumpHDInfo(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
@@ -769,30 +769,24 @@
     }
 
-    /* Now do a lot of consistency checking. */
-    uint64_t uPrevEnd = 0;
-    for (unsigned i = 0; i < pPart->cPartitions-1; i++)
-    {
-        if (pPart->aPartitions[i].cPartDataSectors)
-        {
-            if (pPart->aPartitions[i].uPartDataStart < uPrevEnd)
-            {
-                RTPrintf("Overlapping partition description areas. Aborting\n");
-                return VERR_INVALID_PARAMETER;
-            }
-            uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
-        }
-        if (pPart->aPartitions[i].uStart < uPrevEnd)
-        {
-            RTPrintf("Overlapping partitions. Aborting\n");
-            return VERR_INVALID_PARAMETER;
-        }
-        if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
-            uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
-    }
-
     /* Fill out partitioning location info for MBR. */
     pPart->aPartitions[0].uPartDataStart = 0;
     pPart->aPartitions[0].cPartDataSectors = pPart->aPartitions[0].uStart;
 
+    /* Now do a some partition table consistency checking, to reject the most
+     * obvious garbage which can lead to trouble later. */
+    uint64_t uPrevEnd = 0;
+    for (unsigned i = 0; i < pPart->cPartitions-1; i++)
+    {
+        if (pPart->aPartitions[i].cPartDataSectors)
+            uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
+        if (pPart->aPartitions[i].uStart < uPrevEnd)
+        {
+            RTPrintf("Overlapping partitions. Aborting\n");
+            return VERR_INVALID_PARAMETER;
+        }
+        if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
+            uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
+    }
+
     return VINF_SUCCESS;
 }
@@ -833,13 +827,11 @@
     HOSTPARTITIONS partitions;
     vrc = partRead(RawFile, &partitions);
-    if (RT_FAILURE(vrc))
-        return vrc;
+    /* Don't bail out on errors, print the table and return the result code. */
 
     RTPrintf("Number  Type   StartCHS       EndCHS      Size (MiB)  Start (Sect)\n");
     for (unsigned i = 0; i < partitions.cPartitions; i++)
     {
-        /* Suppress printing the extended partition. Otherwise people
-         * might add it to the list of partitions for raw partition
-         * access (which is not good). */
+        /* Don't show the extended partition, otherwise users might think they
+         * can add it to the list of partitions for raw partition access. */
         if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
             continue;
@@ -858,5 +850,21 @@
     }
 
-    return 0;
+    return vrc;
+}
+
+static PVBOXHDDRAWPARTDESC appendPartDesc(uint32_t *pcPartDescs, PVBOXHDDRAWPARTDESC *ppPartDescs)
+{
+    (*pcPartDescs)++;
+    PVBOXHDDRAWPARTDESC p;
+    p = (PVBOXHDDRAWPARTDESC)RTMemRealloc(*ppPartDescs,
+                                          *pcPartDescs * sizeof(VBOXHDDRAWPARTDESC));
+    *ppPartDescs = p;
+    if (p)
+    {
+        p = p + *pcPartDescs - 1;
+        memset(p, '\0', sizeof(VBOXHDDRAWPARTDESC));
+    }
+
+    return p;
 }
 
@@ -874,6 +882,4 @@
     PVBOXHDD pDisk = NULL;
     VBOXHDDRAW RawDescriptor;
-    HOSTPARTITIONS partitions;
-    uint32_t uPartitions = 0;
     PVDINTERFACE pVDIfs = NULL;
 
@@ -1138,5 +1144,8 @@
         RawDescriptor.fRawDisk = false;
         RawDescriptor.pszRawDisk = NULL;
-        RawDescriptor.cPartitions = 0;
+        RawDescriptor.cPartDescs = 0;
+        RawDescriptor.pPartDescs = NULL;
+
+        uint32_t uPartitions = 0;
 
         const char *p = pszPartitions;
@@ -1163,4 +1172,5 @@
         }
 
+        HOSTPARTITIONS partitions;
         vrc = partRead(RawFile, &partitions);
         if (RT_FAILURE(vrc))
@@ -1186,94 +1196,29 @@
         }
 
-        RawDescriptor.cPartitions = partitions.cPartitions;
-        RawDescriptor.pPartitions = (PVBOXHDDRAWPART)RTMemAllocZ(partitions.cPartitions * sizeof(VBOXHDDRAWPART));
-        if (!RawDescriptor.pPartitions)
-        {
-            RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
-            vrc = VERR_NO_MEMORY;
-            goto out;
-        }
         for (unsigned i = 0; i < partitions.cPartitions; i++)
         {
-            if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
-            {
-                if (fRelative)
+            PVBOXHDDRAWPARTDESC pPartDesc = NULL;
+
+            /* first dump the MBR/EPT data area */
+            if (partitions.aPartitions[i].cPartDataSectors)
+            {
+                pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
+                                           &RawDescriptor.pPartDescs);
+                if (!pPartDesc)
                 {
-#ifdef RT_OS_LINUX
-                    /* Refer to the correct partition and use offset 0. */
-                    char *pszRawName;
-                    vrc = RTStrAPrintf(&pszRawName, "%s%u", rawdisk.raw(),
-                                       partitions.aPartitions[i].uIndex);
-                    if (RT_FAILURE(vrc))
-                    {
-                        RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
-                                 partitions.aPartitions[i].uIndex, vrc);
-                        goto out;
-                    }
-                    RawDescriptor.pPartitions[i].pszRawDevice = pszRawName;
-                    RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
-                    RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
-#elif defined(RT_OS_DARWIN)
-                    /* Refer to the correct partition and use offset 0. */
-                    char *pszRawName;
-                    vrc = RTStrAPrintf(&pszRawName, "%ss%u", rawdisk.raw(),
-                                       partitions.aPartitions[i].uIndex);
-                    if (RT_FAILURE(vrc))
-                    {
-                        RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
-                                 partitions.aPartitions[i].uIndex, vrc);
-                        goto out;
-                    }
-                    RawDescriptor.pPartitions[i].pszRawDevice = pszRawName;
-                    RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
-                    RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
-#else
-                    /** @todo not implemented yet for Windows host. Treat just
-                     * like not specified (this code is actually never reached). */
-                    RawDescriptor.pPartitions[i].pszRawDevice = rawdisk.raw();
-                    RawDescriptor.pPartitions[i].uPartitionStartOffset = partitions.aPartitions[i].uStart * 512;
-                    RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
-#endif
+                    RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
+                    vrc = VERR_NO_MEMORY;
+                    goto out;
                 }
-                else
-                {
-                    /* This is the "everything refers to the base raw device"
-                     * variant. This requires opening the base device in RW
-                     * mode even for creation. */
-                    RawDescriptor.pPartitions[i].pszRawDevice = rawdisk.raw();
-                    RawDescriptor.pPartitions[i].uPartitionStartOffset = partitions.aPartitions[i].uStart * 512;
-                    RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
-                }
-            }
-            else
-            {
-                /* Suppress access to this partition. */
-                RawDescriptor.pPartitions[i].pszRawDevice = NULL;
-                RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
-                /* This is used in the plausibility check in the creation
-                 * code. In theory it's a dummy, but I don't want to make
-                 * the VMDK creatiion any more complicated than what it needs
-                 * to be. */
-                RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
-            }
-            if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
-            {
-                /* Suppress exporting the actual extended partition. Only
-                 * logical partitions should be processed. However completely
-                 * ignoring it leads to leaving out the MBR data. */
-                RawDescriptor.pPartitions[i].cbPartition = 0;
-            }
-            else
-                RawDescriptor.pPartitions[i].cbPartition =  partitions.aPartitions[i].uSize * 512;
-            RawDescriptor.pPartitions[i].uPartitionDataStart = partitions.aPartitions[i].uPartDataStart * 512;
-            /** @todo the clipping below isn't 100% accurate, as it should
-             * actually clip to the track size. However that's easier said
-             * than done as figuring out the track size is heuristics. */
-            RawDescriptor.pPartitions[i].cbPartitionData = RT_MIN(partitions.aPartitions[i].cPartDataSectors, 63) * 512;
-            if (RawDescriptor.pPartitions[i].cbPartitionData)
-            {
-                Assert (RawDescriptor.pPartitions[i].cbPartitionData -
-                        (size_t)RawDescriptor.pPartitions[i].cbPartitionData == 0);
-                void *pPartData = RTMemAlloc((size_t)RawDescriptor.pPartitions[i].cbPartitionData);
+
+                /** @todo the clipping below isn't 100% accurate, as it should
+                 * actually clip to the track size. However that's easier said
+                 * than done as figuring out the track size is heuristics. In
+                 * any case the clipping is adjusted later after sorting, to
+                 * prevent overlapping data areas on the resulting image. */
+                pPartDesc->cbData = RT_MIN(partitions.aPartitions[i].cPartDataSectors, 63) * 512;
+                pPartDesc->uStart = partitions.aPartitions[i].uPartDataStart * 512;
+                Assert(pPartDesc->cbData - (size_t)pPartDesc->cbData == 0);
+                void *pPartData = RTMemAlloc((size_t)pPartDesc->cbData);
                 if (!pPartData)
                 {
@@ -1282,5 +1227,6 @@
                     goto out;
                 }
-                vrc = RTFileReadAt(RawFile, partitions.aPartitions[i].uPartDataStart * 512, pPartData, (size_t)RawDescriptor.pPartitions[i].cbPartitionData, NULL);
+                vrc = RTFileReadAt(RawFile, partitions.aPartitions[i].uPartDataStart * 512,
+                                   pPartData, (size_t)pPartDesc->cbData, NULL);
                 if (RT_FAILURE(vrc))
                 {
@@ -1307,5 +1253,113 @@
                     }
                 }
-                RawDescriptor.pPartitions[i].pvPartitionData = pPartData;
+                pPartDesc->pvPartitionData = pPartData;
+            }
+
+            if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
+            {
+                /* Suppress exporting the actual extended partition. Only
+                 * logical partitions should be processed. However completely
+                 * ignoring it leads to leaving out the EBR data. */
+                continue;
+            }
+
+            /* set up values for non-relative device names */
+            const char *pszRawName = rawdisk.raw();
+            uint64_t uStartOffset = partitions.aPartitions[i].uStart * 512;
+
+            pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
+                                       &RawDescriptor.pPartDescs);
+            if (!pPartDesc)
+            {
+                RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
+                vrc = VERR_NO_MEMORY;
+                goto out;
+            }
+
+            if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
+            {
+                if (fRelative)
+                {
+#ifdef RT_OS_LINUX
+                    /* Refer to the correct partition and use offset 0. */
+                    char *psz;
+                    vrc = RTStrAPrintf(&psz, "%s%u", rawdisk.raw(),
+                                       partitions.aPartitions[i].uIndex);
+                    if (RT_FAILURE(vrc))
+                    {
+                        RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
+                                 partitions.aPartitions[i].uIndex, vrc);
+                        goto out;
+                    }
+                    pszRawName = psz;
+                    uStartOffset = 0;
+#elif defined(RT_OS_DARWIN)
+                    /* Refer to the correct partition and use offset 0. */
+                    char *psz;
+                    vrc = RTStrAPrintf(&psz, "%ss%u", rawdisk.raw(),
+                                       partitions.aPartitions[i].uIndex);
+                    if (RT_FAILURE(vrc))
+                    {
+                        RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
+                                 partitions.aPartitions[i].uIndex, vrc);
+                        goto out;
+                    }
+                    pszRawName = psz;
+                    uStartOffset = 0;
+#else
+                    /** @todo not implemented for other hosts. Treat just like
+                     * not specified (this code is actually never reached). */
+#endif
+                }
+
+                pPartDesc->pszRawDevice = pszRawName;
+                pPartDesc->uStartOffset = uStartOffset;
+            }
+            else
+            {
+                pPartDesc->pszRawDevice = NULL;
+                pPartDesc->uStartOffset = 0;
+            }
+
+            pPartDesc->uStart = partitions.aPartitions[i].uStart * 512;
+            pPartDesc->cbData = partitions.aPartitions[i].uSize * 512;
+        }
+
+        /* Sort data areas in ascending order of start. */
+        for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
+        {
+            unsigned uMinIdx = i;
+            uint64_t uMinVal = RawDescriptor.pPartDescs[i].uStart;
+            for (unsigned j = i + 1; j < RawDescriptor.cPartDescs; j++)
+            {
+                if (RawDescriptor.pPartDescs[j].uStart < uMinVal)
+                {
+                    uMinIdx = j;
+                    uMinVal = RawDescriptor.pPartDescs[j].uStart;
+                }
+            }
+            if (uMinIdx != i)
+            {
+                /* Swap entries at index i and uMinIdx. */
+                VBOXHDDRAWPARTDESC tmp;
+                memcpy(&tmp, &RawDescriptor.pPartDescs[i], sizeof(tmp));
+                memcpy(&RawDescriptor.pPartDescs[i], &RawDescriptor.pPartDescs[uMinIdx], sizeof(tmp));
+                memcpy(&RawDescriptor.pPartDescs[uMinIdx], &tmp, sizeof(tmp));
+            }
+        }
+
+        /* Have a second go at MBR/EPT area clipping. Now that the data areas
+         * are sorted this is much easier to get 100% right. */
+        for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
+        {
+            if (RawDescriptor.pPartDescs[i].pvPartitionData)
+            {
+                RawDescriptor.pPartDescs[i].cbData = RT_MIN(RawDescriptor.pPartDescs[i+1].uStart - RawDescriptor.pPartDescs[i].uStart, RawDescriptor.pPartDescs[i].cbData);
+                if (!RawDescriptor.pPartDescs[i].cbData)
+                {
+                    RTPrintf("MBR/EPT overlaps with data area\n");
+                    vrc = VERR_INVALID_PARAMETER;
+                    goto out;
+                }
             }
         }
@@ -1313,4 +1367,17 @@
 
     RTFileClose(RawFile);
+
+#ifdef DEBUG_klaus
+    RTPrintf("#            start         length    startoffset  partdataptr  device\n");
+    for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
+    {
+        RTPrintf("%2u  %14RU64 %14RU64 %14RU64 %#18p %s\n", i,
+                 RawDescriptor.pPartDescs[i].uStart,
+                 RawDescriptor.pPartDescs[i].cbData,
+                 RawDescriptor.pPartDescs[i].uStartOffset,
+                 RawDescriptor.pPartDescs[i].pvPartitionData,
+                 RawDescriptor.pPartDescs[i].pszRawDevice);
+    }
+#endif
 
     VDINTERFACE      vdInterfaceError;
@@ -1319,5 +1386,5 @@
     vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     vdInterfaceErrorCallbacks.pfnError     = handleVDError;
-    vdInterfaceErrorCallbacks.pfnMessage   = NULL;
+    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
 
     vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
@@ -1357,17 +1424,14 @@
     if (pszPartitions)
     {
-        for (unsigned i = 0; i < partitions.cPartitions; i++)
-        {
-            if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
-            {
-                if (fRelative)
-                {
-#ifdef RT_OS_LINUX
-                    /* Free memory allocated above. */
-                    RTStrFree((char *)(void *)RawDescriptor.pPartitions[i].pszRawDevice);
-#endif /* RT_OS_LINUX */
-                }
-            }
-        }
+        for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
+        {
+            /* Free memory allocated for relative device name. */
+            if (RawDescriptor.pPartDescs[i].pszRawDevice)
+                RTStrFree((char *)(void *)RawDescriptor.pPartDescs[i].pszRawDevice);
+            if (RawDescriptor.pPartDescs[i].pvPartitionData)
+                RTMemFree(RawDescriptor.pPartDescs[i].pvPartitionData);
+        }
+        if (RawDescriptor.pPartDescs)
+            RTMemFree(RawDescriptor.pPartDescs);
     }
 
@@ -1429,5 +1493,5 @@
     vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     vdInterfaceErrorCallbacks.pfnError     = handleVDError;
-    vdInterfaceErrorCallbacks.pfnMessage   = NULL;
+    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
 
     int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
@@ -1511,5 +1575,5 @@
     vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     vdInterfaceErrorCallbacks.pfnError     = handleVDError;
-    vdInterfaceErrorCallbacks.pfnMessage   = NULL;
+    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
 
     int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
@@ -1676,5 +1740,5 @@
     vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
     vdInterfaceErrorCallbacks.pfnError     = handleVDError;
-    vdInterfaceErrorCallbacks.pfnMessage   = NULL;
+    vdInterfaceErrorCallbacks.pfnMessage   = handleVDMessage;
 
     vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
