VBoxManageDisk.cpp revision b87c769f789d9f61e42149aa336e4c086f0f649e
/* $Id$ */
/** @file
*/
/*
* Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef VBOX_ONLY_DOCS
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "VBoxManage.h"
using namespace com;
// funcs
///////////////////////////////////////////////////////////////////////////////
static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
{
}
{
int rc = VINF_SUCCESS;
unsigned uMediumVariant = (unsigned)(*pMediumVariant);
{
if (pszComma)
else
if (len > 0)
{
// Parsing is intentionally inconsistent: "standard" resets the
// variant, whereas the other flags are cumulative.
else
}
if (pszComma)
else
}
if (RT_SUCCESS(rc))
return rc;
}
{
int rc = VINF_SUCCESS;
else
if (RT_SUCCESS(rc))
return rc;
}
/** @todo move this into getopt, as getting bool values is generic */
{
int rc = VINF_SUCCESS;
{
*pb = true;
}
{
*pb = false;
}
else
return rc;
}
bool fSilent)
{
/* If it is no UUID, convert the filename to an absolute one. */
{
if (RT_FAILURE(irc))
{
if (!fSilent)
return E_FAIL;
}
}
if (!fSilent)
pMedium.asOutParam()));
else
pMedium.asOutParam());
return rc;
}
{
/** @todo laziness shortcut. should really check the MediumFormatCapabilities */
{
if (RT_FAILURE(irc))
{
return E_FAIL;
}
}
pMedium.asOutParam()));
return rc;
}
static const RTGETOPTDEF g_aCreateMediumOptions[] =
{
};
int handleCreateMedium(HandlerArg *a)
{
int vrc;
const char *diffparent = NULL;
enum {
bool fBase = true;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateMediumOptions, RT_ELEMENTS(g_aCreateMediumOptions),
{
switch (c)
{
case 'H': // disk
break;
case 'D': // DVD
break;
case 'L': // floppy
cmd = CMD_FLOPPY;
break;
case 'f': // --filename
break;
case 'd': // --diffparent
fBase = false;
break;
case 's': // --size
break;
case 'S': // --sizebyte
break;
case 'o': // --format
break;
case 'F': // --static ("fixed"/"flat")
{
unsigned uMediumVariant = (unsigned)enmMediumVariant;
break;
}
case 'm': // --variant
if (RT_FAILURE(vrc))
break;
case VINF_GETOPT_NOT_OPTION:
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
/* check the outcome */
if (fBase)
{
if ( !filename
|| !*filename
|| size == 0)
{
format = "VDI";
{
format = "RAW";
unsigned uMediumVariant = (unsigned)enmMediumVariant;
}
}
}
else
{
if ( !filename
|| !*filename)
size = 0;
return errorSyntax(USAGE_CREATEMEDIUM, "Creating a differencing medium is only supported for hard disks");
{
/* Skip over . if there is an extension. */
if (pszExt)
pszExt++;
format = "VDI";
else
}
false /* fForceNewUuidOnOpen */, false /* fSilent */);
return 1;
if (pParentMedium.isNull())
{
RTMsgError("Invalid parent hard disk reference, avoiding crash");
return 1;
}
return 1;
if (state == MediumState_Inaccessible)
{
return 1;
}
}
/* check for filename extension */
/** @todo use IMediumFormat to cover all extensions generically */
{
{
else
else if (cmd == CMD_FLOPPY)
}
else if (cmd == CMD_FLOPPY)
{
{
temp &= 1<<i;
}
if (fBase)
CHECK_ERROR(pMedium, CreateBaseStorage(size, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
else
CHECK_ERROR(pParentMedium, CreateDiffStorage(pMedium, ComSafeArrayAsInParam(l_variants), pProgress.asOutParam()));
{
}
}
{
//CHECK_ERROR(pMedium, Close());
}
}
static const RTGETOPTDEF g_aModifyMediumOptions[] =
{
};
int handleModifyMedium(HandlerArg *a)
{
int vrc;
enum {
bool AutoReset = false;
bool fModifyMediumType = false;
bool fModifyAutoReset = false;
bool fModifyProperties = false;
bool fModifyCompact = false;
bool fModifyResize = false;
const char *pszFilenameOrUuid = NULL;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aModifyMediumOptions, RT_ELEMENTS(g_aModifyMediumOptions),
{
switch (c)
{
case 'H': // disk
break;
case 'D': // DVD
break;
case 'L': // floppy
cmd = CMD_FLOPPY;
break;
case 't': // --type
if (RT_FAILURE(vrc))
fModifyMediumType = true;
break;
case 'z': // --autoreset
if (RT_FAILURE(vrc))
fModifyAutoReset = true;
break;
case 'p': // --property
{
/* Parse 'name=value' */
if (pszProperty)
{
if (pDelimiter)
{
*pDelimiter = '\0';
fModifyProperties = true;
}
else
{
}
}
else
{
RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for medium property '%s'\n", ValueUnion.psz);
}
break;
}
case 'c': // --compact
fModifyCompact = true;
break;
case 'r': // --resize
fModifyResize = true;
break;
case 'R': // --resizebyte
fModifyResize = true;
break;
case VINF_GETOPT_NOT_OPTION:
if (!pszFilenameOrUuid)
else
break;
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
if (!pszFilenameOrUuid)
if (!fModifyMediumType && !fModifyAutoReset && !fModifyProperties && !fModifyCompact && !fModifyResize)
/* Always open the medium if necessary, there is no other way. */
false /* fForceNewUuidOnOpen */, false /* fSilent */);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
return 1;
{
RTMsgError("Invalid medium reference, avoiding crash");
return 1;
}
if (fModifyMediumType)
{
if (enmCurrMediumType != enmMediumType)
}
if (fModifyAutoReset)
{
}
if (fModifyProperties)
{
CHECK_ERROR(pMedium, SetProperties(ComSafeArrayAsInParam(mediumPropNames), ComSafeArrayAsInParam(mediumPropValues)));
}
if (fModifyCompact)
{
{
RTMsgError("Compact medium operation is not implemented!");
else if (rc == VBOX_E_NOT_SUPPORTED)
RTMsgError("Compact medium operation for this format is not implemented yet!");
else
RTMsgError("Failed to compact medium!");
}
}
if (fModifyResize)
{
{
RTMsgError("Resize medium operation is not implemented!");
else if (rc == VBOX_E_NOT_SUPPORTED)
RTMsgError("Resize medium operation for this format is not implemented yet!");
else
}
}
}
static const RTGETOPTDEF g_aCloneMediumOptions[] =
{
};
int handleCloneMedium(HandlerArg *a)
{
int vrc;
enum {
bool fExisting = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneMediumOptions, RT_ELEMENTS(g_aCloneMediumOptions),
{
switch (c)
{
case 'd': // disk
break;
case 'D': // DVD
break;
case 'f': // floppy
cmd = CMD_FLOPPY;
break;
case 'o': // --format
break;
case 'F': // --static
{
unsigned uMediumVariant = (unsigned)enmMediumVariant;
break;
}
case 'E': // --existing
fExisting = true;
break;
case 'm': // --variant
if (RT_FAILURE(vrc))
break;
case VINF_GETOPT_NOT_OPTION:
if (!pszSrc)
else if (!pszDst)
else
break;
default:
if (c > 0)
{
if (RT_C_IS_GRAPH(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
if (!pszSrc)
if (!pszDst)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
return 1;
do
{
if (fExisting)
{
false /* fForceNewUuidOnOpen */, false /* fSilent */);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
break;
/* Perform accessibility check now. */
}
else
{
/* use the format of the source medium if unspecified */
else if (cmd == CMD_FLOPPY)
break;
}
{
temp &= 1<<i;
}
CHECK_ERROR_BREAK(pSrcMedium, CloneTo(pDstMedium, ComSafeArrayAsInParam(l_variants), NULL, pProgress.asOutParam()));
RTPrintf("Clone medium created in format '%ls'. UUID: %s\n",
}
while (0);
}
static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
{
};
{
int rc = VINF_SUCCESS;
bool fReadFromStdIn = false;
const char *format = "VDI";
const char *srcfilename = NULL;
const char *dstfilename = NULL;
unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
{
switch (c)
{
case 'u': // --uuid
break;
case 'o': // --format
break;
case 'm': // --variant
{
if (RT_FAILURE(rc))
/// @todo cleaner solution than assuming 1:1 mapping?
uImageFlags = (unsigned)enmMediumVariant;
break;
}
case VINF_GETOPT_NOT_OPTION:
if (!srcfilename)
{
}
else if (!dstfilename)
else if (fReadFromStdIn && !filesize)
else
break;
default:
}
}
/* open raw image file. */
if (fReadFromStdIn)
else
if (RT_FAILURE(rc))
{
goto out;
}
/* get image size. */
if (fReadFromStdIn)
else
if (RT_FAILURE(rc))
{
goto out;
}
char pszComment[256];
if (RT_FAILURE(rc))
{
goto out;
}
LCHS.cCylinders = 0;
if (RT_FAILURE(rc))
{
goto out;
}
if (!pvBuf)
{
rc = VERR_NO_MEMORY;
goto out;
}
offFile = 0;
{
cbRead = 0;
break;
if (RT_FAILURE(rc))
{
goto out;
}
}
out:
if (pvBuf)
if (pDisk)
if (File != NIL_RTFILE)
}
const char *pszParentUUID,
bool fOptLong)
{
do
{
if (pszParentUUID)
/* check for accessibility */
const char *pszState = "unknown";
switch (enmState)
{
case MediumState_NotCreated:
pszState = "not created";
break;
case MediumState_Created:
pszState = "created";
break;
case MediumState_LockedRead:
pszState = "locked read";
break;
case MediumState_LockedWrite:
pszState = "locked write";
break;
case MediumState_Inaccessible:
pszState = "inaccessible";
break;
case MediumState_Creating:
pszState = "creating";
break;
case MediumState_Deleting:
pszState = "deleting";
break;
}
{
}
if (fOptLong)
{
if (!description.isEmpty())
}
const char *typeStr = "unknown";
switch (type)
{
case MediumType_Normal:
typeStr = "normal (differencing)";
else
typeStr = "normal (base)";
break;
case MediumType_Immutable:
typeStr = "immutable";
break;
case MediumType_Writethrough:
typeStr = "writethrough";
break;
case MediumType_Shareable:
typeStr = "shareable";
break;
case MediumType_Readonly:
typeStr = "readonly";
break;
case MediumType_MultiAttach:
typeStr = "multiattach";
break;
}
/* print out information specific for differencing media */
{
}
if (fOptLong)
{
variant |= safeArray_variant[i];
const char *variantStr = "unknown";
{
variantStr = "split2G";
break;
variantStr = "streamOptimized";
break;
case MediumVariant_VmdkESX:
variantStr = "ESX";
break;
case MediumVariant_Standard:
variantStr = "default";
break;
}
const char *variantTypeStr = "dynamic";
if (variant & MediumVariant_Fixed)
variantTypeStr = "fixed";
else if (variant & MediumVariant_Diff)
variantTypeStr = "differencing";
}
if (fOptLong)
{
}
if (fOptLong)
{
pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
bool fFirst = true;
{
if (i < cValues)
RTPrintf("%s%ls=%ls\n",
}
}
if (fOptLong)
{
bool fFirst = true;
{
if (pMachine)
{
RTPrintf("%s%ls (UUID: %ls)",
fFirst = false;
{
if (pSnapshot)
{
}
}
RTPrintf("\n");
}
}
}
if (fOptLong)
{
bool fFirst = true;
{
if (pChild)
{
RTPrintf("%s%ls\n",
fFirst = false;
}
}
}
}
while (0);
return rc;
}
static const RTGETOPTDEF g_aShowMediumInfoOptions[] =
{
};
int handleShowMediumInfo(HandlerArg *a)
{
enum {
const char *pszFilenameOrUuid = NULL;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aShowMediumInfoOptions, RT_ELEMENTS(g_aShowMediumInfoOptions),
{
switch (c)
{
case 'd': // disk
return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
break;
case 'D': // DVD
return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
break;
case 'f': // floppy
return errorSyntax(USAGE_SHOWMEDIUMINFO, "Only one command can be specified: '%s'", ValueUnion.psz);
cmd = CMD_FLOPPY;
break;
case VINF_GETOPT_NOT_OPTION:
if (!pszFilenameOrUuid)
else
break;
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
/* check for required options */
if (!pszFilenameOrUuid)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
return 1;
{
}
}
static const RTGETOPTDEF g_aCloseMediumOptions[] =
{
};
int handleCloseMedium(HandlerArg *a)
{
enum {
const char *pszFilenameOrUuid = NULL;
bool fDelete = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
{
switch (c)
{
case 'd': // disk
break;
case 'D': // DVD
break;
case 'f': // floppy
cmd = CMD_FLOPPY;
break;
case 'r': // --delete
fDelete = true;
break;
case VINF_GETOPT_NOT_OPTION:
if (!pszFilenameOrUuid)
else
break;
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
/* check for required options */
if (!pszFilenameOrUuid)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
{
if (fDelete)
{
{
}
else
}
}
}
int handleMediumProperty(HandlerArg *a)
{
enum {
const char *pszFilenameOrUuid = NULL;
const char *pszProperty = NULL;
{
cmd = CMD_FLOPPY;
else
{
}
a->argv++;
a->argc--;
}
else
{
}
if (a->argc == 0)
&& a->argc != 4)
&& a->argc != 3))
return errorSyntax(USAGE_MEDIUMPROPERTY, "Invalid number of arguments given for action: %s", pszAction);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
false /* fForceNewUuidOnOpen */, false /* fSilent */);
{
{
}
{
}
{
/** @todo */
}
}
}
static const RTGETOPTDEF g_aEncryptMediumOptions[] =
{
};
int handleEncryptMedium(HandlerArg *a)
{
int vrc;
const char *pszPasswordNew = NULL;
const char *pszPasswordOld = NULL;
const char *pszFilenameOrUuid = NULL;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aEncryptMediumOptions, RT_ELEMENTS(g_aEncryptMediumOptions),
{
switch (c)
{
case 'n': // --newpassword
break;
case 'o': // --oldpassword
break;
case 'c': // --cipher
break;
case VINF_GETOPT_NOT_OPTION:
if (!pszFilenameOrUuid)
else
break;
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
if (!pszFilenameOrUuid)
if (!pszPasswordNew && !pszPasswordOld)
/* Always open the medium if necessary, there is no other way. */
false /* fForceNewUuidOnOpen */, false /* fSilent */);
return 1;
{
RTMsgError("Invalid hard disk reference, avoiding crash");
return 1;
}
{
RTMsgError("Encrypt hard disk operation is not implemented!");
else if (rc == VBOX_E_NOT_SUPPORTED)
RTMsgError("Encrypt hard disk operation for this cipher is not implemented yet!");
else
RTMsgError("Failed to encrypt hard disk!");
}
}
#endif /* !VBOX_ONLY_DOCS */