diff options
Diffstat (limited to 'src/VBox/Main/src-server/ApplianceImplExport.cpp')
-rw-r--r-- | src/VBox/Main/src-server/ApplianceImplExport.cpp | 781 |
1 files changed, 600 insertions, 181 deletions
diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp index cc47b4d1..c8c5718f 100644 --- a/src/VBox/Main/src-server/ApplianceImplExport.cpp +++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp @@ -1,11 +1,10 @@ /* $Id: ApplianceImplExport.cpp $ */ /** @file - * * IAppliance and IVirtualSystem COM class implementations. */ /* - * Copyright (C) 2008-2011 Oracle Corporation + * Copyright (C) 2008-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,7 +56,7 @@ using namespace std; * @param appliance * @return */ -STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription) +STDMETHODIMP Machine::ExportTo(IAppliance *aAppliance, IN_BSTR location, IVirtualSystemDescription **aDescription) { HRESULT rc = S_OK; @@ -86,32 +85,32 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // store the machine object so we can dump the XML in Appliance::Write() pNewDesc->m->pMachine = this; - // now fill it with description items - Bstr bstrName1; - Bstr bstrDescription; - Bstr bstrGuestOSType; - uint32_t cCPUs; - uint32_t ulMemSizeMB; - BOOL fUSBEnabled; - BOOL fAudioEnabled; - AudioControllerType_T audioController; + // first, call the COM methods, as they request locks + BOOL fUSBEnabled = FALSE; + com::SafeIfaceArray<IUSBController> usbControllers; + rc = COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbControllers)); + if (SUCCEEDED(rc)) + { + for (unsigned i = 0; i < usbControllers.size(); i++) + { + USBControllerType_T enmType; - ComPtr<IUSBController> pUsbController; - ComPtr<IAudioAdapter> pAudioAdapter; + rc = usbControllers[i]->COMGETTER(Type)(&enmType); + if (FAILED(rc)) throw rc; - // first, call the COM methods, as they request locks - rc = COMGETTER(USBController)(pUsbController.asOutParam()); - if (FAILED(rc)) - fUSBEnabled = false; - else - rc = pUsbController->COMGETTER(Enabled)(&fUSBEnabled); + if (enmType == USBControllerType_OHCI) + fUSBEnabled = TRUE; + } + } // request the machine lock while accessing internal members AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS); - pAudioAdapter = mAudioAdapter; + ComPtr<IAudioAdapter> pAudioAdapter = mAudioAdapter; + BOOL fAudioEnabled; rc = pAudioAdapter->COMGETTER(Enabled)(&fAudioEnabled); if (FAILED(rc)) throw rc; + AudioControllerType_T audioController; rc = pAudioAdapter->COMGETTER(AudioController)(&audioController); if (FAILED(rc)) throw rc; @@ -122,9 +121,9 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // get guest OS Utf8Str strOsTypeVBox = mUserData->s.strOsType; // CPU count - cCPUs = mHWData->mCPUCount; + uint32_t cCPUs = mHWData->mCPUCount; // memory size in MB - ulMemSizeMB = mHWData->mMemorySize; + uint32_t ulMemSizeMB = mHWData->mMemorySize; // VRAM size? // BIOS settings? // 3D acceleration enabled? @@ -132,11 +131,16 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // nested paging enabled? // HWVirtExVPIDEnabled? // PAEEnabled? + // Long mode enabled? + BOOL fLongMode; + rc = GetCPUProperty(CPUPropertyType_LongMode, &fLongMode); + if (FAILED(rc)) throw rc; + // snapshotFolder? // VRDPServer? /* Guest OS type */ - ovf::CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str()); + ovf::CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str(), fLongMode); pNewDesc->addEntry(VirtualSystemDescriptionType_OS, "", Utf8StrFmt("%RI32", cim), @@ -206,41 +210,41 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // <const name="HardDiskControllerIDE" value="6" /> if (!pIDEController.isNull()) { - Utf8Str strVbox; + Utf8Str strVBox; StorageControllerType_T ctlr; rc = pIDEController->COMGETTER(ControllerType)(&ctlr); if (FAILED(rc)) throw rc; switch(ctlr) { - case StorageControllerType_PIIX3: strVbox = "PIIX3"; break; - case StorageControllerType_PIIX4: strVbox = "PIIX4"; break; - case StorageControllerType_ICH6: strVbox = "ICH6"; break; + case StorageControllerType_PIIX3: strVBox = "PIIX3"; break; + case StorageControllerType_PIIX4: strVBox = "PIIX4"; break; + case StorageControllerType_ICH6: strVBox = "ICH6"; break; } - if (strVbox.length()) + if (strVBox.length()) { lIDEControllerPrimaryIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE, Utf8StrFmt("%d", lIDEControllerPrimaryIndex), // strRef - strVbox, // aOvfValue - strVbox); // aVboxValue + strVBox, // aOvfValue + strVBox); // aVBoxValue lIDEControllerSecondaryIndex = lIDEControllerPrimaryIndex + 1; pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE, Utf8StrFmt("%d", lIDEControllerSecondaryIndex), - strVbox, - strVbox); + strVBox, + strVBox); } } // <const name="HardDiskControllerSATA" value="7" /> if (!pSATAController.isNull()) { - Utf8Str strVbox = "AHCI"; + Utf8Str strVBox = "AHCI"; lSATAControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA, Utf8StrFmt("%d", lSATAControllerIndex), - strVbox, - strVbox); + strVBox, + strVBox); } // <const name="HardDiskControllerSCSI" value="8" /> @@ -250,17 +254,17 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS rc = pSCSIController->COMGETTER(ControllerType)(&ctlr); if (SUCCEEDED(rc)) { - Utf8Str strVbox = "LsiLogic"; // the default in VBox + Utf8Str strVBox = "LsiLogic"; // the default in VBox switch(ctlr) { - case StorageControllerType_LsiLogic: strVbox = "LsiLogic"; break; - case StorageControllerType_BusLogic: strVbox = "BusLogic"; break; + case StorageControllerType_LsiLogic: strVBox = "LsiLogic"; break; + case StorageControllerType_BusLogic: strVBox = "BusLogic"; break; } lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI, Utf8StrFmt("%d", lSCSIControllerIndex), - strVbox, - strVbox); + strVBox, + strVBox); } else throw rc; @@ -270,12 +274,12 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS { // VirtualBox considers the SAS controller a class of its own but in OVF // it should be a SCSI controller - Utf8Str strVbox = "LsiLogicSas"; + Utf8Str strVBox = "LsiLogicSas"; lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSAS, Utf8StrFmt("%d", lSCSIControllerIndex), - strVbox, - strVbox); + strVBox, + strVBox); } // <const name="HardDiskImage" value="9" /> @@ -320,15 +324,15 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS rc = pHDA->COMGETTER(Device)(&lDevice); if (FAILED(rc)) throw rc; - Utf8Str strTargetVmdkName; + Utf8Str strTargetImageName; Utf8Str strLocation; LONG64 llSize = 0; - if ( deviceType == DeviceType_HardDisk - && pMedium - ) + if ( deviceType == DeviceType_HardDisk + && pMedium) { Bstr bstrLocation; + rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam()); if (FAILED(rc)) throw rc; strLocation = bstrLocation; @@ -343,12 +347,11 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS // returns pMedium if there are no diff images if (FAILED(rc)) throw rc; - Bstr bstrBaseName; - rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam()); - if (FAILED(rc)) throw rc; - - Utf8Str strTargetName = Utf8Str(locInfo.strPath).stripPath().stripExt(); - strTargetVmdkName = Utf8StrFmt("%s-disk%d.vmdk", strTargetName.c_str(), ++pAppliance->m->cDisks); + Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripExt(); + strTargetImageName = Utf8StrFmt("%s-disk%d.vmdk", strName.c_str(), ++pAppliance->m->cDisks); + if (strTargetImageName.length() > RTTAR_NAME_MAX) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Cannot attach disk '%s' -- file name too long"), strTargetImageName.c_str()); // force reading state, or else size will be returned as 0 MediumState_T ms; @@ -358,7 +361,55 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS rc = pBaseMedium->COMGETTER(Size)(&llSize); if (FAILED(rc)) throw rc; } + else if ( deviceType == DeviceType_DVD + && pMedium) + { + /* + * check the minimal rules to grant access to export an image + * 1. no host drive CD/DVD image + * 2. the image must be accessible and readable + * 3. only ISO image is exported + */ + + //1. no host drive CD/DVD image + BOOL fHostDrive = false; + rc = pMedium->COMGETTER(HostDrive)(&fHostDrive); + if (FAILED(rc)) throw rc; + + if(fHostDrive) + continue; + + //2. the image must be accessible and readable + MediumState_T ms; + rc = pMedium->RefreshState(&ms); + if (FAILED(rc)) throw rc; + + if (ms != MediumState_Created) + continue; + //3. only ISO image is exported + Bstr bstrLocation; + rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam()); + if (FAILED(rc)) throw rc; + + strLocation = bstrLocation; + + Utf8Str ext = strLocation; + ext.assignEx(RTPathExt(ext.c_str()));//returns extension with dot (".iso") + + int eq = ext.compare(".iso", Utf8Str::CaseInsensitive); + if (eq != 0) + continue; + + Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripExt(); + strTargetImageName = Utf8StrFmt("%s-disk%d.iso", strName.c_str(), ++pAppliance->m->cDisks); + if (strTargetImageName.length() > RTTAR_NAME_MAX) + throw setError(VBOX_E_NOT_SUPPORTED, + tr("Cannot attach image '%s' -- file name too long"), strTargetImageName.c_str()); + + rc = pMedium->COMGETTER(Size)(&llSize); + if (FAILED(rc)) throw rc; + } // and how this translates to the virtual system int32_t lControllerVsys = 0; LONG lChannelVsys; @@ -426,19 +477,20 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS case DeviceType_HardDisk: Log(("Adding VirtualSystemDescriptionType_HardDiskImage, disk size: %RI64\n", llSize)); pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage, - strTargetVmdkName, // disk ID: let's use the name - strTargetVmdkName, // OVF value: + strTargetImageName, // disk ID: let's use the name + strTargetImageName, // OVF value: strLocation, // vbox value: media path (uint32_t)(llSize / _1M), strExtra); break; case DeviceType_DVD: + Log(("Adding VirtualSystemDescriptionType_CDROM, disk size: %RI64\n", llSize)); pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, - strEmpty, // disk ID - strEmpty, // OVF value - strEmpty, // vbox value - 1, // ulSize + strTargetImageName, // disk ID + strTargetImageName, // OVF value + strLocation, // vbox value + (uint32_t)(llSize / _1M),// ulSize strExtra); break; @@ -525,11 +577,12 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IN_BSTR location, IVirtualS /** * Public method implementation. * @param format + * @param options * @param path * @param aProgress * @return */ -STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IProgress **aProgress) +STDMETHODIMP Appliance::Write(IN_BSTR format, ComSafeArrayIn(ImportOptions_T, options), IN_BSTR path, IProgress **aProgress) { if (!path) return E_POINTER; CheckComArgOutPointerValid(aProgress); @@ -539,6 +592,31 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (options != NULL) + m->optListExport = com::SafeArray<ExportOptions_T>(ComSafeArrayInArg(options)).toList(); + +// AssertReturn(!(m->optListExport.contains(ExportOptions_CreateManifest) && m->optListExport.contains(ExportOptions_ExportDVDImages)), E_INVALIDARG); + + m->fExportISOImages = m->optListExport.contains(ExportOptions_ExportDVDImages); + + if (!m->fExportISOImages)/* remove all ISO images from VirtualSystemDescription */ + { + list< ComObjPtr<VirtualSystemDescription> >::const_iterator it; + for (it = m->virtualSystemDescriptions.begin(); + it != m->virtualSystemDescriptions.end(); + ++it) + { + ComObjPtr<VirtualSystemDescription> vsdescThis = (*it); + std::list<VirtualSystemDescriptionEntry*> skipped = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM); + std::list<VirtualSystemDescriptionEntry*>:: iterator pItSkipped = skipped.begin(); + while (pItSkipped != skipped.end()) + { + (*pItSkipped)->skipIt = true; + ++pItSkipped; + } + } + } + // do not allow entering this method if the appliance is busy reading or writing if (!isApplianceIdle()) return E_ACCESSDENIED; @@ -550,21 +628,28 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro return setError(VBOX_E_FILE_ERROR, tr("Appliance file must have .ovf or .ova extension")); - m->fManifest = !!fManifest; + m->fManifest = m->optListExport.contains(ExportOptions_CreateManifest); Utf8Str strFormat(format); - OVFFormat ovfF; + + ovf::OVFVersion_T ovfF; if (strFormat == "ovf-0.9") - ovfF = OVF_0_9; + { + ovfF = ovf::OVFVersion_0_9; + } else if (strFormat == "ovf-1.0") - ovfF = OVF_1_0; + { + ovfF = ovf::OVFVersion_1_0; + } else if (strFormat == "ovf-2.0") - ovfF = OVF_2_0; + { + ovfF = ovf::OVFVersion_2_0; + } else return setError(VBOX_E_FILE_ERROR, tr("Invalid format \"%s\" specified"), strFormat.c_str()); /* as of OVF 2.0 we have to use SHA256 */ - m->fSha256 = ovfF >= OVF_2_0; + m->fSha256 = ovfF >= ovf::OVFVersion_2_0; ComObjPtr<Progress> progress; HRESULT rc = S_OK; @@ -614,7 +699,7 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, BOOL fManifest, IN_BSTR path, IPro * @param aProgress * @return */ -HRESULT Appliance::writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress) +HRESULT Appliance::writeImpl(ovf::OVFVersion_T aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress) { HRESULT rc = S_OK; try @@ -658,18 +743,30 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, xml::Document &doc, XMLStack &stack, const Utf8Str &strPath, - OVFFormat enFormat) + ovf::OVFVersion_T enFormat) { xml::ElementNode *pelmRoot = doc.createRootElement("Envelope"); - pelmRoot->setAttribute("ovf:version", enFormat == OVF_2_0 ? "2.0" - : enFormat == OVF_1_0 ? "1.0" + pelmRoot->setAttribute("ovf:version", enFormat == ovf::OVFVersion_2_0 ? "2.0" + : enFormat == ovf::OVFVersion_1_0 ? "1.0" : "0.9"); pelmRoot->setAttribute("xml:lang", "en-US"); - Utf8Str strNamespace = (enFormat == OVF_0_9) - ? "http://www.vmware.com/schema/ovf/1/envelope" // 0.9 - : "http://schemas.dmtf.org/ovf/envelope/1"; // 1.0 + Utf8Str strNamespace; + + if (enFormat == ovf::OVFVersion_0_9) + { + strNamespace = ovf::OVF09_URI_string; + } + else if (enFormat == ovf::OVFVersion_1_0) + { + strNamespace = ovf::OVF10_URI_string; + } + else + { + strNamespace = ovf::OVF20_URI_string; + } + pelmRoot->setAttribute("xmlns", strNamespace); pelmRoot->setAttribute("xmlns:ovf", strNamespace); @@ -680,6 +777,14 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, pelmRoot->setAttribute("xmlns:vbox", "http://www.virtualbox.org/ovf/machine"); // pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd"); + if (enFormat == ovf::OVFVersion_2_0) + { + pelmRoot->setAttribute("xmlns:epasd", + "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_EthernetPortAllocationSettingData.xsd"); + pelmRoot->setAttribute("xmlns:sasd", + "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_StorageAllocationSettingData.xsd"); + } + // <Envelope>/<References> xml::ElementNode *pelmReferences = pelmRoot->createChild("References"); // 0.9 and 1.0 @@ -689,7 +794,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, <Disk ovf:capacity="4294967296" ovf:diskId="lamp" ovf:format="..." ovf:populatedSize="1924967692"/> </DiskSection> */ xml::ElementNode *pelmDiskSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { // <Section xsi:type="ovf:DiskSection_Type"> pelmDiskSection = pelmRoot->createChild("Section"); @@ -709,7 +814,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, </Network> </NetworkSection> */ xml::ElementNode *pelmNetworkSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { // <Section xsi:type="ovf:NetworkSection_Type"> pelmNetworkSection = pelmRoot->createChild("Section"); @@ -729,7 +834,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, xml::ElementNode *pelmToAddVirtualSystemsTo; if (m->virtualSystemDescriptions.size() > 1) { - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) throw setError(VBOX_E_FILE_ERROR, tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0")); @@ -783,19 +888,46 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, const VirtualSystemDescriptionEntry *pDiskEntry = itS->second; // source path: where the VBox image is - const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent; + const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent; Bstr bstrSrcFilePath(strSrcFilePath); + //skip empty Medium. There are no information to add into section <References> or <DiskSection> + if (strSrcFilePath.isEmpty() || + pDiskEntry->skipIt == true) + continue; + // Do NOT check here whether the file exists. FindMedium will figure // that out, and filesystem-based tests are simply wrong in the // general case (think of iSCSI). // We need some info from the source disks ComPtr<IMedium> pSourceDisk; + //DeviceType_T deviceType = DeviceType_HardDisk;// by default Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw())); - HRESULT rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, pSourceDisk.asOutParam()); - if (FAILED(rc)) throw rc; + + HRESULT rc; + + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage) + { + rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), + DeviceType_HardDisk, + AccessMode_ReadWrite, + FALSE /* fForceNewUuid */, + pSourceDisk.asOutParam()); + if (FAILED(rc)) + throw rc; + } + else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD + { + rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(), + DeviceType_DVD, + AccessMode_ReadOnly, + FALSE, + pSourceDisk.asOutParam()); + if (FAILED(rc)) + throw rc; + } Bstr uuidSource; rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam()); @@ -811,7 +943,7 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, strTargetFilePath.append(strTargetFileNameOnly); // We are always exporting to VMDK stream optimized for now - Bstr bstrSrcFormat = L"VMDK"; + //Bstr bstrSrcFormat = L"VMDK";//not used diskList.push_back(strTargetFilePath); @@ -843,12 +975,22 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str()); pelmDisk->setAttribute("ovf:diskId", strDiskID); pelmDisk->setAttribute("ovf:fileRef", strFileRef); - pelmDisk->setAttribute("ovf:format", - (enFormat == OVF_0_9) - ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool chokes - : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" - // correct string as communicated to us by VMware (public bug #6612) - ); + + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk + { + pelmDisk->setAttribute("ovf:format", + (enFormat == ovf::OVFVersion_0_9) + ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool ch + : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" + // correct string as communicated to us by VMware (public bug #6612) + ); + } + else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD + { + pelmDisk->setAttribute("ovf:format", + "http://www.ecma-international.org/publications/standards/Ecma-119.htm" + ); + } // add the UUID of the newly target image to the OVF disk element, but in the // vbox: namespace since it's not part of the standard @@ -891,13 +1033,13 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, xml::ElementNode &elmToAddVirtualSystemsTo, std::list<xml::ElementNode*> *pllElementsWithUuidAttributes, ComObjPtr<VirtualSystemDescription> &vsdescThis, - OVFFormat enFormat, + ovf::OVFVersion_T enFormat, XMLStack &stack) { LogFlowFunc(("ENTER appliance %p\n", this)); xml::ElementNode *pelmVirtualSystem; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { // <Section xsi:type="ovf:NetworkSection_Type"> pelmVirtualSystem = elmToAddVirtualSystemsTo.createChild("Content"); @@ -909,10 +1051,9 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, /*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine"); std::list<VirtualSystemDescriptionEntry*> llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); - if (llName.size() != 1) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Missing VM name")); - Utf8Str &strVMName = llName.front()->strVboxCurrent; + if (!llName.size()) + throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing VM name")); + Utf8Str &strVMName = llName.back()->strVBoxCurrent; pelmVirtualSystem->setAttribute("ovf:id", strVMName); // product info @@ -921,11 +1062,11 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor); std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl); std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version); - bool fProduct = llProduct.size() && !llProduct.front()->strVboxCurrent.isEmpty(); - bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVboxCurrent.isEmpty(); - bool fVendor = llVendor.size() && !llVendor.front()->strVboxCurrent.isEmpty(); - bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVboxCurrent.isEmpty(); - bool fVersion = llVersion.size() && !llVersion.front()->strVboxCurrent.isEmpty(); + bool fProduct = llProduct.size() && !llProduct.back()->strVBoxCurrent.isEmpty(); + bool fProductUrl = llProductUrl.size() && !llProductUrl.back()->strVBoxCurrent.isEmpty(); + bool fVendor = llVendor.size() && !llVendor.back()->strVBoxCurrent.isEmpty(); + bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.back()->strVBoxCurrent.isEmpty(); + bool fVersion = llVersion.size() && !llVersion.back()->strVBoxCurrent.isEmpty(); if (fProduct || fProductUrl || fVersion || @@ -941,7 +1082,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, <VendorUrl>http://www.sun.com</VendorUrl> </Section> */ xml::ElementNode *pelmAnnotationSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type"> pelmAnnotationSection = pelmVirtualSystem->createChild("Section"); @@ -952,28 +1093,28 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software"); if (fProduct) - pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Product")->addContent(llProduct.back()->strVBoxCurrent); if (fVendor) - pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.back()->strVBoxCurrent); if (fVersion) - pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Version")->addContent(llVersion.back()->strVBoxCurrent); if (fProductUrl) - pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVboxCurrent); + pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.back()->strVBoxCurrent); if (fVendorUrl) - pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVboxCurrent); + pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.back()->strVBoxCurrent); } // description std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description); if (llDescription.size() && - !llDescription.front()->strVboxCurrent.isEmpty()) + !llDescription.back()->strVBoxCurrent.isEmpty()) { /* <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type"> <Info>A human-readable annotation</Info> <Annotation>Plan 9</Annotation> </Section> */ xml::ElementNode *pelmAnnotationSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type"> pelmAnnotationSection = pelmVirtualSystem->createChild("Section"); @@ -983,20 +1124,20 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection"); pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation"); - pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVboxCurrent); + pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.back()->strVBoxCurrent); } // license std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License); if (llLicense.size() && - !llLicense.front()->strVboxCurrent.isEmpty()) + !llLicense.back()->strVBoxCurrent.isEmpty()) { /* <EulaSection> <Info ovf:msgid="6">License agreement for the Virtual System.</Info> <License ovf:msgid="1">License terms can go in here.</License> </EulaSection> */ xml::ElementNode *pelmEulaSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { pelmEulaSection = pelmVirtualSystem->createChild("Section"); pelmEulaSection->setAttribute("xsi:type", "ovf:EulaSection_Type"); @@ -1005,21 +1146,20 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmEulaSection = pelmVirtualSystem->createChild("EulaSection"); pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system"); - pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVboxCurrent); + pelmEulaSection->createChild("License")->addContent(llLicense.back()->strVBoxCurrent); } // operating system std::list<VirtualSystemDescriptionEntry*> llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS); - if (llOS.size() != 1) - throw setError(VBOX_E_NOT_SUPPORTED, - tr("Missing OS type")); + if (!llOS.size()) + throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing OS type")); /* <OperatingSystemSection ovf:id="82"> <Info>Guest Operating System</Info> <Description>Linux 2.6.x</Description> </OperatingSystemSection> */ - VirtualSystemDescriptionEntry *pvsdeOS = llOS.front(); + VirtualSystemDescriptionEntry *pvsdeOS = llOS.back(); xml::ElementNode *pelmOperatingSystemSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section"); pelmOperatingSystemSection->setAttribute("xsi:type", "ovf:OperatingSystemSection_Type"); @@ -1035,11 +1175,11 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, // add the VirtualBox ostype in a custom tag in a different namespace xml::ElementNode *pelmVBoxOSType = pelmOperatingSystemSection->createChild("vbox:OSType"); pelmVBoxOSType->setAttribute("ovf:required", "false"); - pelmVBoxOSType->addContent(pvsdeOS->strVboxCurrent); + pelmVBoxOSType->addContent(pvsdeOS->strVBoxCurrent); // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso"> xml::ElementNode *pelmVirtualHardwareSection; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) { // <Section xsi:type="ovf:VirtualHardwareSection_Type"> pelmVirtualHardwareSection = pelmVirtualSystem->createChild("Section"); @@ -1062,7 +1202,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmSystem->createChild("vssd:ElementName")->addContent("Virtual Hardware Family"); // required OVF 1.0 // <vssd:InstanceId>0</vssd:InstanceId> - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) pelmSystem->createChild("vssd:InstanceId")->addContent("0"); else // capitalization changed... pelmSystem->createChild("vssd:InstanceID")->addContent("0"); @@ -1071,7 +1211,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, pelmSystem->createChild("vssd:VirtualSystemIdentifier")->addContent(strVMName); // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType> const char *pcszHardware = "virtualbox-2.2"; - if (enFormat == OVF_0_9) + if (enFormat == ovf::OVFVersion_0_9) // pretend to be vmware compatible then pcszHardware = "vmx-6"; pelmSystem->createChild("vssd:VirtualSystemType")->addContent(pcszHardware); @@ -1105,7 +1245,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { const VirtualSystemDescriptionEntry &desc = *itD; - LogFlowFunc(("Loop %u: handling description entry ulIndex=%u, type=%s, strRef=%s, strOvf=%s, strVbox=%s, strExtraConfig=%s\n", + LogFlowFunc(("Loop %u: handling description entry ulIndex=%u, type=%s, strRef=%s, strOvf=%s, strVBox=%s, strExtraConfig=%s\n", uLoop, desc.ulIndex, ( desc.type == VirtualSystemDescriptionType_HardDiskControllerIDE ? "HardDiskControllerIDE" @@ -1116,7 +1256,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, : Utf8StrFmt("%d", desc.type).c_str()), desc.strRef.c_str(), desc.strOvf.c_str(), - desc.strVboxCurrent.c_str(), + desc.strVBoxCurrent.c_str(), desc.strExtraConfigCurrent.c_str())); ovf::ResourceType_T type = (ovf::ResourceType_T)0; // if this becomes != 0 then we do stuff @@ -1140,6 +1280,10 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, uint64_t uTemp; + ovf::VirtualHardwareItem vhi; + ovf::StorageItem si; + ovf::EthernetPortItem epi; + switch (desc.type) { case VirtualSystemDescriptionType_CPU: @@ -1155,7 +1299,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { strDescription = "Number of virtual CPUs"; type = ovf::ResourceType_Processor; // 3 - desc.strVboxCurrent.toInt(uTemp); + desc.strVBoxCurrent.toInt(uTemp); lVirtualQuantity = (int32_t)uTemp; strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity); // without this ovftool won't eat the item } @@ -1175,7 +1319,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { strDescription = "Memory Size"; type = ovf::ResourceType_Memory; // 4 - desc.strVboxCurrent.toInt(uTemp); + desc.strVBoxCurrent.toInt(uTemp); lVirtualQuantity = (int32_t)(uTemp / _1M); strAllocationUnits = "MegaBytes"; strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity); // without this ovftool won't eat the item @@ -1195,7 +1339,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, { strDescription = "IDE Controller"; type = ovf::ResourceType_IDEController; // 5 - strResourceSubType = desc.strVboxCurrent; + strResourceSubType = desc.strVBoxCurrent; if (!lIDEPrimaryControllerIndex) { @@ -1241,13 +1385,13 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, lAddress = 0; lBusNumber = 0; - if ( desc.strVboxCurrent.isEmpty() // AHCI is the default in VirtualBox - || (!desc.strVboxCurrent.compare("ahci", Utf8Str::CaseInsensitive)) + if ( desc.strVBoxCurrent.isEmpty() // AHCI is the default in VirtualBox + || (!desc.strVBoxCurrent.compare("ahci", Utf8Str::CaseInsensitive)) ) strResourceSubType = "AHCI"; else throw setError(VBOX_E_NOT_SUPPORTED, - tr("Invalid config string \"%s\" in SATA controller"), desc.strVboxCurrent.c_str()); + tr("Invalid config string \"%s\" in SATA controller"), desc.strVBoxCurrent.c_str()); // remember this ID idSATAController = ulInstanceID; @@ -1277,17 +1421,17 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, lAddress = 0; lBusNumber = 0; - if ( desc.strVboxCurrent.isEmpty() // LsiLogic is the default in VirtualBox - || (!desc.strVboxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive)) + if ( desc.strVBoxCurrent.isEmpty() // LsiLogic is the default in VirtualBox + || (!desc.strVBoxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive)) ) strResourceSubType = "lsilogic"; - else if (!desc.strVboxCurrent.compare("buslogic", Utf8Str::CaseInsensitive)) + else if (!desc.strVBoxCurrent.compare("buslogic", Utf8Str::CaseInsensitive)) strResourceSubType = "buslogic"; - else if (!desc.strVboxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive)) + else if (!desc.strVBoxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive)) strResourceSubType = "lsilogicsas"; else throw setError(VBOX_E_NOT_SUPPORTED, - tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVboxCurrent.c_str()); + tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVBoxCurrent.c_str()); // remember this ID idSCSIController = ulInstanceID; @@ -1360,13 +1504,32 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, break; case VirtualSystemDescriptionType_CDROM: + /* <Item> + <rasd:Caption>cdrom1</rasd:Caption> + <rasd:InstanceId>8</rasd:InstanceId> + <rasd:ResourceType>15</rasd:ResourceType> + <rasd:HostResource>/disk/cdrom1</rasd:HostResource> + <rasd:Parent>4</rasd:Parent> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + </Item> */ if (uLoop == 2) { + //uint32_t cDisks = stack.mapDisks.size(); + Utf8Str strDiskID = Utf8StrFmt("iso%RI32", ++cDVDs); + strDescription = "CD-ROM Drive"; - strCaption = Utf8StrFmt("cdrom%RI32", ++cDVDs); // OVFTool starts with 1 + strCaption = Utf8StrFmt("cdrom%RI32", cDVDs); // OVFTool starts with 1 type = ovf::ResourceType_CDDrive; // 15 lAutomaticAllocation = 1; + //skip empty Medium. There are no information to add into section <References> or <DiskSection> + if (desc.strVBoxCurrent.isNotEmpty() && + desc.skipIt == false) + { + // the following references the "<Disks>" XML block + strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str()); + } + // controller=<index>;channel=<c> size_t pos1 = desc.strExtraConfigCurrent.find("controller="); size_t pos2 = desc.strExtraConfigCurrent.find("channel="); @@ -1395,6 +1558,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing or bad extra config string in DVD drive medium: \"%s\""), desc.strExtraConfigCurrent.c_str()); + stack.mapDisks[strDiskID] = &desc; // there is no DVD drive map to update because it is // handled completely with this entry. } @@ -1409,7 +1573,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, <rasd:InstanceID>3</rasd:InstanceID> <rasd:ResourceType>10</rasd:ResourceType> </Item> */ - if (uLoop == 1) + if (uLoop == 2) { lAutomaticAllocation = 1; strCaption = Utf8StrFmt("Ethernet adapter on '%s'", desc.strOvf.c_str()); @@ -1418,7 +1582,7 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, * To be compatible with vmware & others we set * PCNet32 for our PCNet types & E1000 for the * E1000 cards. */ - switch (desc.strVboxCurrent.toInt32()) + switch (desc.strVBoxCurrent.toInt32()) { case NetworkAdapterType_Am79C970A: case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break; @@ -1478,65 +1642,176 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, if (type) { xml::ElementNode *pItem; + xml::ElementNode *pItemHelper; + RTCString itemElement; + RTCString itemElementHelper; - pItem = pelmVirtualHardwareSection->createChild("Item"); + if (enFormat == ovf::OVFVersion_2_0) + { + if(uLoop == 2) + { + if (desc.type == VirtualSystemDescriptionType_NetworkAdapter) + { + itemElement = "epasd:"; + pItem = pelmVirtualHardwareSection->createChild("EthernetPortItem"); + } + else if (desc.type == VirtualSystemDescriptionType_CDROM || + desc.type == VirtualSystemDescriptionType_HardDiskImage) + { + itemElement = "sasd:"; + pItem = pelmVirtualHardwareSection->createChild("StorageItem"); + } + else + pItem = NULL; + } + else + { + itemElement = "rasd:"; + pItem = pelmVirtualHardwareSection->createChild("Item"); + } + } + else + { + itemElement = "rasd:"; + pItem = pelmVirtualHardwareSection->createChild("Item"); + } // NOTE: DO NOT CHANGE THE ORDER of these items! The OVF standards prescribes that // the elements from the rasd: namespace must be sorted by letter, and VMware // actually requires this as well (see public bug #6612) if (lAddress != -1) - pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress)); + { + //pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Address").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lAddress)); + } if (lAddressOnParent != -1) - pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent)); + { + //pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("AddressOnParent").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lAddressOnParent)); + } if (!strAllocationUnits.isEmpty()) - pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits); + { + //pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("AllocationUnits").c_str()); + pItemHelper->addContent(strAllocationUnits); + } if (lAutomaticAllocation != -1) - pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" ); + { + //pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" ); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("AutomaticAllocation").c_str()); + pItemHelper->addContent((lAutomaticAllocation) ? "true" : "false" ); + } if (lBusNumber != -1) - if (enFormat == OVF_0_9) // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool compatibility - pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber)); + { + if (enFormat == ovf::OVFVersion_0_9) + { + // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool + //pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("BusNumber").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lBusNumber)); + } + } if (!strCaption.isEmpty()) - pItem->createChild("rasd:Caption")->addContent(strCaption); + { + //pItem->createChild("rasd:Caption")->addContent(strCaption); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Caption").c_str()); + pItemHelper->addContent(strCaption); + } if (!strConnection.isEmpty()) - pItem->createChild("rasd:Connection")->addContent(strConnection); + { + //pItem->createChild("rasd:Connection")->addContent(strConnection); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Connection").c_str()); + pItemHelper->addContent(strConnection); + } if (!strDescription.isEmpty()) - pItem->createChild("rasd:Description")->addContent(strDescription); + { + //pItem->createChild("rasd:Description")->addContent(strDescription); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Description").c_str()); + pItemHelper->addContent(strDescription); + } if (!strCaption.isEmpty()) - if (enFormat == OVF_1_0) - pItem->createChild("rasd:ElementName")->addContent(strCaption); + { + if (enFormat == ovf::OVFVersion_1_0) + { + //pItem->createChild("rasd:ElementName")->addContent(strCaption); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("ElementName").c_str()); + pItemHelper->addContent(strCaption); + } + } if (!strHostResource.isEmpty()) - pItem->createChild("rasd:HostResource")->addContent(strHostResource); + { + //pItem->createChild("rasd:HostResource")->addContent(strHostResource); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("HostResource").c_str()); + pItemHelper->addContent(strHostResource); + } - // <rasd:InstanceID>1</rasd:InstanceID> - xml::ElementNode *pelmInstanceID; - if (enFormat == OVF_0_9) - pelmInstanceID = pItem->createChild("rasd:InstanceId"); - else - pelmInstanceID = pItem->createChild("rasd:InstanceID"); // capitalization changed... - pelmInstanceID->addContent(Utf8StrFmt("%d", ulInstanceID++)); + { + // <rasd:InstanceID>1</rasd:InstanceID> + itemElementHelper = itemElement; + if (enFormat == ovf::OVFVersion_0_9) + //pelmInstanceID = pItem->createChild("rasd:InstanceId"); + pItemHelper = pItem->createChild(itemElementHelper.append("InstanceId").c_str()); + else + //pelmInstanceID = pItem->createChild("rasd:InstanceID"); // capitalization changed... + pItemHelper = pItem->createChild(itemElementHelper.append("InstanceID").c_str()); + + pItemHelper->addContent(Utf8StrFmt("%d", ulInstanceID++)); + } if (ulParent) - pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent)); + { + //pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("Parent").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", ulParent)); + } if (!strResourceSubType.isEmpty()) - pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType); + { + //pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("ResourceSubType").c_str()); + pItemHelper->addContent(strResourceSubType); + } - // <rasd:ResourceType>3</rasd:ResourceType> - pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type)); + { + // <rasd:ResourceType>3</rasd:ResourceType> + //pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("ResourceType").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", type)); + } // <rasd:VirtualQuantity>1</rasd:VirtualQuantity> if (lVirtualQuantity != -1) - pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity)); + { + //pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity)); + itemElementHelper = itemElement; + pItemHelper = pItem->createChild(itemElementHelper.append("VirtualQuantity").c_str()); + pItemHelper->addContent(Utf8StrFmt("%d", lVirtualQuantity)); + } } } } // for (size_t uLoop = 1; uLoop <= 2; ++uLoop) @@ -1558,10 +1833,26 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, AutoWriteLock machineLock(vsdescThis->m->pMachine COMMA_LOCKVAL_SRC_POS); // fill the machine config vsdescThis->m->pMachine->copyMachineDataToSettings(*pConfig); + + // Apply export tweaks to machine settings + bool fStripAllMACs = m->optListExport.contains(ExportOptions_StripAllMACs); + bool fStripAllNonNATMACs = m->optListExport.contains(ExportOptions_StripAllNonNATMACs); + if (fStripAllMACs || fStripAllNonNATMACs) + { + for (settings::NetworkAdaptersList::iterator it = pConfig->hardwareMachine.llNetworkAdapters.begin(); + it != pConfig->hardwareMachine.llNetworkAdapters.end(); + ++it) + { + settings::NetworkAdapter &nic = *it; + if (fStripAllMACs || (fStripAllNonNATMACs && nic.mode != NetworkAttachmentType_NAT)) + nic.strMACAddress.setNull(); + } + } + // write the machine config to the vbox:Machine element pConfig->buildMachineXML(*pelmVBoxMachine, - settings::MachineConfigFile::BuildMachineXML_WriteVboxVersionAttribute - | settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia + settings::MachineConfigFile::BuildMachineXML_WriteVBoxVersionAttribute + /*| settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia*/ | settings::MachineConfigFile::BuildMachineXML_SuppressSavedState, // but not BuildMachineXML_IncludeSnapshots nor BuildMachineXML_MediaRegistry pllElementsWithUuidAttributes); @@ -1648,7 +1939,11 @@ HRESULT Appliance::writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) RT_ZERO(storage); storage.fCreateDigest = m->fManifest; storage.fSha256 = m->fSha256; - int vrc = VDInterfaceAdd(&pFileIo->Core, "Appliance::IOFile", + + + Utf8Str name = applianceIOName(applianceIOFile); + + int vrc = VDInterfaceAdd(&pFileIo->Core, name.c_str(), VDINTERFACETYPE_IO, 0, sizeof(VDINTERFACEIO), &storage.pVDImageIfaces); if (RT_FAILURE(vrc)) @@ -1657,7 +1952,7 @@ HRESULT Appliance::writeFSOVF(TaskOVF *pTask, AutoWriteLockBase& writeLock) break; } rc = writeFSImpl(pTask, writeLock, pShaIo, &storage); - }while(0); + } while (0); /* Cleanup */ if (pShaIo) @@ -1702,16 +1997,20 @@ HRESULT Appliance::writeFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) RT_ZERO(storage); storage.fCreateDigest = m->fManifest; storage.fSha256 = m->fSha256; - vrc = VDInterfaceAdd(&pTarIo->Core, "Appliance::IOTar", + + Utf8Str name = applianceIOName(applianceIOTar); + + vrc = VDInterfaceAdd(&pTarIo->Core, name.c_str(), VDINTERFACETYPE_IO, tar, sizeof(VDINTERFACEIO), &storage.pVDImageIfaces); + if (RT_FAILURE(vrc)) { rc = E_FAIL; break; } rc = writeFSImpl(pTask, writeLock, pShaIo, &storage); - }while(0); + } while (0); RTTarClose(tar); @@ -1722,7 +2021,7 @@ HRESULT Appliance::writeFSOVA(TaskOVF *pTask, AutoWriteLockBase& writeLock) RTMemFree(pTarIo); /* Delete ova file on error */ - if(FAILED(rc)) + if (FAILED(rc)) RTFileDelete(pTask->locInfo.strPath.c_str()); LogFlowFuncLeave(); @@ -1749,8 +2048,10 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD xml::Document doc; // Now fully build a valid ovf document in memory buildXML(writeLock, doc, stack, pTask->locInfo.strPath, pTask->enFormat); + /* Extract the OVA file name */ + Utf8Str strOvaFile = pTask->locInfo.strPath; /* Extract the path */ - Utf8Str strOvfFile = Utf8Str(pTask->locInfo.strPath).stripExt().append(".ovf"); + Utf8Str strOvfFile = strOvaFile.stripExt().append(".ovf"); // Create a memory buffer containing the XML. */ void *pvBuf = 0; size_t cbSize; @@ -1770,12 +2071,16 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD } // We need a proper format description + ComObjPtr<MediumFormat> formatTemp; + ComObjPtr<MediumFormat> format; // Scope for the AutoReadLock { SystemProperties *pSysProps = mVirtualBox->getSystemProperties(); AutoReadLock propsLock(pSysProps COMMA_LOCKVAL_SRC_POS); // We are always exporting to VMDK stream optimized for now + formatTemp = pSysProps->mediumFormatFromExtension("iso"); + format = pSysProps->mediumFormat("VMDK"); if (format.isNull()) throw setError(VBOX_E_NOT_SUPPORTED, @@ -1791,7 +2096,12 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD const VirtualSystemDescriptionEntry *pDiskEntry = itS->second; // source path: where the VBox image is - const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent; + const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent; + + //skip empty Medium. In common, It's may be empty CD/DVD + if (strSrcFilePath.isEmpty() || + pDiskEntry->skipIt == true) + continue; // Do NOT check here whether the file exists. findHardDisk will // figure that out, and filesystem-based tests are simply wrong @@ -1801,8 +2111,21 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD ComObjPtr<Medium> pSourceDisk; Log(("Finding source disk \"%s\"\n", strSrcFilePath.c_str())); - rc = mVirtualBox->findHardDiskByLocation(strSrcFilePath, true, &pSourceDisk); - if (FAILED(rc)) throw rc; + + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage) + { + rc = mVirtualBox->findHardDiskByLocation(strSrcFilePath, true, &pSourceDisk); + if (FAILED(rc)) throw rc; + } + else//may be CD or DVD + { + rc = mVirtualBox->findDVDOrFloppyImage(DeviceType_DVD, + NULL, + strSrcFilePath, + true, + &pSourceDisk); + if (FAILED(rc)) throw rc; + } Bstr uuidSource; rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam()); @@ -1821,22 +2144,118 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD writeLock.release(); try { - ComObjPtr<Progress> pProgress2; - pProgress2.createObject(); - rc = pProgress2->init(mVirtualBox, static_cast<IAppliance*>(this), BstrFmt(tr("Creating medium '%s'"), strTargetFilePath.c_str()).raw(), TRUE); - if (FAILED(rc)) throw rc; - // advance to the next operation pTask->pProgress->SetNextOperation(BstrFmt(tr("Exporting to disk image '%s'"), RTPathFilename(strTargetFilePath.c_str())).raw(), pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally // create a flat copy of the source disk image - rc = pSourceDisk->exportFile(strTargetFilePath.c_str(), format, MediumVariant_VmdkStreamOptimized, pIfIo, pStorage, pProgress2); - if (FAILED(rc)) throw rc; + if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage) + { + ComObjPtr<Progress> pProgress2; + pProgress2.createObject(); + rc = pProgress2->init(mVirtualBox, static_cast<IAppliance*>(this), BstrFmt(tr("Creating medium '%s'"), strTargetFilePath.c_str()).raw(), TRUE); + if (FAILED(rc)) throw rc; + + rc = pSourceDisk->exportFile(strTargetFilePath.c_str(), + format, + MediumVariant_VmdkStreamOptimized, + pIfIo, + pStorage, + pProgress2); + if (FAILED(rc)) throw rc; + + ComPtr<IProgress> pProgress3(pProgress2); + // now wait for the background disk operation to complete; this throws HRESULTs on error + waitForAsyncProgress(pTask->pProgress, pProgress3); + } + else//pDiskEntry->type == VirtualSystemDescriptionType_CDROM + { + //copy/clone CD/DVD image + /* Read the ISO file and add one to OVA/OVF package */ + { + void *pvStorage; + RTFILE pFile = NULL; + void *pvUser = pStorage; + + vrc = pIfIo->pfnOpen(pvUser, strTargetFilePath.c_str(), + RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE, + 0, + &pvStorage); + if (RT_FAILURE(vrc)) + throw setError(VBOX_E_FILE_ERROR, + tr("Could not create or open file '%s' (%Rrc)"), + strTargetFilePath.c_str(), vrc); + + vrc = RTFileOpen(&pFile, + strSrcFilePath.c_str(), + RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE); + + if (RT_FAILURE(vrc) || pFile == NULL) + { + pIfIo->pfnClose(pvUser, pvStorage); + throw setError(VBOX_E_FILE_ERROR, + tr("Could not create or open file '%s' (%Rrc)"), + strSrcFilePath.c_str(), vrc); + } + + void *pvTmpBuf = 0; + size_t cbTmpSize = _1M; + uint64_t cbAllWritten = 0; + uint64_t cbFile = 0; + size_t cbSize = 0; + + vrc = RTFileGetSize(pFile, &cbFile); + + do + { + pvTmpBuf = RTMemAlloc(cbTmpSize); + if (!pvTmpBuf) + { + vrc = VERR_NO_MEMORY; + break; + } - ComPtr<IProgress> pProgress3(pProgress2); - // now wait for the background disk operation to complete; this throws HRESULTs on error - waitForAsyncProgress(pTask->pProgress, pProgress3); + for (;;) + { + // copy raw data into the buffer pvTmpBuf + vrc = RTFileRead(pFile, pvTmpBuf, cbTmpSize, &cbSize); + + if (RT_FAILURE(vrc) || cbSize == 0) + break; + + size_t cbToWrite = cbSize; + size_t cbWritten = 0; + + vrc = pIfIo->pfnWriteSync(pvUser, + pvStorage, + cbAllWritten, + pvTmpBuf, + cbToWrite,&cbWritten); + + if (RT_FAILURE(vrc)) + break; + + cbAllWritten += cbWritten; + } + } while (0); + + pIfIo->pfnClose(pvUser, pvStorage); + RTFileClose(pFile); + + if (pvTmpBuf) + RTMemFree(pvTmpBuf); + + if (RT_FAILURE(vrc)) + { + if (vrc == VERR_EOF) + vrc = VINF_SUCCESS; + else + throw setError(VBOX_E_FILE_ERROR, + tr("Error during copy CD/DVD image '%s' (%Rrc)"), + strSrcFilePath.c_str(), vrc); + } + } + } } catch (HRESULT rc3) { |