Changeset 97313 in vbox for trunk/src/VBox/Frontends/VBoxManage
- Timestamp:
- Oct 26, 2022 6:27:37 PM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 154304
- Location:
- trunk/src/VBox/Frontends/VBoxManage
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp
r96407 r97313 183 183 "\n" 184 184 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" 185 "WARNING: This is a development tool and sh allonly be used to analyse\n"185 "WARNING: This is a development tool and should only be used to analyse\n" 186 186 " problems. It is completely unsupported and will change in\n" 187 187 " incompatible ways without warning.\n"), … … 228 228 (enmCommand == USAGE_I_CREATERAWVMDK || enmCommand == USAGE_I_ALL) 229 229 ? 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" 245 253 "\n") 246 254 : "", … … 1290 1298 } 1291 1299 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; 1300 static 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 1316 static RTEXITCODE CmdCreateRawVMDK(int argc, char **argv, HandlerArg *a) 1317 { 1318 const char *pszFilename = NULL; 1319 const char *pszRawdisk = NULL; 1299 1320 const char *pszPartitions = NULL; 1321 const char *pszMbr = NULL; 1300 1322 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; 1346 1346 #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) 1361 1362 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; 2014 1403 } 2015 1404 … … 2721 2110 return CmdListPartitions(a->argc - 1, &a->argv[1], a->virtualBox, a->session); 2722 2111 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); 2724 2113 if (!strcmp(pszCmd, "renamevmdk")) 2725 2114 return CmdRenameVMDK(a->argc - 1, &a->argv[1], a->virtualBox, a->session); -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
r97260 r97313 471 471 { 472 472 if (!filename || !*filename) 473 return errorSyntax(Disk::tr("Parameter s--filename is required"));473 return errorSyntax(Disk::tr("Parameter --filename is required")); 474 474 if ((enmMediumVariant & MediumVariant_VmdkRawDisk) == 0 && size == 0) 475 return errorSyntax(Disk::tr("Parameter s--size is required"));475 return errorSyntax(Disk::tr("Parameter --size is required")); 476 476 if (!format || !*format) 477 477 {
Note:
See TracChangeset
for help on using the changeset viewer.