vbox-img.cpp revision d72aa6b0dab3e9b60aa78bfca99c767c48a406b0
/* $Id$ */
/** @file
* Standalone image manipulation tool
*/
/*
* Copyright (C) 2010 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/initterm.h>
#include <iprt/buildconfig.h>
const char *g_pszProgName = "";
{
"Usage: %s\n"
" setuuid --filename <filename>\n"
" [--format VDI|VMDK|VHD|...]\n"
" [--uuid <uuid>]\n"
" [--parentuuid <uuid>]\n"
" [--zeroparentuuid]\n"
"\n"
" convert --srcfilename <filename>\n"
" --dstfilename <filename>\n"
" [--stdin]|[--stdout]\n"
" [--srcformat VDI|VMDK|VHD|RAW|..]\n"
" [--dstformat VDI|VMDK|VHD|RAW|..]\n"
" [--variant Standard,Fixed,Split2G,Stream,ESX]\n"
"\n"
" info --filename <filename>\n"
"\n"
" compact --filename <filename>\n",
}
{
static bool s_fShown; /* show only once */
if (!s_fShown)
{
"All rights reserved.\n"
"\n");
s_fShown = true;
}
}
/** command handler argument */
struct HandlerArg
{
int argc;
char **argv;
};
{
}
{
return VINF_SUCCESS;
}
/**
* Print a usage synopsis and the syntax error message.
*/
int errorSyntax(const char *pszFormat, ...)
{
return 1;
}
int errorRuntime(const char *pszFormat, ...)
{
return 1;
}
int handleSetUUID(HandlerArg *a)
{
const char *pszFilename = NULL;
bool fSetImageUuid = false;
bool fSetParentUuid = false;
int rc;
/* Parse the command line. */
static const RTGETOPTDEF s_aOptions[] =
{
};
int ch;
{
switch (ch)
{
case 'f': // --filename
break;
case 'o': // --format
break;
case 'u': // --uuid
fSetImageUuid = true;
break;
case 'p': // --parentuuid
fSetParentUuid = true;
break;
case 'P': // --zeroparentuuid
fSetParentUuid = true;
break;
default:
return ch;
}
}
/* Check for mandatory parameters. */
if (!pszFilename)
return errorSyntax("Mandatory --filename option missing\n");
/* Check for consistency of optional parameters. */
return errorSyntax("Invalid parameter to --uuid option\n");
/* Autodetect image format. */
if (!pszFormat)
{
/* Don't pass error interface, as that would triggers error messages
* because some backends fail to open the image. */
if (RT_FAILURE(rc))
}
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
return errorRuntime("Cannot open the virtual disk image \"%s\": %Rrc\n",
pszFilename, rc);
if (RT_FAILURE(rc))
return errorRuntime("Cannot get UUID of virtual disk image \"%s\": %Rrc\n",
pszFilename, rc);
if (RT_FAILURE(rc))
return errorRuntime("Cannot get parent UUID of virtual disk image \"%s\": %Rrc\n",
pszFilename, rc);
if (fSetImageUuid)
{
if (RT_FAILURE(rc))
return errorRuntime("Cannot set UUID of virtual disk image \"%s\": %Rrc\n",
pszFilename, rc);
}
if (fSetParentUuid)
{
if (RT_FAILURE(rc))
return errorRuntime("Cannot set parent UUID of virtual disk image \"%s\": %Rrc\n",
pszFilename, rc);
}
if (RT_FAILURE(rc))
if (pszFormat)
{
}
return 0;
}
typedef struct FILEIOSTATE
{
/** Offset in the file. */
/** Offset where the buffer contents start. UINT64_MAX=buffer invalid. */
/** Size of valid data in the buffer. */
/** Buffer for efficient I/O */
} FILEIOSTATE, *PFILEIOSTATE;
void **ppStorage)
{
/* Validate input. */
if (RT_FAILURE(rc))
return rc;
/* No need to clear the buffer, the data will be read from disk. */
if (!pFS)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
}
unsigned fMove)
{
}
{
*pcbFreeSpace = 0;
return VINF_SUCCESS;
}
{
}
{
}
{
}
{
int rc;
/* Fill buffer if it is empty. */
{
/* Repeat reading until buffer is full or EOF. */
do
{
if (RT_FAILURE(rc))
return rc;
}
/* Read several blocks and assemble the result if necessary */
size_t cbTotalRead = 0;
do
{
/* Skip over areas no one wants to read. */
{
{
if (pcbRead)
*pcbRead = cbTotalRead;
return VERR_EOF;
}
/* Repeat reading until buffer is full or EOF. */
do
{
if (RT_FAILURE(rc))
return rc;
}
uOffset += cbThisRead;
cbBuffer -= cbThisRead;
} while (cbBuffer > 0);
if (pcbRead)
*pcbRead = cbTotalRead;
return VINF_SUCCESS;
}
{
}
{
return VINF_SUCCESS;
}
void **ppStorage)
{
/* Validate input. */
if (RT_FAILURE(rc))
return rc;
/* Must clear buffer, so that skipped over data is initialized properly. */
if (!pFS)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
/* Flush any remaining buffer contents. */
return rc;
}
{
}
unsigned fMove)
{
}
{
return VINF_SUCCESS;
}
{
}
{
}
{
}
{
}
{
int rc;
/* Write the data to the buffer, flushing as required. */
size_t cbTotalWritten = 0;
do
{
/* Flush the buffer if we need a new one. */
{
}
uOffset += cbThisWrite;
cbBuffer -= cbThisWrite;
} while (cbBuffer > 0);
if (pcbWritten)
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
int handleConvert(HandlerArg *a)
{
const char *pszSrcFilename = NULL;
const char *pszDstFilename = NULL;
bool fStdIn = false;
bool fStdOut = false;
const char *pszSrcFormat = NULL;
const char *pszDstFormat = NULL;
const char *pszVariant = NULL;
unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
int rc = VINF_SUCCESS;
/* Parse the command line. */
static const RTGETOPTDEF s_aOptions[] =
{
};
int ch;
{
switch (ch)
{
case 'i': // --srcfilename
break;
case 'o': // --dstfilename
break;
case 'p': // --stdin
fStdIn = true;
break;
case 'P': // --stdout
fStdOut = true;
break;
case 's': // --srcformat
break;
case 'd': // --dstformat
break;
case 'v': // --variant
break;
default:
return ch;
}
}
if (fStdIn && !pszSrcFormat)
return errorSyntax("Mandatory --srcformat option missing\n");
if (!pszDstFormat)
pszDstFormat = "VDI";
if (fStdIn && !pszSrcFilename)
{
/* Complete dummy, will be just passed to various calls to fulfill
* the "must be non-NULL" requirement, and is completely ignored
* otherwise. It shown in the stderr message below. */
pszSrcFilename = "stdin";
}
if (fStdOut && !pszDstFilename)
{
/* Will be stored in the destination image if it is a streamOptimized
* VMDK, but it isn't really relevant - use it for "branding". */
pszDstFilename = "VirtualBoxStream.vmdk";
else
pszDstFilename = "stdout";
}
if (!pszSrcFilename)
return errorSyntax("Mandatory --srcfilename option missing\n");
if (!pszDstFilename)
return errorSyntax("Mandatory --dstfilename option missing\n");
if (fStdIn)
{
}
if (fStdOut)
{
}
/* check the variant parameter */
if (pszVariant)
{
char *psz = (char*)pszVariant;
{
if (pszComma)
else
if (len > 0)
{
else
return errorSyntax("Invalid --variant option\n");
}
if (pszComma)
else
}
}
do
{
/* try to determine input format if not specified */
if (!pszSrcFormat)
{
if (RT_FAILURE(rc))
{
break;
}
}
if (RT_FAILURE(rc))
{
break;
}
if (RT_FAILURE(rc))
{
break;
}
if (RT_FAILURE(rc))
{
break;
}
RTStrmPrintf(g_pStdErr, "Converting image \"%s\" with size %RU64 bytes (%RU64MB)...\n", pszSrcFilename, cbSize, (cbSize + _1M - 1) / _1M);
/* Create the output image */
if (RT_FAILURE(rc))
{
break;
}
}
while (0);
if (pDstDisk)
if (pSrcDisk)
}
int handleInfo(HandlerArg *a)
{
int rc = VINF_SUCCESS;
const char *pszFilename = NULL;
/* Parse the command line. */
static const RTGETOPTDEF s_aOptions[] =
{
};
int ch;
{
switch (ch)
{
case 'f': // --filename
break;
default:
return ch;
}
}
/* Check for mandatory parameters. */
if (!pszFilename)
return errorSyntax("Mandatory --filename option missing\n");
/* just try it */
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
/* Open the image */
if (RT_FAILURE(rc))
return rc;
}
int handleCompact(HandlerArg *a)
{
int rc = VINF_SUCCESS;
const char *pszFilename = NULL;
/* Parse the command line. */
static const RTGETOPTDEF s_aOptions[] =
{
};
int ch;
{
switch (ch)
{
case 'f': // --filename
break;
default:
return ch;
}
}
/* Check for mandatory parameters. */
if (!pszFilename)
return errorSyntax("Mandatory --filename option missing\n");
/* just try it */
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
/* Open the image */
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
return rc;
}
{
RTR3Init();
int rc;
int exitcode = 0;
bool fShowLogo = false;
int iCmd = 1;
int iCmdArg;
/* global options */
{
{
return 0;
}
{
/* Print version number, and do nothing else. */
return 0;
}
{
/* suppress the logo */
fShowLogo = false;
iCmd++;
}
else
{
break;
}
}
if (fShowLogo)
/* initialize the VD backend with dummy handlers */
if (RT_FAILURE(rc))
{
return 1;
}
/*
* All registered command handlers
*/
static const struct
{
const char *command;
int (*handler)(HandlerArg *a);
} s_commandHandlers[] =
{
{ "setuuid", handleSetUUID },
{ "convert", handleConvert },
{ "info", handleInfo },
{ "compact", handleCompact },
};
int commandIndex;
{
{
break;
}
}
{
return 1;
}
rc = VDShutdown();
if (RT_FAILURE(rc))
{
return 1;
}
return exitcode;
}
/* dummy stub for RuntimeR3 */
#ifndef RT_OS_WINDOWS
RTDECL(bool) RTAssertShouldPanic(void)
{
return true;
}
#endif