VirtualBox

Ignore:
Timestamp:
Oct 26, 2022 6:27:37 PM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
154304
Message:

Frontends/VBoxManage: 'VBoxManage internalcommands createrawvmdk' no
longer works after the implementation was moved to the API as part of
xTracker #9224. Update the 'createrawvmdk' subcommand to maps its
arguments to the equivalent 'VBoxManage createmedium disk --Variant
Rawdisk ...' invocation and invoke that command instead. Also include
a warning message that the 'createrawvmdk' subcommand is deprecated and
'VBoxManage createmedium' should be used instead. bugref:9224
ticketref:21125

Location:
trunk/src/VBox/Frontends/VBoxManage
Files:
2 edited

Legend:

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

    r96407 r97313  
    183183         "\n"
    184184         "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
    185          "WARNING: This is a development tool and shall only be used to analyse\n"
     185         "WARNING: This is a development tool and should only be used to analyse\n"
    186186         "         problems. It is completely unsupported and will change in\n"
    187187         "         incompatible ways without warning.\n"),
     
    228228        (enmCommand == USAGE_I_CREATERAWVMDK || enmCommand == USAGE_I_ALL)
    229229        ? Internal::tr(
    230            "  createrawvmdk -filename <filename> -rawdisk <diskname>\n"
    231            "                [-partitions <list of partition numbers> [-mbr <filename>] ]\n"
    232            "                [-relative]\n"
    233            "       Creates a new VMDK image which gives access to an entire host disk (if\n"
    234            "       the parameter -partitions is not specified) or some partitions of a\n"
    235            "       host disk. If access to individual partitions is granted, then the\n"
    236            "       parameter -mbr can be used to specify an alternative MBR to be used\n"
    237            "       (the partitioning information in the MBR file is ignored).\n"
    238            "       The diskname is on Linux e.g. /dev/sda, and on Windows e.g.\n"
    239            "       \\\\.\\PhysicalDrive0).\n"
    240            "       On Linux or FreeBSD host the parameter -relative causes a VMDK file to\n"
    241            "       be created which refers to individual partitions instead to the entire\n"
    242            "       disk.\n"
    243            "       The necessary partition numbers can be queried with\n"
    244            "         VBoxManage internalcommands listpartitions\n"
     230           "  createrawvmdk --filename <filename> --rawdisk <diskname>\n"
     231           "                [--partitions <list of partition numbers> [--mbr <filename>] ]\n"
     232           "                [--relative]\n"
     233           "       Creates a new VMDK image which gives direct access to a physical hard\n"
     234           "       disk on the host. The entire disk can be presented to the guest or\n"
     235           "       just specific partitions specified using the --partitions parameter.\n"
     236           "       If access to individual partitions is granted, then the --mbr parameter\n"
     237           "       can be used to specify an alternative Master Boot Record (MBR) (note\n"
     238           "       that the partitioning information in the MBR file is ignored). The\n"
     239           "       format of the diskname argument for the --rawdisk parameter varies by\n"
     240           "       platform but can be determined using the command:\n"
     241           "         VBoxManage list hostdrives\n"
     242           "       The output lists the available drives and their partitions along with\n"
     243           "       their partition types and sizes.\n"
     244           "       On Linux, FreeBSD, and Windows hosts the --relative parameter creates a\n"
     245           "       VMDK image file which references the specified individual partitions\n"
     246           "       directly instead of referencing the partitions by their offset from\n"
     247           "       the start of the physical disk.\n"
     248           "\n"
     249           "       Nota Bene: The 'createrawvdk' subcommand is deprecated. The equivalent\n"
     250           "       functionality is available using the 'VBoxManage createmedium' command\n"
     251           "       and should be used instead. See 'VBoxManage help createmedium' for\n"
     252           "       details.\n"
    245253           "\n")
    246254        : "",
     
    12901298}
    12911299
    1292 static RTEXITCODE CmdCreateRawVMDK(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
    1293 {
    1294     RT_NOREF(aVirtualBox, aSession);
    1295     HRESULT hrc = S_OK;
    1296     Utf8Str filename;
    1297     const char *pszMBRFilename = NULL;
    1298     Utf8Str rawdisk;
     1300static const RTGETOPTDEF g_aCreateRawVMDKOptions[] =
     1301{
     1302    { "--filename",     'f', RTGETOPT_REQ_STRING },
     1303    { "-filename",      'f', RTGETOPT_REQ_STRING },
     1304    { "--rawdisk",      'd', RTGETOPT_REQ_STRING },
     1305    { "-rawdisk",       'd', RTGETOPT_REQ_STRING },
     1306    { "--partitions",   'p', RTGETOPT_REQ_STRING },
     1307    { "-partitions",    'p', RTGETOPT_REQ_STRING },
     1308    { "--mbr",          'm', RTGETOPT_REQ_STRING },
     1309    { "-mbr",           'm', RTGETOPT_REQ_STRING },
     1310#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_WINDOWS)
     1311    { "--relative",     'r', RTGETOPT_REQ_NOTHING },
     1312    { "-relative",      'r', RTGETOPT_REQ_NOTHING },
     1313#endif /* RT_OS_LINUX || RT_OS_FREEBSD || RT_OS_WINDOWS */
     1314};
     1315
     1316static RTEXITCODE CmdCreateRawVMDK(int argc, char **argv, HandlerArg *a)
     1317{
     1318    const char *pszFilename = NULL;
     1319    const char *pszRawdisk = NULL;
    12991320    const char *pszPartitions = NULL;
     1321    const char *pszMbr = NULL;
    13001322    bool fRelative = false;
    1301 
    1302     uint64_t cbSize = 0;
    1303     PVDISK pDisk = NULL;
    1304     VDISKRAW RawDescriptor;
    1305     PVDINTERFACE pVDIfs = NULL;
    1306 
    1307     /* let's have a closer look at the arguments */
    1308     for (int i = 0; i < argc; i++)
    1309     {
    1310         if (strcmp(argv[i], "-filename") == 0)
    1311         {
    1312             if (argc <= i + 1)
    1313             {
    1314                 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
    1315             }
    1316             i++;
    1317             filename = argv[i];
    1318         }
    1319         else if (strcmp(argv[i], "-mbr") == 0)
    1320         {
    1321             if (argc <= i + 1)
    1322             {
    1323                 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
    1324             }
    1325             i++;
    1326             pszMBRFilename = argv[i];
    1327         }
    1328         else if (strcmp(argv[i], "-rawdisk") == 0)
    1329         {
    1330             if (argc <= i + 1)
    1331             {
    1332                 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
    1333             }
    1334             i++;
    1335             rawdisk = argv[i];
    1336         }
    1337         else if (strcmp(argv[i], "-partitions") == 0)
    1338         {
    1339             if (argc <= i + 1)
    1340             {
    1341                 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
    1342             }
    1343             i++;
    1344             pszPartitions = argv[i];
    1345         }
     1323    int c;
     1324    RTGETOPTUNION ValueUnion;
     1325    RTGETOPTSTATE GetState;
     1326    RTGetOptInit(&GetState, argc, argv, g_aCreateRawVMDKOptions, RT_ELEMENTS(g_aCreateRawVMDKOptions), 0, 0);
     1327    while ((c = RTGetOpt(&GetState, &ValueUnion)))
     1328    {
     1329        switch (c)
     1330        {
     1331            case 'f':   // --filename
     1332                pszFilename = ValueUnion.psz;
     1333                break;
     1334
     1335            case 'd':   // --rawdisk
     1336                pszRawdisk = ValueUnion.psz;
     1337                break;
     1338
     1339            case 'p':   // --partitions
     1340                pszPartitions = ValueUnion.psz;
     1341                break;
     1342
     1343            case 'm':   // --mbr
     1344                pszMbr = ValueUnion.psz;
     1345                break;
    13461346#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_WINDOWS)
    1347         else if (strcmp(argv[i], "-relative") == 0)
    1348         {
    1349             fRelative = true;
    1350         }
    1351 #endif /* RT_OS_LINUX || RT_OS_FREEBSD */
    1352         else
    1353             return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Invalid parameter '%s'"), argv[i]);
    1354     }
    1355 
    1356     if (filename.isEmpty())
    1357         return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Mandatory parameter -filename missing"));
    1358     if (rawdisk.isEmpty())
    1359         return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Mandatory parameter -rawdisk missing"));
    1360     if (!pszPartitions && pszMBRFilename)
     1347            case 'r':   // --relative
     1348                fRelative = true;
     1349                break;
     1350#endif /* RT_OS_LINUX || RT_OS_FREEBSD || RT_OS_WINDOWS */
     1351
     1352            default:
     1353                return errorGetOptInternal(USAGE_I_CREATERAWVMDK, c, &ValueUnion);
     1354        }
     1355    }
     1356
     1357    if (!pszFilename || !*pszFilename)
     1358        return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Mandatory parameter --filename missing"));
     1359    if (!pszRawdisk || !*pszRawdisk)
     1360        return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Mandatory parameter --rawdisk missing"));
     1361    if (!pszPartitions && pszMbr)
    13611362        return errorSyntaxInternal(USAGE_I_CREATERAWVMDK,
    1362                            Internal::tr("The parameter -mbr is only valid when the parameter -partitions is also present"));
    1363 
    1364 #ifdef RT_OS_DARWIN
    1365     fRelative = true;
    1366 #endif /* RT_OS_DARWIN */
    1367     RTFILE hRawFile;
    1368     int vrc = RTFileOpen(&hRawFile, rawdisk.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    1369     if (RT_FAILURE(vrc))
    1370     {
    1371         RTMsgError(Internal::tr("Cannot open the raw disk '%s': %Rrc"), rawdisk.c_str(), vrc);
    1372         goto out;
    1373     }
    1374 
    1375 #ifdef RT_OS_WINDOWS
    1376     /* Windows NT has no IOCTL_DISK_GET_LENGTH_INFORMATION ioctl. This was
    1377      * added to Windows XP, so we have to use the available info from DriveGeo.
    1378      * Note that we cannot simply use IOCTL_DISK_GET_DRIVE_GEOMETRY as it
    1379      * yields a slightly different result than IOCTL_DISK_GET_LENGTH_INFO.
    1380      * We call IOCTL_DISK_GET_DRIVE_GEOMETRY first as we need to check the media
    1381      * type anyway, and if IOCTL_DISK_GET_LENGTH_INFORMATION is supported
    1382      * we will later override cbSize.
    1383      */
    1384     DISK_GEOMETRY DriveGeo;
    1385     DWORD cbDriveGeo;
    1386     if (DeviceIoControl((HANDLE)RTFileToNative(hRawFile),
    1387                         IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
    1388                         &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL))
    1389     {
    1390         if (   DriveGeo.MediaType == FixedMedia
    1391             || DriveGeo.MediaType == RemovableMedia)
    1392         {
    1393             cbSize =     DriveGeo.Cylinders.QuadPart
    1394                      *   DriveGeo.TracksPerCylinder
    1395                      *   DriveGeo.SectorsPerTrack
    1396                      *   DriveGeo.BytesPerSector;
    1397         }
    1398         else
    1399         {
    1400             RTMsgError(Internal::tr("File '%s' is no fixed/removable medium device"), rawdisk.c_str());
    1401             vrc = VERR_INVALID_PARAMETER;
    1402             goto out;
    1403         }
    1404 
    1405         GET_LENGTH_INFORMATION DiskLenInfo;
    1406         DWORD junk;
    1407         if (DeviceIoControl((HANDLE)RTFileToNative(hRawFile),
    1408                             IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
    1409                             &DiskLenInfo, sizeof(DiskLenInfo), &junk, (LPOVERLAPPED)NULL))
    1410         {
    1411             /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */
    1412             cbSize = DiskLenInfo.Length.QuadPart;
    1413         }
    1414         if (   fRelative
    1415             && !rawdisk.startsWith("\\\\.\\PhysicalDrive", Utf8Str::CaseInsensitive))
    1416         {
    1417             RTMsgError(Internal::tr("The -relative parameter is invalid for raw disk %s"), rawdisk.c_str());
    1418             vrc = VERR_INVALID_PARAMETER;
    1419             goto out;
    1420         }
    1421     }
    1422     else
    1423     {
    1424         /*
    1425          * Could be raw image, remember error code and try to get the size first
    1426          * before failing.
    1427          */
    1428         vrc = RTErrConvertFromWin32(GetLastError());
    1429         if (RT_FAILURE(RTFileQuerySize(hRawFile, &cbSize)))
    1430         {
    1431             RTMsgError(Internal::tr("Cannot get the geometry of the raw disk '%s': %Rrc"), rawdisk.c_str(), vrc);
    1432             goto out;
    1433         }
    1434         else
    1435         {
    1436             if (fRelative)
    1437             {
    1438                 RTMsgError(Internal::tr("The -relative parameter is invalid for raw images"));
    1439                 vrc = VERR_INVALID_PARAMETER;
    1440                 goto out;
    1441             }
    1442             vrc = VINF_SUCCESS;
    1443         }
    1444     }
    1445 #elif defined(RT_OS_LINUX)
    1446     struct stat DevStat;
    1447     if (!fstat(RTFileToNative(hRawFile), &DevStat))
    1448     {
    1449         if (S_ISBLK(DevStat.st_mode))
    1450         {
    1451 #ifdef BLKGETSIZE64
    1452             /* BLKGETSIZE64 is broken up to 2.4.17 and in many 2.5.x. In 2.6.0
    1453              * it works without problems. */
    1454             struct utsname utsname;
    1455             if (    uname(&utsname) == 0
    1456                 &&  (   (strncmp(utsname.release, "2.5.", 4) == 0 && atoi(&utsname.release[4]) >= 18)
    1457                      || (strncmp(utsname.release, "2.", 2) == 0 && atoi(&utsname.release[2]) >= 6)))
    1458             {
    1459                 uint64_t cbBlk;
    1460                 if (!ioctl(RTFileToNative(hRawFile), BLKGETSIZE64, &cbBlk))
    1461                     cbSize = cbBlk;
    1462             }
    1463 #endif /* BLKGETSIZE64 */
    1464             if (!cbSize)
    1465             {
    1466                 long cBlocks;
    1467                 if (!ioctl(RTFileToNative(hRawFile), BLKGETSIZE, &cBlocks))
    1468                     cbSize = (uint64_t)cBlocks << 9;
    1469                 else
    1470                 {
    1471                     vrc = RTErrConvertFromErrno(errno);
    1472                     RTMsgError(Internal::tr("Cannot get the size of the raw disk '%s': %Rrc"), rawdisk.c_str(), vrc);
    1473                     goto out;
    1474                 }
    1475             }
    1476         }
    1477         else if (S_ISREG(DevStat.st_mode))
    1478         {
    1479             vrc = RTFileQuerySize(hRawFile, &cbSize);
    1480             if (RT_FAILURE(vrc))
    1481             {
    1482                 RTMsgError(Internal::tr("Failed to get size of file '%s': %Rrc"), rawdisk.c_str(), vrc);
    1483                 goto out;
    1484             }
    1485             else if (fRelative)
    1486             {
    1487                 RTMsgError(Internal::tr("The -relative parameter is invalid for raw images"));
    1488                 vrc = VERR_INVALID_PARAMETER;
    1489                 goto out;
    1490             }
    1491         }
    1492         else
    1493         {
    1494             RTMsgError(Internal::tr("File '%s' is no block device"), rawdisk.c_str());
    1495             vrc = VERR_INVALID_PARAMETER;
    1496             goto out;
    1497         }
    1498     }
    1499     else
    1500     {
    1501         vrc = RTErrConvertFromErrno(errno);
    1502         RTMsgError(Internal::tr("Failed to get file informtation for raw disk '%s': %Rrc"),
    1503                    rawdisk.c_str(), vrc);
    1504     }
    1505 #elif defined(RT_OS_DARWIN)
    1506     struct stat DevStat;
    1507     if (!fstat(RTFileToNative(hRawFile), &DevStat))
    1508     {
    1509         if (S_ISBLK(DevStat.st_mode))
    1510         {
    1511             uint64_t cBlocks;
    1512             uint32_t cbBlock;
    1513             if (!ioctl(RTFileToNative(hRawFile), DKIOCGETBLOCKCOUNT, &cBlocks))
    1514             {
    1515                 if (!ioctl(RTFileToNative(hRawFile), DKIOCGETBLOCKSIZE, &cbBlock))
    1516                     cbSize = cBlocks * cbBlock;
    1517                 else
    1518                 {
    1519                     RTMsgError(Internal::tr("Cannot get the block size for file '%s': %Rrc", rawdisk.c_str()), vrc);
    1520                     vrc = RTErrConvertFromErrno(errno);
    1521                     goto out;
    1522                 }
    1523             }
    1524             else
    1525             {
    1526                 vrc = RTErrConvertFromErrno(errno);
    1527                 RTMsgError(Internal::tr("Cannot get the block count for file '%s': %Rrc"), rawdisk.c_str(), vrc);
    1528                 goto out;
    1529             }
    1530         }
    1531         else if (S_ISREG(DevStat.st_mode))
    1532         {
    1533             fRelative = false; /* Must be false for raw image files. */
    1534             vrc = RTFileQuerySize(hRawFile, &cbSize);
    1535             if (RT_FAILURE(vrc))
    1536             {
    1537                 RTMsgError(Internal::tr("Failed to get size of file '%s': %Rrc"), rawdisk.c_str(), vrc);
    1538                 goto out;
    1539             }
    1540         }
    1541         else
    1542         {
    1543             RTMsgError(Internal::tr("File '%s' is neither block device nor regular file"), rawdisk.c_str());
    1544             vrc = VERR_INVALID_PARAMETER;
    1545             goto out;
    1546         }
    1547     }
    1548     else
    1549     {
    1550         vrc = RTErrConvertFromErrno(errno);
    1551         RTMsgError(Internal::tr("Failed to get file informtation for raw disk '%s': %Rrc"),
    1552                    rawdisk.c_str(), vrc);
    1553     }
    1554 #elif defined(RT_OS_SOLARIS)
    1555     struct stat DevStat;
    1556     if (!fstat(RTFileToNative(hRawFile), &DevStat))
    1557     {
    1558         if (S_ISBLK(DevStat.st_mode) || S_ISCHR(DevStat.st_mode))
    1559         {
    1560             struct dk_minfo mediainfo;
    1561             if (!ioctl(RTFileToNative(hRawFile), DKIOCGMEDIAINFO, &mediainfo))
    1562                 cbSize = mediainfo.dki_capacity * mediainfo.dki_lbsize;
    1563             else
    1564             {
    1565                 vrc = RTErrConvertFromErrno(errno);
    1566                 RTMsgError(Internal::tr("Cannot get the size of the raw disk '%s': %Rrc"), rawdisk.c_str(), vrc);
    1567                 goto out;
    1568             }
    1569         }
    1570         else if (S_ISREG(DevStat.st_mode))
    1571         {
    1572             vrc = RTFileQuerySize(hRawFile, &cbSize);
    1573             if (RT_FAILURE(vrc))
    1574             {
    1575                 RTMsgError(Internal::tr("Failed to get size of file '%s': %Rrc"), rawdisk.c_str(), vrc);
    1576                 goto out;
    1577             }
    1578         }
    1579         else
    1580         {
    1581             RTMsgError(Internal::tr("File '%s' is no block or char device"), rawdisk.c_str());
    1582             vrc = VERR_INVALID_PARAMETER;
    1583             goto out;
    1584         }
    1585     }
    1586     else
    1587     {
    1588         vrc = RTErrConvertFromErrno(errno);
    1589         RTMsgError(Internal::tr("Failed to get file informtation for raw disk '%s': %Rrc"),
    1590                    rawdisk.c_str(), vrc);
    1591     }
    1592 #elif defined(RT_OS_FREEBSD)
    1593     struct stat DevStat;
    1594     if (!fstat(RTFileToNative(hRawFile), &DevStat))
    1595     {
    1596         if (S_ISCHR(DevStat.st_mode))
    1597         {
    1598             off_t cbMedia = 0;
    1599             if (!ioctl(RTFileToNative(hRawFile), DIOCGMEDIASIZE, &cbMedia))
    1600                 cbSize = cbMedia;
    1601             else
    1602             {
    1603                 vrc = RTErrConvertFromErrno(errno);
    1604                 RTMsgError(Internal::tr("Cannot get the block count for file '%s': %Rrc"), rawdisk.c_str(), vrc);
    1605                 goto out;
    1606             }
    1607         }
    1608         else if (S_ISREG(DevStat.st_mode))
    1609         {
    1610             if (fRelative)
    1611             {
    1612                 RTMsgError(Internal::tr("The -relative parameter is invalid for raw images"));
    1613                 vrc = VERR_INVALID_PARAMETER;
    1614                 goto out;
    1615             }
    1616             cbSize = DevStat.st_size;
    1617         }
    1618         else
    1619         {
    1620             RTMsgError(Internal::tr("File '%s' is neither character device nor regular file"), rawdisk.c_str());
    1621             vrc = VERR_INVALID_PARAMETER;
    1622             goto out;
    1623         }
    1624     }
    1625     else
    1626     {
    1627         vrc = RTErrConvertFromErrno(errno);
    1628         RTMsgError(Internal::tr("Failed to get file informtation for raw disk '%s': %Rrc"),
    1629                    rawdisk.c_str(), vrc);
    1630     }
    1631 #else /* all unrecognized OSes */
    1632     /* Hopefully this works on all other hosts. If it doesn't, it'll just fail
    1633      * creating the VMDK, so no real harm done. */
    1634     vrc = RTFileQuerySize(hRawFile, &cbSize);
    1635     if (RT_FAILURE(vrc))
    1636     {
    1637         RTMsgError(Internal::tr("Cannot get the size of the raw disk '%s': %Rrc"), rawdisk.c_str(), vrc);
    1638         goto out;
    1639     }
    1640 #endif
    1641 
    1642     /* Check whether cbSize is actually sensible. */
    1643     if (!cbSize || cbSize % 512)
    1644     {
    1645         RTMsgError(Internal::tr("Detected size of raw disk '%s' is %RU64, an invalid value"), rawdisk.c_str(), cbSize);
    1646         vrc = VERR_INVALID_PARAMETER;
    1647         goto out;
    1648     }
    1649 
    1650     RawDescriptor.szSignature[0] = 'R';
    1651     RawDescriptor.szSignature[1] = 'A';
    1652     RawDescriptor.szSignature[2] = 'W';
    1653     RawDescriptor.szSignature[3] = '\0';
    1654     if (!pszPartitions)
    1655     {
    1656         RawDescriptor.uFlags = VDISKRAW_DISK;
    1657         RawDescriptor.pszRawDisk = (char *)rawdisk.c_str();
    1658     }
    1659     else
    1660     {
    1661         RawDescriptor.uFlags = VDISKRAW_NORMAL;
    1662         RawDescriptor.pszRawDisk = NULL;
    1663         RawDescriptor.cPartDescs = 0;
    1664         RawDescriptor.pPartDescs = NULL;
    1665 
    1666         uint32_t uPartitions = 0;
    1667         uint32_t uPartitionsRO = 0;
    1668 
    1669         const char *p = pszPartitions;
    1670         char *pszNext;
    1671         uint32_t u32;
    1672         while (*p != '\0')
    1673         {
    1674             vrc = RTStrToUInt32Ex(p, &pszNext, 0, &u32);
    1675             if (RT_FAILURE(vrc))
    1676             {
    1677                 RTMsgError(Internal::tr("Incorrect value in partitions parameter"));
    1678                 goto out;
    1679             }
    1680             uPartitions |= RT_BIT(u32);
    1681             p = pszNext;
    1682             if (*p == 'r')
    1683             {
    1684                 uPartitionsRO |= RT_BIT(u32);
    1685                 p++;
    1686             }
    1687             if (*p == ',')
    1688                 p++;
    1689             else if (*p != '\0')
    1690             {
    1691                 RTMsgError(Internal::tr("Incorrect separator in partitions parameter"));
    1692                 vrc = VERR_INVALID_PARAMETER;
    1693                 goto out;
    1694             }
    1695         }
    1696 
    1697         HOSTPARTITIONS partitions;
    1698         vrc = partRead(hRawFile, &partitions);
    1699         if (RT_FAILURE(vrc))
    1700         {
    1701             RTMsgError(Internal::tr("Cannot read the partition information from '%s'"), rawdisk.c_str());
    1702             goto out;
    1703         }
    1704 
    1705         RawDescriptor.enmPartitioningType = partitions.uPartitioningType;
    1706 
    1707         for (unsigned i = 0; i < partitions.cPartitions; i++)
    1708         {
    1709             if (    uPartitions & RT_BIT(partitions.aPartitions[i].uIndex)
    1710                 &&  PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
    1711             {
    1712                 /* Some ignorant user specified an extended partition.
    1713                  * Bad idea, as this would trigger an overlapping
    1714                  * partitions error later during VMDK creation. So warn
    1715                  * here and ignore what the user requested. */
    1716                 RTMsgWarning(Internal::tr(
    1717                                 "It is not possible (and necessary) to explicitly give access to the "
    1718                                 "extended partition %u. If required, enable access to all logical "
    1719                                 "partitions inside this extended partition."),
    1720                              partitions.aPartitions[i].uIndex);
    1721                 uPartitions &= ~RT_BIT(partitions.aPartitions[i].uIndex);
    1722             }
    1723         }
    1724 
    1725         for (unsigned i = 0; i < partitions.cPartitions; i++)
    1726         {
    1727             PVDISKRAWPARTDESC pPartDesc = NULL;
    1728 
    1729             /* first dump the MBR/EPT data area */
    1730             if (partitions.aPartitions[i].cPartDataSectors)
    1731             {
    1732                 pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
    1733                                            &RawDescriptor.pPartDescs);
    1734                 if (!pPartDesc)
    1735                 {
    1736                     RTMsgError(Internal::tr("Out of memory allocating the partition list for '%s'"), rawdisk.c_str());
    1737                     vrc = VERR_NO_MEMORY;
    1738                     goto out;
    1739                 }
    1740 
    1741                 /** @todo the clipping below isn't 100% accurate, as it should
    1742                  * actually clip to the track size. However, that's easier said
    1743                  * than done as figuring out the track size is heuristics. In
    1744                  * any case the clipping is adjusted later after sorting, to
    1745                  * prevent overlapping data areas on the resulting image. */
    1746                 pPartDesc->cbData = RT_MIN(partitions.aPartitions[i].cPartDataSectors, 63) * 512;
    1747                 pPartDesc->offStartInVDisk = partitions.aPartitions[i].uPartDataStart * 512;
    1748                 Assert(pPartDesc->cbData - (size_t)pPartDesc->cbData == 0);
    1749                 void *pPartData = RTMemAlloc((size_t)pPartDesc->cbData);
    1750                 if (!pPartData)
    1751                 {
    1752                     RTMsgError(Internal::tr("Out of memory allocating the partition descriptor for '%s'"),
    1753                                rawdisk.c_str());
    1754                     vrc = VERR_NO_MEMORY;
    1755                     goto out;
    1756                 }
    1757                 vrc = RTFileReadAt(hRawFile, partitions.aPartitions[i].uPartDataStart * 512,
    1758                                    pPartData, (size_t)pPartDesc->cbData, NULL);
    1759                 if (RT_FAILURE(vrc))
    1760                 {
    1761                     RTMsgError(Internal::tr("Cannot read partition data from raw device '%s': %Rrc"),
    1762                                rawdisk.c_str(), vrc);
    1763                     goto out;
    1764                 }
    1765                 /* Splice in the replacement MBR code if specified. */
    1766                 if (    partitions.aPartitions[i].uPartDataStart == 0
    1767                     &&  pszMBRFilename)
    1768                 {
    1769                     RTFILE MBRFile;
    1770                     vrc = RTFileOpen(&MBRFile, pszMBRFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    1771                     if (RT_FAILURE(vrc))
    1772                     {
    1773                         RTMsgError(Internal::tr("Cannot open replacement MBR file '%s' specified with -mbr: %Rrc"),
    1774                                    pszMBRFilename, vrc);
    1775                         goto out;
    1776                     }
    1777                     vrc = RTFileReadAt(MBRFile, 0, pPartData, 0x1be, NULL);
    1778                     RTFileClose(MBRFile);
    1779                     if (RT_FAILURE(vrc))
    1780                     {
    1781                         RTMsgError(Internal::tr("Cannot read replacement MBR file '%s': %Rrc"), pszMBRFilename, vrc);
    1782                         goto out;
    1783                     }
    1784                 }
    1785                 pPartDesc->pvPartitionData = pPartData;
    1786             }
    1787 
    1788             if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
    1789             {
    1790                 /* Suppress exporting the actual extended partition. Only
    1791                  * logical partitions should be processed. However completely
    1792                  * ignoring it leads to leaving out the EBR data. */
    1793                 continue;
    1794             }
    1795 
    1796             /* set up values for non-relative device names */
    1797             const char *pszRawName = rawdisk.c_str();
    1798             uint64_t uStartOffset = partitions.aPartitions[i].uStart * 512;
    1799 
    1800             pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
    1801                                        &RawDescriptor.pPartDescs);
    1802             if (!pPartDesc)
    1803             {
    1804                 RTMsgError(Internal::tr("Out of memory allocating the partition list for '%s'"), rawdisk.c_str());
    1805                 vrc = VERR_NO_MEMORY;
    1806                 goto out;
    1807             }
    1808 
    1809             if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
    1810             {
    1811                 if (uPartitionsRO & RT_BIT(partitions.aPartitions[i].uIndex))
    1812                     pPartDesc->uFlags |= VDISKRAW_READONLY;
    1813 
    1814                 if (fRelative)
    1815                 {
    1816 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    1817                     /* Refer to the correct partition and use offset 0. */
    1818                     char *psz;
    1819 #if defined(RT_OS_LINUX)
    1820                     /*
    1821                      * Check whether raw disk ends with a digit. In that case
    1822                      * insert a p before adding the partition number.
    1823                      * This is used for nvme devices only currently which look like
    1824                      * /dev/nvme0n1p1 but might be extended to other devices in the
    1825                      * future.
    1826                      */
    1827                     size_t cchRawDisk = rawdisk.length();
    1828                     if (RT_C_IS_DIGIT(pszRawName[cchRawDisk - 1]))
    1829                         RTStrAPrintf(&psz,
    1830                                      "%sp%u",
    1831                                      rawdisk.c_str(),
    1832                                      partitions.aPartitions[i].uIndex);
    1833                     else
    1834                         RTStrAPrintf(&psz,
    1835                                      "%s%u",
    1836                                      rawdisk.c_str(),
    1837                                      partitions.aPartitions[i].uIndex);
    1838 #elif defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    1839                     RTStrAPrintf(&psz,
    1840                                  "%ss%u",
    1841                                  rawdisk.c_str(),
    1842                                  partitions.aPartitions[i].uIndex);
    1843 #endif
    1844                     if (!psz)
    1845                     {
    1846                         vrc = VERR_NO_STR_MEMORY;
    1847                         RTMsgError(Internal::tr("Cannot create reference to individual partition %u, rc=%Rrc"),
    1848                                    partitions.aPartitions[i].uIndex, vrc);
    1849                         goto out;
    1850                     }
    1851                     pszRawName = psz;
    1852                     uStartOffset = 0;
    1853 #elif defined(RT_OS_WINDOWS)
    1854                     /* Refer to the correct partition and use offset 0. */
    1855                     char *psz;
    1856                     RTStrAPrintf(&psz, "\\\\.\\Harddisk%sPartition%u",
    1857                                  rawdisk.c_str() + 17,
    1858                                  partitions.aPartitions[i].uIndexWin);
    1859                     if (!psz)
    1860                     {
    1861                         vrc = VERR_NO_STR_MEMORY;
    1862                         RTMsgError(Internal::tr("Cannot create reference to individual partition %u (numbered %u), rc=%Rrc"),
    1863                                    partitions.aPartitions[i].uIndex, partitions.aPartitions[i].uIndexWin, vrc);
    1864                         goto out;
    1865                     }
    1866                     pszRawName = psz;
    1867                     uStartOffset = 0;
    1868 #else
    1869                     /** @todo not implemented for other hosts. Treat just like
    1870                      * not specified (this code is actually never reached). */
    1871 #endif
    1872                 }
    1873 
    1874                 pPartDesc->pszRawDevice = (char *)pszRawName;
    1875                 pPartDesc->offStartInDevice = uStartOffset;
    1876             }
    1877             else
    1878             {
    1879                 pPartDesc->pszRawDevice = NULL;
    1880                 pPartDesc->offStartInDevice = 0;
    1881             }
    1882 
    1883             pPartDesc->offStartInVDisk = partitions.aPartitions[i].uStart * 512;
    1884             pPartDesc->cbData = partitions.aPartitions[i].uSize * 512;
    1885         }
    1886 
    1887         /* Sort data areas in ascending order of start. */
    1888         for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
    1889         {
    1890             unsigned uMinIdx = i;
    1891             uint64_t uMinVal = RawDescriptor.pPartDescs[i].offStartInVDisk;
    1892             for (unsigned j = i + 1; j < RawDescriptor.cPartDescs; j++)
    1893             {
    1894                 if (RawDescriptor.pPartDescs[j].offStartInVDisk < uMinVal)
    1895                 {
    1896                     uMinIdx = j;
    1897                     uMinVal = RawDescriptor.pPartDescs[j].offStartInVDisk;
    1898                 }
    1899             }
    1900             if (uMinIdx != i)
    1901             {
    1902                 /* Swap entries at index i and uMinIdx. */
    1903                 VDISKRAWPARTDESC tmp;
    1904                 memcpy(&tmp, &RawDescriptor.pPartDescs[i], sizeof(tmp));
    1905                 memcpy(&RawDescriptor.pPartDescs[i], &RawDescriptor.pPartDescs[uMinIdx], sizeof(tmp));
    1906                 memcpy(&RawDescriptor.pPartDescs[uMinIdx], &tmp, sizeof(tmp));
    1907             }
    1908         }
    1909 
    1910         /* Have a second go at MBR/EPT, GPT area clipping. Now that the data areas
    1911          * are sorted this is much easier to get 100% right. */
    1912         //for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
    1913         for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
    1914         {
    1915             if (RawDescriptor.pPartDescs[i].pvPartitionData)
    1916             {
    1917                 RawDescriptor.pPartDescs[i].cbData = RT_MIN(  RawDescriptor.pPartDescs[i+1].offStartInVDisk
    1918                                                             - RawDescriptor.pPartDescs[i].offStartInVDisk,
    1919                                                             RawDescriptor.pPartDescs[i].cbData);
    1920                 if (!RawDescriptor.pPartDescs[i].cbData)
    1921                 {
    1922                     if (RawDescriptor.enmPartitioningType == VDISKPARTTYPE_MBR)
    1923                     {
    1924                         RTMsgError(Internal::tr("MBR/EPT overlaps with data area"));
    1925                         vrc = VERR_INVALID_PARAMETER;
    1926                         goto out;
    1927                     }
    1928                     if (RawDescriptor.cPartDescs != i+1)
    1929                     {
    1930                         RTMsgError(Internal::tr("GPT overlaps with data area"));
    1931                         vrc = VERR_INVALID_PARAMETER;
    1932                         goto out;
    1933                     }
    1934                 }
    1935             }
    1936         }
    1937     }
    1938 
    1939     RTFileClose(hRawFile);
    1940 
    1941 #ifdef DEBUG_klaus
    1942     if (!(RawDescriptor.uFlags & VDISKRAW_DISK))
    1943     {
    1944         RTPrintf("#            start         length    startoffset  partdataptr  device\n");
    1945         for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
    1946         {
    1947             RTPrintf("%2u  %14RU64 %14RU64 %14RU64 %#18p %s\n", i,
    1948                      RawDescriptor.pPartDescs[i].offStartInVDisk,
    1949                      RawDescriptor.pPartDescs[i].cbData,
    1950                      RawDescriptor.pPartDescs[i].offStartInDevice,
    1951                      RawDescriptor.pPartDescs[i].pvPartitionData,
    1952                      RawDescriptor.pPartDescs[i].pszRawDevice);
    1953         }
    1954     }
    1955 #endif
    1956 
    1957     VDINTERFACEERROR vdInterfaceError;
    1958     vdInterfaceError.pfnError     = handleVDError;
    1959     vdInterfaceError.pfnMessage   = handleVDMessage;
    1960 
    1961     hrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
    1962                          NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
    1963     AssertRC(vrc);
    1964 
    1965     vrc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk); /* Raw VMDK's are harddisk only. */
    1966     if (RT_FAILURE(vrc))
    1967     {
    1968         RTMsgError(Internal::tr("Cannot create the virtual disk container: %Rrc"), vrc);
    1969         goto out;
    1970     }
    1971 
    1972     Assert(RT_MIN(cbSize / 512 / 16 / 63, 16383) -
    1973            (unsigned int)RT_MIN(cbSize / 512 / 16 / 63, 16383) == 0);
    1974     VDGEOMETRY PCHS, LCHS;
    1975     PCHS.cCylinders = (unsigned int)RT_MIN(cbSize / 512 / 16 / 63, 16383);
    1976     PCHS.cHeads = 16;
    1977     PCHS.cSectors = 63;
    1978     LCHS.cCylinders = 0;
    1979     LCHS.cHeads = 0;
    1980     LCHS.cSectors = 0;
    1981     vrc = VDCreateBase(pDisk, "VMDK", filename.c_str(), cbSize,
    1982                        VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_RAWDISK,
    1983                        (char *)&RawDescriptor, &PCHS, &LCHS, NULL,
    1984                        VD_OPEN_FLAGS_NORMAL, NULL, NULL);
    1985     if (RT_FAILURE(vrc))
    1986     {
    1987         RTMsgError(Internal::tr("Cannot create the raw disk VMDK: %Rrc"), vrc);
    1988         goto out;
    1989     }
    1990     RTPrintf(Internal::tr("RAW host disk access VMDK file %s created successfully.\n"), filename.c_str());
    1991 
    1992     VDCloseAll(pDisk);
    1993 
    1994     /* Clean up allocated memory etc. */
    1995     if (pszPartitions)
    1996     {
    1997         for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
    1998         {
    1999             /* Free memory allocated for relative device name. */
    2000             if (fRelative && RawDescriptor.pPartDescs[i].pszRawDevice)
    2001                 RTStrFree((char *)(void *)RawDescriptor.pPartDescs[i].pszRawDevice);
    2002             if (RawDescriptor.pPartDescs[i].pvPartitionData)
    2003                 RTMemFree((void *)RawDescriptor.pPartDescs[i].pvPartitionData);
    2004         }
    2005         if (RawDescriptor.pPartDescs)
    2006             RTMemFree(RawDescriptor.pPartDescs);
    2007     }
    2008 
    2009     return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    2010 
    2011 out:
    2012     RTMsgError(Internal::tr("The raw disk vmdk file was not created"));
    2013     return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     1363                           Internal::tr("The parameter --mbr is only valid when the parameter -partitions is also present"));
     1364
     1365    /* Construct the equivalent 'VBoxManage createmedium disk --variant RawDisk ...' command line. */
     1366    size_t cMaxArgs = 9; /* all possible 'createmedium' args based on the 'createrawvmdk' options + 1 for NULL */
     1367    char **papszNewArgv = (char **)RTMemAllocZ(sizeof(papszNewArgv[0]) * cMaxArgs);
     1368    if (!papszNewArgv)
     1369            return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Failed to allocate memory for argument array"));
     1370    size_t cArgs = 0;
     1371
     1372    papszNewArgv[cArgs++] = RTStrDup("disk");
     1373    papszNewArgv[cArgs++] = RTStrDup("--variant=RawDisk");
     1374    papszNewArgv[cArgs++] = RTStrDup("--format=VMDK");
     1375
     1376    for (size_t i = 0; i < cArgs; i++)
     1377        if (!papszNewArgv[i])
     1378            return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Failed to allocate memory for argument array"));
     1379
     1380    if (   RTStrAPrintf(&papszNewArgv[cArgs++], "--filename=%s", pszFilename) == -1
     1381        || RTStrAPrintf(&papszNewArgv[cArgs++], "--property=RawDrive=%s", pszRawdisk) == -1
     1382        || (pszPartitions && (RTStrAPrintf(&papszNewArgv[cArgs++], "--property=Partitions=%s", pszPartitions) == -1))
     1383        || (pszMbr && (RTStrAPrintf(&papszNewArgv[cArgs++], "--property-filename=%s", pszMbr) == -1))
     1384        || (fRelative && (RTStrAPrintf(&papszNewArgv[cArgs++], "--property=Relative=%d", fRelative) == -1)))
     1385        return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Failed to allocate memory for argument array"));
     1386
     1387    papszNewArgv[cArgs] = NULL;
     1388
     1389    RTStrmPrintf(g_pStdErr,
     1390                 Internal::tr("\nThe 'createrawvdk' subcommand is deprecated.  The equivalent functionality is\n"
     1391                              "available using the 'VBoxManage createmedium' command and should be used\n"
     1392                              "instead.  See 'VBoxManage help createmedium' for details.\n\n"));
     1393
     1394    a->argc = cArgs;
     1395    a->argv = papszNewArgv;
     1396    RTEXITCODE rcExit = handleCreateMedium(a);
     1397
     1398    for (size_t i = 0; i < cArgs; i++)
     1399        RTStrFree(papszNewArgv[i]);
     1400    RTMemFree(papszNewArgv);
     1401
     1402    return rcExit;
    20141403}
    20151404
     
    27212110        return CmdListPartitions(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
    27222111    if (!strcmp(pszCmd, "createrawvmdk"))
    2723         return CmdCreateRawVMDK(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
     2112        return CmdCreateRawVMDK(a->argc - 1, &a->argv[1], a);
    27242113    if (!strcmp(pszCmd, "renamevmdk"))
    27252114        return CmdRenameVMDK(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp

    r97260 r97313  
    471471    {
    472472        if (!filename || !*filename)
    473             return errorSyntax(Disk::tr("Parameters --filename is required"));
     473            return errorSyntax(Disk::tr("Parameter --filename is required"));
    474474        if ((enmMediumVariant & MediumVariant_VmdkRawDisk) == 0 && size == 0)
    475             return errorSyntax(Disk::tr("Parameters --size is required"));
     475            return errorSyntax(Disk::tr("Parameter --size is required"));
    476476        if (!format || !*format)
    477477        {
Note: See TracChangeset for help on using the changeset viewer.

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