VirtualBox

Changeset 27882 in vbox


Ignore:
Timestamp:
Mar 31, 2010 11:52:27 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
59569
Message:

Main/OVF: sort import code into separate file as well

Location:
trunk/src/VBox/Main
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/ApplianceImpl.cpp

    r27829 r27882  
    480480}
    481481
    482 /**
    483  * Public method implementation.
    484  * @return
    485  */
    486 STDMETHODIMP Appliance::Interpret()
    487 {
    488     // @todo:
    489     //  - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
    490     //  - Appropriate handle errors like not supported file formats
    491     AutoCaller autoCaller(this);
    492     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    493 
    494     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    495 
    496     if (!isApplianceIdle())
    497         return E_ACCESSDENIED;
    498 
    499     HRESULT rc = S_OK;
    500 
    501     /* Clear any previous virtual system descriptions */
    502     m->virtualSystemDescriptions.clear();
    503 
    504     /* We need the default path for storing disk images */
    505     ComPtr<ISystemProperties> systemProps;
    506     rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
    507     if (FAILED(rc)) return rc;
    508     Bstr bstrDefaultHardDiskLocation;
    509     rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskLocation.asOutParam());
    510     if (FAILED(rc)) return rc;
    511 
    512     if (!m->pReader)
    513         return setError(E_FAIL,
    514                         tr("Cannot interpret appliance without reading it first (call read() before interpret())"));
    515 
    516     // Change the appliance state so we can safely leave the lock while doing time-consuming
    517     // disk imports; also the below method calls do all kinds of locking which conflicts with
    518     // the appliance object lock
    519     m->state = Data::ApplianceImporting;
    520     alock.release();
    521 
    522     /* Try/catch so we can clean up on error */
    523     try
    524     {
    525         list<VirtualSystem>::const_iterator it;
    526         /* Iterate through all virtual systems */
    527         for (it = m->pReader->m_llVirtualSystems.begin();
    528              it != m->pReader->m_llVirtualSystems.end();
    529              ++it)
    530         {
    531             const VirtualSystem &vsysThis = *it;
    532 
    533             ComObjPtr<VirtualSystemDescription> pNewDesc;
    534             rc = pNewDesc.createObject();
    535             if (FAILED(rc)) throw rc;
    536             rc = pNewDesc->init();
    537             if (FAILED(rc)) throw rc;
    538 
    539             /* Guest OS type */
    540             Utf8Str strOsTypeVBox,
    541                     strCIMOSType = Utf8StrFmt("%RI32", (uint32_t)vsysThis.cimos);
    542             convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos, vsysThis.strCimosDesc);
    543             pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
    544                                "",
    545                                strCIMOSType,
    546                                strOsTypeVBox);
    547 
    548             /* VM name */
    549             /* If the there isn't any name specified create a default one out of
    550              * the OS type */
    551             Utf8Str nameVBox = vsysThis.strName;
    552             if (nameVBox.isEmpty())
    553                 nameVBox = strOsTypeVBox;
    554             searchUniqueVMName(nameVBox);
    555             pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
    556                                "",
    557                                vsysThis.strName,
    558                                nameVBox);
    559 
    560             /* VM Product */
    561             if (!vsysThis.strProduct.isEmpty())
    562                 pNewDesc->addEntry(VirtualSystemDescriptionType_Product,
    563                                     "",
    564                                     vsysThis.strProduct,
    565                                     vsysThis.strProduct);
    566 
    567             /* VM Vendor */
    568             if (!vsysThis.strVendor.isEmpty())
    569                 pNewDesc->addEntry(VirtualSystemDescriptionType_Vendor,
    570                                     "",
    571                                     vsysThis.strVendor,
    572                                     vsysThis.strVendor);
    573 
    574             /* VM Version */
    575             if (!vsysThis.strVersion.isEmpty())
    576                 pNewDesc->addEntry(VirtualSystemDescriptionType_Version,
    577                                     "",
    578                                     vsysThis.strVersion,
    579                                     vsysThis.strVersion);
    580 
    581             /* VM ProductUrl */
    582             if (!vsysThis.strProductUrl.isEmpty())
    583                 pNewDesc->addEntry(VirtualSystemDescriptionType_ProductUrl,
    584                                     "",
    585                                     vsysThis.strProductUrl,
    586                                     vsysThis.strProductUrl);
    587 
    588             /* VM VendorUrl */
    589             if (!vsysThis.strVendorUrl.isEmpty())
    590                 pNewDesc->addEntry(VirtualSystemDescriptionType_VendorUrl,
    591                                     "",
    592                                     vsysThis.strVendorUrl,
    593                                     vsysThis.strVendorUrl);
    594 
    595             /* VM description */
    596             if (!vsysThis.strDescription.isEmpty())
    597                 pNewDesc->addEntry(VirtualSystemDescriptionType_Description,
    598                                     "",
    599                                     vsysThis.strDescription,
    600                                     vsysThis.strDescription);
    601 
    602             /* VM license */
    603             if (!vsysThis.strLicenseText.isEmpty())
    604                 pNewDesc->addEntry(VirtualSystemDescriptionType_License,
    605                                     "",
    606                                     vsysThis.strLicenseText,
    607                                     vsysThis.strLicenseText);
    608 
    609             /* Now that we know the OS type, get our internal defaults based on that. */
    610             ComPtr<IGuestOSType> pGuestOSType;
    611             rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), pGuestOSType.asOutParam());
    612             if (FAILED(rc)) throw rc;
    613 
    614             /* CPU count */
    615             ULONG cpuCountVBox = vsysThis.cCPUs;
    616             /* Check for the constrains */
    617             if (cpuCountVBox > SchemaDefs::MaxCPUCount)
    618             {
    619                 addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
    620                            vsysThis.strName.c_str(), cpuCountVBox, SchemaDefs::MaxCPUCount);
    621                 cpuCountVBox = SchemaDefs::MaxCPUCount;
    622             }
    623             if (vsysThis.cCPUs == 0)
    624                 cpuCountVBox = 1;
    625             pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
    626                                "",
    627                                Utf8StrFmt("%RI32", (uint32_t)vsysThis.cCPUs),
    628                                Utf8StrFmt("%RI32", (uint32_t)cpuCountVBox));
    629 
    630             /* RAM */
    631             uint64_t ullMemSizeVBox = vsysThis.ullMemorySize / _1M;
    632             /* Check for the constrains */
    633             if (ullMemSizeVBox != 0 &&
    634                 (ullMemSizeVBox < MM_RAM_MIN_IN_MB ||
    635                  ullMemSizeVBox > MM_RAM_MAX_IN_MB))
    636             {
    637                 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."),
    638                               vsysThis.strName.c_str(), ullMemSizeVBox, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
    639                 ullMemSizeVBox = RT_MIN(RT_MAX(ullMemSizeVBox, MM_RAM_MIN_IN_MB), MM_RAM_MAX_IN_MB);
    640             }
    641             if (vsysThis.ullMemorySize == 0)
    642             {
    643                 /* If the RAM of the OVF is zero, use our predefined values */
    644                 ULONG memSizeVBox2;
    645                 rc = pGuestOSType->COMGETTER(RecommendedRAM)(&memSizeVBox2);
    646                 if (FAILED(rc)) throw rc;
    647                 /* VBox stores that in MByte */
    648                 ullMemSizeVBox = (uint64_t)memSizeVBox2;
    649             }
    650             pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
    651                                "",
    652                                Utf8StrFmt("%RI64", (uint64_t)vsysThis.ullMemorySize),
    653                                Utf8StrFmt("%RI64", (uint64_t)ullMemSizeVBox));
    654 
    655             /* Audio */
    656             if (!vsysThis.strSoundCardType.isEmpty())
    657                 /* Currently we set the AC97 always.
    658                    @todo: figure out the hardware which could be possible */
    659                 pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
    660                                    "",
    661                                    vsysThis.strSoundCardType,
    662                                    Utf8StrFmt("%RI32", (uint32_t)AudioControllerType_AC97));
    663 
    664 #ifdef VBOX_WITH_USB
    665             /* USB Controller */
    666             if (vsysThis.fHasUsbController)
    667                 pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
    668 #endif /* VBOX_WITH_USB */
    669 
    670             /* Network Controller */
    671             size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size();
    672             if (cEthernetAdapters > 0)
    673             {
    674                 /* Check for the constrains */
    675                 if (cEthernetAdapters > SchemaDefs::NetworkAdapterCount)
    676                     addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
    677                                   vsysThis.strName.c_str(), cEthernetAdapters, SchemaDefs::NetworkAdapterCount);
    678 
    679                 /* Get the default network adapter type for the selected guest OS */
    680                 NetworkAdapterType_T defaultAdapterVBox = NetworkAdapterType_Am79C970A;
    681                 rc = pGuestOSType->COMGETTER(AdapterType)(&defaultAdapterVBox);
    682                 if (FAILED(rc)) throw rc;
    683 
    684                 EthernetAdaptersList::const_iterator itEA;
    685                 /* Iterate through all abstract networks. We support 8 network
    686                  * adapters at the maximum, so the first 8 will be added only. */
    687                 size_t a = 0;
    688                 for (itEA = vsysThis.llEthernetAdapters.begin();
    689                      itEA != vsysThis.llEthernetAdapters.end() && a < SchemaDefs::NetworkAdapterCount;
    690                      ++itEA, ++a)
    691                 {
    692                     const EthernetAdapter &ea = *itEA; // logical network to connect to
    693                     Utf8Str strNetwork = ea.strNetworkName;
    694                     // make sure it's one of these two
    695                     if (    (strNetwork.compare("Null", Utf8Str::CaseInsensitive))
    696                          && (strNetwork.compare("NAT", Utf8Str::CaseInsensitive))
    697                          && (strNetwork.compare("Bridged", Utf8Str::CaseInsensitive))
    698                          && (strNetwork.compare("Internal", Utf8Str::CaseInsensitive))
    699                          && (strNetwork.compare("HostOnly", Utf8Str::CaseInsensitive))
    700                        )
    701                         strNetwork = "Bridged";     // VMware assumes this is the default apparently
    702 
    703                     /* Figure out the hardware type */
    704                     NetworkAdapterType_T nwAdapterVBox = defaultAdapterVBox;
    705                     if (!ea.strAdapterType.compare("PCNet32", Utf8Str::CaseInsensitive))
    706                     {
    707                         /* If the default adapter is already one of the two
    708                          * PCNet adapters use the default one. If not use the
    709                          * Am79C970A as fallback. */
    710                         if (!(defaultAdapterVBox == NetworkAdapterType_Am79C970A ||
    711                               defaultAdapterVBox == NetworkAdapterType_Am79C973))
    712                             nwAdapterVBox = NetworkAdapterType_Am79C970A;
    713                     }
    714 #ifdef VBOX_WITH_E1000
    715                     /* VMWare accidentally write this with VirtualCenter 3.5,
    716                        so make sure in this case always to use the VMWare one */
    717                     else if (!ea.strAdapterType.compare("E10000", Utf8Str::CaseInsensitive))
    718                         nwAdapterVBox = NetworkAdapterType_I82545EM;
    719                     else if (!ea.strAdapterType.compare("E1000", Utf8Str::CaseInsensitive))
    720                     {
    721                         /* Check if this OVF was written by VirtualBox */
    722                         if (Utf8Str(vsysThis.strVirtualSystemType).contains("virtualbox", Utf8Str::CaseInsensitive))
    723                         {
    724                             /* If the default adapter is already one of the three
    725                              * E1000 adapters use the default one. If not use the
    726                              * I82545EM as fallback. */
    727                             if (!(defaultAdapterVBox == NetworkAdapterType_I82540EM ||
    728                                   defaultAdapterVBox == NetworkAdapterType_I82543GC ||
    729                                   defaultAdapterVBox == NetworkAdapterType_I82545EM))
    730                             nwAdapterVBox = NetworkAdapterType_I82540EM;
    731                         }
    732                         else
    733                             /* Always use this one since it's what VMware uses */
    734                             nwAdapterVBox = NetworkAdapterType_I82545EM;
    735                     }
    736 #endif /* VBOX_WITH_E1000 */
    737 
    738                     pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
    739                                        "",      // ref
    740                                        ea.strNetworkName,      // orig
    741                                        Utf8StrFmt("%RI32", (uint32_t)nwAdapterVBox),   // conf
    742                                        0,
    743                                        Utf8StrFmt("type=%s", strNetwork.c_str()));       // extra conf
    744                 }
    745             }
    746 
    747             /* Floppy Drive */
    748             if (vsysThis.fHasFloppyDrive)
    749                 pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy, "", "", "");
    750 
    751             /* CD Drive */
    752             if (vsysThis.fHasCdromDrive)
    753                 pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");
    754 
    755             /* Hard disk Controller */
    756             uint16_t cIDEused = 0;
    757             uint16_t cSATAused = 0; NOREF(cSATAused);
    758             uint16_t cSCSIused = 0; NOREF(cSCSIused);
    759             ControllersMap::const_iterator hdcIt;
    760             /* Iterate through all hard disk controllers */
    761             for (hdcIt = vsysThis.mapControllers.begin();
    762                  hdcIt != vsysThis.mapControllers.end();
    763                  ++hdcIt)
    764             {
    765                 const HardDiskController &hdc = hdcIt->second;
    766                 Utf8Str strControllerID = Utf8StrFmt("%RI32", (uint32_t)hdc.idController);
    767 
    768                 switch (hdc.system)
    769                 {
    770                     case HardDiskController::IDE:
    771                         {
    772                             /* Check for the constrains */
    773                             /* @todo: I'm very confused! Are these bits *one* controller or
    774                                is every port/bus declared as an extra controller. */
    775                             if (cIDEused < 4)
    776                             {
    777                                 // @todo: figure out the IDE types
    778                                 /* Use PIIX4 as default */
    779                                 Utf8Str strType = "PIIX4";
    780                                 if (!hdc.strControllerType.compare("PIIX3", Utf8Str::CaseInsensitive))
    781                                     strType = "PIIX3";
    782                                 else if (!hdc.strControllerType.compare("ICH6", Utf8Str::CaseInsensitive))
    783                                     strType = "ICH6";
    784                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
    785                                                    strControllerID,
    786                                                    hdc.strControllerType,
    787                                                    strType);
    788                             }
    789                             else
    790                             {
    791                                 /* Warn only once */
    792                                 if (cIDEused == 1)
    793                                     addWarning(tr("The virtual \"%s\" system requests support for more than one IDE controller, but VirtualBox has support for only one."),
    794                                                vsysThis.strName.c_str());
    795 
    796                             }
    797                             ++cIDEused;
    798                             break;
    799                         }
    800 
    801                     case HardDiskController::SATA:
    802                         {
    803 #ifdef VBOX_WITH_AHCI
    804                             /* Check for the constrains */
    805                             if (cSATAused < 1)
    806                             {
    807                                 // @todo: figure out the SATA types
    808                                 /* We only support a plain AHCI controller, so use them always */
    809                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
    810                                                    strControllerID,
    811                                                    hdc.strControllerType,
    812                                                    "AHCI");
    813                             }
    814                             else
    815                             {
    816                                 /* Warn only once */
    817                                 if (cSATAused == 1)
    818                                     addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"),
    819                                                vsysThis.strName.c_str());
    820 
    821                             }
    822                             ++cSATAused;
    823                             break;
    824 #else /* !VBOX_WITH_AHCI */
    825                             addWarning(tr("The virtual system \"%s\" requests at least one SATA controller but this version of VirtualBox does not provide a SATA controller emulation"),
    826                                       vsysThis.strName.c_str());
    827 #endif /* !VBOX_WITH_AHCI */
    828                         }
    829 
    830                     case HardDiskController::SCSI:
    831                         {
    832 #ifdef VBOX_WITH_LSILOGIC
    833                             /* Check for the constrains */
    834                             if (cSCSIused < 1)
    835                             {
    836                                 Utf8Str hdcController = "LsiLogic";
    837                                 if (!hdc.strControllerType.compare("BusLogic", Utf8Str::CaseInsensitive))
    838                                     hdcController = "BusLogic";
    839                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
    840                                                    strControllerID,
    841                                                    hdc.strControllerType,
    842                                                    hdcController);
    843                             }
    844                             else
    845                                 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."),
    846                                            vsysThis.strName.c_str(),
    847                                            hdc.strControllerType.c_str(),
    848                                            strControllerID.c_str());
    849                             ++cSCSIused;
    850                             break;
    851 #else /* !VBOX_WITH_LSILOGIC */
    852                             addWarning(tr("The virtual system \"%s\" requests at least one SATA controller but this version of VirtualBox does not provide a SCSI controller emulation"),
    853                                        vsysThis.strName.c_str());
    854 #endif /* !VBOX_WITH_LSILOGIC */
    855                         }
    856                 }
    857             }
    858 
    859             /* Hard disks */
    860             if (vsysThis.mapVirtualDisks.size() > 0)
    861             {
    862                 VirtualDisksMap::const_iterator itVD;
    863                 /* Iterate through all hard disks ()*/
    864                 for (itVD = vsysThis.mapVirtualDisks.begin();
    865                      itVD != vsysThis.mapVirtualDisks.end();
    866                      ++itVD)
    867                 {
    868                     const VirtualDisk &hd = itVD->second;
    869                     /* Get the associated disk image */
    870                     const DiskImage &di = m->pReader->m_mapDisks[hd.strDiskId];
    871 
    872                     // @todo:
    873                     //  - figure out all possible vmdk formats we also support
    874                     //  - figure out if there is a url specifier for vhd already
    875                     //  - we need a url specifier for the vdi format
    876                     if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
    877                         || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
    878                     {
    879                         /* If the href is empty use the VM name as filename */
    880                         Utf8Str strFilename = di.strHref;
    881                         if (!strFilename.length())
    882                             strFilename = Utf8StrFmt("%s.vmdk", nameVBox.c_str());
    883                         /* Construct a unique target path */
    884                         Utf8StrFmt strPath("%ls%c%s",
    885                                            bstrDefaultHardDiskLocation.raw(),
    886                                            RTPATH_DELIMITER,
    887                                            strFilename.c_str());
    888                         searchUniqueDiskImageFilePath(strPath);
    889 
    890                         /* find the description for the hard disk controller
    891                          * that has the same ID as hd.idController */
    892                         const VirtualSystemDescriptionEntry *pController;
    893                         if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
    894                             throw setError(E_FAIL,
    895                                            tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"),
    896                                            hd.idController,
    897                                            di.strHref.c_str());
    898 
    899                         /* controller to attach to, and the bus within that controller */
    900                         Utf8StrFmt strExtraConfig("controller=%RI16;channel=%RI16",
    901                                                   pController->ulIndex,
    902                                                   hd.ulAddressOnParent);
    903                         ULONG ulSize = 0;
    904                         if (di.iCapacity != -1)
    905                             ulSize = (ULONG)(di.iCapacity / _1M);
    906                         else if (di.iPopulatedSize != -1)
    907                             ulSize = (ULONG)(di.iPopulatedSize / _1M);
    908                         else if (di.iSize != -1)
    909                             ulSize = (ULONG)(di.iSize / _1M);
    910                         if (ulSize == 0)
    911                             ulSize = 10000;         // assume 10 GB, this is for the progress bar only anyway
    912                         pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
    913                                            hd.strDiskId,
    914                                            di.strHref,
    915                                            strPath,
    916                                            ulSize,
    917                                            strExtraConfig);
    918                     }
    919                     else
    920                         throw setError(VBOX_E_FILE_ERROR,
    921                                        tr("Unsupported format for virtual disk image in OVF: \"%s\"", di.strFormat.c_str()));
    922                 }
    923             }
    924 
    925             m->virtualSystemDescriptions.push_back(pNewDesc);
    926         }
    927     }
    928     catch (HRESULT aRC)
    929     {
    930         /* On error we clear the list & return */
    931         m->virtualSystemDescriptions.clear();
    932         rc = aRC;
    933     }
    934 
    935     // reset the appliance state
    936     alock.acquire();
    937     m->state = Data::ApplianceIdle;
    938 
    939     return rc;
    940 }
    941 
    942 /**
    943  * Public method implementation.
    944  * @param aProgress
    945  * @return
    946  */
    947 STDMETHODIMP Appliance::ImportMachines(IProgress **aProgress)
    948 {
    949     CheckComArgOutPointerValid(aProgress);
    950 
    951     AutoCaller autoCaller(this);
    952     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    953 
    954     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    955 
    956     // do not allow entering this method if the appliance is busy reading or writing
    957     if (!isApplianceIdle())
    958         return E_ACCESSDENIED;
    959 
    960     if (!m->pReader)
    961         return setError(E_FAIL,
    962                         tr("Cannot import machines without reading it first (call read() before importMachines())"));
    963 
    964     ComObjPtr<Progress> progress;
    965     HRESULT rc = S_OK;
    966     try
    967     {
    968         rc = importImpl(m->locInfo, progress);
    969     }
    970     catch (HRESULT aRC)
    971     {
    972         rc = aRC;
    973     }
    974 
    975     if (SUCCEEDED(rc))
    976         /* Return progress to the caller */
    977         progress.queryInterfaceTo(aProgress);
    978 
    979     return rc;
    980 }
    981 
    982482STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
    983483{
     
    1431931}
    1432932
    1433 HRESULT Appliance::readImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    1434 {
    1435     /* Initialize our worker task */
    1436     std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
    1437     /* What should the task do */
    1438     task->taskType = TaskImportOVF::Read;
    1439     /* Copy the current location info to the task */
    1440     task->locInfo = aLocInfo;
    1441 
    1442     BstrFmt bstrDesc = BstrFmt(tr("Read appliance '%s'"),
    1443                                aLocInfo.strPath.c_str());
    1444     HRESULT rc;
    1445     /* Create the progress object */
    1446     aProgress.createObject();
    1447     if (task->locInfo.storageType == VFSType_File)
    1448     {
    1449         /* 1 operation only */
    1450         rc = aProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    1451                              bstrDesc,
    1452                              TRUE /* aCancelable */);
    1453     }
    1454     else
    1455     {
    1456         /* 4/5 is downloading, 1/5 is reading */
    1457         rc = aProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    1458                              bstrDesc,
    1459                              TRUE /* aCancelable */,
    1460                              2, // ULONG cOperations,
    1461                              5, // ULONG ulTotalOperationsWeight,
    1462                              BstrFmt(tr("Download appliance '%s'"),
    1463                                      aLocInfo.strPath.c_str()), // CBSTR bstrFirstOperationDescription,
    1464                              4); // ULONG ulFirstOperationWeight,
    1465     }
    1466     if (FAILED(rc)) throw rc;
    1467 
    1468     task->progress = aProgress;
    1469 
    1470     rc = task->startThread();
    1471     if (FAILED(rc)) throw rc;
    1472 
    1473     /* Don't destruct on success */
    1474     task.release();
    1475 
    1476     return rc;
    1477 }
    1478 
    1479 /**
    1480  * Implementation of the import code. This gets called from the public Appliance::ImportMachines()
    1481  * method as well as Appliance::importS3().
    1482  * @param aLocInfo
    1483  * @param aProgress
    1484  * @return
    1485  */
    1486 HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    1487 {
    1488     /* Initialize our worker task */
    1489     std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
    1490     /* What should the task do */
    1491     task->taskType = TaskImportOVF::Import;
    1492     /* Copy the current location info to the task */
    1493     task->locInfo = aLocInfo;
    1494 
    1495     Bstr progressDesc = BstrFmt(tr("Import appliance '%s'"),
    1496                                 aLocInfo.strPath.c_str());
    1497 
    1498     HRESULT rc = S_OK;
    1499 
    1500     /* todo: This progress init stuff should be done a little bit more generic */
    1501     if (task->locInfo.storageType == VFSType_File)
    1502         rc = setUpProgressFS(aProgress, progressDesc);
    1503     else
    1504         rc = setUpProgressImportS3(aProgress, progressDesc);
    1505     if (FAILED(rc)) throw rc;
    1506 
    1507     task->progress = aProgress;
    1508 
    1509     rc = task->startThread();
    1510     if (FAILED(rc)) throw rc;
    1511 
    1512     /* Don't destruct on success */
    1513     task.release();
    1514 
    1515     return rc;
    1516 }
    1517 
    1518 /**
    1519  * Worker thread implementation for Read() (ovf reader).
    1520  * @param aThread
    1521  * @param pvUser
    1522  */
    1523 /* static */
    1524 DECLCALLBACK(int) Appliance::taskThreadImportOVF(RTTHREAD /* aThread */, void *pvUser)
    1525 {
    1526     std::auto_ptr<TaskImportOVF> task(static_cast<TaskImportOVF*>(pvUser));
    1527     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    1528 
    1529     Appliance *pAppliance = task->pAppliance;
    1530 
    1531     LogFlowFuncEnter();
    1532     LogFlowFunc(("Appliance %p\n", pAppliance));
    1533 
    1534     HRESULT rc = S_OK;
    1535 
    1536     switch (task->taskType)
    1537     {
    1538         case TaskImportOVF::Read:
    1539         {
    1540             if (task->locInfo.storageType == VFSType_File)
    1541                 rc = pAppliance->readFS(task.get());
    1542             else if (task->locInfo.storageType == VFSType_S3)
    1543                 rc = pAppliance->readS3(task.get());
    1544             break;
    1545         }
    1546         case TaskImportOVF::Import:
    1547         {
    1548             if (task->locInfo.storageType == VFSType_File)
    1549                 rc = pAppliance->importFS(task.get());
    1550             else if (task->locInfo.storageType == VFSType_S3)
    1551                 rc = pAppliance->importS3(task.get());
    1552             break;
    1553         }
    1554     }
    1555 
    1556     LogFlowFunc(("rc=%Rhrc\n", rc));
    1557     LogFlowFuncLeave();
    1558 
    1559     return VINF_SUCCESS;
    1560 }
    1561 
    1562 int Appliance::TaskImportOVF::startThread()
    1563 {
    1564     int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOVF, this,
    1565                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    1566                              "Appliance::Task");
    1567 
    1568     ComAssertMsgRCRet(vrc,
    1569                       ("Could not create taskThreadImportOVF (%Rrc)\n", vrc), E_FAIL);
    1570 
    1571     return S_OK;
    1572 }
    1573 
    1574 int Appliance::readFS(TaskImportOVF *pTask)
    1575 {
    1576     LogFlowFuncEnter();
    1577     LogFlowFunc(("Appliance %p\n", this));
    1578 
    1579     AutoCaller autoCaller(this);
    1580     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1581 
    1582     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    1583 
    1584     HRESULT rc = S_OK;
    1585 
    1586     try
    1587     {
    1588         /* Read & parse the XML structure of the OVF file */
    1589         m->pReader = new OVFReader(pTask->locInfo.strPath);
    1590         /* Create the SHA1 sum of the OVF file for later validation */
    1591         char *pszDigest;
    1592         int vrc = RTSha1Digest(pTask->locInfo.strPath.c_str(), &pszDigest);
    1593         if (RT_FAILURE(vrc))
    1594             throw setError(VBOX_E_FILE_ERROR,
    1595                            tr("Couldn't calculate SHA1 digest for file '%s' (%Rrc)"),
    1596                            RTPathFilename(pTask->locInfo.strPath.c_str()), vrc);
    1597         m->strOVFSHA1Digest = pszDigest;
    1598         RTStrFree(pszDigest);
    1599     }
    1600     catch(xml::Error &x)
    1601     {
    1602         rc = setError(VBOX_E_FILE_ERROR,
    1603                       x.what());
    1604     }
    1605     catch(HRESULT aRC)
    1606     {
    1607         rc = aRC;
    1608     }
    1609 
    1610     pTask->rc = rc;
    1611 
    1612     if (!pTask->progress.isNull())
    1613         pTask->progress->notifyComplete(rc);
    1614 
    1615     LogFlowFunc(("rc=%Rhrc\n", rc));
    1616     LogFlowFuncLeave();
    1617 
    1618     return VINF_SUCCESS;
    1619 }
    1620 
    1621 int Appliance::readS3(TaskImportOVF *pTask)
    1622 {
    1623     LogFlowFuncEnter();
    1624     LogFlowFunc(("Appliance %p\n", this));
    1625 
    1626     AutoCaller autoCaller(this);
    1627     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1628 
    1629     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    1630 
    1631     HRESULT rc = S_OK;
    1632     int vrc = VINF_SUCCESS;
    1633     RTS3 hS3 = NIL_RTS3;
    1634     char szOSTmpDir[RTPATH_MAX];
    1635     RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
    1636     /* The template for the temporary directory created below */
    1637     char *pszTmpDir;
    1638     RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
    1639     list< pair<Utf8Str, ULONG> > filesList;
    1640     Utf8Str strTmpOvf;
    1641 
    1642     try
    1643     {
    1644         /* Extract the bucket */
    1645         Utf8Str tmpPath = pTask->locInfo.strPath;
    1646         Utf8Str bucket;
    1647         parseBucket(tmpPath, bucket);
    1648 
    1649         /* We need a temporary directory which we can put the OVF file & all
    1650          * disk images in */
    1651         vrc = RTDirCreateTemp(pszTmpDir);
    1652         if (RT_FAILURE(vrc))
    1653             throw setError(VBOX_E_FILE_ERROR,
    1654                            tr("Cannot create temporary directory '%s'"), pszTmpDir);
    1655 
    1656         /* The temporary name of the target OVF file */
    1657         strTmpOvf = Utf8StrFmt("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str()));
    1658 
    1659         /* Next we have to download the OVF */
    1660         vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
    1661         if(RT_FAILURE(vrc))
    1662             throw setError(VBOX_E_IPRT_ERROR,
    1663                            tr("Cannot create S3 service handler"));
    1664         RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
    1665 
    1666         /* Get it */
    1667         char *pszFilename = RTPathFilename(strTmpOvf.c_str());
    1668         vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strTmpOvf.c_str());
    1669         if (RT_FAILURE(vrc))
    1670         {
    1671             if(vrc == VERR_S3_CANCELED)
    1672                 throw S_OK; /* todo: !!!!!!!!!!!!! */
    1673             else if(vrc == VERR_S3_ACCESS_DENIED)
    1674                 throw setError(E_ACCESSDENIED,
    1675                                tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that your credentials are right. Also check that your host clock is properly synced"), pszFilename);
    1676             else if(vrc == VERR_S3_NOT_FOUND)
    1677                 throw setError(VBOX_E_FILE_ERROR,
    1678                                tr("Cannot download file '%s' from S3 storage server (File not found)"), pszFilename);
    1679             else
    1680                 throw setError(VBOX_E_IPRT_ERROR,
    1681                                tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
    1682         }
    1683 
    1684         /* Close the connection early */
    1685         RTS3Destroy(hS3);
    1686         hS3 = NIL_RTS3;
    1687 
    1688         if (!pTask->progress.isNull())
    1689             pTask->progress->SetNextOperation(Bstr(tr("Reading")), 1);
    1690 
    1691         /* Prepare the temporary reading of the OVF */
    1692         ComObjPtr<Progress> progress;
    1693         LocationInfo li;
    1694         li.strPath = strTmpOvf;
    1695         /* Start the reading from the fs */
    1696         rc = readImpl(li, progress);
    1697         if (FAILED(rc)) throw rc;
    1698 
    1699         /* Unlock the appliance for the reading thread */
    1700         appLock.release();
    1701         /* Wait until the reading is done, but report the progress back to the
    1702            caller */
    1703         ComPtr<IProgress> progressInt(progress);
    1704         waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
    1705 
    1706         /* Again lock the appliance for the next steps */
    1707         appLock.acquire();
    1708     }
    1709     catch(HRESULT aRC)
    1710     {
    1711         rc = aRC;
    1712     }
    1713     /* Cleanup */
    1714     RTS3Destroy(hS3);
    1715     /* Delete all files which where temporary created */
    1716     if (RTPathExists(strTmpOvf.c_str()))
    1717     {
    1718         vrc = RTFileDelete(strTmpOvf.c_str());
    1719         if(RT_FAILURE(vrc))
    1720             rc = setError(VBOX_E_FILE_ERROR,
    1721                           tr("Cannot delete file '%s' (%Rrc)"), strTmpOvf.c_str(), vrc);
    1722     }
    1723     /* Delete the temporary directory */
    1724     if (RTPathExists(pszTmpDir))
    1725     {
    1726         vrc = RTDirRemove(pszTmpDir);
    1727         if(RT_FAILURE(vrc))
    1728             rc = setError(VBOX_E_FILE_ERROR,
    1729                           tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
    1730     }
    1731     if (pszTmpDir)
    1732         RTStrFree(pszTmpDir);
    1733 
    1734     pTask->rc = rc;
    1735 
    1736     if (!pTask->progress.isNull())
    1737         pTask->progress->notifyComplete(rc);
    1738 
    1739     LogFlowFunc(("rc=%Rhrc\n", rc));
    1740     LogFlowFuncLeave();
    1741 
    1742     return VINF_SUCCESS;
    1743 }
    1744 
    1745 int Appliance::importFS(TaskImportOVF *pTask)
    1746 {
    1747     LogFlowFuncEnter();
    1748     LogFlowFunc(("Appliance %p\n", this));
    1749 
    1750     AutoCaller autoCaller(this);
    1751     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1752 
    1753     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    1754 
    1755     if (!isApplianceIdle())
    1756         return VERR_ACCESS_DENIED;
    1757 
    1758     // Change the appliance state so we can safely leave the lock while doing time-consuming
    1759     // disk imports; also the below method calls do all kinds of locking which conflicts with
    1760     // the appliance object lock
    1761     m->state = Data::ApplianceImporting;
    1762     appLock.release();
    1763 
    1764     HRESULT rc = S_OK;
    1765 
    1766     // rollback for errors:
    1767     // a list of images that we created/imported
    1768     list<MyHardDiskAttachment> llHardDiskAttachments;
    1769     list< ComPtr<IMedium> > llHardDisksCreated;
    1770     list<Bstr> llMachinesRegistered;            // list of string UUIDs
    1771 
    1772     ComPtr<ISession> session;
    1773     bool fSessionOpen = false;
    1774     rc = session.createInprocObject(CLSID_Session);
    1775     if (FAILED(rc)) return rc;
    1776 
    1777     const OVFReader &reader = *m->pReader;
    1778     // this is safe to access because this thread only gets started
    1779     // if pReader != NULL
    1780 
    1781     /* If an manifest file exists, verify the content. Therefore we need all
    1782      * files which are referenced by the OVF & the OVF itself */
    1783     Utf8Str strMfFile = manifestFileName(pTask->locInfo.strPath);
    1784     list<Utf8Str> filesList;
    1785     if (RTPathExists(strMfFile.c_str()))
    1786     {
    1787         Utf8Str strSrcDir(pTask->locInfo.strPath);
    1788         strSrcDir.stripFilename();
    1789         /* Add every disks of every virtual system to an internal list */
    1790         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    1791         for (it = m->virtualSystemDescriptions.begin();
    1792              it != m->virtualSystemDescriptions.end();
    1793              ++it)
    1794         {
    1795             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    1796             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    1797             std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    1798             for (itH = avsdeHDs.begin();
    1799                  itH != avsdeHDs.end();
    1800                  ++itH)
    1801             {
    1802                 VirtualSystemDescriptionEntry *vsdeHD = *itH;
    1803                 /* Find the disk from the OVF's disk list */
    1804                 DiskImagesMap::const_iterator itDiskImage = reader.m_mapDisks.find(vsdeHD->strRef);
    1805                 const DiskImage &di = itDiskImage->second;
    1806                 Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
    1807                 filesList.push_back(strSrcFilePath);
    1808             }
    1809         }
    1810         /* Create the test list */
    1811         PRTMANIFESTTEST pTestList = (PRTMANIFESTTEST)RTMemAllocZ(sizeof(RTMANIFESTTEST)*(filesList.size()+1));
    1812         pTestList[0].pszTestFile = (char*)pTask->locInfo.strPath.c_str();
    1813         pTestList[0].pszTestDigest = (char*)m->strOVFSHA1Digest.c_str();
    1814         int vrc = VINF_SUCCESS;
    1815         size_t i = 1;
    1816         list<Utf8Str>::const_iterator it1;
    1817         for (it1 = filesList.begin();
    1818              it1 != filesList.end();
    1819              ++it1, ++i)
    1820         {
    1821             char* pszDigest;
    1822             vrc = RTSha1Digest((*it1).c_str(), &pszDigest);
    1823             pTestList[i].pszTestFile = (char*)(*it1).c_str();
    1824             pTestList[i].pszTestDigest = pszDigest;
    1825         }
    1826         size_t cIndexOnError;
    1827         vrc = RTManifestVerify(strMfFile.c_str(), pTestList, filesList.size() + 1, &cIndexOnError);
    1828         if (vrc == VERR_MANIFEST_DIGEST_MISMATCH)
    1829             rc = setError(VBOX_E_FILE_ERROR,
    1830                           tr("The SHA1 digest of '%s' doesn't match to the one in '%s'"),
    1831                           RTPathFilename(pTestList[cIndexOnError].pszTestFile),
    1832                           RTPathFilename(strMfFile.c_str()));
    1833         else if (RT_FAILURE(vrc))
    1834             rc = setError(VBOX_E_FILE_ERROR,
    1835                           tr("Couldn't verify the content of '%s' against the available files (%Rrc)"),
    1836                           RTPathFilename(strMfFile.c_str()),
    1837                           vrc);
    1838         /* Cleanup */
    1839         for (size_t j = 1;
    1840              j < filesList.size();
    1841              ++j)
    1842             RTStrFree(pTestList[j].pszTestDigest);
    1843         RTMemFree(pTestList);
    1844         if (FAILED(rc))
    1845         {
    1846             /* Return on error */
    1847             pTask->rc = rc;
    1848 
    1849             if (!pTask->progress.isNull())
    1850                 pTask->progress->notifyComplete(rc);
    1851             return rc;
    1852         }
    1853     }
    1854 
    1855     list<VirtualSystem>::const_iterator it;
    1856     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
    1857     /* Iterate through all virtual systems of that appliance */
    1858     size_t i = 0;
    1859     for (it = reader.m_llVirtualSystems.begin(),
    1860          it1 = m->virtualSystemDescriptions.begin();
    1861          it != reader.m_llVirtualSystems.end();
    1862          ++it, ++it1, ++i)
    1863     {
    1864         const VirtualSystem &vsysThis = *it;
    1865         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it1);
    1866 
    1867         ComPtr<IMachine> pNewMachine;
    1868 
    1869         /* Catch possible errors */
    1870         try
    1871         {
    1872             /* Guest OS type */
    1873             std::list<VirtualSystemDescriptionEntry*> vsdeOS;
    1874             vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
    1875             if (vsdeOS.size() < 1)
    1876                 throw setError(VBOX_E_FILE_ERROR,
    1877                                tr("Missing guest OS type"));
    1878             const Utf8Str &strOsTypeVBox = vsdeOS.front()->strVbox;
    1879 
    1880             /* Now that we know the base system get our internal defaults based on that. */
    1881             ComPtr<IGuestOSType> osType;
    1882             rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam());
    1883             if (FAILED(rc)) throw rc;
    1884 
    1885             /* Create the machine */
    1886             /* First get the name */
    1887             std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
    1888             if (vsdeName.size() < 1)
    1889                 throw setError(VBOX_E_FILE_ERROR,
    1890                                tr("Missing VM name"));
    1891             const Utf8Str &strNameVBox = vsdeName.front()->strVbox;
    1892             rc = mVirtualBox->CreateMachine(Bstr(strNameVBox), Bstr(strOsTypeVBox),
    1893                                                  Bstr(), Bstr(), FALSE,
    1894                                                  pNewMachine.asOutParam());
    1895             if (FAILED(rc)) throw rc;
    1896 
    1897             // and the description
    1898             std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
    1899             if (vsdeDescription.size())
    1900             {
    1901                 const Utf8Str &strDescription = vsdeDescription.front()->strVbox;
    1902                 rc = pNewMachine->COMSETTER(Description)(Bstr(strDescription));
    1903                 if (FAILED(rc)) throw rc;
    1904             }
    1905 
    1906             /* CPU count */
    1907             std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU);
    1908             ComAssertMsgThrow(vsdeCPU.size() == 1, ("CPU count missing"), E_FAIL);
    1909             const Utf8Str &cpuVBox = vsdeCPU.front()->strVbox;
    1910             ULONG tmpCount = (ULONG)RTStrToUInt64(cpuVBox.c_str());
    1911             rc = pNewMachine->COMSETTER(CPUCount)(tmpCount);
    1912             if (FAILED(rc)) throw rc;
    1913             bool fEnableIOApic = false;
    1914             /* We need HWVirt & IO-APIC if more than one CPU is requested */
    1915             if (tmpCount > 1)
    1916             {
    1917                 rc = pNewMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, TRUE);
    1918                 if (FAILED(rc)) throw rc;
    1919 
    1920                 fEnableIOApic = true;
    1921             }
    1922 
    1923             /* RAM */
    1924             std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
    1925             ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL);
    1926             const Utf8Str &memoryVBox = vsdeRAM.front()->strVbox;
    1927             ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str());
    1928             rc = pNewMachine->COMSETTER(MemorySize)(tt);
    1929             if (FAILED(rc)) throw rc;
    1930 
    1931             /* VRAM */
    1932             /* Get the recommended VRAM for this guest OS type */
    1933             ULONG vramVBox;
    1934             rc = osType->COMGETTER(RecommendedVRAM)(&vramVBox);
    1935             if (FAILED(rc)) throw rc;
    1936 
    1937             /* Set the VRAM */
    1938             rc = pNewMachine->COMSETTER(VRAMSize)(vramVBox);
    1939             if (FAILED(rc)) throw rc;
    1940 
    1941             /* I/O APIC: so far we have no setting for this. Enable it if we
    1942               import a Windows VM because if if Windows was installed without IOAPIC,
    1943               it will not mind finding an one later on, but if Windows was installed
    1944               _with_ an IOAPIC, it will bluescreen if it's not found */
    1945             Bstr bstrFamilyId;
    1946             rc = osType->COMGETTER(FamilyId)(bstrFamilyId.asOutParam());
    1947             if (FAILED(rc)) throw rc;
    1948 
    1949             Utf8Str strFamilyId(bstrFamilyId);
    1950             if (strFamilyId == "Windows")
    1951                 fEnableIOApic = true;
    1952 
    1953             /* If IP-APIC should be enabled could be have different reasons.
    1954                See CPU count & the Win test above. Here we enable it if it was
    1955                previously requested. */
    1956             if (fEnableIOApic)
    1957             {
    1958                 ComPtr<IBIOSSettings> pBIOSSettings;
    1959                 rc = pNewMachine->COMGETTER(BIOSSettings)(pBIOSSettings.asOutParam());
    1960                 if (FAILED(rc)) throw rc;
    1961 
    1962                 rc = pBIOSSettings->COMSETTER(IOAPICEnabled)(TRUE);
    1963                 if (FAILED(rc)) throw rc;
    1964             }
    1965 
    1966             /* Audio Adapter */
    1967             std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
    1968             /* @todo: we support one audio adapter only */
    1969             if (vsdeAudioAdapter.size() > 0)
    1970             {
    1971                 const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strVbox;
    1972                 if (audioAdapterVBox.compare("null", Utf8Str::CaseInsensitive) != 0)
    1973                 {
    1974                     uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str());
    1975                     ComPtr<IAudioAdapter> audioAdapter;
    1976                     rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
    1977                     if (FAILED(rc)) throw rc;
    1978                     rc = audioAdapter->COMSETTER(Enabled)(true);
    1979                     if (FAILED(rc)) throw rc;
    1980                     rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio));
    1981                     if (FAILED(rc)) throw rc;
    1982                 }
    1983             }
    1984 
    1985 #ifdef VBOX_WITH_USB
    1986             /* USB Controller */
    1987             std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
    1988             // USB support is enabled if there's at least one such entry; to disable USB support,
    1989             // the type of the USB item would have been changed to "ignore"
    1990             bool fUSBEnabled = vsdeUSBController.size() > 0;
    1991 
    1992             ComPtr<IUSBController> usbController;
    1993             rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
    1994             if (FAILED(rc)) throw rc;
    1995             rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
    1996             if (FAILED(rc)) throw rc;
    1997 #endif /* VBOX_WITH_USB */
    1998 
    1999             /* Change the network adapters */
    2000             std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
    2001             if (vsdeNW.size() == 0)
    2002             {
    2003                 /* No network adapters, so we have to disable our default one */
    2004                 ComPtr<INetworkAdapter> nwVBox;
    2005                 rc = pNewMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
    2006                 if (FAILED(rc)) throw rc;
    2007                 rc = nwVBox->COMSETTER(Enabled)(false);
    2008                 if (FAILED(rc)) throw rc;
    2009             }
    2010             else
    2011             {
    2012                 list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
    2013                 /* Iterate through all network cards. We support 8 network adapters
    2014                  * at the maximum. (@todo: warn if there are more!) */
    2015                 size_t a = 0;
    2016                 for (nwIt = vsdeNW.begin();
    2017                      (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
    2018                      ++nwIt, ++a)
    2019                 {
    2020                     const VirtualSystemDescriptionEntry* pvsys = *nwIt;
    2021 
    2022                     const Utf8Str &nwTypeVBox = pvsys->strVbox;
    2023                     uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
    2024                     ComPtr<INetworkAdapter> pNetworkAdapter;
    2025                     rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
    2026                     if (FAILED(rc)) throw rc;
    2027                     /* Enable the network card & set the adapter type */
    2028                     rc = pNetworkAdapter->COMSETTER(Enabled)(true);
    2029                     if (FAILED(rc)) throw rc;
    2030                     rc = pNetworkAdapter->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
    2031                     if (FAILED(rc)) throw rc;
    2032 
    2033                     // default is NAT; change to "bridged" if extra conf says so
    2034                     if (!pvsys->strExtraConfig.compare("type=Bridged", Utf8Str::CaseInsensitive))
    2035                     {
    2036                         /* Attach to the right interface */
    2037                         rc = pNetworkAdapter->AttachToBridgedInterface();
    2038                         if (FAILED(rc)) throw rc;
    2039                         ComPtr<IHost> host;
    2040                         rc = mVirtualBox->COMGETTER(Host)(host.asOutParam());
    2041                         if (FAILED(rc)) throw rc;
    2042                         com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
    2043                         rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
    2044                         if (FAILED(rc)) throw rc;
    2045                         /* We search for the first host network interface which
    2046                          * is usable for bridged networking */
    2047                         for (size_t j = 0;
    2048                              j < nwInterfaces.size();
    2049                              ++j)
    2050                         {
    2051                             HostNetworkInterfaceType_T itype;
    2052                             rc = nwInterfaces[j]->COMGETTER(InterfaceType)(&itype);
    2053                             if (FAILED(rc)) throw rc;
    2054                             if (itype == HostNetworkInterfaceType_Bridged)
    2055                             {
    2056                                 Bstr name;
    2057                                 rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam());
    2058                                 if (FAILED(rc)) throw rc;
    2059                                 /* Set the interface name to attach to */
    2060                                 pNetworkAdapter->COMSETTER(HostInterface)(name);
    2061                                 if (FAILED(rc)) throw rc;
    2062                                 break;
    2063                             }
    2064                         }
    2065                     }
    2066                     /* Next test for host only interfaces */
    2067                     else if (!pvsys->strExtraConfig.compare("type=HostOnly", Utf8Str::CaseInsensitive))
    2068                     {
    2069                         /* Attach to the right interface */
    2070                         rc = pNetworkAdapter->AttachToHostOnlyInterface();
    2071                         if (FAILED(rc)) throw rc;
    2072                         ComPtr<IHost> host;
    2073                         rc = mVirtualBox->COMGETTER(Host)(host.asOutParam());
    2074                         if (FAILED(rc)) throw rc;
    2075                         com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
    2076                         rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
    2077                         if (FAILED(rc)) throw rc;
    2078                         /* We search for the first host network interface which
    2079                          * is usable for host only networking */
    2080                         for (size_t j = 0;
    2081                              j < nwInterfaces.size();
    2082                              ++j)
    2083                         {
    2084                             HostNetworkInterfaceType_T itype;
    2085                             rc = nwInterfaces[j]->COMGETTER(InterfaceType)(&itype);
    2086                             if (FAILED(rc)) throw rc;
    2087                             if (itype == HostNetworkInterfaceType_HostOnly)
    2088                             {
    2089                                 Bstr name;
    2090                                 rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam());
    2091                                 if (FAILED(rc)) throw rc;
    2092                                 /* Set the interface name to attach to */
    2093                                 pNetworkAdapter->COMSETTER(HostInterface)(name);
    2094                                 if (FAILED(rc)) throw rc;
    2095                                 break;
    2096                             }
    2097                         }
    2098                     }
    2099                 }
    2100             }
    2101 
    2102             /* Hard disk controller IDE */
    2103             std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
    2104             if (vsdeHDCIDE.size() > 1)
    2105                 throw setError(VBOX_E_FILE_ERROR,
    2106                                tr("Too many IDE controllers in OVF; import facility only supports one"));
    2107             if (vsdeHDCIDE.size() == 1)
    2108             {
    2109                 ComPtr<IStorageController> pController;
    2110                 rc = pNewMachine->AddStorageController(Bstr("IDE Controller"), StorageBus_IDE, pController.asOutParam());
    2111                 if (FAILED(rc)) throw rc;
    2112 
    2113                 const char *pcszIDEType = vsdeHDCIDE.front()->strVbox.c_str();
    2114                 if (!strcmp(pcszIDEType, "PIIX3"))
    2115                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3);
    2116                 else if (!strcmp(pcszIDEType, "PIIX4"))
    2117                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX4);
    2118                 else if (!strcmp(pcszIDEType, "ICH6"))
    2119                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_ICH6);
    2120                 else
    2121                     throw setError(VBOX_E_FILE_ERROR,
    2122                                    tr("Invalid IDE controller type \"%s\""),
    2123                                    pcszIDEType);
    2124                 if (FAILED(rc)) throw rc;
    2125             }
    2126 #ifdef VBOX_WITH_AHCI
    2127             /* Hard disk controller SATA */
    2128             std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
    2129             if (vsdeHDCSATA.size() > 1)
    2130                 throw setError(VBOX_E_FILE_ERROR,
    2131                                tr("Too many SATA controllers in OVF; import facility only supports one"));
    2132             if (vsdeHDCSATA.size() > 0)
    2133             {
    2134                 ComPtr<IStorageController> pController;
    2135                 const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVbox;
    2136                 if (hdcVBox == "AHCI")
    2137                 {
    2138                     rc = pNewMachine->AddStorageController(Bstr("SATA Controller"), StorageBus_SATA, pController.asOutParam());
    2139                     if (FAILED(rc)) throw rc;
    2140                 }
    2141                 else
    2142                     throw setError(VBOX_E_FILE_ERROR,
    2143                                    tr("Invalid SATA controller type \"%s\""),
    2144                                    hdcVBox.c_str());
    2145             }
    2146 #endif /* VBOX_WITH_AHCI */
    2147 
    2148 #ifdef VBOX_WITH_LSILOGIC
    2149             /* Hard disk controller SCSI */
    2150             std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
    2151             if (vsdeHDCSCSI.size() > 1)
    2152                 throw setError(VBOX_E_FILE_ERROR,
    2153                                tr("Too many SCSI controllers in OVF; import facility only supports one"));
    2154             if (vsdeHDCSCSI.size() > 0)
    2155             {
    2156                 ComPtr<IStorageController> pController;
    2157                 StorageControllerType_T controllerType;
    2158                 const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVbox;
    2159                 if (hdcVBox == "LsiLogic")
    2160                     controllerType = StorageControllerType_LsiLogic;
    2161                 else if (hdcVBox == "BusLogic")
    2162                     controllerType = StorageControllerType_BusLogic;
    2163                 else
    2164                     throw setError(VBOX_E_FILE_ERROR,
    2165                                    tr("Invalid SCSI controller type \"%s\""),
    2166                                    hdcVBox.c_str());
    2167 
    2168                 rc = pNewMachine->AddStorageController(Bstr("SCSI Controller"), StorageBus_SCSI, pController.asOutParam());
    2169                 if (FAILED(rc)) throw rc;
    2170                 rc = pController->COMSETTER(ControllerType)(controllerType);
    2171                 if (FAILED(rc)) throw rc;
    2172             }
    2173 #endif /* VBOX_WITH_LSILOGIC */
    2174 
    2175             /* Now its time to register the machine before we add any hard disks */
    2176             rc = mVirtualBox->RegisterMachine(pNewMachine);
    2177             if (FAILED(rc)) throw rc;
    2178 
    2179             Bstr bstrNewMachineId;
    2180             rc = pNewMachine->COMGETTER(Id)(bstrNewMachineId.asOutParam());
    2181             if (FAILED(rc)) throw rc;
    2182 
    2183             // store new machine for roll-back in case of errors
    2184             llMachinesRegistered.push_back(bstrNewMachineId);
    2185 
    2186             // Add floppies and CD-ROMs to the appropriate controllers.
    2187             std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
    2188             if (vsdeFloppy.size() > 1)
    2189                 throw setError(VBOX_E_FILE_ERROR,
    2190                                tr("Too many floppy controllers in OVF; import facility only supports one"));
    2191             std::list<VirtualSystemDescriptionEntry*> vsdeCDROM = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM);
    2192             if (    (vsdeFloppy.size() > 0)
    2193                  || (vsdeCDROM.size() > 0)
    2194                )
    2195             {
    2196                 // If there's an error here we need to close the session, so
    2197                 // we need another try/catch block.
    2198 
    2199                 try
    2200                 {
    2201                     /* In order to attach things we need to open a session
    2202                      * for the new machine */
    2203                     rc = mVirtualBox->OpenSession(session, bstrNewMachineId);
    2204                     if (FAILED(rc)) throw rc;
    2205                     fSessionOpen = true;
    2206 
    2207                     ComPtr<IMachine> sMachine;
    2208                     rc = session->COMGETTER(Machine)(sMachine.asOutParam());
    2209                     if (FAILED(rc)) throw rc;
    2210 
    2211                     // floppy first
    2212                     if (vsdeFloppy.size() == 1)
    2213                     {
    2214                         ComPtr<IStorageController> pController;
    2215                         rc = sMachine->AddStorageController(Bstr("Floppy Controller"), StorageBus_Floppy, pController.asOutParam());
    2216                         if (FAILED(rc)) throw rc;
    2217 
    2218                         Bstr bstrName;
    2219                         rc = pController->COMGETTER(Name)(bstrName.asOutParam());
    2220                         if (FAILED(rc)) throw rc;
    2221 
    2222                         // this is for rollback later
    2223                         MyHardDiskAttachment mhda;
    2224                         mhda.bstrUuid = bstrNewMachineId;
    2225                         mhda.pMachine = pNewMachine;
    2226                         mhda.controllerType = bstrName;
    2227                         mhda.lChannel = 0;
    2228                         mhda.lDevice = 0;
    2229 
    2230                         Log(("Attaching floppy\n"));
    2231 
    2232                         rc = sMachine->AttachDevice(mhda.controllerType,
    2233                                                     mhda.lChannel,
    2234                                                     mhda.lDevice,
    2235                                                     DeviceType_Floppy,
    2236                                                     NULL);
    2237                         if (FAILED(rc)) throw rc;
    2238 
    2239                         llHardDiskAttachments.push_back(mhda);
    2240                     }
    2241 
    2242 
    2243                     // CD-ROMs next
    2244                     for (std::list<VirtualSystemDescriptionEntry*>::const_iterator jt = vsdeCDROM.begin();
    2245                          jt != vsdeCDROM.end();
    2246                          ++jt)
    2247                     {
    2248                         // for now always attach to secondary master on IDE controller;
    2249                         // there seems to be no useful information in OVF where else to
    2250                         // attach jt (@todo test with latest versions of OVF software)
    2251 
    2252                         // find the IDE controller
    2253                         const HardDiskController *pController = NULL;
    2254                         for (ControllersMap::const_iterator kt = vsysThis.mapControllers.begin();
    2255                              kt != vsysThis.mapControllers.end();
    2256                              ++kt)
    2257                         {
    2258                             if (kt->second.system == HardDiskController::IDE)
    2259                             {
    2260                                 pController = &kt->second;
    2261                             }
    2262                         }
    2263 
    2264                         if (!pController)
    2265                             throw setError(VBOX_E_FILE_ERROR,
    2266                                            tr("OVF wants a CD-ROM drive but cannot find IDE controller, which is required in this version of VirtualBox"));
    2267 
    2268                         // this is for rollback later
    2269                         MyHardDiskAttachment mhda;
    2270                         mhda.bstrUuid = bstrNewMachineId;
    2271                         mhda.pMachine = pNewMachine;
    2272 
    2273                         ConvertDiskAttachmentValues(*pController,
    2274                                                     2,     // interpreted as secondary master
    2275                                                     mhda.controllerType,        // Bstr
    2276                                                     mhda.lChannel,
    2277                                                     mhda.lDevice);
    2278 
    2279                         Log(("Attaching CD-ROM to channel %d on device %d\n", mhda.lChannel, mhda.lDevice));
    2280 
    2281                         rc = sMachine->AttachDevice(mhda.controllerType,
    2282                                                     mhda.lChannel,
    2283                                                     mhda.lDevice,
    2284                                                     DeviceType_DVD,
    2285                                                     NULL);
    2286                         if (FAILED(rc)) throw rc;
    2287 
    2288                         llHardDiskAttachments.push_back(mhda);
    2289                     } // end for (itHD = avsdeHDs.begin();
    2290 
    2291                     rc = sMachine->SaveSettings();
    2292                     if (FAILED(rc)) throw rc;
    2293 
    2294                     // only now that we're done with all disks, close the session
    2295                     rc = session->Close();
    2296                     if (FAILED(rc)) throw rc;
    2297                     fSessionOpen = false;
    2298                 }
    2299                 catch(HRESULT /* aRC */)
    2300                 {
    2301                     if (fSessionOpen)
    2302                         session->Close();
    2303 
    2304                     throw;
    2305                 }
    2306             }
    2307 
    2308             /* Create the hard disks & connect them to the appropriate controllers. */
    2309             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    2310             if (avsdeHDs.size() > 0)
    2311             {
    2312                 // If there's an error here we need to close the session, so
    2313                 // we need another try/catch block.
    2314                 ComPtr<IMedium> srcHdVBox;
    2315                 bool fSourceHdNeedsClosing = false;
    2316 
    2317                 try
    2318                 {
    2319                     /* In order to attach hard disks we need to open a session
    2320                      * for the new machine */
    2321                     rc = mVirtualBox->OpenSession(session, bstrNewMachineId);
    2322                     if (FAILED(rc)) throw rc;
    2323                     fSessionOpen = true;
    2324 
    2325                     /* The disk image has to be on the same place as the OVF file. So
    2326                      * strip the filename out of the full file path. */
    2327                     Utf8Str strSrcDir(pTask->locInfo.strPath);
    2328                     strSrcDir.stripFilename();
    2329 
    2330                     /* Iterate over all given disk images */
    2331                     list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
    2332                     for (itHD = avsdeHDs.begin();
    2333                          itHD != avsdeHDs.end();
    2334                          ++itHD)
    2335                     {
    2336                         VirtualSystemDescriptionEntry *vsdeHD = *itHD;
    2337 
    2338                         /* Check if the destination file exists already or the
    2339                          * destination path is empty. */
    2340                         if (    vsdeHD->strVbox.isEmpty()
    2341                              || RTPathExists(vsdeHD->strVbox.c_str())
    2342                            )
    2343                             /* This isn't allowed */
    2344                             throw setError(VBOX_E_FILE_ERROR,
    2345                                            tr("Destination file '%s' exists",
    2346                                               vsdeHD->strVbox.c_str()));
    2347 
    2348                         /* Find the disk from the OVF's disk list */
    2349                         DiskImagesMap::const_iterator itDiskImage = reader.m_mapDisks.find(vsdeHD->strRef);
    2350                         /* vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
    2351                            in the virtual system's disks map under that ID and also in the global images map. */
    2352                         VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
    2353 
    2354                         if (    itDiskImage == reader.m_mapDisks.end()
    2355                              || itVirtualDisk == vsysThis.mapVirtualDisks.end()
    2356                            )
    2357                             throw setError(E_FAIL,
    2358                                            tr("Internal inconsistency looking up disk images."));
    2359 
    2360                         const DiskImage &di = itDiskImage->second;
    2361                         const VirtualDisk &vd = itVirtualDisk->second;
    2362 
    2363                         /* Make sure all target directories exists */
    2364                         rc = VirtualBox::ensureFilePathExists(vsdeHD->strVbox.c_str());
    2365                         if (FAILED(rc))
    2366                             throw rc;
    2367 
    2368                         // subprogress object for hard disk
    2369                         ComPtr<IProgress> pProgress2;
    2370 
    2371                         ComPtr<IMedium> dstHdVBox;
    2372                         /* If strHref is empty we have to create a new file */
    2373                         if (di.strHref.isEmpty())
    2374                         {
    2375                             /* Which format to use? */
    2376                             Bstr srcFormat = L"VDI";
    2377                             if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
    2378                                 || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
    2379                                 srcFormat = L"VMDK";
    2380                             /* Create an empty hard disk */
    2381                             rc = mVirtualBox->CreateHardDisk(srcFormat, Bstr(vsdeHD->strVbox), dstHdVBox.asOutParam());
    2382                             if (FAILED(rc)) throw rc;
    2383 
    2384                             /* Create a dynamic growing disk image with the given capacity */
    2385                             rc = dstHdVBox->CreateBaseStorage(di.iCapacity / _1M, MediumVariant_Standard, pProgress2.asOutParam());
    2386                             if (FAILED(rc)) throw rc;
    2387 
    2388                             /* Advance to the next operation */
    2389                             if (!pTask->progress.isNull())
    2390                                 pTask->progress->SetNextOperation(BstrFmt(tr("Creating virtual disk image '%s'"), vsdeHD->strVbox.c_str()),
    2391                                                                  vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally
    2392                         }
    2393                         else
    2394                         {
    2395                             /* Construct the source file path */
    2396                             Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
    2397                             /* Check if the source file exists */
    2398                             if (!RTPathExists(strSrcFilePath.c_str()))
    2399                                 /* This isn't allowed */
    2400                                 throw setError(VBOX_E_FILE_ERROR,
    2401                                                tr("Source virtual disk image file '%s' doesn't exist"),
    2402                                                   strSrcFilePath.c_str());
    2403 
    2404                             /* Clone the disk image (this is necessary cause the id has
    2405                              * to be recreated for the case the same hard disk is
    2406                              * attached already from a previous import) */
    2407 
    2408                             /* First open the existing disk image */
    2409                             rc = mVirtualBox->OpenHardDisk(Bstr(strSrcFilePath),
    2410                                                            AccessMode_ReadOnly,
    2411                                                            false,
    2412                                                            NULL,
    2413                                                            false,
    2414                                                            NULL,
    2415                                                            srcHdVBox.asOutParam());
    2416                             if (FAILED(rc)) throw rc;
    2417                             fSourceHdNeedsClosing = true;
    2418 
    2419                             /* We need the format description of the source disk image */
    2420                             Bstr srcFormat;
    2421                             rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
    2422                             if (FAILED(rc)) throw rc;
    2423                             /* Create a new hard disk interface for the destination disk image */
    2424                             rc = mVirtualBox->CreateHardDisk(srcFormat, Bstr(vsdeHD->strVbox), dstHdVBox.asOutParam());
    2425                             if (FAILED(rc)) throw rc;
    2426                             /* Clone the source disk image */
    2427                             rc = srcHdVBox->CloneTo(dstHdVBox, MediumVariant_Standard, NULL, pProgress2.asOutParam());
    2428                             if (FAILED(rc)) throw rc;
    2429 
    2430                             /* Advance to the next operation */
    2431                             if (!pTask->progress.isNull())
    2432                                 pTask->progress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), strSrcFilePath.c_str()),
    2433                                                                  vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
    2434                         }
    2435 
    2436                         // now wait for the background disk operation to complete; this throws HRESULTs on error
    2437                         waitForAsyncProgress(pTask->progress, pProgress2);
    2438 
    2439                         if (fSourceHdNeedsClosing)
    2440                         {
    2441                             rc = srcHdVBox->Close();
    2442                             if (FAILED(rc)) throw rc;
    2443                             fSourceHdNeedsClosing = false;
    2444                         }
    2445 
    2446                         llHardDisksCreated.push_back(dstHdVBox);
    2447                         /* Now use the new uuid to attach the disk image to our new machine */
    2448                         ComPtr<IMachine> sMachine;
    2449                         rc = session->COMGETTER(Machine)(sMachine.asOutParam());
    2450                         if (FAILED(rc)) throw rc;
    2451                         Bstr hdId;
    2452                         rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());
    2453                         if (FAILED(rc)) throw rc;
    2454 
    2455                         /* For now we assume we have one controller of every type only */
    2456                         HardDiskController hdc = (*vsysThis.mapControllers.find(vd.idController)).second;
    2457 
    2458                         // this is for rollback later
    2459                         MyHardDiskAttachment mhda;
    2460                         mhda.bstrUuid = bstrNewMachineId;
    2461                         mhda.pMachine = pNewMachine;
    2462 
    2463                         ConvertDiskAttachmentValues(hdc,
    2464                                                     vd.ulAddressOnParent,
    2465                                                     mhda.controllerType,        // Bstr
    2466                                                     mhda.lChannel,
    2467                                                     mhda.lDevice);
    2468 
    2469                         Log(("Attaching disk %s to channel %d on device %d\n", vsdeHD->strVbox.c_str(), mhda.lChannel, mhda.lDevice));
    2470 
    2471                         rc = sMachine->AttachDevice(mhda.controllerType,
    2472                                                     mhda.lChannel,
    2473                                                     mhda.lDevice,
    2474                                                     DeviceType_HardDisk,
    2475                                                     hdId);
    2476                         if (FAILED(rc)) throw rc;
    2477 
    2478                         llHardDiskAttachments.push_back(mhda);
    2479 
    2480                         rc = sMachine->SaveSettings();
    2481                         if (FAILED(rc)) throw rc;
    2482                     } // end for (itHD = avsdeHDs.begin();
    2483 
    2484                     // only now that we're done with all disks, close the session
    2485                     rc = session->Close();
    2486                     if (FAILED(rc)) throw rc;
    2487                     fSessionOpen = false;
    2488                 }
    2489                 catch(HRESULT /* aRC */)
    2490                 {
    2491                     if (fSourceHdNeedsClosing)
    2492                         srcHdVBox->Close();
    2493 
    2494                     if (fSessionOpen)
    2495                         session->Close();
    2496 
    2497                     throw;
    2498                 }
    2499             }
    2500         }
    2501         catch(HRESULT aRC)
    2502         {
    2503             rc = aRC;
    2504         }
    2505 
    2506         if (FAILED(rc))
    2507             break;
    2508 
    2509     } // for (it = pAppliance->m->llVirtualSystems.begin(),
    2510 
    2511     if (FAILED(rc))
    2512     {
    2513         // with _whatever_ error we've had, do a complete roll-back of
    2514         // machines and disks we've created; unfortunately this is
    2515         // not so trivially done...
    2516 
    2517         HRESULT rc2;
    2518         // detach all hard disks from all machines we created
    2519         list<MyHardDiskAttachment>::iterator itM;
    2520         for (itM = llHardDiskAttachments.begin();
    2521              itM != llHardDiskAttachments.end();
    2522              ++itM)
    2523         {
    2524             const MyHardDiskAttachment &mhda = *itM;
    2525             Bstr bstrUuid(mhda.bstrUuid);           // make a copy, Windows can't handle const Bstr
    2526             rc2 = mVirtualBox->OpenSession(session, bstrUuid);
    2527             if (SUCCEEDED(rc2))
    2528             {
    2529                 ComPtr<IMachine> sMachine;
    2530                 rc2 = session->COMGETTER(Machine)(sMachine.asOutParam());
    2531                 if (SUCCEEDED(rc2))
    2532                 {
    2533                     rc2 = sMachine->DetachDevice(Bstr(mhda.controllerType), mhda.lChannel, mhda.lDevice);
    2534                     rc2 = sMachine->SaveSettings();
    2535                 }
    2536                 session->Close();
    2537             }
    2538         }
    2539 
    2540         // now clean up all hard disks we created
    2541         list< ComPtr<IMedium> >::iterator itHD;
    2542         for (itHD = llHardDisksCreated.begin();
    2543              itHD != llHardDisksCreated.end();
    2544              ++itHD)
    2545         {
    2546             ComPtr<IMedium> pDisk = *itHD;
    2547             ComPtr<IProgress> pProgress;
    2548             rc2 = pDisk->DeleteStorage(pProgress.asOutParam());
    2549             rc2 = pProgress->WaitForCompletion(-1);
    2550         }
    2551 
    2552         // finally, deregister and remove all machines
    2553         list<Bstr>::iterator itID;
    2554         for (itID = llMachinesRegistered.begin();
    2555              itID != llMachinesRegistered.end();
    2556              ++itID)
    2557         {
    2558             Bstr bstrGuid = *itID;      // make a copy, Windows can't handle const Bstr
    2559             ComPtr<IMachine> failedMachine;
    2560             rc2 = mVirtualBox->UnregisterMachine(bstrGuid, failedMachine.asOutParam());
    2561             if (SUCCEEDED(rc2))
    2562                 rc2 = failedMachine->DeleteSettings();
    2563         }
    2564     }
    2565 
    2566     // restore the appliance state
    2567     appLock.acquire();
    2568     m->state = Data::ApplianceIdle;
    2569 
    2570     pTask->rc = rc;
    2571 
    2572     if (!pTask->progress.isNull())
    2573         pTask->progress->notifyComplete(rc);
    2574 
    2575     LogFlowFunc(("rc=%Rhrc\n", rc));
    2576     LogFlowFuncLeave();
    2577 
    2578     return VINF_SUCCESS;
    2579 }
    2580 
    2581 /**
    2582  * Helper that converts VirtualSystem attachment values into VirtualBox attachment values.
    2583  * Throws HRESULT values on errors!
    2584  *
    2585  * @param hdc
    2586  * @param vd
    2587  * @param mhda
    2588  */
    2589 void Appliance::ConvertDiskAttachmentValues(const HardDiskController &hdc,
    2590                                             uint32_t ulAddressOnParent,
    2591                                             Bstr &controllerType,
    2592                                             int32_t &lChannel,
    2593                                             int32_t &lDevice)
    2594 {
    2595     switch (hdc.system)
    2596     {
    2597         case HardDiskController::IDE:
    2598             // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
    2599             // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
    2600             // the device number can be either 0 or 1, to specify the master or the slave device,
    2601             // respectively. For the secondary IDE controller, the device number is always 1 because
    2602             // the master device is reserved for the CD-ROM drive.
    2603             controllerType = Bstr("IDE Controller");
    2604             switch (ulAddressOnParent)
    2605             {
    2606                 case 0:     // interpret this as primary master
    2607                     lChannel = (long)0;
    2608                     lDevice = (long)0;
    2609                 break;
    2610 
    2611                 case 1:     // interpret this as primary slave
    2612                     lChannel = (long)0;
    2613                     lDevice = (long)1;
    2614                 break;
    2615 
    2616                 case 2:     // interpret this as secondary master
    2617                     lChannel = (long)1;
    2618                     lDevice = (long)0;
    2619                 break;
    2620 
    2621                 case 3:     // interpret this as secondary slave
    2622                     lChannel = (long)1;
    2623                     lDevice = (long)1;
    2624                 break;
    2625 
    2626                 default:
    2627                     throw setError(VBOX_E_NOT_SUPPORTED,
    2628                                     tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), ulAddressOnParent);
    2629                 break;
    2630             }
    2631         break;
    2632 
    2633         case HardDiskController::SATA:
    2634             controllerType = Bstr("SATA Controller");
    2635             lChannel = (long)ulAddressOnParent;
    2636             lDevice = (long)0;
    2637         break;
    2638 
    2639         case HardDiskController::SCSI:
    2640             controllerType = Bstr("SCSI Controller");
    2641             lChannel = (long)ulAddressOnParent;
    2642             lDevice = (long)0;
    2643         break;
    2644 
    2645         default: break;
    2646     }
    2647 }
    2648 
    2649 int Appliance::importS3(TaskImportOVF *pTask)
    2650 {
    2651     LogFlowFuncEnter();
    2652     LogFlowFunc(("Appliance %p\n", this));
    2653 
    2654     AutoCaller autoCaller(this);
    2655     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2656 
    2657     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    2658 
    2659     int vrc = VINF_SUCCESS;
    2660     RTS3 hS3 = NIL_RTS3;
    2661     char szOSTmpDir[RTPATH_MAX];
    2662     RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
    2663     /* The template for the temporary directory created below */
    2664     char *pszTmpDir;
    2665     RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
    2666     list< pair<Utf8Str, ULONG> > filesList;
    2667 
    2668     HRESULT rc = S_OK;
    2669     try
    2670     {
    2671         /* Extract the bucket */
    2672         Utf8Str tmpPath = pTask->locInfo.strPath;
    2673         Utf8Str bucket;
    2674         parseBucket(tmpPath, bucket);
    2675 
    2676         /* We need a temporary directory which we can put the all disk images
    2677          * in */
    2678         vrc = RTDirCreateTemp(pszTmpDir);
    2679         if (RT_FAILURE(vrc))
    2680             throw setError(VBOX_E_FILE_ERROR,
    2681                            tr("Cannot create temporary directory '%s'"), pszTmpDir);
    2682 
    2683         /* Add every disks of every virtual system to an internal list */
    2684         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    2685         for (it = m->virtualSystemDescriptions.begin();
    2686              it != m->virtualSystemDescriptions.end();
    2687              ++it)
    2688         {
    2689             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    2690             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    2691             std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    2692             for (itH = avsdeHDs.begin();
    2693                  itH != avsdeHDs.end();
    2694                  ++itH)
    2695             {
    2696                 const Utf8Str &strTargetFile = (*itH)->strOvf;
    2697                 if (!strTargetFile.isEmpty())
    2698                 {
    2699                     /* The temporary name of the target disk file */
    2700                     Utf8StrFmt strTmpDisk("%s/%s", pszTmpDir, RTPathFilename(strTargetFile.c_str()));
    2701                     filesList.push_back(pair<Utf8Str, ULONG>(strTmpDisk, (*itH)->ulSizeMB));
    2702                 }
    2703             }
    2704         }
    2705 
    2706         /* Next we have to download the disk images */
    2707         vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
    2708         if(RT_FAILURE(vrc))
    2709             throw setError(VBOX_E_IPRT_ERROR,
    2710                            tr("Cannot create S3 service handler"));
    2711         RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
    2712 
    2713         /* Download all files */
    2714         for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    2715         {
    2716             const pair<Utf8Str, ULONG> &s = (*it1);
    2717             const Utf8Str &strSrcFile = s.first;
    2718             /* Construct the source file name */
    2719             char *pszFilename = RTPathFilename(strSrcFile.c_str());
    2720             /* Advance to the next operation */
    2721             if (!pTask->progress.isNull())
    2722                 pTask->progress->SetNextOperation(BstrFmt(tr("Downloading file '%s'"), pszFilename), s.second);
    2723 
    2724             vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strSrcFile.c_str());
    2725             if (RT_FAILURE(vrc))
    2726             {
    2727                 if(vrc == VERR_S3_CANCELED)
    2728                     throw S_OK; /* todo: !!!!!!!!!!!!! */
    2729                 else if(vrc == VERR_S3_ACCESS_DENIED)
    2730                     throw setError(E_ACCESSDENIED,
    2731                                    tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that your credentials are right. Also check that your host clock is properly synced"), pszFilename);
    2732                 else if(vrc == VERR_S3_NOT_FOUND)
    2733                     throw setError(VBOX_E_FILE_ERROR,
    2734                                    tr("Cannot download file '%s' from S3 storage server (File not found)"), pszFilename);
    2735                 else
    2736                     throw setError(VBOX_E_IPRT_ERROR,
    2737                                    tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
    2738             }
    2739         }
    2740 
    2741         /* Provide a OVF file (haven't to exist) so the import routine can
    2742          * figure out where the disk images/manifest file are located. */
    2743         Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str()));
    2744         /* Now check if there is an manifest file. This is optional. */
    2745         Utf8Str strManifestFile = manifestFileName(strTmpOvf);
    2746         char *pszFilename = RTPathFilename(strManifestFile.c_str());
    2747         if (!pTask->progress.isNull())
    2748             pTask->progress->SetNextOperation(BstrFmt(tr("Downloading file '%s'"), pszFilename), 1);
    2749 
    2750         /* Try to download it. If the error is VERR_S3_NOT_FOUND, it isn't fatal. */
    2751         vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strManifestFile.c_str());
    2752         if (RT_SUCCESS(vrc))
    2753             filesList.push_back(pair<Utf8Str, ULONG>(strManifestFile, 0));
    2754         else if (RT_FAILURE(vrc))
    2755         {
    2756             if(vrc == VERR_S3_CANCELED)
    2757                 throw S_OK; /* todo: !!!!!!!!!!!!! */
    2758             else if(vrc == VERR_S3_NOT_FOUND)
    2759                 vrc = VINF_SUCCESS; /* Not found is ok */
    2760             else if(vrc == VERR_S3_ACCESS_DENIED)
    2761                 throw setError(E_ACCESSDENIED,
    2762                                tr("Cannot download file '%s' from S3 storage server (Access denied). Make sure that your credentials are right. Also check that your host clock is properly synced"), pszFilename);
    2763             else
    2764                 throw setError(VBOX_E_IPRT_ERROR,
    2765                                tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
    2766         }
    2767 
    2768         /* Close the connection early */
    2769         RTS3Destroy(hS3);
    2770         hS3 = NIL_RTS3;
    2771 
    2772         if (!pTask->progress.isNull())
    2773             pTask->progress->SetNextOperation(BstrFmt(tr("Importing appliance")), m->ulWeightPerOperation);
    2774 
    2775         ComObjPtr<Progress> progress;
    2776         /* Import the whole temporary OVF & the disk images */
    2777         LocationInfo li;
    2778         li.strPath = strTmpOvf;
    2779         rc = importImpl(li, progress);
    2780         if (FAILED(rc)) throw rc;
    2781 
    2782         /* Unlock the appliance for the fs import thread */
    2783         appLock.release();
    2784         /* Wait until the import is done, but report the progress back to the
    2785            caller */
    2786         ComPtr<IProgress> progressInt(progress);
    2787         waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
    2788 
    2789         /* Again lock the appliance for the next steps */
    2790         appLock.acquire();
    2791     }
    2792     catch(HRESULT aRC)
    2793     {
    2794         rc = aRC;
    2795     }
    2796     /* Cleanup */
    2797     RTS3Destroy(hS3);
    2798     /* Delete all files which where temporary created */
    2799     for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    2800     {
    2801         const char *pszFilePath = (*it1).first.c_str();
    2802         if (RTPathExists(pszFilePath))
    2803         {
    2804             vrc = RTFileDelete(pszFilePath);
    2805             if(RT_FAILURE(vrc))
    2806                 rc = setError(VBOX_E_FILE_ERROR,
    2807                               tr("Cannot delete file '%s' (%Rrc)"), pszFilePath, vrc);
    2808         }
    2809     }
    2810     /* Delete the temporary directory */
    2811     if (RTPathExists(pszTmpDir))
    2812     {
    2813         vrc = RTDirRemove(pszTmpDir);
    2814         if(RT_FAILURE(vrc))
    2815             rc = setError(VBOX_E_FILE_ERROR,
    2816                           tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
    2817     }
    2818     if (pszTmpDir)
    2819         RTStrFree(pszTmpDir);
    2820 
    2821     pTask->rc = rc;
    2822 
    2823     if (!pTask->progress.isNull())
    2824         pTask->progress->notifyComplete(rc);
    2825 
    2826     LogFlowFunc(("rc=%Rhrc\n", rc));
    2827     LogFlowFuncLeave();
    2828 
    2829     return VINF_SUCCESS;
    2830 }
    2831 
    2832933int Appliance::TaskExportOVF::startThread()
    2833934{
  • trunk/src/VBox/Main/ApplianceImplImport.cpp

    r27855 r27882  
    5151////////////////////////////////////////////////////////////////////////////////
    5252//
    53 // Internal helpers
    54 //
    55 ////////////////////////////////////////////////////////////////////////////////
    56 
    57 static const struct
    58 {
    59     CIMOSType_T     cim;
    60     const char      *pcszVbox;
    61 }
    62 g_osTypes[] =
    63 {
    64     { CIMOSType_CIMOS_Unknown,                              SchemaDefs_OSTypeId_Other },
    65     { CIMOSType_CIMOS_OS2,                                  SchemaDefs_OSTypeId_OS2 },
    66     { CIMOSType_CIMOS_MSDOS,                                SchemaDefs_OSTypeId_DOS },
    67     { CIMOSType_CIMOS_WIN3x,                                SchemaDefs_OSTypeId_Windows31 },
    68     { CIMOSType_CIMOS_WIN95,                                SchemaDefs_OSTypeId_Windows95 },
    69     { CIMOSType_CIMOS_WIN98,                                SchemaDefs_OSTypeId_Windows98 },
    70     { CIMOSType_CIMOS_WINNT,                                SchemaDefs_OSTypeId_WindowsNT4 },
    71     { CIMOSType_CIMOS_NetWare,                              SchemaDefs_OSTypeId_Netware },
    72     { CIMOSType_CIMOS_NovellOES,                            SchemaDefs_OSTypeId_Netware },
    73     { CIMOSType_CIMOS_Solaris,                              SchemaDefs_OSTypeId_OpenSolaris },
    74     { CIMOSType_CIMOS_SunOS,                                SchemaDefs_OSTypeId_OpenSolaris },
    75     { CIMOSType_CIMOS_FreeBSD,                              SchemaDefs_OSTypeId_FreeBSD },
    76     { CIMOSType_CIMOS_NetBSD,                               SchemaDefs_OSTypeId_NetBSD },
    77     { CIMOSType_CIMOS_QNX,                                  SchemaDefs_OSTypeId_QNX },
    78     { CIMOSType_CIMOS_Windows2000,                          SchemaDefs_OSTypeId_Windows2000 },
    79     { CIMOSType_CIMOS_WindowsMe,                            SchemaDefs_OSTypeId_WindowsMe },
    80     { CIMOSType_CIMOS_OpenBSD,                              SchemaDefs_OSTypeId_OpenBSD },
    81     { CIMOSType_CIMOS_WindowsXP,                            SchemaDefs_OSTypeId_WindowsXP },
    82     { CIMOSType_CIMOS_WindowsXPEmbedded,                    SchemaDefs_OSTypeId_WindowsXP },
    83     { CIMOSType_CIMOS_WindowsEmbeddedforPointofService,     SchemaDefs_OSTypeId_WindowsXP },
    84     { CIMOSType_CIMOS_MicrosoftWindowsServer2003,           SchemaDefs_OSTypeId_Windows2003 },
    85     { CIMOSType_CIMOS_MicrosoftWindowsServer2003_64,        SchemaDefs_OSTypeId_Windows2003_64 },
    86     { CIMOSType_CIMOS_WindowsXP_64,                         SchemaDefs_OSTypeId_WindowsXP_64 },
    87     { CIMOSType_CIMOS_WindowsVista,                         SchemaDefs_OSTypeId_WindowsVista },
    88     { CIMOSType_CIMOS_WindowsVista_64,                      SchemaDefs_OSTypeId_WindowsVista_64 },
    89     { CIMOSType_CIMOS_MicrosoftWindowsServer2008,           SchemaDefs_OSTypeId_Windows2008 },
    90     { CIMOSType_CIMOS_MicrosoftWindowsServer2008_64,        SchemaDefs_OSTypeId_Windows2008_64 },
    91     { CIMOSType_CIMOS_FreeBSD_64,                           SchemaDefs_OSTypeId_FreeBSD_64 },
    92     { CIMOSType_CIMOS_RedHatEnterpriseLinux,                SchemaDefs_OSTypeId_RedHat },
    93     { CIMOSType_CIMOS_RedHatEnterpriseLinux_64,             SchemaDefs_OSTypeId_RedHat_64 },
    94     { CIMOSType_CIMOS_Solaris_64,                           SchemaDefs_OSTypeId_OpenSolaris_64 },
    95     { CIMOSType_CIMOS_SUSE,                                 SchemaDefs_OSTypeId_OpenSUSE },
    96     { CIMOSType_CIMOS_SLES,                                 SchemaDefs_OSTypeId_OpenSUSE },
    97     { CIMOSType_CIMOS_NovellLinuxDesktop,                   SchemaDefs_OSTypeId_OpenSUSE },
    98     { CIMOSType_CIMOS_SUSE_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
    99     { CIMOSType_CIMOS_SLES_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
    100     { CIMOSType_CIMOS_LINUX,                                SchemaDefs_OSTypeId_Linux },
    101     { CIMOSType_CIMOS_SunJavaDesktopSystem,                 SchemaDefs_OSTypeId_Linux },
    102     { CIMOSType_CIMOS_TurboLinux,                           SchemaDefs_OSTypeId_Linux},
    103 
    104     //                { CIMOSType_CIMOS_TurboLinux_64, },
    105 
    106     { CIMOSType_CIMOS_Mandriva,                             SchemaDefs_OSTypeId_Mandriva },
    107     { CIMOSType_CIMOS_Mandriva_64,                          SchemaDefs_OSTypeId_Mandriva_64 },
    108     { CIMOSType_CIMOS_Ubuntu,                               SchemaDefs_OSTypeId_Ubuntu },
    109     { CIMOSType_CIMOS_Ubuntu_64,                            SchemaDefs_OSTypeId_Ubuntu_64 },
    110     { CIMOSType_CIMOS_Debian,                               SchemaDefs_OSTypeId_Debian },
    111     { CIMOSType_CIMOS_Debian_64,                            SchemaDefs_OSTypeId_Debian_64 },
    112     { CIMOSType_CIMOS_Linux_2_4_x,                          SchemaDefs_OSTypeId_Linux24 },
    113     { CIMOSType_CIMOS_Linux_2_4_x_64,                       SchemaDefs_OSTypeId_Linux24_64 },
    114     { CIMOSType_CIMOS_Linux_2_6_x,                          SchemaDefs_OSTypeId_Linux26 },
    115     { CIMOSType_CIMOS_Linux_2_6_x_64,                       SchemaDefs_OSTypeId_Linux26_64 },
    116     { CIMOSType_CIMOS_Linux_64,                             SchemaDefs_OSTypeId_Linux26_64 }
    117 };
    118 
    119 /* Pattern structure for matching the OS type description field */
    120 struct osTypePattern
    121 {
    122     const char *pcszPattern;
    123     const char *pcszVbox;
    124 };
    125 
    126 /* These are the 32-Bit ones. They are sorted by priority. */
    127 static const osTypePattern g_osTypesPattern[] =
    128 {
    129     {"Windows NT",    SchemaDefs_OSTypeId_WindowsNT4},
    130     {"Windows XP",    SchemaDefs_OSTypeId_WindowsXP},
    131     {"Windows 2000",  SchemaDefs_OSTypeId_Windows2000},
    132     {"Windows 2003",  SchemaDefs_OSTypeId_Windows2003},
    133     {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista},
    134     {"Windows 2008",  SchemaDefs_OSTypeId_Windows2008},
    135     {"SUSE",          SchemaDefs_OSTypeId_OpenSUSE},
    136     {"Novell",        SchemaDefs_OSTypeId_OpenSUSE},
    137     {"Red Hat",       SchemaDefs_OSTypeId_RedHat},
    138     {"Mandriva",      SchemaDefs_OSTypeId_Mandriva},
    139     {"Ubuntu",        SchemaDefs_OSTypeId_Ubuntu},
    140     {"Debian",        SchemaDefs_OSTypeId_Debian},
    141     {"QNX",           SchemaDefs_OSTypeId_QNX},
    142     {"Linux 2.4",     SchemaDefs_OSTypeId_Linux24},
    143     {"Linux 2.6",     SchemaDefs_OSTypeId_Linux26},
    144     {"Linux",         SchemaDefs_OSTypeId_Linux},
    145     {"OpenSolaris",   SchemaDefs_OSTypeId_OpenSolaris},
    146     {"Solaris",       SchemaDefs_OSTypeId_OpenSolaris},
    147     {"FreeBSD",       SchemaDefs_OSTypeId_FreeBSD},
    148     {"NetBSD",        SchemaDefs_OSTypeId_NetBSD},
    149     {"Windows 95",    SchemaDefs_OSTypeId_Windows95},
    150     {"Windows 98",    SchemaDefs_OSTypeId_Windows98},
    151     {"Windows Me",    SchemaDefs_OSTypeId_WindowsMe},
    152     {"Windows 3.",    SchemaDefs_OSTypeId_Windows31},
    153     {"DOS",           SchemaDefs_OSTypeId_DOS},
    154     {"OS2",           SchemaDefs_OSTypeId_OS2}
    155 };
    156 
    157 /* These are the 64-Bit ones. They are sorted by priority. */
    158 static const osTypePattern g_osTypesPattern64[] =
    159 {
    160     {"Windows XP",    SchemaDefs_OSTypeId_WindowsXP_64},
    161     {"Windows 2003",  SchemaDefs_OSTypeId_Windows2003_64},
    162     {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista_64},
    163     {"Windows 2008",  SchemaDefs_OSTypeId_Windows2008_64},
    164     {"SUSE",          SchemaDefs_OSTypeId_OpenSUSE_64},
    165     {"Novell",        SchemaDefs_OSTypeId_OpenSUSE_64},
    166     {"Red Hat",       SchemaDefs_OSTypeId_RedHat_64},
    167     {"Mandriva",      SchemaDefs_OSTypeId_Mandriva_64},
    168     {"Ubuntu",        SchemaDefs_OSTypeId_Ubuntu_64},
    169     {"Debian",        SchemaDefs_OSTypeId_Debian_64},
    170     {"Linux 2.4",     SchemaDefs_OSTypeId_Linux24_64},
    171     {"Linux 2.6",     SchemaDefs_OSTypeId_Linux26_64},
    172     {"Linux",         SchemaDefs_OSTypeId_Linux26_64},
    173     {"OpenSolaris",   SchemaDefs_OSTypeId_OpenSolaris_64},
    174     {"Solaris",       SchemaDefs_OSTypeId_OpenSolaris_64},
    175     {"FreeBSD",       SchemaDefs_OSTypeId_FreeBSD_64},
    176 };
    177 
    178 /**
    179  * Private helper func that suggests a VirtualBox guest OS type
    180  * for the given OVF operating system type.
    181  * @param osTypeVBox
    182  * @param c
    183  * @param cStr
    184  */
    185 void convertCIMOSType2VBoxOSType(Utf8Str &strType, CIMOSType_T c, const Utf8Str &cStr)
    186 {
    187     /* First check if the type is other/other_64 */
    188     if (c == CIMOSType_CIMOS_Other)
    189     {
    190         for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern); ++i)
    191             if (cStr.contains (g_osTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive))
    192             {
    193                 strType = g_osTypesPattern[i].pcszVbox;
    194                 return;
    195             }
    196     }
    197     else if (c == CIMOSType_CIMOS_Other_64)
    198     {
    199         for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern64); ++i)
    200             if (cStr.contains (g_osTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive))
    201             {
    202                 strType = g_osTypesPattern64[i].pcszVbox;
    203                 return;
    204             }
    205     }
    206 
    207     for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
    208     {
    209         if (c == g_osTypes[i].cim)
    210         {
    211             strType = g_osTypes[i].pcszVbox;
    212             return;
    213         }
    214     }
    215 
    216     strType = SchemaDefs_OSTypeId_Other;
    217 }
    218 
    219 /**
    220  * Private helper func that suggests a VirtualBox guest OS type
    221  * for the given OVF operating system type.
    222  * @param osTypeVBox
    223  * @param c
    224  */
    225 CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
    226 {
    227     for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
    228     {
    229         if (!RTStrICmp(pcszVbox, g_osTypes[i].pcszVbox))
    230             return g_osTypes[i].cim;
    231     }
    232 
    233     return CIMOSType_CIMOS_Other;
    234 }
    235 
    236 ////////////////////////////////////////////////////////////////////////////////
    237 //
    238 // IVirtualBox public methods
    239 //
    240 ////////////////////////////////////////////////////////////////////////////////
    241 
    242 // This code is here so we won't have to include the appliance headers in the
    243 // IVirtualBox implementation.
    244 
    245 /**
    246  * Implementation for IVirtualBox::createAppliance.
    247  *
    248  * @param anAppliance IAppliance object created if S_OK is returned.
    249  * @return S_OK or error.
    250  */
    251 STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
    252 {
    253     HRESULT rc;
    254 
    255     ComObjPtr<Appliance> appliance;
    256     appliance.createObject();
    257     rc = appliance->init(this);
    258 
    259     if (SUCCEEDED(rc))
    260         appliance.queryInterfaceTo(anAppliance);
    261 
    262     return rc;
    263 }
    264 
    265 ////////////////////////////////////////////////////////////////////////////////
    266 //
    267 // Appliance constructor / destructor
    268 //
    269 ////////////////////////////////////////////////////////////////////////////////
    270 
    271 Appliance::Appliance()
    272     : mVirtualBox(NULL)
    273 {
    274 }
    275 
    276 Appliance::~Appliance()
    277 {
    278 }
    279 
    280 /**
    281  * Appliance COM initializer.
    282  * @param
    283  * @return
    284  */
    285 HRESULT Appliance::init(VirtualBox *aVirtualBox)
    286 {
    287     /* Enclose the state transition NotReady->InInit->Ready */
    288     AutoInitSpan autoInitSpan(this);
    289     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    290 
    291     /* Weak reference to a VirtualBox object */
    292     unconst(mVirtualBox) = aVirtualBox;
    293 
    294     // initialize data
    295     m = new Data;
    296 
    297     /* Confirm a successful initialization */
    298     autoInitSpan.setSucceeded();
    299 
    300     return S_OK;
    301 }
    302 
    303 /**
    304  * Appliance COM uninitializer.
    305  * @return
    306  */
    307 void Appliance::uninit()
    308 {
    309     /* Enclose the state transition Ready->InUninit->NotReady */
    310     AutoUninitSpan autoUninitSpan(this);
    311     if (autoUninitSpan.uninitDone())
    312         return;
    313 
    314     delete m;
    315     m = NULL;
    316 }
    317 
    318 ////////////////////////////////////////////////////////////////////////////////
    319 //
    32053// IAppliance public methods
    32154//
    32255////////////////////////////////////////////////////////////////////////////////
    323 
    324 /**
    325  * Public method implementation.
    326  * @param
    327  * @return
    328  */
    329 STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
    330 {
    331     if (!aPath)
    332         return E_POINTER;
    333 
    334     AutoCaller autoCaller(this);
    335     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    336 
    337     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    338 
    339     if (!isApplianceIdle())
    340         return E_ACCESSDENIED;
    341 
    342     Bstr bstrPath(m->locInfo.strPath);
    343     bstrPath.cloneTo(aPath);
    344 
    345     return S_OK;
    346 }
    347 
    348 /**
    349  * Public method implementation.
    350  * @param
    351  * @return
    352  */
    353 STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
    354 {
    355     CheckComArgOutSafeArrayPointerValid(aDisks);
    356 
    357     AutoCaller autoCaller(this);
    358     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    359 
    360     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    361 
    362     if (!isApplianceIdle())
    363         return E_ACCESSDENIED;
    364 
    365     if (m->pReader) // OVFReader instantiated?
    366     {
    367         size_t c = m->pReader->m_mapDisks.size();
    368         com::SafeArray<BSTR> sfaDisks(c);
    369 
    370         DiskImagesMap::const_iterator it;
    371         size_t i = 0;
    372         for (it = m->pReader->m_mapDisks.begin();
    373              it != m->pReader->m_mapDisks.end();
    374              ++it, ++i)
    375         {
    376             // create a string representing this disk
    377             const DiskImage &d = it->second;
    378             char *psz = NULL;
    379             RTStrAPrintf(&psz,
    380                          "%s\t"
    381                          "%RI64\t"
    382                          "%RI64\t"
    383                          "%s\t"
    384                          "%s\t"
    385                          "%RI64\t"
    386                          "%RI64\t"
    387                          "%s",
    388                          d.strDiskId.c_str(),
    389                          d.iCapacity,
    390                          d.iPopulatedSize,
    391                          d.strFormat.c_str(),
    392                          d.strHref.c_str(),
    393                          d.iSize,
    394                          d.iChunkSize,
    395                          d.strCompression.c_str());
    396             Utf8Str utf(psz);
    397             Bstr bstr(utf);
    398             // push to safearray
    399             bstr.cloneTo(&sfaDisks[i]);
    400             RTStrFree(psz);
    401         }
    402 
    403         sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
    404     }
    405 
    406     return S_OK;
    407 }
    408 
    409 /**
    410  * Public method implementation.
    411  * @param
    412  * @return
    413  */
    414 STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
    415 {
    416     CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
    417 
    418     AutoCaller autoCaller(this);
    419     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    420 
    421     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    422 
    423     if (!isApplianceIdle())
    424         return E_ACCESSDENIED;
    425 
    426     SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
    427     sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
    428 
    429     return S_OK;
    430 }
    431 
    432 /**
    433  * Public method implementation.
    434  * @param path
    435  * @return
    436  */
    437 STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress)
    438 {
    439     if (!path) return E_POINTER;
    440     CheckComArgOutPointerValid(aProgress);
    441 
    442     AutoCaller autoCaller(this);
    443     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    444 
    445     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    446 
    447     if (!isApplianceIdle())
    448         return E_ACCESSDENIED;
    449 
    450     if (m->pReader)
    451     {
    452         delete m->pReader;
    453         m->pReader = NULL;
    454     }
    455 
    456     // see if we can handle this file; for now we insist it has an ".ovf" extension
    457     Utf8Str strPath (path);
    458     if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    459         return setError(VBOX_E_FILE_ERROR,
    460                         tr("Appliance file must have .ovf extension"));
    461 
    462     ComObjPtr<Progress> progress;
    463     HRESULT rc = S_OK;
    464     try
    465     {
    466         /* Parse all necessary info out of the URI */
    467         parseURI(strPath, m->locInfo);
    468         rc = readImpl(m->locInfo, progress);
    469     }
    470     catch (HRESULT aRC)
    471     {
    472         rc = aRC;
    473     }
    474 
    475     if (SUCCEEDED(rc))
    476         /* Return progress to the caller */
    477         progress.queryInterfaceTo(aProgress);
    478 
    479     return S_OK;
    480 }
    48156
    48257/**
     
    980555}
    981556
    982 STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
    983 {
    984     CheckComArgOutPointerValid(aExplorer);
    985 
    986     AutoCaller autoCaller(this);
    987     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    988 
    989     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    990 
    991     ComObjPtr<VFSExplorer> explorer;
    992     HRESULT rc = S_OK;
    993     try
    994     {
    995         Utf8Str uri(aURI);
    996         /* Check which kind of export the user has requested */
    997         LocationInfo li;
    998         parseURI(uri, li);
    999         /* Create the explorer object */
    1000         explorer.createObject();
    1001         rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
    1002     }
    1003     catch (HRESULT aRC)
    1004     {
    1005         rc = aRC;
    1006     }
    1007 
    1008     if (SUCCEEDED(rc))
    1009         /* Return explorer to the caller */
    1010         explorer.queryInterfaceTo(aExplorer);
    1011 
    1012     return rc;
    1013 }
    1014 
    1015 /**
    1016 * Public method implementation.
    1017  * @return
    1018  */
    1019 STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
    1020 {
    1021     if (ComSafeArrayOutIsNull(aWarnings))
    1022         return E_POINTER;
    1023 
    1024     AutoCaller autoCaller(this);
    1025     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1026 
    1027     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1028 
    1029     com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
    1030 
    1031     list<Utf8Str>::const_iterator it;
    1032     size_t i = 0;
    1033     for (it = m->llWarnings.begin();
    1034          it != m->llWarnings.end();
    1035          ++it, ++i)
    1036     {
    1037         Bstr bstr = *it;
    1038         bstr.cloneTo(&sfaWarnings[i]);
    1039     }
    1040 
    1041     sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
    1042 
    1043     return S_OK;
    1044 }
    1045 
    1046557////////////////////////////////////////////////////////////////////////////////
    1047558//
     
    1051562
    1052563/**
    1053  * Returns true if the appliance is in "idle" state. This should always be the
    1054  * case unless an import or export is currently in progress. Similar to machine
    1055  * states, this permits the Appliance implementation code to let go of the
    1056  * Appliance object lock while a time-consuming disk conversion is in progress
    1057  * without exposing the appliance to conflicting calls.
    1058564 *
    1059  * This sets an error on "this" (the appliance) and returns false if the appliance
    1060  * is busy. The caller should then return E_ACCESSDENIED.
    1061  *
    1062  * Must be called from under the object lock!
    1063  *
     565 * @param aLocInfo
     566 * @param aProgress
    1064567 * @return
    1065568 */
    1066 bool Appliance::isApplianceIdle() const
    1067 {
    1068     if (m->state == Data::ApplianceImporting)
    1069         setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy importing files");
    1070     else if (m->state == Data::ApplianceExporting)
    1071         setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy exporting files");
    1072     else
    1073         return true;
    1074 
    1075     return false;
    1076 }
    1077 
    1078 HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
    1079 {
    1080     IMachine *machine = NULL;
    1081     char *tmpName = RTStrDup(aName.c_str());
    1082     int i = 1;
    1083     /* @todo: Maybe too cost-intensive; try to find a lighter way */
    1084     while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
    1085     {
    1086         RTStrFree(tmpName);
    1087         RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
    1088         ++i;
    1089     }
    1090     aName = tmpName;
    1091     RTStrFree(tmpName);
    1092 
    1093     return S_OK;
    1094 }
    1095 
    1096 HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
    1097 {
    1098     IMedium *harddisk = NULL;
    1099     char *tmpName = RTStrDup(aName.c_str());
    1100     int i = 1;
    1101     /* Check if the file exists or if a file with this path is registered
    1102      * already */
    1103     /* @todo: Maybe too cost-intensive; try to find a lighter way */
    1104     while (RTPathExists(tmpName) ||
    1105            mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
    1106     {
    1107         RTStrFree(tmpName);
    1108         char *tmpDir = RTStrDup(aName.c_str());
    1109         RTPathStripFilename(tmpDir);;
    1110         char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
    1111         RTPathStripExt(tmpFile);
    1112         const char *tmpExt = RTPathExt(aName.c_str());
    1113         RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
    1114         RTStrFree(tmpFile);
    1115         RTStrFree(tmpDir);
    1116         ++i;
    1117     }
    1118     aName = tmpName;
    1119     RTStrFree(tmpName);
    1120 
    1121     return S_OK;
    1122 }
    1123 
    1124 /**
    1125  * Called from the import and export background threads to synchronize the second
    1126  * background disk thread's progress object with the current progress object so
    1127  * that the user interface sees progress correctly and that cancel signals are
    1128  * passed on to the second thread.
    1129  * @param pProgressThis Progress object of the current thread.
    1130  * @param pProgressAsync Progress object of asynchronous task running in background.
    1131  */
    1132 void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
    1133                                      ComPtr<IProgress> &pProgressAsync)
    1134 {
    1135     HRESULT rc;
    1136 
    1137     // now loop until the asynchronous operation completes and then report its result
    1138     BOOL fCompleted;
    1139     BOOL fCanceled;
    1140     ULONG currentPercent;
    1141     while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
    1142     {
    1143         rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
    1144         if (FAILED(rc)) throw rc;
    1145         if (fCanceled)
    1146         {
    1147             pProgressAsync->Cancel();
    1148             break;
    1149         }
    1150 
    1151         rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
    1152         if (FAILED(rc)) throw rc;
    1153         if (!pProgressThis.isNull())
    1154             pProgressThis->SetCurrentOperationProgress(currentPercent);
    1155         if (fCompleted)
    1156             break;
    1157 
    1158         /* Make sure the loop is not too tight */
    1159         rc = pProgressAsync->WaitForCompletion(100);
    1160         if (FAILED(rc)) throw rc;
    1161     }
    1162     // report result of asynchronous operation
    1163     LONG iRc;
    1164     rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
    1165     if (FAILED(rc)) throw rc;
    1166 
    1167 
    1168     // if the thread of the progress object has an error, then
    1169     // retrieve the error info from there, or it'll be lost
    1170     if (FAILED(iRc))
    1171     {
    1172         ProgressErrorInfo info(pProgressAsync);
    1173         Utf8Str str(info.getText());
    1174         const char *pcsz = str.c_str();
    1175         HRESULT rc2 = setError(iRc, pcsz);
    1176         throw rc2;
    1177     }
    1178 }
    1179 
    1180 void Appliance::addWarning(const char* aWarning, ...)
    1181 {
    1182     va_list args;
    1183     va_start(args, aWarning);
    1184     Utf8StrFmtVA str(aWarning, args);
    1185     va_end(args);
    1186     m->llWarnings.push_back(str);
    1187 }
    1188 
    1189 void Appliance::disksWeight(uint32_t &ulTotalMB, uint32_t &cDisks) const
    1190 {
    1191     ulTotalMB = 0;
    1192     cDisks = 0;
    1193     /* Weigh the disk images according to their sizes */
    1194     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    1195     for (it = m->virtualSystemDescriptions.begin();
    1196          it != m->virtualSystemDescriptions.end();
    1197          ++it)
    1198     {
    1199         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    1200         /* One for every hard disk of the Virtual System */
    1201         std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    1202         std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    1203         for (itH = avsdeHDs.begin();
    1204              itH != avsdeHDs.end();
    1205              ++itH)
    1206         {
    1207             const VirtualSystemDescriptionEntry *pHD = *itH;
    1208             ulTotalMB += pHD->ulSizeMB;
    1209             ++cDisks;
    1210         }
    1211     }
    1212 
    1213 }
    1214 
    1215 HRESULT Appliance::setUpProgressFS(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    1216 {
    1217     HRESULT rc;
    1218 
    1219     /* Create the progress object */
    1220     pProgress.createObject();
    1221 
    1222     /* Weigh the disk images according to their sizes */
    1223     uint32_t ulTotalMB;
    1224     uint32_t cDisks;
    1225     disksWeight(ulTotalMB, cDisks);
    1226 
    1227     ULONG cOperations = 1 + cDisks;     // one op per disk plus 1 for the XML
    1228 
    1229     ULONG ulTotalOperationsWeight;
    1230     if (ulTotalMB)
    1231     {
    1232         m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1  / 100);    // use 1% of the progress for the XML
    1233         ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
    1234     }
    1235     else
    1236     {
    1237         // no disks to export:
    1238         ulTotalOperationsWeight = 1;
    1239         m->ulWeightPerOperation = 1;
    1240     }
    1241 
    1242     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    1243          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    1244 
    1245     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    1246                          bstrDescription,
    1247                          TRUE /* aCancelable */,
    1248                          cOperations, // ULONG cOperations,
    1249                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    1250                          bstrDescription, // CBSTR bstrFirstOperationDescription,
    1251                          m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
    1252     return rc;
    1253 }
    1254 
    1255 HRESULT Appliance::setUpProgressImportS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    1256 {
    1257     HRESULT rc;
    1258 
    1259     /* Create the progress object */
    1260     pProgress.createObject();
    1261 
    1262     /* Weigh the disk images according to their sizes */
    1263     uint32_t ulTotalMB;
    1264     uint32_t cDisks;
    1265     disksWeight(ulTotalMB, cDisks);
    1266 
    1267     ULONG cOperations = 1 + 1 + 1 + cDisks;     // one op per disk plus 1 for init, plus 1 for the manifest file & 1 plus for the import */
    1268 
    1269     ULONG ulTotalOperationsWeight = ulTotalMB;
    1270     if (!ulTotalOperationsWeight)
    1271         // no disks to export:
    1272         ulTotalOperationsWeight = 1;
    1273 
    1274     ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50  / 100);  // use 50% for import
    1275     ulTotalOperationsWeight += ulImportWeight;
    1276 
    1277     m->ulWeightPerOperation = ulImportWeight; /* save for using later */
    1278 
    1279     ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1  / 100);  // use 0.1% for init
    1280     ulTotalOperationsWeight += ulInitWeight;
    1281 
    1282     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    1283          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    1284 
    1285     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    1286                          bstrDescription,
    1287                          TRUE /* aCancelable */,
    1288                          cOperations, // ULONG cOperations,
    1289                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    1290                          Bstr(tr("Init")), // CBSTR bstrFirstOperationDescription,
    1291                          ulInitWeight); // ULONG ulFirstOperationWeight,
    1292     return rc;
    1293 }
    1294 
    1295 HRESULT Appliance::setUpProgressWriteS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    1296 {
    1297     HRESULT rc;
    1298 
    1299     /* Create the progress object */
    1300     pProgress.createObject();
    1301 
    1302     /* Weigh the disk images according to their sizes */
    1303     uint32_t ulTotalMB;
    1304     uint32_t cDisks;
    1305     disksWeight(ulTotalMB, cDisks);
    1306 
    1307     ULONG cOperations = 1 + 1 + 1 + cDisks;     // one op per disk plus 1 for the OVF, plus 1 for the mf & 1 plus to the temporary creation */
    1308 
    1309     ULONG ulTotalOperationsWeight;
    1310     if (ulTotalMB)
    1311     {
    1312         m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1  / 100);    // use 1% of the progress for OVF file upload (we didn't know the size at this point)
    1313         ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
    1314     }
    1315     else
    1316     {
    1317         // no disks to export:
    1318         ulTotalOperationsWeight = 1;
    1319         m->ulWeightPerOperation = 1;
    1320     }
    1321     ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
    1322     ulTotalOperationsWeight += ulOVFCreationWeight;
    1323 
    1324     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    1325          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    1326 
    1327     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    1328                          bstrDescription,
    1329                          TRUE /* aCancelable */,
    1330                          cOperations, // ULONG cOperations,
    1331                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    1332                          bstrDescription, // CBSTR bstrFirstOperationDescription,
    1333                          ulOVFCreationWeight); // ULONG ulFirstOperationWeight,
    1334     return rc;
    1335 }
    1336 
    1337 void Appliance::parseURI(Utf8Str strUri, LocationInfo &locInfo) const
    1338 {
    1339     /* Check the URI for the protocol */
    1340     if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
    1341     {
    1342         locInfo.storageType = VFSType_File;
    1343         strUri = strUri.substr(sizeof("file://") - 1);
    1344     }
    1345     else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
    1346     {
    1347         locInfo.storageType = VFSType_S3;
    1348         strUri = strUri.substr(sizeof("SunCloud://") - 1);
    1349     }
    1350     else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
    1351     {
    1352         locInfo.storageType = VFSType_S3;
    1353         strUri = strUri.substr(sizeof("S3://") - 1);
    1354     }
    1355     else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
    1356         throw E_NOTIMPL;
    1357 
    1358     /* Not necessary on a file based URI */
    1359     if (locInfo.storageType != VFSType_File)
    1360     {
    1361         size_t uppos = strUri.find("@"); /* username:password combo */
    1362         if (uppos != Utf8Str::npos)
    1363         {
    1364             locInfo.strUsername = strUri.substr(0, uppos);
    1365             strUri = strUri.substr(uppos + 1);
    1366             size_t upos = locInfo.strUsername.find(":");
    1367             if (upos != Utf8Str::npos)
    1368             {
    1369                 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
    1370                 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
    1371             }
    1372         }
    1373         size_t hpos = strUri.find("/"); /* hostname part */
    1374         if (hpos != Utf8Str::npos)
    1375         {
    1376             locInfo.strHostname = strUri.substr(0, hpos);
    1377             strUri = strUri.substr(hpos);
    1378         }
    1379     }
    1380 
    1381     locInfo.strPath = strUri;
    1382 }
    1383 
    1384 void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket) const
    1385 {
    1386     /* Buckets are S3 specific. So parse the bucket out of the file path */
    1387     if (!aPath.startsWith("/"))
    1388         throw setError(E_INVALIDARG,
    1389                        tr("The path '%s' must start with /"), aPath.c_str());
    1390     size_t bpos = aPath.find("/", 1);
    1391     if (bpos != Utf8Str::npos)
    1392     {
    1393         aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
    1394         aPath = aPath.substr(bpos); /* The rest of the file path */
    1395     }
    1396     /* If there is no bucket name provided reject it */
    1397     if (aBucket.isEmpty())
    1398         throw setError(E_INVALIDARG,
    1399                        tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
    1400 }
    1401 
    1402 Utf8Str Appliance::manifestFileName(Utf8Str aPath) const
    1403 {
    1404     /* Get the name part */
    1405     char *pszMfName = RTStrDup(RTPathFilename(aPath.c_str()));
    1406     /* Strip any extensions */
    1407     RTPathStripExt(pszMfName);
    1408     /* Path without the filename */
    1409     aPath.stripFilename();
    1410     /* Format the manifest path */
    1411     Utf8StrFmt strMfFile("%s/%s.mf", aPath.c_str(), pszMfName);
    1412     RTStrFree(pszMfName);
    1413     return strMfFile;
    1414 }
    1415 
    1416 /* static */
    1417 int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
    1418 {
    1419     Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
    1420 
    1421     if (    pTask
    1422          && !pTask->progress.isNull())
    1423     {
    1424         BOOL fCanceled;
    1425         pTask->progress->COMGETTER(Canceled)(&fCanceled);
    1426         if (fCanceled)
    1427             return -1;
    1428         pTask->progress->SetCurrentOperationProgress(uPercent);
    1429     }
    1430     return VINF_SUCCESS;
    1431 }
    1432 
    1433569HRESULT Appliance::readImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    1434570{
     
    1478614
    1479615/**
    1480  * Implementation of the import code. This gets called from the public Appliance::ImportMachines()
    1481  * method as well as Appliance::importS3().
    1482  * @param aLocInfo
    1483  * @param aProgress
     616 *
     617 * @param pTask
    1484618 * @return
    1485619 */
    1486 HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    1487 {
    1488     /* Initialize our worker task */
    1489     std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
    1490     /* What should the task do */
    1491     task->taskType = TaskImportOVF::Import;
    1492     /* Copy the current location info to the task */
    1493     task->locInfo = aLocInfo;
    1494 
    1495     Bstr progressDesc = BstrFmt(tr("Import appliance '%s'"),
    1496                                 aLocInfo.strPath.c_str());
    1497 
    1498     HRESULT rc = S_OK;
    1499 
    1500     /* todo: This progress init stuff should be done a little bit more generic */
    1501     if (task->locInfo.storageType == VFSType_File)
    1502         rc = setUpProgressFS(aProgress, progressDesc);
    1503     else
    1504         rc = setUpProgressImportS3(aProgress, progressDesc);
    1505     if (FAILED(rc)) throw rc;
    1506 
    1507     task->progress = aProgress;
    1508 
    1509     rc = task->startThread();
    1510     if (FAILED(rc)) throw rc;
    1511 
    1512     /* Don't destruct on success */
    1513     task.release();
    1514 
    1515     return rc;
    1516 }
    1517 
    1518 /**
    1519  * Worker thread implementation for Read() (ovf reader).
    1520  * @param aThread
    1521  * @param pvUser
    1522  */
    1523 /* static */
    1524 DECLCALLBACK(int) Appliance::taskThreadImportOVF(RTTHREAD /* aThread */, void *pvUser)
    1525 {
    1526     std::auto_ptr<TaskImportOVF> task(static_cast<TaskImportOVF*>(pvUser));
    1527     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    1528 
    1529     Appliance *pAppliance = task->pAppliance;
    1530 
    1531     LogFlowFuncEnter();
    1532     LogFlowFunc(("Appliance %p\n", pAppliance));
    1533 
    1534     HRESULT rc = S_OK;
    1535 
    1536     switch (task->taskType)
    1537     {
    1538         case TaskImportOVF::Read:
    1539         {
    1540             if (task->locInfo.storageType == VFSType_File)
    1541                 rc = pAppliance->readFS(task.get());
    1542             else if (task->locInfo.storageType == VFSType_S3)
    1543                 rc = pAppliance->readS3(task.get());
    1544             break;
    1545         }
    1546         case TaskImportOVF::Import:
    1547         {
    1548             if (task->locInfo.storageType == VFSType_File)
    1549                 rc = pAppliance->importFS(task.get());
    1550             else if (task->locInfo.storageType == VFSType_S3)
    1551                 rc = pAppliance->importS3(task.get());
    1552             break;
    1553         }
    1554     }
    1555 
    1556     LogFlowFunc(("rc=%Rhrc\n", rc));
    1557     LogFlowFuncLeave();
    1558 
    1559     return VINF_SUCCESS;
    1560 }
    1561 
    1562 int Appliance::TaskImportOVF::startThread()
    1563 {
    1564     int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOVF, this,
    1565                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    1566                              "Appliance::Task");
    1567 
    1568     ComAssertMsgRCRet(vrc,
    1569                       ("Could not create taskThreadImportOVF (%Rrc)\n", vrc), E_FAIL);
    1570 
    1571     return S_OK;
    1572 }
    1573 
    1574620int Appliance::readFS(TaskImportOVF *pTask)
    1575621{
     
    1619665}
    1620666
     667/**
     668 *
     669 * @param pTask
     670 * @return
     671 */
    1621672int Appliance::readS3(TaskImportOVF *pTask)
    1622673{
     
    1743794}
    1744795
     796/**
     797 * Helper that converts VirtualSystem attachment values into VirtualBox attachment values.
     798 * Throws HRESULT values on errors!
     799 *
     800 * @param hdc
     801 * @param vd
     802 * @param mhda
     803 */
     804void Appliance::convertDiskAttachmentValues(const HardDiskController &hdc,
     805                                            uint32_t ulAddressOnParent,
     806                                            Bstr &controllerType,
     807                                            int32_t &lChannel,
     808                                            int32_t &lDevice)
     809{
     810    switch (hdc.system)
     811    {
     812        case HardDiskController::IDE:
     813            // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
     814            // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
     815            // the device number can be either 0 or 1, to specify the master or the slave device,
     816            // respectively. For the secondary IDE controller, the device number is always 1 because
     817            // the master device is reserved for the CD-ROM drive.
     818            controllerType = Bstr("IDE Controller");
     819            switch (ulAddressOnParent)
     820            {
     821                case 0:     // interpret this as primary master
     822                    lChannel = (long)0;
     823                    lDevice = (long)0;
     824                break;
     825
     826                case 1:     // interpret this as primary slave
     827                    lChannel = (long)0;
     828                    lDevice = (long)1;
     829                break;
     830
     831                case 2:     // interpret this as secondary master
     832                    lChannel = (long)1;
     833                    lDevice = (long)0;
     834                break;
     835
     836                case 3:     // interpret this as secondary slave
     837                    lChannel = (long)1;
     838                    lDevice = (long)1;
     839                break;
     840
     841                default:
     842                    throw setError(VBOX_E_NOT_SUPPORTED,
     843                                    tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), ulAddressOnParent);
     844                break;
     845            }
     846        break;
     847
     848        case HardDiskController::SATA:
     849            controllerType = Bstr("SATA Controller");
     850            lChannel = (long)ulAddressOnParent;
     851            lDevice = (long)0;
     852        break;
     853
     854        case HardDiskController::SCSI:
     855            controllerType = Bstr("SCSI Controller");
     856            lChannel = (long)ulAddressOnParent;
     857            lDevice = (long)0;
     858        break;
     859
     860        default: break;
     861    }
     862}
     863
     864/**
     865 * Implementation of the import code. This gets called from the public Appliance::ImportMachines()
     866 * method as well as Appliance::importS3().
     867 * @param aLocInfo
     868 * @param aProgress
     869 * @return
     870 */
     871HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
     872{
     873    /* Initialize our worker task */
     874    std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
     875    /* What should the task do */
     876    task->taskType = TaskImportOVF::Import;
     877    /* Copy the current location info to the task */
     878    task->locInfo = aLocInfo;
     879
     880    Bstr progressDesc = BstrFmt(tr("Import appliance '%s'"),
     881                                aLocInfo.strPath.c_str());
     882
     883    HRESULT rc = S_OK;
     884
     885    /* todo: This progress init stuff should be done a little bit more generic */
     886    if (task->locInfo.storageType == VFSType_File)
     887        rc = setUpProgressFS(aProgress, progressDesc);
     888    else
     889        rc = setUpProgressImportS3(aProgress, progressDesc);
     890    if (FAILED(rc)) throw rc;
     891
     892    task->progress = aProgress;
     893
     894    rc = task->startThread();
     895    if (FAILED(rc)) throw rc;
     896
     897    /* Don't destruct on success */
     898    task.release();
     899
     900    return rc;
     901}
     902
     903/**
     904 * Worker thread implementation for Read() (ovf reader).
     905 * @param aThread
     906 * @param pvUser
     907 */
     908/* static */
     909DECLCALLBACK(int) Appliance::taskThreadImportOVF(RTTHREAD /* aThread */, void *pvUser)
     910{
     911    std::auto_ptr<TaskImportOVF> task(static_cast<TaskImportOVF*>(pvUser));
     912    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
     913
     914    Appliance *pAppliance = task->pAppliance;
     915
     916    LogFlowFuncEnter();
     917    LogFlowFunc(("Appliance %p\n", pAppliance));
     918
     919    switch (task->taskType)
     920    {
     921        case TaskImportOVF::Read:
     922        {
     923            if (task->locInfo.storageType == VFSType_File)
     924                pAppliance->readFS(task.get());
     925            else if (task->locInfo.storageType == VFSType_S3)
     926                pAppliance->readS3(task.get());
     927            break;
     928        }
     929        case TaskImportOVF::Import:
     930        {
     931            if (task->locInfo.storageType == VFSType_File)
     932                pAppliance->importFS(task.get());
     933            else if (task->locInfo.storageType == VFSType_S3)
     934                pAppliance->importS3(task.get());
     935            break;
     936        }
     937    }
     938
     939    LogFlowFuncLeave();
     940
     941    return VINF_SUCCESS;
     942}
     943
     944/**
     945 *
     946 * @return
     947 */
     948int Appliance::TaskImportOVF::startThread()
     949{
     950    int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOVF, this,
     951                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
     952                             "Appliance::Task");
     953
     954    ComAssertMsgRCRet(vrc,
     955                      ("Could not create taskThreadImportOVF (%Rrc)\n", vrc), E_FAIL);
     956
     957    return S_OK;
     958}
     959
     960/**
     961 *
     962 * @param pTask
     963 * @return
     964 */
    1745965int Appliance::importFS(TaskImportOVF *pTask)
    1746966{
     
    22711491                        mhda.pMachine = pNewMachine;
    22721492
    2273                         ConvertDiskAttachmentValues(*pController,
     1493                        convertDiskAttachmentValues(*pController,
    22741494                                                    2,     // interpreted as secondary master
    22751495                                                    mhda.controllerType,        // Bstr
     
    24611681                        mhda.pMachine = pNewMachine;
    24621682
    2463                         ConvertDiskAttachmentValues(hdc,
     1683                        convertDiskAttachmentValues(hdc,
    24641684                                                    vd.ulAddressOnParent,
    24651685                                                    mhda.controllerType,        // Bstr
     
    25801800
    25811801/**
    2582  * Helper that converts VirtualSystem attachment values into VirtualBox attachment values.
    2583  * Throws HRESULT values on errors!
    25841802 *
    2585  * @param hdc
    2586  * @param vd
    2587  * @param mhda
     1803 * @param pTask
     1804 * @return
    25881805 */
    2589 void Appliance::ConvertDiskAttachmentValues(const HardDiskController &hdc,
    2590                                             uint32_t ulAddressOnParent,
    2591                                             Bstr &controllerType,
    2592                                             int32_t &lChannel,
    2593                                             int32_t &lDevice)
    2594 {
    2595     switch (hdc.system)
    2596     {
    2597         case HardDiskController::IDE:
    2598             // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
    2599             // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
    2600             // the device number can be either 0 or 1, to specify the master or the slave device,
    2601             // respectively. For the secondary IDE controller, the device number is always 1 because
    2602             // the master device is reserved for the CD-ROM drive.
    2603             controllerType = Bstr("IDE Controller");
    2604             switch (ulAddressOnParent)
    2605             {
    2606                 case 0:     // interpret this as primary master
    2607                     lChannel = (long)0;
    2608                     lDevice = (long)0;
    2609                 break;
    2610 
    2611                 case 1:     // interpret this as primary slave
    2612                     lChannel = (long)0;
    2613                     lDevice = (long)1;
    2614                 break;
    2615 
    2616                 case 2:     // interpret this as secondary master
    2617                     lChannel = (long)1;
    2618                     lDevice = (long)0;
    2619                 break;
    2620 
    2621                 case 3:     // interpret this as secondary slave
    2622                     lChannel = (long)1;
    2623                     lDevice = (long)1;
    2624                 break;
    2625 
    2626                 default:
    2627                     throw setError(VBOX_E_NOT_SUPPORTED,
    2628                                     tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), ulAddressOnParent);
    2629                 break;
    2630             }
    2631         break;
    2632 
    2633         case HardDiskController::SATA:
    2634             controllerType = Bstr("SATA Controller");
    2635             lChannel = (long)ulAddressOnParent;
    2636             lDevice = (long)0;
    2637         break;
    2638 
    2639         case HardDiskController::SCSI:
    2640             controllerType = Bstr("SCSI Controller");
    2641             lChannel = (long)ulAddressOnParent;
    2642             lDevice = (long)0;
    2643         break;
    2644 
    2645         default: break;
    2646     }
    2647 }
    2648 
    26491806int Appliance::importS3(TaskImportOVF *pTask)
    26501807{
     
    28301987}
    28311988
    2832 int Appliance::TaskExportOVF::startThread()
    2833 {
    2834     int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this,
    2835                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    2836                              "Appliance::Task");
    2837 
    2838     ComAssertMsgRCRet(vrc,
    2839                       ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL);
    2840 
    2841     return S_OK;
    2842 }
    2843 
    2844 ////////////////////////////////////////////////////////////////////////////////
    2845 //
    2846 // IVirtualSystemDescription constructor / destructor
    2847 //
    2848 ////////////////////////////////////////////////////////////////////////////////
    2849 
    2850 DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
    2851 
    2852 /**
    2853  * COM initializer.
    2854  * @return
    2855  */
    2856 HRESULT VirtualSystemDescription::init()
    2857 {
    2858     /* Enclose the state transition NotReady->InInit->Ready */
    2859     AutoInitSpan autoInitSpan(this);
    2860     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    2861 
    2862     /* Initialize data */
    2863     m = new Data();
    2864 
    2865     /* Confirm a successful initialization */
    2866     autoInitSpan.setSucceeded();
    2867     return S_OK;
    2868 }
    2869 
    2870 /**
    2871 * COM uninitializer.
    2872 */
    2873 
    2874 void VirtualSystemDescription::uninit()
    2875 {
    2876     delete m;
    2877     m = NULL;
    2878 }
    2879 
    2880 ////////////////////////////////////////////////////////////////////////////////
    2881 //
    2882 // IVirtualSystemDescription public methods
    2883 //
    2884 ////////////////////////////////////////////////////////////////////////////////
    2885 
    2886 /**
    2887  * Public method implementation.
    2888  * @param
    2889  * @return
    2890  */
    2891 STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
    2892 {
    2893     if (!aCount)
    2894         return E_POINTER;
    2895 
    2896     AutoCaller autoCaller(this);
    2897     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2898 
    2899     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2900 
    2901     *aCount = (ULONG)m->llDescriptions.size();
    2902 
    2903     return S_OK;
    2904 }
    2905 
    2906 /**
    2907  * Public method implementation.
    2908  * @return
    2909  */
    2910 STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
    2911                                                       ComSafeArrayOut(BSTR, aRefs),
    2912                                                       ComSafeArrayOut(BSTR, aOrigValues),
    2913                                                       ComSafeArrayOut(BSTR, aVboxValues),
    2914                                                       ComSafeArrayOut(BSTR, aExtraConfigValues))
    2915 {
    2916     if (ComSafeArrayOutIsNull(aTypes) ||
    2917         ComSafeArrayOutIsNull(aRefs) ||
    2918         ComSafeArrayOutIsNull(aOrigValues) ||
    2919         ComSafeArrayOutIsNull(aVboxValues) ||
    2920         ComSafeArrayOutIsNull(aExtraConfigValues))
    2921         return E_POINTER;
    2922 
    2923     AutoCaller autoCaller(this);
    2924     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2925 
    2926     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2927 
    2928     ULONG c = (ULONG)m->llDescriptions.size();
    2929     com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
    2930     com::SafeArray<BSTR> sfaRefs(c);
    2931     com::SafeArray<BSTR> sfaOrigValues(c);
    2932     com::SafeArray<BSTR> sfaVboxValues(c);
    2933     com::SafeArray<BSTR> sfaExtraConfigValues(c);
    2934 
    2935     list<VirtualSystemDescriptionEntry>::const_iterator it;
    2936     size_t i = 0;
    2937     for (it = m->llDescriptions.begin();
    2938          it != m->llDescriptions.end();
    2939          ++it, ++i)
    2940     {
    2941         const VirtualSystemDescriptionEntry &vsde = (*it);
    2942 
    2943         sfaTypes[i] = vsde.type;
    2944 
    2945         Bstr bstr = vsde.strRef;
    2946         bstr.cloneTo(&sfaRefs[i]);
    2947 
    2948         bstr = vsde.strOvf;
    2949         bstr.cloneTo(&sfaOrigValues[i]);
    2950 
    2951         bstr = vsde.strVbox;
    2952         bstr.cloneTo(&sfaVboxValues[i]);
    2953 
    2954         bstr = vsde.strExtraConfig;
    2955         bstr.cloneTo(&sfaExtraConfigValues[i]);
    2956     }
    2957 
    2958     sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
    2959     sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
    2960     sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
    2961     sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
    2962     sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
    2963 
    2964     return S_OK;
    2965 }
    2966 
    2967 /**
    2968  * Public method implementation.
    2969  * @return
    2970  */
    2971 STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
    2972                                                             ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
    2973                                                             ComSafeArrayOut(BSTR, aRefs),
    2974                                                             ComSafeArrayOut(BSTR, aOrigValues),
    2975                                                             ComSafeArrayOut(BSTR, aVboxValues),
    2976                                                             ComSafeArrayOut(BSTR, aExtraConfigValues))
    2977 {
    2978     if (ComSafeArrayOutIsNull(aTypes) ||
    2979         ComSafeArrayOutIsNull(aRefs) ||
    2980         ComSafeArrayOutIsNull(aOrigValues) ||
    2981         ComSafeArrayOutIsNull(aVboxValues) ||
    2982         ComSafeArrayOutIsNull(aExtraConfigValues))
    2983         return E_POINTER;
    2984 
    2985     AutoCaller autoCaller(this);
    2986     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2987 
    2988     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2989 
    2990     std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
    2991     ULONG c = (ULONG)vsd.size();
    2992     com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
    2993     com::SafeArray<BSTR> sfaRefs(c);
    2994     com::SafeArray<BSTR> sfaOrigValues(c);
    2995     com::SafeArray<BSTR> sfaVboxValues(c);
    2996     com::SafeArray<BSTR> sfaExtraConfigValues(c);
    2997 
    2998     list<VirtualSystemDescriptionEntry*>::const_iterator it;
    2999     size_t i = 0;
    3000     for (it = vsd.begin();
    3001          it != vsd.end();
    3002          ++it, ++i)
    3003     {
    3004         const VirtualSystemDescriptionEntry *vsde = (*it);
    3005 
    3006         sfaTypes[i] = vsde->type;
    3007 
    3008         Bstr bstr = vsde->strRef;
    3009         bstr.cloneTo(&sfaRefs[i]);
    3010 
    3011         bstr = vsde->strOvf;
    3012         bstr.cloneTo(&sfaOrigValues[i]);
    3013 
    3014         bstr = vsde->strVbox;
    3015         bstr.cloneTo(&sfaVboxValues[i]);
    3016 
    3017         bstr = vsde->strExtraConfig;
    3018         bstr.cloneTo(&sfaExtraConfigValues[i]);
    3019     }
    3020 
    3021     sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
    3022     sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
    3023     sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
    3024     sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
    3025     sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
    3026 
    3027     return S_OK;
    3028 }
    3029 
    3030 /**
    3031  * Public method implementation.
    3032  * @return
    3033  */
    3034 STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
    3035                                                        VirtualSystemDescriptionValueType_T aWhich,
    3036                                                        ComSafeArrayOut(BSTR, aValues))
    3037 {
    3038     if (ComSafeArrayOutIsNull(aValues))
    3039         return E_POINTER;
    3040 
    3041     AutoCaller autoCaller(this);
    3042     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3043 
    3044     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3045 
    3046     std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
    3047     com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
    3048 
    3049     list<VirtualSystemDescriptionEntry*>::const_iterator it;
    3050     size_t i = 0;
    3051     for (it = vsd.begin();
    3052          it != vsd.end();
    3053          ++it, ++i)
    3054     {
    3055         const VirtualSystemDescriptionEntry *vsde = (*it);
    3056 
    3057         Bstr bstr;
    3058         switch (aWhich)
    3059         {
    3060             case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
    3061             case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
    3062             case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVbox; break;
    3063             case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfig; break;
    3064         }
    3065 
    3066         bstr.cloneTo(&sfaValues[i]);
    3067     }
    3068 
    3069     sfaValues.detachTo(ComSafeArrayOutArg(aValues));
    3070 
    3071     return S_OK;
    3072 }
    3073 
    3074 /**
    3075  * Public method implementation.
    3076  * @return
    3077  */
    3078 STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
    3079                                                       ComSafeArrayIn(IN_BSTR, argVboxValues),
    3080                                                       ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
    3081 {
    3082 #ifndef RT_OS_WINDOWS
    3083     NOREF(aEnabledSize);
    3084 #endif /* RT_OS_WINDOWS */
    3085 
    3086     CheckComArgSafeArrayNotNull(aEnabled);
    3087     CheckComArgSafeArrayNotNull(argVboxValues);
    3088     CheckComArgSafeArrayNotNull(argExtraConfigValues);
    3089 
    3090     AutoCaller autoCaller(this);
    3091     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3092 
    3093     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3094 
    3095     com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
    3096     com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
    3097     com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
    3098 
    3099     if (    (sfaEnabled.size() != m->llDescriptions.size())
    3100          || (sfaVboxValues.size() != m->llDescriptions.size())
    3101          || (sfaExtraConfigValues.size() != m->llDescriptions.size())
    3102        )
    3103         return E_INVALIDARG;
    3104 
    3105     list<VirtualSystemDescriptionEntry>::iterator it;
    3106     size_t i = 0;
    3107     for (it = m->llDescriptions.begin();
    3108          it != m->llDescriptions.end();
    3109          ++it, ++i)
    3110     {
    3111         VirtualSystemDescriptionEntry& vsde = *it;
    3112 
    3113         if (sfaEnabled[i])
    3114         {
    3115             vsde.strVbox = sfaVboxValues[i];
    3116             vsde.strExtraConfig = sfaExtraConfigValues[i];
    3117         }
    3118         else
    3119             vsde.type = VirtualSystemDescriptionType_Ignore;
    3120     }
    3121 
    3122     return S_OK;
    3123 }
    3124 
    3125 /**
    3126  * Public method implementation.
    3127  * @return
    3128  */
    3129 STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
    3130                                                       IN_BSTR aVboxValue,
    3131                                                       IN_BSTR aExtraConfigValue)
    3132 {
    3133     AutoCaller autoCaller(this);
    3134     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3135 
    3136     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3137 
    3138     addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
    3139 
    3140     return S_OK;
    3141 }
    3142 
    3143 /**
    3144  * Internal method; adds a new description item to the member list.
    3145  * @param aType Type of description for the new item.
    3146  * @param strRef Reference item; only used with hard disk controllers.
    3147  * @param aOrigValue Corresponding original value from OVF.
    3148  * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
    3149  * @param ulSizeMB Weight for IProgress
    3150  * @param strExtraConfig Extra configuration; meaning dependent on type.
    3151  */
    3152 void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
    3153                                         const Utf8Str &strRef,
    3154                                         const Utf8Str &aOrigValue,
    3155                                         const Utf8Str &aAutoValue,
    3156                                         uint32_t ulSizeMB,
    3157                                         const Utf8Str &strExtraConfig /*= ""*/)
    3158 {
    3159     VirtualSystemDescriptionEntry vsde;
    3160     vsde.ulIndex = (uint32_t)m->llDescriptions.size();      // each entry gets an index so the client side can reference them
    3161     vsde.type = aType;
    3162     vsde.strRef = strRef;
    3163     vsde.strOvf = aOrigValue;
    3164     vsde.strVbox = aAutoValue;
    3165     vsde.strExtraConfig = strExtraConfig;
    3166     vsde.ulSizeMB = ulSizeMB;
    3167 
    3168     m->llDescriptions.push_back(vsde);
    3169 }
    3170 
    3171 /**
    3172  * Private method; returns a list of description items containing all the items from the member
    3173  * description items of this virtual system that match the given type.
    3174  * @param aType
    3175  * @return
    3176  */
    3177 std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
    3178 {
    3179     std::list<VirtualSystemDescriptionEntry*> vsd;
    3180 
    3181     list<VirtualSystemDescriptionEntry>::iterator it;
    3182     for (it = m->llDescriptions.begin();
    3183          it != m->llDescriptions.end();
    3184          ++it)
    3185     {
    3186         if (it->type == aType)
    3187             vsd.push_back(&(*it));
    3188     }
    3189 
    3190     return vsd;
    3191 }
    3192 
    3193 /**
    3194  * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
    3195  * the given reference ID. Useful when needing the controller for a particular
    3196  * virtual disk.
    3197  * @param id
    3198  * @return
    3199  */
    3200 const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
    3201 {
    3202     Utf8Str strRef = Utf8StrFmt("%RI32", id);
    3203     list<VirtualSystemDescriptionEntry>::const_iterator it;
    3204     for (it = m->llDescriptions.begin();
    3205          it != m->llDescriptions.end();
    3206          ++it)
    3207     {
    3208         const VirtualSystemDescriptionEntry &d = *it;
    3209         switch (d.type)
    3210         {
    3211             case VirtualSystemDescriptionType_HardDiskControllerIDE:
    3212             case VirtualSystemDescriptionType_HardDiskControllerSATA:
    3213             case VirtualSystemDescriptionType_HardDiskControllerSCSI:
    3214                 if (d.strRef == strRef)
    3215                     return &d;
    3216             break;
    3217         }
    3218     }
    3219 
    3220     return NULL;
    3221 }
    3222 
  • trunk/src/VBox/Main/Makefile.kmk

    r27857 r27882  
    292292        ApplianceImpl.cpp \
    293293        ApplianceImplExport.cpp \
     294        ApplianceImplImport.cpp \
    294295        xml/ovfreader.cpp \
    295296        VFSExplorerImpl.cpp \
  • trunk/src/VBox/Main/include/ApplianceImpl.h

    r27835 r27882  
    116116
    117117    HRESULT readImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress);
    118     HRESULT importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress);
    119118
    120119    struct TaskOVF;
     120
    121121    struct TaskImportOVF; /* Worker threads for import */
    122     static DECLCALLBACK(int) taskThreadImportOVF(RTTHREAD aThread, void *pvUser);
    123 
    124122    int readFS(TaskImportOVF *pTask);
    125123    int readS3(TaskImportOVF *pTask);
    126124
    127     int importFS(TaskImportOVF *pTask);
    128     int importS3(TaskImportOVF *pTask);
    129 
    130     void ConvertDiskAttachmentValues(const HardDiskController &hdc,
     125    void convertDiskAttachmentValues(const HardDiskController &hdc,
    131126                                     uint32_t ulAddressOnParent,
    132127                                     Bstr &controllerType,
    133128                                     int32_t &lChannel,
    134129                                     int32_t &lDevice);
     130
     131    HRESULT importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress);
     132
     133    static DECLCALLBACK(int) taskThreadImportOVF(RTTHREAD aThread, void *pvUser);
     134
     135    int importFS(TaskImportOVF *pTask);
     136    int importS3(TaskImportOVF *pTask);
    135137
    136138    HRESULT writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette