ApplianceImplImport.cpp revision 48b14aaf804d764e2c7bec8243c379f7ff489ebb
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * IAppliance and IVirtualSystem COM class implementations.
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * Copyright (C) 2008-2013 Oracle Corporation
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * available from http://www.virtualbox.org. This file is free software;
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * General Public License (GPL) as published by the Free Software
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsyncusing namespace std;
64eea8161bef2aa3c6516481383c830bca27abfevboxsync////////////////////////////////////////////////////////////////////////////////
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync// IAppliance public methods
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync////////////////////////////////////////////////////////////////////////////////
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * Public method implementation. This opens the OVF with ovfreader.cpp.
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * Thread implementation is in Appliance::readImpl().
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsync * @param path
634a322713c795d9663e89dba496ecc6a78bfcc9vboxsyncSTDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress)
if (!isApplianceIdle())
return E_ACCESSDENIED;
if (m->pReader)
delete m->pReader;
return S_OK;
* Public method implementation. This looks at the output of ovfreader.cpp and creates
// - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
if (!isApplianceIdle())
return E_ACCESSDENIED;
if (!m->pReader)
++it)
// 2) Otherwise, if there is OperatingSystemSection/vbox:OSType, use that one.
nameVBox);
addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
if ( ullMemSizeVBox != 0
addWarning(tr("The virtual system \"%s\" claims support for %llu MB RAM size, but VirtualBox has support for min %u & max %u MB RAM size only."),
strSoundCard = Utf8StrFmt("%RU32", (uint32_t)pNewDesc->m->pConfig->hardwareMachine.audioAdapter.controllerType);
#ifdef VBOX_WITH_USB
uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(pNewDesc->m->pConfig->hardwareMachine.chipsetType);
const settings::NetworkAdaptersList &llNetworkAdapters = pNewDesc->m->pConfig->hardwareMachine.llNetworkAdapters;
addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
size_t a = 0;
++it1, ++a)
addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
size_t a = 0;
++itEA, ++a)
#ifdef VBOX_WITH_E1000
bool fFloppy = false;
bool fDVD = false;
settings::StorageControllersList &llControllers = pNewDesc->m->pConfig->storageMachine.llStorageControllers;
++it3)
++it4)
if (fFloppy)
if (fDVD)
++hdcIt)
addWarning(tr("The virtual \"%s\" system requests support for more than two IDE controller channels, but VirtualBox supports only two."),
++cIDEused;
addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"),
++cSATAused;
addWarning(tr("The virtual system \"%s\" requests support for an additional SCSI controller of type \"%s\" with ID %s, but VirtualBox presently supports only one SCSI controller."),
++cSCSIused;
++itVD)
if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"),
return rc;
STDMETHODIMP Appliance::ImportMachines(ComSafeArrayIn(ImportOptions_T, options), IProgress **aProgress)
AssertReturn(!(m->optList.contains(ImportOptions_KeepAllMACs) && m->optList.contains(ImportOptions_KeepNATMACs)), E_INVALIDARG);
if (!isApplianceIdle())
return E_ACCESSDENIED;
if (!m->pReader)
return rc;
* This will then open the OVF with ovfreader.cpp.
* 2) in a second worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl(), which
* called Appliance::readFSOVA(), which called Appliance::importImpl(), which then called this again.
* 3) from Appliance::readS3(), which got called from a previous instance of Appliance::taskThreadImportOrExport().
return rc;
* Actual worker code for reading an OVF from disk. This is called from Appliance::taskThreadImportOrExport()
* and therefore runs on the OVF read worker thread. This opens the OVF with ovfreader.cpp.
return rc;
if (!pShaIo)
if (!pFileIo)
if (pShaIo)
if (pFileIo)
return rc;
int vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true);
char *pszFilename = 0;
if (!pShaIo)
if (!pTarIo)
if (pszFilename)
if (pShaIo)
if (pTarIo)
return rc;
HRESULT Appliance::readFSImpl(TaskOVF *pTask, const RTCString &strFilename, PVDINTERFACEIO pIfIo, PSHASTORAGE pStorage)
void *pvTmpBuf = 0;
|| !pvTmpBuf)
x.what());
if (pvTmpBuf)
return rc;
#ifdef VBOX_WITH_S3
* Worker code for reading OVF from the cloud. This is called from Appliance::taskThreadImportOrExport()
vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that your credentials are right."
if (pszTmpDir)
return rc;
* This creates one or more new machines according to the VirtualSystemScription instances created by
* 2) from Appliance::importS3(), which got called from a previous instance of Appliance::taskThreadImportOrExport().
mode);
return rc;
* Actual worker code for importing OVF data into VirtualBox. This is called from Appliance::taskThreadImportOrExport()
* and therefore runs on the OVF import worker thread. This creates one or more new machines according to the
* 1) in a first worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl();
* 2) in a second worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl(), which
* called Appliance::importFSOVA(), which called Appliance::importImpl(), which then called this again.
* 3) in a second worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl(), which
if (!isApplianceIdle())
return E_ACCESSDENIED;
++itID)
rc2 = failedMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(aMedia));
return rc;
if (!pFileIo)
if (!pShaIo)
if (pvMfBuf)
if (pShaIo)
if (pFileIo)
return rc;
int vrc = RTTarOpen(&tar, pTask->locInfo.strPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, true);
char *pszFilename = 0;
void *pvMfBuf = 0;
if (!pShaIo)
if (!pTarIo)
if (!pvMfBuf)
if (pvMfBuf)
stack.llSrcDisksDigest.push_front(STRPAIR(Utf8Str(pszFilename).stripExt().append(".ovf"), m->strOVFSHADigest));
if (pszFilename)
if (pvMfBuf)
if (pShaIo)
if (pTarIo)
return rc;
#ifdef VBOX_WITH_S3
* Worker code for importing OVF from the cloud. This is called from Appliance::taskThreadImportOrExport()
++it)
std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
++itH)
vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
pTask->pProgress->SetNextOperation(BstrFmt(tr("Downloading file '%s'"), pszFilename).raw(), s.second);
pTask->pProgress->SetNextOperation(BstrFmt(tr("Importing appliance")).raw(), m->ulWeightForXmlOperation);
for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
if (pszTmpDir)
return rc;
HRESULT Appliance::readManifestFile(const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage)
return rc;
HRESULT Appliance::readTarManifestFile(RTTAR tar, const Utf8Str &strFile, void **ppvBuf, size_t *pcbSize, PVDINTERFACEIO pCallbacks, PSHASTORAGE pStorage)
char *pszCurFile;
return rc;
HRESULT Appliance::verifyManifestFile(const Utf8Str &strFile, ImportStack &stack, void *pvBuf, size_t cbSize)
PRTMANIFESTTEST paTests = (PRTMANIFESTTEST)RTMemAlloc(sizeof(RTMANIFESTTEST) * stack.llSrcDisksDigest.size());
if (!paTests)
return E_OUTOFMEMORY;
size_t i = 0;
++it1, ++i)
int vrc = RTManifestVerifyFilesBuf(pvBuf, cbSize, paTests, stack.llSrcDisksDigest.size(), &iFailed);
return rc;
* @param controllerType out: the name of the hard disk controller to attach to (e.g. "IDE Controller").
Log(("Appliance::convertDiskAttachmentValues: hdc.system=%d, hdc.fPrimary=%d, ulAddressOnParent=%d\n", hdc.system, hdc.fPrimary, ulAddressOnParent));
switch (ulAddressOnParent)
lDevice = (long)0;
lControllerPort = (long)0;
lDevice = (long)0;
lControllerPort = (long)0;
lDevice = (long)0;
lDevice = (long)0;
lDevice = (long)0;
* the caller needs to pass in the ovf::DiskImage structure from ovfreader.cpp.
* As a result, in both cases, if di.strHref is empty, we create a new disk as per the OVF
* @param di ovfreader.cpp structure describing the disk image from the OVF that is to be imported
* @param pTargetHD out: The newly created target disk. This also gets pushed on stack.llHardDisksCreated for cleanup.
HRESULT rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this), BstrFmt(tr("Creating medium '%s'"), strTargetPath.c_str()).raw(), TRUE);
Utf8StrFmt strSrcFilePath("%s%c%s", stack.strSourceDir.c_str(), RTPATH_DELIMITER, strSourceOVF.c_str());
rc = pTargetHD->CreateBaseStorage(di.iCapacity / _1M, ComSafeArrayAsInParam(mediumVariant), ComPtr<IProgress>(pProgress).asOutParam());
stack.pProgress->SetNextOperation(BstrFmt(tr("Creating disk image '%s'"), strTargetPath.c_str()).raw(),
if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/interfaces/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive)
stack.pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), RTPathFilename(strSrcFilePath.c_str())).raw(),
* Imports one OVF virtual system (described by the given ovf::VirtualSystem and VirtualSystemDescription)
* up any leftovers from this function. For this, the given ImportStack instance has received information
#ifdef VBOX_WITH_USB
std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
size_t a = 0;
++nwIt, ++a)
for (size_t j = 0;
for (size_t j = 0;
std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
// In OVF (at least VMware's version of it), an IDE controller has two ports, so VirtualBox's single IDE controller
// with two channels and two ports each counts as two OVF IDE controllers -- so we accept one or two such IDE controllers
rc = pNewMachine->AddStorageController(Bstr("IDE Controller").raw(), StorageBus_IDE, pController.asOutParam());
std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
rc = pNewMachine->AddStorageController(Bstr("SATA Controller").raw(), StorageBus_SATA, pController.asOutParam());
std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
std::list<VirtualSystemDescriptionEntry*> vsdeHDCSAS = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSAS);
rc = pNewMachine->AddStorageController(Bstr(L"SAS Controller").raw(), StorageBus_SAS, pController.asOutParam());
std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
std::list<VirtualSystemDescriptionEntry*> vsdeCDROM = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM);
rc = sMachine->AddStorageController(Bstr("Floppy Controller").raw(), StorageBus_Floppy, pController.asOutParam());
NULL);
++jt)
++kt)
if (!pController)
tr("OVF wants a CD-ROM drive but cannot find IDE controller, which is required in this version of VirtualBox"));
NULL);
std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
++itHD)
pStorage);
Log(("Attaching disk %s to port %d on device %d\n", vsdeHD->strVboxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice));
* up any leftovers from this function. For this, the given ImportStack instance has received information
#ifdef VBOX_WITH_USB
config.hardwareMachine.audioAdapter.controllerType = (AudioControllerType_T)stack.strAudioAdapter.toUInt32();
if (!( fKeepAllMACs
std::list<VirtualSystemDescriptionEntry*> avsdeNWs = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
++itNW)
++it1)
bool fInconsistent = false;
bool fRepairDuplicate = false;
++it3)
if ( ( !fDVD
( !fFloppy
cHardDisks++;
fInconsistent = true;
fInconsistent = true;
fRepairDuplicate = true;
++it4;
fRepairDuplicate = false;
std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
fRepairDuplicate = false;
for (settings::StorageControllersList::iterator sit = config.storageMachine.llStorageControllers.begin();
++sit)
case StorageBus_SATA:
case StorageBus_SCSI:
case StorageBus_IDE:
case StorageBus_SAS:
++dit)
if (fRepairDuplicate)
++avsdeHDsIt;
bool fFound = false;
++oit)
++itHD)
if (!vsdeTargetHD)
pStorage);
fFound = true;
if (!fFound)
tr("<vbox:Machine> element in OVF contains a medium attachment for the disk image %s but the OVF describes no such image"),
} // for (settings::StorageControllersList::const_iterator sit = config.storageMachine.llStorageControllers.begin();
stack.strNameVBox, // name from OVF preparations; can be suffixed to avoid duplicates, or changed by user
size_t i = 0;
// -- either this OVF was written by vbox 3.2 or later, in which case there is a <vbox:Machine> element
// in the <VirtualSystem>; then the VirtualSystemDescription::Data has a settings::MachineConfigFile
// Even for the vbox:Machine case, there are a number of configuration items that will be taken from
std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU);
std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
#ifdef VBOX_WITH_USB
std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
// for the description of the new machine, always use the OVF entry, the user may have changed it in the import config