VirtualBox

Changeset 27829 in vbox for trunk/src


Ignore:
Timestamp:
Mar 30, 2010 1:54:07 PM (15 years ago)
Author:
vboxsync
Message:

Main/OVF: sort code into several files + document export code

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

Legend:

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

    r27796 r27829  
    4545#include "Logging.h"
    4646
     47#include "ApplianceImplPrivate.h"
     48
    4749using namespace std;
    4850
    4951////////////////////////////////////////////////////////////////////////////////
    5052//
    51 // Appliance data definition
    52 //
    53 ////////////////////////////////////////////////////////////////////////////////
    54 
    55 /* Describe a location for the import/export. The location could be a file on a
    56  * local hard disk or a remote target based on the supported inet protocols. */
    57 struct Appliance::LocationInfo
    58 {
    59     LocationInfo()
    60       : storageType(VFSType_File) {}
    61     VFSType_T storageType; /* Which type of storage should be handled */
    62     Utf8Str strPath;       /* File path for the import/export */
    63     Utf8Str strHostname;   /* Hostname on remote storage locations (could be empty) */
    64     Utf8Str strUsername;   /* Username on remote storage locations (could be empty) */
    65     Utf8Str strPassword;   /* Password on remote storage locations (could be empty) */
    66 };
    67 
    68 // opaque private instance data of Appliance class
    69 struct Appliance::Data
    70 {
    71     enum ApplianceState { ApplianceIdle, ApplianceImporting, ApplianceExporting };
    72 
    73     Data()
    74       : state(ApplianceIdle),
    75         pReader(NULL)
    76     {
    77     }
    78 
    79     ~Data()
    80     {
    81         if (pReader)
    82         {
    83             delete pReader;
    84             pReader = NULL;
    85         }
    86     }
    87 
    88     ApplianceState  state;
    89 
    90     LocationInfo    locInfo;       // location info for the currently processed OVF
    91 
    92     OVFReader       *pReader;
    93 
    94     bool            fBusyWriting;          // state protection; while this is true nobody else can call methods
    95 
    96     list< ComObjPtr<VirtualSystemDescription> >
    97                     virtualSystemDescriptions;
    98 
    99     list<Utf8Str>   llWarnings;
    100 
    101     ULONG           ulWeightPerOperation;
    102     Utf8Str         strOVFSHA1Digest;
    103 };
    104 
    105 struct VirtualSystemDescription::Data
    106 {
    107     list<VirtualSystemDescriptionEntry> llDescriptions;
    108 };
    109 
    110 ////////////////////////////////////////////////////////////////////////////////
    111 //
    112 // internal helpers
     53// Internal helpers
    11354//
    11455////////////////////////////////////////////////////////////////////////////////
     
    242183 * @param cStr
    243184 */
    244 static void convertCIMOSType2VBoxOSType(Utf8Str &strType, CIMOSType_T c, const Utf8Str &cStr)
     185void convertCIMOSType2VBoxOSType(Utf8Str &strType, CIMOSType_T c, const Utf8Str &cStr)
    245186{
    246187    /* First check if the type is other/other_64 */
     
    282223 * @param c
    283224 */
    284 static CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
     225CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
    285226{
    286227    for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
     
    373314    delete m;
    374315    m = NULL;
     316}
     317
     318////////////////////////////////////////////////////////////////////////////////
     319//
     320// IAppliance public methods
     321//
     322////////////////////////////////////////////////////////////////////////////////
     323
     324/**
     325 * Public method implementation.
     326 * @param
     327 * @return
     328 */
     329STDMETHODIMP 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 */
     353STDMETHODIMP 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 */
     414STDMETHODIMP 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 */
     437STDMETHODIMP 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}
     481
     482/**
     483 * Public method implementation.
     484 * @return
     485 */
     486STDMETHODIMP 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 */
     947STDMETHODIMP 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
     982STDMETHODIMP 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 */
     1019STDMETHODIMP 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;
    3751044}
    3761045
     
    7441413    return strMfFile;
    7451414}
    746 
    747 struct Appliance::TaskOVF
    748 {
    749     TaskOVF(Appliance *aThat)
    750       : pAppliance(aThat),
    751         rc(S_OK)
    752     {}
    753 
    754     static int updateProgress(unsigned uPercent, void *pvUser);
    755 
    756     LocationInfo locInfo;
    757     Appliance *pAppliance;
    758     ComObjPtr<Progress> progress;
    759     HRESULT rc;
    760 };
    761 
    762 struct Appliance::TaskImportOVF : Appliance::TaskOVF
    763 {
    764     enum TaskType
    765     {
    766         Read,
    767         Import
    768     };
    769 
    770     TaskImportOVF(Appliance *aThat)
    771         : TaskOVF(aThat),
    772           taskType(Read)
    773     {}
    774 
    775     int startThread();
    776 
    777     TaskType taskType;
    778 };
    779 
    780 struct Appliance::TaskExportOVF : Appliance::TaskOVF
    781 {
    782     enum OVFFormat
    783     {
    784         unspecified,
    785         OVF_0_9,
    786         OVF_1_0
    787     };
    788     enum TaskType
    789     {
    790         Write
    791     };
    792 
    793     TaskExportOVF(Appliance *aThat)
    794         : TaskOVF(aThat),
    795           taskType(Write)
    796     {}
    797 
    798     int startThread();
    799 
    800     TaskType taskType;
    801     OVFFormat enFormat;
    802 };
    803 
    804 struct MyHardDiskAttachment
    805 {
    806     Bstr                bstrUuid;
    807     ComPtr<IMachine>    pMachine;
    808     Bstr                controllerType;
    809     int32_t             lChannel;
    810     int32_t             lDevice;
    811 };
    8121415
    8131416/* static */
     
    22272830}
    22282831
    2229 HRESULT Appliance::writeImpl(int aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    2230 {
    2231     HRESULT rc = S_OK;
    2232     try
    2233     {
    2234         /* Initialize our worker task */
    2235         std::auto_ptr<TaskExportOVF> task(new TaskExportOVF(this));
    2236         /* What should the task do */
    2237         task->taskType = TaskExportOVF::Write;
    2238         /* The OVF version to write */
    2239         task->enFormat = (TaskExportOVF::OVFFormat)aFormat;
    2240         /* Copy the current location info to the task */
    2241         task->locInfo = aLocInfo;
    2242 
    2243         Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"),
    2244                                     task->locInfo.strPath.c_str());
    2245 
    2246         /* todo: This progress init stuff should be done a little bit more generic */
    2247         if (task->locInfo.storageType == VFSType_File)
    2248             rc = setUpProgressFS(aProgress, progressDesc);
    2249         else
    2250             rc = setUpProgressWriteS3(aProgress, progressDesc);
    2251 
    2252         task->progress = aProgress;
    2253 
    2254         rc = task->startThread();
    2255         if (FAILED(rc)) throw rc;
    2256 
    2257         /* Don't destruct on success */
    2258         task.release();
    2259     }
    2260     catch (HRESULT aRC)
    2261     {
    2262         rc = aRC;
    2263     }
    2264 
    2265     return rc;
    2266 }
    2267 
    2268 DECLCALLBACK(int) Appliance::taskThreadWriteOVF(RTTHREAD /* aThread */, void *pvUser)
    2269 {
    2270     std::auto_ptr<TaskExportOVF> task(static_cast<TaskExportOVF*>(pvUser));
    2271     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    2272 
    2273     Appliance *pAppliance = task->pAppliance;
    2274 
    2275     LogFlowFuncEnter();
    2276     LogFlowFunc(("Appliance %p\n", pAppliance));
    2277 
    2278     HRESULT rc = S_OK;
    2279 
    2280     switch(task->taskType)
    2281     {
    2282         case TaskExportOVF::Write:
    2283         {
    2284             if (task->locInfo.storageType == VFSType_File)
    2285                 rc = pAppliance->writeFS(task.get());
    2286             else if (task->locInfo.storageType == VFSType_S3)
    2287                 rc = pAppliance->writeS3(task.get());
    2288             break;
    2289         }
    2290     }
    2291 
    2292     LogFlowFunc(("rc=%Rhrc\n", rc));
    2293     LogFlowFuncLeave();
    2294 
    2295     return VINF_SUCCESS;
    2296 }
    2297 
    22982832int Appliance::TaskExportOVF::startThread()
    22992833{
     
    23042838    ComAssertMsgRCRet(vrc,
    23052839                      ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL);
    2306 
    2307     return S_OK;
    2308 }
    2309 
    2310 int Appliance::writeFS(TaskExportOVF *pTask)
    2311 {
    2312     LogFlowFuncEnter();
    2313     LogFlowFunc(("Appliance %p\n", this));
    2314 
    2315     AutoCaller autoCaller(this);
    2316     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2317 
    2318     HRESULT rc = S_OK;
    2319 
    2320     try
    2321     {
    2322         AutoMultiWriteLock2 multiLock(&mVirtualBox->getMediaTreeLockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS);
    2323 
    2324         xml::Document doc;
    2325         xml::ElementNode *pelmRoot = doc.createRootElement("Envelope");
    2326 
    2327         pelmRoot->setAttribute("ovf:version", (pTask->enFormat == TaskExportOVF::OVF_1_0) ? "1.0" : "0.9");
    2328         pelmRoot->setAttribute("xml:lang", "en-US");
    2329 
    2330         Utf8Str strNamespace = (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2331             ? "http://www.vmware.com/schema/ovf/1/envelope"     // 0.9
    2332             : "http://schemas.dmtf.org/ovf/envelope/1";         // 1.0
    2333         pelmRoot->setAttribute("xmlns", strNamespace);
    2334         pelmRoot->setAttribute("xmlns:ovf", strNamespace);
    2335 
    2336 //         pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");
    2337         pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData");
    2338         pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData");
    2339         pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    2340 //         pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
    2341 
    2342         // <Envelope>/<References>
    2343         xml::ElementNode *pelmReferences = pelmRoot->createChild("References");     // 0.9 and 1.0
    2344 
    2345         /* <Envelope>/<DiskSection>:
    2346             <DiskSection>
    2347                 <Info>List of the virtual disks used in the package</Info>
    2348                 <Disk ovf:capacity="4294967296" ovf:diskId="lamp" ovf:format="http://www.vmware.com/specifications/vmdk.html#compressed" ovf:populatedSize="1924967692"/>
    2349             </DiskSection> */
    2350         xml::ElementNode *pelmDiskSection;
    2351         if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2352         {
    2353             // <Section xsi:type="ovf:DiskSection_Type">
    2354             pelmDiskSection = pelmRoot->createChild("Section");
    2355             pelmDiskSection->setAttribute("xsi:type", "ovf:DiskSection_Type");
    2356         }
    2357         else
    2358             pelmDiskSection = pelmRoot->createChild("DiskSection");
    2359 
    2360         xml::ElementNode *pelmDiskSectionInfo = pelmDiskSection->createChild("Info");
    2361         pelmDiskSectionInfo->addContent("List of the virtual disks used in the package");
    2362         // for now, set up a map so we have a list of unique disk names (to make
    2363         // sure the same disk name is only added once)
    2364         map<Utf8Str, const VirtualSystemDescriptionEntry*> mapDisks;
    2365 
    2366         /* <Envelope>/<NetworkSection>:
    2367             <NetworkSection>
    2368                 <Info>Logical networks used in the package</Info>
    2369                 <Network ovf:name="VM Network">
    2370                     <Description>The network that the LAMP Service will be available on</Description>
    2371                 </Network>
    2372             </NetworkSection> */
    2373         xml::ElementNode *pelmNetworkSection;
    2374         if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2375         {
    2376             // <Section xsi:type="ovf:NetworkSection_Type">
    2377             pelmNetworkSection = pelmRoot->createChild("Section");
    2378             pelmNetworkSection->setAttribute("xsi:type", "ovf:NetworkSection_Type");
    2379         }
    2380         else
    2381             pelmNetworkSection = pelmRoot->createChild("NetworkSection");
    2382 
    2383         xml::ElementNode *pelmNetworkSectionInfo = pelmNetworkSection->createChild("Info");
    2384         pelmNetworkSectionInfo->addContent("Logical networks used in the package");
    2385         // for now, set up a map so we have a list of unique network names (to make
    2386         // sure the same network name is only added once)
    2387         map<Utf8Str, bool> mapNetworks;
    2388                 // we fill this later below when we iterate over the networks
    2389 
    2390         // and here come the virtual systems:
    2391 
    2392         // write a collection if we have more than one virtual system _and_ we're
    2393         // writing OVF 1.0; otherwise fail since ovftool can't import more than
    2394         // one machine, it seems
    2395         xml::ElementNode *pelmToAddVirtualSystemsTo;
    2396         if (m->virtualSystemDescriptions.size() > 1)
    2397         {
    2398             if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2399                 throw setError(VBOX_E_FILE_ERROR,
    2400                                tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0"));
    2401 
    2402             pelmToAddVirtualSystemsTo = pelmRoot->createChild("VirtualSystemCollection");
    2403             /* xml::AttributeNode *pattrVirtualSystemCollectionId = */ pelmToAddVirtualSystemsTo->setAttribute("ovf:name", "ExportedVirtualBoxMachines");      // whatever
    2404         }
    2405         else
    2406             pelmToAddVirtualSystemsTo = pelmRoot;       // add virtual system directly under root element
    2407 
    2408         uint32_t cDisks = 0;
    2409 
    2410         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    2411         /* Iterate through all virtual systems of that appliance */
    2412         for (it = m->virtualSystemDescriptions.begin();
    2413              it != m->virtualSystemDescriptions.end();
    2414              ++it)
    2415         {
    2416             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    2417 
    2418             xml::ElementNode *pelmVirtualSystem;
    2419             if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2420             {
    2421                 // <Section xsi:type="ovf:NetworkSection_Type">
    2422                 pelmVirtualSystem = pelmToAddVirtualSystemsTo->createChild("Content");
    2423                 pelmVirtualSystem->setAttribute("xsi:type", "ovf:VirtualSystem_Type");
    2424             }
    2425             else
    2426                 pelmVirtualSystem = pelmToAddVirtualSystemsTo->createChild("VirtualSystem");
    2427 
    2428             /*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine");
    2429 
    2430             std::list<VirtualSystemDescriptionEntry*> llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
    2431             if (llName.size() != 1)
    2432                 throw setError(VBOX_E_NOT_SUPPORTED,
    2433                                tr("Missing VM name"));
    2434             Utf8Str &strVMName = llName.front()->strVbox;
    2435             pelmVirtualSystem->setAttribute("ovf:id", strVMName);
    2436 
    2437             // product info
    2438             std::list<VirtualSystemDescriptionEntry*> llProduct = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
    2439             std::list<VirtualSystemDescriptionEntry*> llProductUrl = vsdescThis->findByType(VirtualSystemDescriptionType_ProductUrl);
    2440             std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
    2441             std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
    2442             std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
    2443             bool fProduct = llProduct.size() && !llProduct.front()->strVbox.isEmpty();
    2444             bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVbox.isEmpty();
    2445             bool fVendor = llVendor.size() && !llVendor.front()->strVbox.isEmpty();
    2446             bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVbox.isEmpty();
    2447             bool fVersion = llVersion.size() && !llVersion.front()->strVbox.isEmpty();
    2448             if (fProduct ||
    2449                 fProductUrl ||
    2450                 fVersion ||
    2451                 fVendorUrl ||
    2452                 fVersion)
    2453             {
    2454                 /* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
    2455                     <Info>Meta-information about the installed software</Info>
    2456                     <Product>VAtest</Product>
    2457                     <Vendor>SUN Microsystems</Vendor>
    2458                     <Version>10.0</Version>
    2459                     <ProductUrl>http://blogs.sun.com/VirtualGuru</ProductUrl>
    2460                     <VendorUrl>http://www.sun.com</VendorUrl>
    2461                 </Section> */
    2462                 xml::ElementNode *pelmAnnotationSection;
    2463                 if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2464                 {
    2465                     // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
    2466                     pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
    2467                     pelmAnnotationSection->setAttribute("xsi:type", "ovf:ProductSection_Type");
    2468                 }
    2469                 else
    2470                     pelmAnnotationSection = pelmVirtualSystem->createChild("ProductSection");
    2471 
    2472                 pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software");
    2473                 if (fProduct)
    2474                     pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVbox);
    2475                 if (fVendor)
    2476                     pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVbox);
    2477                 if (fVersion)
    2478                     pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVbox);
    2479                 if (fProductUrl)
    2480                     pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVbox);
    2481                 if (fVendorUrl)
    2482                     pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVbox);
    2483             }
    2484 
    2485             // description
    2486             std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
    2487             if (llDescription.size() &&
    2488                 !llDescription.front()->strVbox.isEmpty())
    2489             {
    2490                 /*  <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
    2491                         <Info>A human-readable annotation</Info>
    2492                         <Annotation>Plan 9</Annotation>
    2493                     </Section> */
    2494                 xml::ElementNode *pelmAnnotationSection;
    2495                 if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2496                 {
    2497                     // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
    2498                     pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
    2499                     pelmAnnotationSection->setAttribute("xsi:type", "ovf:AnnotationSection_Type");
    2500                 }
    2501                 else
    2502                     pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection");
    2503 
    2504                 pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation");
    2505                 pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVbox);
    2506             }
    2507 
    2508             // license
    2509             std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License);
    2510             if (llLicense.size() &&
    2511                 !llLicense.front()->strVbox.isEmpty())
    2512             {
    2513                 /* <EulaSection>
    2514                    <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
    2515                    <License ovf:msgid="1">License terms can go in here.</License>
    2516                    </EulaSection> */
    2517                 xml::ElementNode *pelmEulaSection;
    2518                 if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2519                 {
    2520                     pelmEulaSection = pelmVirtualSystem->createChild("Section");
    2521                     pelmEulaSection->setAttribute("xsi:type", "ovf:EulaSection_Type");
    2522                 }
    2523                 else
    2524                     pelmEulaSection = pelmVirtualSystem->createChild("EulaSection");
    2525 
    2526                 pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system");
    2527                 pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVbox);
    2528             }
    2529 
    2530             // operating system
    2531             std::list<VirtualSystemDescriptionEntry*> llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
    2532             if (llOS.size() != 1)
    2533                 throw setError(VBOX_E_NOT_SUPPORTED,
    2534                                tr("Missing OS type"));
    2535             /*  <OperatingSystemSection ovf:id="82">
    2536                     <Info>Guest Operating System</Info>
    2537                     <Description>Linux 2.6.x</Description>
    2538                 </OperatingSystemSection> */
    2539             xml::ElementNode *pelmOperatingSystemSection;
    2540             if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2541             {
    2542                 pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section");
    2543                 pelmOperatingSystemSection->setAttribute("xsi:type", "ovf:OperatingSystemSection_Type");
    2544             }
    2545             else
    2546                 pelmOperatingSystemSection = pelmVirtualSystem->createChild("OperatingSystemSection");
    2547 
    2548             pelmOperatingSystemSection->setAttribute("ovf:id", llOS.front()->strOvf);
    2549             pelmOperatingSystemSection->createChild("Info")->addContent("The kind of installed guest operating system");
    2550             Utf8Str strOSDesc;
    2551             convertCIMOSType2VBoxOSType(strOSDesc, (CIMOSType_T)llOS.front()->strOvf.toInt32(), "");
    2552             pelmOperatingSystemSection->createChild("Description")->addContent(strOSDesc);
    2553 
    2554             // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso">
    2555             xml::ElementNode *pelmVirtualHardwareSection;
    2556             if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2557             {
    2558                 // <Section xsi:type="ovf:VirtualHardwareSection_Type">
    2559                 pelmVirtualHardwareSection = pelmVirtualSystem->createChild("Section");
    2560                 pelmVirtualHardwareSection->setAttribute("xsi:type", "ovf:VirtualHardwareSection_Type");
    2561             }
    2562             else
    2563                 pelmVirtualHardwareSection = pelmVirtualSystem->createChild("VirtualHardwareSection");
    2564 
    2565             pelmVirtualHardwareSection->createChild("Info")->addContent("Virtual hardware requirements for a virtual machine");
    2566 
    2567             /*  <System>
    2568                     <vssd:Description>Description of the virtual hardware section.</vssd:Description>
    2569                     <vssd:ElementName>vmware</vssd:ElementName>
    2570                     <vssd:InstanceID>1</vssd:InstanceID>
    2571                     <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
    2572                     <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
    2573                 </System> */
    2574             xml::ElementNode *pelmSystem = pelmVirtualHardwareSection->createChild("System");
    2575 
    2576             pelmSystem->createChild("vssd:ElementName")->addContent("Virtual Hardware Family"); // required OVF 1.0
    2577 
    2578             // <vssd:InstanceId>0</vssd:InstanceId>
    2579             if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2580                 pelmSystem->createChild("vssd:InstanceId")->addContent("0");
    2581             else // capitalization changed...
    2582                 pelmSystem->createChild("vssd:InstanceID")->addContent("0");
    2583 
    2584             // <vssd:VirtualSystemIdentifier>VAtest</vssd:VirtualSystemIdentifier>
    2585             pelmSystem->createChild("vssd:VirtualSystemIdentifier")->addContent(strVMName);
    2586             // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
    2587             const char *pcszHardware = "virtualbox-2.2";
    2588             if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2589                 // pretend to be vmware compatible then
    2590                 pcszHardware = "vmx-6";
    2591             pelmSystem->createChild("vssd:VirtualSystemType")->addContent(pcszHardware);
    2592 
    2593             // loop thru all description entries twice; once to write out all
    2594             // devices _except_ disk images, and a second time to assign the
    2595             // disk images; this is because disk images need to reference
    2596             // IDE controllers, and we can't know their instance IDs without
    2597             // assigning them first
    2598 
    2599             uint32_t idIDEController = 0;
    2600             int32_t lIDEControllerIndex = 0;
    2601             uint32_t idSATAController = 0;
    2602             int32_t lSATAControllerIndex = 0;
    2603             uint32_t idSCSIController = 0;
    2604             int32_t lSCSIControllerIndex = 0;
    2605 
    2606             uint32_t ulInstanceID = 1;
    2607 
    2608             for (size_t uLoop = 1;
    2609                  uLoop <= 2;
    2610                  ++uLoop)
    2611             {
    2612                 int32_t lIndexThis = 0;
    2613                 list<VirtualSystemDescriptionEntry>::const_iterator itD;
    2614                 for (itD = vsdescThis->m->llDescriptions.begin();
    2615                     itD != vsdescThis->m->llDescriptions.end();
    2616                     ++itD, ++lIndexThis)
    2617                 {
    2618                     const VirtualSystemDescriptionEntry &desc = *itD;
    2619 
    2620                     OVFResourceType_T type = (OVFResourceType_T)0;      // if this becomes != 0 then we do stuff
    2621                     Utf8Str strResourceSubType;
    2622 
    2623                     Utf8Str strDescription;                             // results in <rasd:Description>...</rasd:Description> block
    2624                     Utf8Str strCaption;                                 // results in <rasd:Caption>...</rasd:Caption> block
    2625 
    2626                     uint32_t ulParent = 0;
    2627 
    2628                     int32_t lVirtualQuantity = -1;
    2629                     Utf8Str strAllocationUnits;
    2630 
    2631                     int32_t lAddress = -1;
    2632                     int32_t lBusNumber = -1;
    2633                     int32_t lAddressOnParent = -1;
    2634 
    2635                     int32_t lAutomaticAllocation = -1;                  // 0 means "false", 1 means "true"
    2636                     Utf8Str strConnection;                              // results in <rasd:Connection>...</rasd:Connection> block
    2637                     Utf8Str strHostResource;
    2638 
    2639                     uint64_t uTemp;
    2640 
    2641                     switch (desc.type)
    2642                     {
    2643                         case VirtualSystemDescriptionType_CPU:
    2644                             /*  <Item>
    2645                                     <rasd:Caption>1 virtual CPU</rasd:Caption>
    2646                                     <rasd:Description>Number of virtual CPUs</rasd:Description>
    2647                                     <rasd:ElementName>virtual CPU</rasd:ElementName>
    2648                                     <rasd:InstanceID>1</rasd:InstanceID>
    2649                                     <rasd:ResourceType>3</rasd:ResourceType>
    2650                                     <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
    2651                                 </Item> */
    2652                             if (uLoop == 1)
    2653                             {
    2654                                 strDescription = "Number of virtual CPUs";
    2655                                 type = OVFResourceType_Processor; // 3
    2656                                 desc.strVbox.toInt(uTemp);
    2657                                 lVirtualQuantity = (int32_t)uTemp;
    2658                                 strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity);     // without this ovftool won't eat the item
    2659                             }
    2660                         break;
    2661 
    2662                         case VirtualSystemDescriptionType_Memory:
    2663                             /*  <Item>
    2664                                     <rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
    2665                                     <rasd:Caption>256 MB of memory</rasd:Caption>
    2666                                     <rasd:Description>Memory Size</rasd:Description>
    2667                                     <rasd:ElementName>Memory</rasd:ElementName>
    2668                                     <rasd:InstanceID>2</rasd:InstanceID>
    2669                                     <rasd:ResourceType>4</rasd:ResourceType>
    2670                                     <rasd:VirtualQuantity>256</rasd:VirtualQuantity>
    2671                                 </Item> */
    2672                             if (uLoop == 1)
    2673                             {
    2674                                 strDescription = "Memory Size";
    2675                                 type = OVFResourceType_Memory; // 4
    2676                                 desc.strVbox.toInt(uTemp);
    2677                                 lVirtualQuantity = (int32_t)(uTemp / _1M);
    2678                                 strAllocationUnits = "MegaBytes";
    2679                                 strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity);     // without this ovftool won't eat the item
    2680                             }
    2681                         break;
    2682 
    2683                         case VirtualSystemDescriptionType_HardDiskControllerIDE:
    2684                             /* <Item>
    2685                                     <rasd:Caption>ideController1</rasd:Caption>
    2686                                     <rasd:Description>IDE Controller</rasd:Description>
    2687                                     <rasd:InstanceId>5</rasd:InstanceId>
    2688                                     <rasd:ResourceType>5</rasd:ResourceType>
    2689                                     <rasd:Address>1</rasd:Address>
    2690                                     <rasd:BusNumber>1</rasd:BusNumber>
    2691                                 </Item> */
    2692                             if (uLoop == 1)
    2693                             {
    2694                                 strDescription = "IDE Controller";
    2695                                 strCaption = "ideController0";
    2696                                 type = OVFResourceType_IDEController; // 5
    2697                                 strResourceSubType = desc.strVbox;
    2698                                 // it seems that OVFTool always writes these two, and since we can only
    2699                                 // have one IDE controller, we'll use this as well
    2700                                 lAddress = 1;
    2701                                 lBusNumber = 1;
    2702 
    2703                                 // remember this ID
    2704                                 idIDEController = ulInstanceID;
    2705                                 lIDEControllerIndex = lIndexThis;
    2706                             }
    2707                         break;
    2708 
    2709                         case VirtualSystemDescriptionType_HardDiskControllerSATA:
    2710                             /*  <Item>
    2711                                     <rasd:Caption>sataController0</rasd:Caption>
    2712                                     <rasd:Description>SATA Controller</rasd:Description>
    2713                                     <rasd:InstanceId>4</rasd:InstanceId>
    2714                                     <rasd:ResourceType>20</rasd:ResourceType>
    2715                                     <rasd:ResourceSubType>ahci</rasd:ResourceSubType>
    2716                                     <rasd:Address>0</rasd:Address>
    2717                                     <rasd:BusNumber>0</rasd:BusNumber>
    2718                                 </Item>
    2719                             */
    2720                             if (uLoop == 1)
    2721                             {
    2722                                 strDescription = "SATA Controller";
    2723                                 strCaption = "sataController0";
    2724                                 type = OVFResourceType_OtherStorageDevice; // 20
    2725                                 // it seems that OVFTool always writes these two, and since we can only
    2726                                 // have one SATA controller, we'll use this as well
    2727                                 lAddress = 0;
    2728                                 lBusNumber = 0;
    2729 
    2730                                 if (    desc.strVbox.isEmpty()      // AHCI is the default in VirtualBox
    2731                                      || (!desc.strVbox.compare("ahci", Utf8Str::CaseInsensitive))
    2732                                    )
    2733                                     strResourceSubType = "AHCI";
    2734                                 else
    2735                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2736                                                    tr("Invalid config string \"%s\" in SATA controller"), desc.strVbox.c_str());
    2737 
    2738                                 // remember this ID
    2739                                 idSATAController = ulInstanceID;
    2740                                 lSATAControllerIndex = lIndexThis;
    2741                             }
    2742                         break;
    2743 
    2744                         case VirtualSystemDescriptionType_HardDiskControllerSCSI:
    2745                             /*  <Item>
    2746                                     <rasd:Caption>scsiController0</rasd:Caption>
    2747                                     <rasd:Description>SCSI Controller</rasd:Description>
    2748                                     <rasd:InstanceId>4</rasd:InstanceId>
    2749                                     <rasd:ResourceType>6</rasd:ResourceType>
    2750                                     <rasd:ResourceSubType>buslogic</rasd:ResourceSubType>
    2751                                     <rasd:Address>0</rasd:Address>
    2752                                     <rasd:BusNumber>0</rasd:BusNumber>
    2753                                 </Item>
    2754                             */
    2755                             if (uLoop == 1)
    2756                             {
    2757                                 strDescription = "SCSI Controller";
    2758                                 strCaption = "scsiController0";
    2759                                 type = OVFResourceType_ParallelSCSIHBA; // 6
    2760                                 // it seems that OVFTool always writes these two, and since we can only
    2761                                 // have one SATA controller, we'll use this as well
    2762                                 lAddress = 0;
    2763                                 lBusNumber = 0;
    2764 
    2765                                 if (    desc.strVbox.isEmpty()      // LsiLogic is the default in VirtualBox
    2766                                      || (!desc.strVbox.compare("lsilogic", Utf8Str::CaseInsensitive))
    2767                                    )
    2768                                     strResourceSubType = "lsilogic";
    2769                                 else if (!desc.strVbox.compare("buslogic", Utf8Str::CaseInsensitive))
    2770                                     strResourceSubType = "buslogic";
    2771                                 else
    2772                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2773                                                    tr("Invalid config string \"%s\" in SCSI controller"), desc.strVbox.c_str());
    2774 
    2775                                 // remember this ID
    2776                                 idSCSIController = ulInstanceID;
    2777                                 lSCSIControllerIndex = lIndexThis;
    2778                             }
    2779                         break;
    2780 
    2781                         case VirtualSystemDescriptionType_HardDiskImage:
    2782                             /*  <Item>
    2783                                     <rasd:Caption>disk1</rasd:Caption>
    2784                                     <rasd:InstanceId>8</rasd:InstanceId>
    2785                                     <rasd:ResourceType>17</rasd:ResourceType>
    2786                                     <rasd:HostResource>/disk/vmdisk1</rasd:HostResource>
    2787                                     <rasd:Parent>4</rasd:Parent>
    2788                                     <rasd:AddressOnParent>0</rasd:AddressOnParent>
    2789                                 </Item> */
    2790                             if (uLoop == 2)
    2791                             {
    2792                                 Utf8Str strDiskID = Utf8StrFmt("vmdisk%RI32", ++cDisks);
    2793 
    2794                                 strDescription = "Disk Image";
    2795                                 strCaption = Utf8StrFmt("disk%RI32", cDisks);        // this is not used for anything else
    2796                                 type = OVFResourceType_HardDisk; // 17
    2797 
    2798                                 // the following references the "<Disks>" XML block
    2799                                 strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str());
    2800 
    2801                                 // controller=<index>;channel=<c>
    2802                                 size_t pos1 = desc.strExtraConfig.find("controller=");
    2803                                 size_t pos2 = desc.strExtraConfig.find("channel=");
    2804                                 if (pos1 != Utf8Str::npos)
    2805                                 {
    2806                                     int32_t lControllerIndex = -1;
    2807                                     RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos1 + 11, NULL, 0, &lControllerIndex);
    2808                                     if (lControllerIndex == lIDEControllerIndex)
    2809                                         ulParent = idIDEController;
    2810                                     else if (lControllerIndex == lSCSIControllerIndex)
    2811                                         ulParent = idSCSIController;
    2812                                     else if (lControllerIndex == lSATAControllerIndex)
    2813                                         ulParent = idSATAController;
    2814                                 }
    2815                                 if (pos2 != Utf8Str::npos)
    2816                                     RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos2 + 8, NULL, 0, &lAddressOnParent);
    2817 
    2818                                 if (    !ulParent
    2819                                      || lAddressOnParent == -1
    2820                                    )
    2821                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2822                                                    tr("Missing or bad extra config string in hard disk image: \"%s\""), desc.strExtraConfig.c_str());
    2823 
    2824                                 mapDisks[strDiskID] = &desc;
    2825                             }
    2826                         break;
    2827 
    2828                         case VirtualSystemDescriptionType_Floppy:
    2829                             if (uLoop == 1)
    2830                             {
    2831                                 strDescription = "Floppy Drive";
    2832                                 strCaption = "floppy0";         // this is what OVFTool writes
    2833                                 type = OVFResourceType_FloppyDrive; // 14
    2834                                 lAutomaticAllocation = 0;
    2835                                 lAddressOnParent = 0;           // this is what OVFTool writes
    2836                             }
    2837                         break;
    2838 
    2839                         case VirtualSystemDescriptionType_CDROM:
    2840                             if (uLoop == 2)
    2841                             {
    2842                                 // we can't have a CD without an IDE controller
    2843                                 if (!idIDEController)
    2844                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2845                                                    tr("Can't have CD-ROM without IDE controller"));
    2846 
    2847                                 strDescription = "CD-ROM Drive";
    2848                                 strCaption = "cdrom1";          // this is what OVFTool writes
    2849                                 type = OVFResourceType_CDDrive; // 15
    2850                                 lAutomaticAllocation = 1;
    2851                                 ulParent = idIDEController;
    2852                                 lAddressOnParent = 0;           // this is what OVFTool writes
    2853                             }
    2854                         break;
    2855 
    2856                         case VirtualSystemDescriptionType_NetworkAdapter:
    2857                             /* <Item>
    2858                                     <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
    2859                                     <rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
    2860                                     <rasd:Connection>VM Network</rasd:Connection>
    2861                                     <rasd:ElementName>VM network</rasd:ElementName>
    2862                                     <rasd:InstanceID>3</rasd:InstanceID>
    2863                                     <rasd:ResourceType>10</rasd:ResourceType>
    2864                                 </Item> */
    2865                             if (uLoop == 1)
    2866                             {
    2867                                 lAutomaticAllocation = 1;
    2868                                 strCaption = Utf8StrFmt("Ethernet adapter on '%s'", desc.strOvf.c_str());
    2869                                 type = OVFResourceType_EthernetAdapter; // 10
    2870                                 /* Set the hardware type to something useful.
    2871                                  * To be compatible with vmware & others we set
    2872                                  * PCNet32 for our PCNet types & E1000 for the
    2873                                  * E1000 cards. */
    2874                                 switch (desc.strVbox.toInt32())
    2875                                 {
    2876                                     case NetworkAdapterType_Am79C970A:
    2877                                     case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break;
    2878 #ifdef VBOX_WITH_E1000
    2879                                     case NetworkAdapterType_I82540EM:
    2880                                     case NetworkAdapterType_I82545EM:
    2881                                     case NetworkAdapterType_I82543GC: strResourceSubType = "E1000"; break;
    2882 #endif /* VBOX_WITH_E1000 */
    2883                                 }
    2884                                 strConnection = desc.strOvf;
    2885 
    2886                                 mapNetworks[desc.strOvf] = true;
    2887                             }
    2888                         break;
    2889 
    2890                         case VirtualSystemDescriptionType_USBController:
    2891                             /*  <Item ovf:required="false">
    2892                                     <rasd:Caption>usb</rasd:Caption>
    2893                                     <rasd:Description>USB Controller</rasd:Description>
    2894                                     <rasd:InstanceId>3</rasd:InstanceId>
    2895                                     <rasd:ResourceType>23</rasd:ResourceType>
    2896                                     <rasd:Address>0</rasd:Address>
    2897                                     <rasd:BusNumber>0</rasd:BusNumber>
    2898                                 </Item> */
    2899                             if (uLoop == 1)
    2900                             {
    2901                                 strDescription = "USB Controller";
    2902                                 strCaption = "usb";
    2903                                 type = OVFResourceType_USBController; // 23
    2904                                 lAddress = 0;                   // this is what OVFTool writes
    2905                                 lBusNumber = 0;                 // this is what OVFTool writes
    2906                             }
    2907                         break;
    2908 
    2909                        case VirtualSystemDescriptionType_SoundCard:
    2910                         /*  <Item ovf:required="false">
    2911                                 <rasd:Caption>sound</rasd:Caption>
    2912                                 <rasd:Description>Sound Card</rasd:Description>
    2913                                 <rasd:InstanceId>10</rasd:InstanceId>
    2914                                 <rasd:ResourceType>35</rasd:ResourceType>
    2915                                 <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
    2916                                 <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
    2917                                 <rasd:AddressOnParent>3</rasd:AddressOnParent>
    2918                             </Item> */
    2919                             if (uLoop == 1)
    2920                             {
    2921                                 strDescription = "Sound Card";
    2922                                 strCaption = "sound";
    2923                                 type = OVFResourceType_SoundCard; // 35
    2924                                 strResourceSubType = desc.strOvf;       // e.g. ensoniq1371
    2925                                 lAutomaticAllocation = 0;
    2926                                 lAddressOnParent = 3;               // what gives? this is what OVFTool writes
    2927                             }
    2928                         break;
    2929                     }
    2930 
    2931                     if (type)
    2932                     {
    2933                         xml::ElementNode *pItem;
    2934 
    2935                         pItem = pelmVirtualHardwareSection->createChild("Item");
    2936 
    2937                         // NOTE: do not change the order of these items without good reason! While we don't care
    2938                         // about ordering, VMware's ovftool does and fails if the items are not written in
    2939                         // exactly this order, as stupid as it seems.
    2940 
    2941                         if (!strCaption.isEmpty())
    2942                         {
    2943                             pItem->createChild("rasd:Caption")->addContent(strCaption);
    2944                             if (pTask->enFormat == TaskExportOVF::OVF_1_0)
    2945                                 pItem->createChild("rasd:ElementName")->addContent(strCaption);
    2946                         }
    2947 
    2948                         if (!strDescription.isEmpty())
    2949                             pItem->createChild("rasd:Description")->addContent(strDescription);
    2950 
    2951                         // <rasd:InstanceID>1</rasd:InstanceID>
    2952                         xml::ElementNode *pelmInstanceID;
    2953                         if (pTask->enFormat == TaskExportOVF::OVF_0_9)
    2954                             pelmInstanceID = pItem->createChild("rasd:InstanceId");
    2955                         else
    2956                             pelmInstanceID = pItem->createChild("rasd:InstanceID");      // capitalization changed...
    2957                         pelmInstanceID->addContent(Utf8StrFmt("%d", ulInstanceID++));
    2958 
    2959                         // <rasd:ResourceType>3</rasd:ResourceType>
    2960                         pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type));
    2961                         if (!strResourceSubType.isEmpty())
    2962                             pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType);
    2963 
    2964                         if (!strHostResource.isEmpty())
    2965                             pItem->createChild("rasd:HostResource")->addContent(strHostResource);
    2966 
    2967                         if (!strAllocationUnits.isEmpty())
    2968                             pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits);
    2969 
    2970                         // <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
    2971                         if (lVirtualQuantity != -1)
    2972                             pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity));
    2973 
    2974                         if (lAutomaticAllocation != -1)
    2975                             pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" );
    2976 
    2977                         if (!strConnection.isEmpty())
    2978                             pItem->createChild("rasd:Connection")->addContent(strConnection);
    2979 
    2980                         if (lAddress != -1)
    2981                             pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress));
    2982 
    2983                         if (lBusNumber != -1)
    2984                             if (pTask->enFormat == TaskExportOVF::OVF_0_9) // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool compatibility
    2985                                 pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber));
    2986 
    2987                         if (ulParent)
    2988                             pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent));
    2989                         if (lAddressOnParent != -1)
    2990                             pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent));
    2991                     }
    2992                 }
    2993             } // for (size_t uLoop = 0; ...
    2994         }
    2995 
    2996         // now, fill in the network section we set up empty above according
    2997         // to the networks we found with the hardware items
    2998         map<Utf8Str, bool>::const_iterator itN;
    2999         for (itN = mapNetworks.begin();
    3000              itN != mapNetworks.end();
    3001              ++itN)
    3002         {
    3003             const Utf8Str &strNetwork = itN->first;
    3004             xml::ElementNode *pelmNetwork = pelmNetworkSection->createChild("Network");
    3005             pelmNetwork->setAttribute("ovf:name", strNetwork.c_str());
    3006             pelmNetwork->createChild("Description")->addContent("Logical network used by this appliance.");
    3007         }
    3008 
    3009         // Finally, write out the disks!
    3010 
    3011         // This can take a very long time so leave the locks; in particular, we have the media tree
    3012         // lock which Medium::CloneTo() will request, and that would deadlock. Instead, protect
    3013         // the appliance by resetting its state so we can safely leave the lock
    3014         m->state = Data::ApplianceExporting;
    3015         multiLock.release();
    3016 
    3017         list<Utf8Str> diskList;
    3018         map<Utf8Str, const VirtualSystemDescriptionEntry*>::const_iterator itS;
    3019         uint32_t ulFile = 1;
    3020         for (itS = mapDisks.begin();
    3021              itS != mapDisks.end();
    3022              ++itS)
    3023         {
    3024             const Utf8Str &strDiskID = itS->first;
    3025             const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
    3026 
    3027             // source path: where the VBox image is
    3028             const Utf8Str &strSrcFilePath = pDiskEntry->strVbox;
    3029             Bstr bstrSrcFilePath(strSrcFilePath);
    3030             if (!RTPathExists(strSrcFilePath.c_str()))
    3031                 /* This isn't allowed */
    3032                 throw setError(VBOX_E_FILE_ERROR,
    3033                                tr("Source virtual disk image file '%s' doesn't exist"),
    3034                                strSrcFilePath.c_str());
    3035 
    3036             // output filename
    3037             const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
    3038             // target path needs to be composed from where the output OVF is
    3039             Utf8Str strTargetFilePath(pTask->locInfo.strPath);
    3040             strTargetFilePath.stripFilename();
    3041             strTargetFilePath.append("/");
    3042             strTargetFilePath.append(strTargetFileNameOnly);
    3043 
    3044             // clone the disk:
    3045             ComPtr<IMedium> pSourceDisk;
    3046             ComPtr<IMedium> pTargetDisk;
    3047             ComPtr<IProgress> pProgress2;
    3048 
    3049             Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
    3050             rc = mVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());
    3051             if (FAILED(rc)) throw rc;
    3052 
    3053             /* We are always exporting to vmdfk stream optimized for now */
    3054             Bstr bstrSrcFormat = L"VMDK";
    3055 
    3056             // create a new hard disk interface for the destination disk image
    3057             Log(("Creating target disk \"%s\"\n", strTargetFilePath.raw()));
    3058             rc = mVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam());
    3059             if (FAILED(rc)) throw rc;
    3060 
    3061             // the target disk is now registered and needs to be removed again,
    3062             // both after successful cloning or if anything goes bad!
    3063             try
    3064             {
    3065                 // create a flat copy of the source disk image
    3066                 rc = pSourceDisk->CloneTo(pTargetDisk, MediumVariant_VmdkStreamOptimized, NULL, pProgress2.asOutParam());
    3067                 if (FAILED(rc)) throw rc;
    3068 
    3069                 // advance to the next operation
    3070                 if (!pTask->progress.isNull())
    3071                     pTask->progress->SetNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),
    3072                                                       pDiskEntry->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
    3073 
    3074                 // now wait for the background disk operation to complete; this throws HRESULTs on error
    3075                 waitForAsyncProgress(pTask->progress, pProgress2);
    3076             }
    3077             catch (HRESULT rc3)
    3078             {
    3079                 // upon error after registering, close the disk or
    3080                 // it'll stick in the registry forever
    3081                 pTargetDisk->Close();
    3082                 throw rc3;
    3083             }
    3084             diskList.push_back(strTargetFilePath);
    3085 
    3086             // we need the following for the XML
    3087             uint64_t cbFile = 0;        // actual file size
    3088             rc = pTargetDisk->COMGETTER(Size)(&cbFile);
    3089             if (FAILED(rc)) throw rc;
    3090 
    3091             ULONG64 cbCapacity = 0;     // size reported to guest
    3092             rc = pTargetDisk->COMGETTER(LogicalSize)(&cbCapacity);
    3093             if (FAILED(rc)) throw rc;
    3094             // capacity is reported in megabytes, so...
    3095             cbCapacity *= _1M;
    3096 
    3097             // upon success, close the disk as well
    3098             rc = pTargetDisk->Close();
    3099             if (FAILED(rc)) throw rc;
    3100 
    3101             // now handle the XML for the disk:
    3102             Utf8StrFmt strFileRef("file%RI32", ulFile++);
    3103             // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
    3104             xml::ElementNode *pelmFile = pelmReferences->createChild("File");
    3105             pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
    3106             pelmFile->setAttribute("ovf:id", strFileRef);
    3107             pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
    3108 
    3109             // add disk to XML Disks section
    3110             // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse"/>
    3111             xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
    3112             pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
    3113             pelmDisk->setAttribute("ovf:diskId", strDiskID);
    3114             pelmDisk->setAttribute("ovf:fileRef", strFileRef);
    3115             pelmDisk->setAttribute("ovf:format", "http://www.vmware.com/specifications/vmdk.html#sparse");      // must be sparse or ovftool chokes
    3116         }
    3117 
    3118         // now go write the XML
    3119         xml::XmlFileWriter writer(doc);
    3120         writer.write(pTask->locInfo.strPath.c_str());
    3121 
    3122         /* Create & write the manifest file */
    3123         const char** ppManifestFiles = (const char**)RTMemAlloc(sizeof(char*)*diskList.size() + 1);
    3124         ppManifestFiles[0] = pTask->locInfo.strPath.c_str();
    3125         list<Utf8Str>::const_iterator it1;
    3126         size_t i = 1;
    3127         for (it1 = diskList.begin();
    3128              it1 != diskList.end();
    3129              ++it1, ++i)
    3130             ppManifestFiles[i] = (*it1).c_str();
    3131         Utf8Str strMfFile = manifestFileName(pTask->locInfo.strPath.c_str());
    3132         int vrc = RTManifestWriteFiles(strMfFile.c_str(), ppManifestFiles, diskList.size()+1);
    3133         if (RT_FAILURE(vrc))
    3134             throw setError(VBOX_E_FILE_ERROR,
    3135                            tr("Couldn't create manifest file '%s' (%Rrc)"),
    3136                            RTPathFilename(strMfFile.c_str()), vrc);
    3137         RTMemFree(ppManifestFiles);
    3138     }
    3139     catch(xml::Error &x)
    3140     {
    3141         rc = setError(VBOX_E_FILE_ERROR,
    3142                       x.what());
    3143     }
    3144     catch(HRESULT aRC)
    3145     {
    3146         rc = aRC;
    3147     }
    3148 
    3149     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    3150     // reset the state so others can call methods again
    3151     m->state = Data::ApplianceIdle;
    3152 
    3153     pTask->rc = rc;
    3154 
    3155     if (!pTask->progress.isNull())
    3156         pTask->progress->notifyComplete(rc);
    3157 
    3158     LogFlowFunc(("rc=%Rhrc\n", rc));
    3159     LogFlowFuncLeave();
    3160 
    3161     return VINF_SUCCESS;
    3162 }
    3163 
    3164 int Appliance::writeS3(TaskExportOVF *pTask)
    3165 {
    3166     LogFlowFuncEnter();
    3167     LogFlowFunc(("Appliance %p\n", this));
    3168 
    3169     AutoCaller autoCaller(this);
    3170     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3171 
    3172     HRESULT rc = S_OK;
    3173 
    3174     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    3175 
    3176     int vrc = VINF_SUCCESS;
    3177     RTS3 hS3 = NIL_RTS3;
    3178     char szOSTmpDir[RTPATH_MAX];
    3179     RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
    3180     /* The template for the temporary directory created below */
    3181     char *pszTmpDir;
    3182     RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
    3183     list< pair<Utf8Str, ULONG> > filesList;
    3184 
    3185     // todo:
    3186     // - usable error codes
    3187     // - seems snapshot filenames are problematic {uuid}.vdi
    3188     try
    3189     {
    3190         /* Extract the bucket */
    3191         Utf8Str tmpPath = pTask->locInfo.strPath;
    3192         Utf8Str bucket;
    3193         parseBucket(tmpPath, bucket);
    3194 
    3195         /* We need a temporary directory which we can put the OVF file & all
    3196          * disk images in */
    3197         vrc = RTDirCreateTemp(pszTmpDir);
    3198         if (RT_FAILURE(vrc))
    3199             throw setError(VBOX_E_FILE_ERROR,
    3200                            tr("Cannot create temporary directory '%s'"), pszTmpDir);
    3201 
    3202         /* The temporary name of the target OVF file */
    3203         Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str()));
    3204 
    3205         /* Prepare the temporary writing of the OVF */
    3206         ComObjPtr<Progress> progress;
    3207         /* Create a temporary file based location info for the sub task */
    3208         LocationInfo li;
    3209         li.strPath = strTmpOvf;
    3210         rc = writeImpl(pTask->enFormat, li, progress);
    3211         if (FAILED(rc)) throw rc;
    3212 
    3213         /* Unlock the appliance for the writing thread */
    3214         appLock.release();
    3215         /* Wait until the writing is done, but report the progress back to the
    3216            caller */
    3217         ComPtr<IProgress> progressInt(progress);
    3218         waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
    3219 
    3220         /* Again lock the appliance for the next steps */
    3221         appLock.acquire();
    3222 
    3223         vrc = RTPathExists(strTmpOvf.c_str()); /* Paranoid check */
    3224         if(RT_FAILURE(vrc))
    3225             throw setError(VBOX_E_FILE_ERROR,
    3226                            tr("Cannot find source file '%s'"), strTmpOvf.c_str());
    3227         /* Add the OVF file */
    3228         filesList.push_back(pair<Utf8Str, ULONG>(strTmpOvf, m->ulWeightPerOperation)); /* Use 1% of the total for the OVF file upload */
    3229         Utf8Str strMfFile = manifestFileName(strTmpOvf);
    3230         filesList.push_back(pair<Utf8Str, ULONG>(strMfFile , m->ulWeightPerOperation)); /* Use 1% of the total for the manifest file upload */
    3231 
    3232         /* Now add every disks of every virtual system */
    3233         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    3234         for (it = m->virtualSystemDescriptions.begin();
    3235              it != m->virtualSystemDescriptions.end();
    3236              ++it)
    3237         {
    3238             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    3239             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    3240             std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    3241             for (itH = avsdeHDs.begin();
    3242                  itH != avsdeHDs.end();
    3243                  ++itH)
    3244             {
    3245                 const Utf8Str &strTargetFileNameOnly = (*itH)->strOvf;
    3246                 /* Target path needs to be composed from where the output OVF is */
    3247                 Utf8Str strTargetFilePath(strTmpOvf);
    3248                 strTargetFilePath.stripFilename();
    3249                 strTargetFilePath.append("/");
    3250                 strTargetFilePath.append(strTargetFileNameOnly);
    3251                 vrc = RTPathExists(strTargetFilePath.c_str()); /* Paranoid check */
    3252                 if(RT_FAILURE(vrc))
    3253                     throw setError(VBOX_E_FILE_ERROR,
    3254                                    tr("Cannot find source file '%s'"), strTargetFilePath.c_str());
    3255                 filesList.push_back(pair<Utf8Str, ULONG>(strTargetFilePath, (*itH)->ulSizeMB));
    3256             }
    3257         }
    3258         /* Next we have to upload the OVF & all disk images */
    3259         vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
    3260         if(RT_FAILURE(vrc))
    3261             throw setError(VBOX_E_IPRT_ERROR,
    3262                            tr("Cannot create S3 service handler"));
    3263         RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
    3264 
    3265         /* Upload all files */
    3266         for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    3267         {
    3268             const pair<Utf8Str, ULONG> &s = (*it1);
    3269             char *pszFilename = RTPathFilename(s.first.c_str());
    3270             /* Advance to the next operation */
    3271             if (!pTask->progress.isNull())
    3272                 pTask->progress->SetNextOperation(BstrFmt(tr("Uploading file '%s'"), pszFilename), s.second);
    3273             vrc = RTS3PutKey(hS3, bucket.c_str(), pszFilename, s.first.c_str());
    3274             if (RT_FAILURE(vrc))
    3275             {
    3276                 if(vrc == VERR_S3_CANCELED)
    3277                     break;
    3278                 else if(vrc == VERR_S3_ACCESS_DENIED)
    3279                     throw setError(E_ACCESSDENIED,
    3280                                    tr("Cannot upload file '%s' to S3 storage server (Access denied). Make sure that your credentials are right. Also check that your host clock is properly synced"), pszFilename);
    3281                 else if(vrc == VERR_S3_NOT_FOUND)
    3282                     throw setError(VBOX_E_FILE_ERROR,
    3283                                    tr("Cannot upload file '%s' to S3 storage server (File not found)"), pszFilename);
    3284                 else
    3285                     throw setError(VBOX_E_IPRT_ERROR,
    3286                                    tr("Cannot upload file '%s' to S3 storage server (%Rrc)"), pszFilename, vrc);
    3287             }
    3288         }
    3289     }
    3290     catch(HRESULT aRC)
    3291     {
    3292         rc = aRC;
    3293     }
    3294     /* Cleanup */
    3295     RTS3Destroy(hS3);
    3296     /* Delete all files which where temporary created */
    3297     for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    3298     {
    3299         const char *pszFilePath = (*it1).first.c_str();
    3300         if (RTPathExists(pszFilePath))
    3301         {
    3302             vrc = RTFileDelete(pszFilePath);
    3303             if(RT_FAILURE(vrc))
    3304                 rc = setError(VBOX_E_FILE_ERROR,
    3305                               tr("Cannot delete file '%s' (%Rrc)"), pszFilePath, vrc);
    3306         }
    3307     }
    3308     /* Delete the temporary directory */
    3309     if (RTPathExists(pszTmpDir))
    3310     {
    3311         vrc = RTDirRemove(pszTmpDir);
    3312         if(RT_FAILURE(vrc))
    3313             rc = setError(VBOX_E_FILE_ERROR,
    3314                           tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
    3315     }
    3316     if (pszTmpDir)
    3317         RTStrFree(pszTmpDir);
    3318 
    3319     pTask->rc = rc;
    3320 
    3321     if (!pTask->progress.isNull())
    3322         pTask->progress->notifyComplete(rc);
    3323 
    3324     LogFlowFunc(("rc=%Rhrc\n", rc));
    3325     LogFlowFuncLeave();
    3326 
    3327     return VINF_SUCCESS;
    3328 }
    3329 
    3330 ////////////////////////////////////////////////////////////////////////////////
    3331 //
    3332 // IAppliance public methods
    3333 //
    3334 ////////////////////////////////////////////////////////////////////////////////
    3335 
    3336 /**
    3337  * Public method implementation.
    3338  * @param
    3339  * @return
    3340  */
    3341 STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
    3342 {
    3343     if (!aPath)
    3344         return E_POINTER;
    3345 
    3346     AutoCaller autoCaller(this);
    3347     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3348 
    3349     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3350 
    3351     if (!isApplianceIdle())
    3352         return E_ACCESSDENIED;
    3353 
    3354     Bstr bstrPath(m->locInfo.strPath);
    3355     bstrPath.cloneTo(aPath);
    3356 
    3357     return S_OK;
    3358 }
    3359 
    3360 /**
    3361  * Public method implementation.
    3362  * @param
    3363  * @return
    3364  */
    3365 STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
    3366 {
    3367     CheckComArgOutSafeArrayPointerValid(aDisks);
    3368 
    3369     AutoCaller autoCaller(this);
    3370     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3371 
    3372     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3373 
    3374     if (!isApplianceIdle())
    3375         return E_ACCESSDENIED;
    3376 
    3377     if (m->pReader) // OVFReader instantiated?
    3378     {
    3379         size_t c = m->pReader->m_mapDisks.size();
    3380         com::SafeArray<BSTR> sfaDisks(c);
    3381 
    3382         DiskImagesMap::const_iterator it;
    3383         size_t i = 0;
    3384         for (it = m->pReader->m_mapDisks.begin();
    3385              it != m->pReader->m_mapDisks.end();
    3386              ++it, ++i)
    3387         {
    3388             // create a string representing this disk
    3389             const DiskImage &d = it->second;
    3390             char *psz = NULL;
    3391             RTStrAPrintf(&psz,
    3392                          "%s\t"
    3393                          "%RI64\t"
    3394                          "%RI64\t"
    3395                          "%s\t"
    3396                          "%s\t"
    3397                          "%RI64\t"
    3398                          "%RI64\t"
    3399                          "%s",
    3400                          d.strDiskId.c_str(),
    3401                          d.iCapacity,
    3402                          d.iPopulatedSize,
    3403                          d.strFormat.c_str(),
    3404                          d.strHref.c_str(),
    3405                          d.iSize,
    3406                          d.iChunkSize,
    3407                          d.strCompression.c_str());
    3408             Utf8Str utf(psz);
    3409             Bstr bstr(utf);
    3410             // push to safearray
    3411             bstr.cloneTo(&sfaDisks[i]);
    3412             RTStrFree(psz);
    3413         }
    3414 
    3415         sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
    3416     }
    3417 
    3418     return S_OK;
    3419 }
    3420 
    3421 /**
    3422  * Public method implementation.
    3423  * @param
    3424  * @return
    3425  */
    3426 STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
    3427 {
    3428     CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
    3429 
    3430     AutoCaller autoCaller(this);
    3431     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3432 
    3433     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3434 
    3435     if (!isApplianceIdle())
    3436         return E_ACCESSDENIED;
    3437 
    3438     SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
    3439     sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
    3440 
    3441     return S_OK;
    3442 }
    3443 
    3444 /**
    3445  * Public method implementation.
    3446  * @param path
    3447  * @return
    3448  */
    3449 STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress)
    3450 {
    3451     if (!path) return E_POINTER;
    3452     CheckComArgOutPointerValid(aProgress);
    3453 
    3454     AutoCaller autoCaller(this);
    3455     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3456 
    3457     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3458 
    3459     if (!isApplianceIdle())
    3460         return E_ACCESSDENIED;
    3461 
    3462     if (m->pReader)
    3463     {
    3464         delete m->pReader;
    3465         m->pReader = NULL;
    3466     }
    3467 
    3468     // see if we can handle this file; for now we insist it has an ".ovf" extension
    3469     Utf8Str strPath (path);
    3470     if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    3471         return setError(VBOX_E_FILE_ERROR,
    3472                         tr("Appliance file must have .ovf extension"));
    3473 
    3474     ComObjPtr<Progress> progress;
    3475     HRESULT rc = S_OK;
    3476     try
    3477     {
    3478         /* Parse all necessary info out of the URI */
    3479         parseURI(strPath, m->locInfo);
    3480         rc = readImpl(m->locInfo, progress);
    3481     }
    3482     catch (HRESULT aRC)
    3483     {
    3484         rc = aRC;
    3485     }
    3486 
    3487     if (SUCCEEDED(rc))
    3488         /* Return progress to the caller */
    3489         progress.queryInterfaceTo(aProgress);
    3490 
    3491     return S_OK;
    3492 }
    3493 
    3494 /**
    3495  * Public method implementation.
    3496  * @return
    3497  */
    3498 STDMETHODIMP Appliance::Interpret()
    3499 {
    3500     // @todo:
    3501     //  - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
    3502     //  - Appropriate handle errors like not supported file formats
    3503     AutoCaller autoCaller(this);
    3504     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3505 
    3506     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3507 
    3508     if (!isApplianceIdle())
    3509         return E_ACCESSDENIED;
    3510 
    3511     HRESULT rc = S_OK;
    3512 
    3513     /* Clear any previous virtual system descriptions */
    3514     m->virtualSystemDescriptions.clear();
    3515 
    3516     /* We need the default path for storing disk images */
    3517     ComPtr<ISystemProperties> systemProps;
    3518     rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
    3519     if (FAILED(rc)) return rc;
    3520     Bstr bstrDefaultHardDiskLocation;
    3521     rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskLocation.asOutParam());
    3522     if (FAILED(rc)) return rc;
    3523 
    3524     if (!m->pReader)
    3525         return setError(E_FAIL,
    3526                         tr("Cannot interpret appliance without reading it first (call read() before interpret())"));
    3527 
    3528     // Change the appliance state so we can safely leave the lock while doing time-consuming
    3529     // disk imports; also the below method calls do all kinds of locking which conflicts with
    3530     // the appliance object lock
    3531     m->state = Data::ApplianceImporting;
    3532     alock.release();
    3533 
    3534     /* Try/catch so we can clean up on error */
    3535     try
    3536     {
    3537         list<VirtualSystem>::const_iterator it;
    3538         /* Iterate through all virtual systems */
    3539         for (it = m->pReader->m_llVirtualSystems.begin();
    3540              it != m->pReader->m_llVirtualSystems.end();
    3541              ++it)
    3542         {
    3543             const VirtualSystem &vsysThis = *it;
    3544 
    3545             ComObjPtr<VirtualSystemDescription> pNewDesc;
    3546             rc = pNewDesc.createObject();
    3547             if (FAILED(rc)) throw rc;
    3548             rc = pNewDesc->init();
    3549             if (FAILED(rc)) throw rc;
    3550 
    3551             /* Guest OS type */
    3552             Utf8Str strOsTypeVBox,
    3553                     strCIMOSType = Utf8StrFmt("%RI32", (uint32_t)vsysThis.cimos);
    3554             convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos, vsysThis.strCimosDesc);
    3555             pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
    3556                                "",
    3557                                strCIMOSType,
    3558                                strOsTypeVBox);
    3559 
    3560             /* VM name */
    3561             /* If the there isn't any name specified create a default one out of
    3562              * the OS type */
    3563             Utf8Str nameVBox = vsysThis.strName;
    3564             if (nameVBox.isEmpty())
    3565                 nameVBox = strOsTypeVBox;
    3566             searchUniqueVMName(nameVBox);
    3567             pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
    3568                                "",
    3569                                vsysThis.strName,
    3570                                nameVBox);
    3571 
    3572             /* VM Product */
    3573             if (!vsysThis.strProduct.isEmpty())
    3574                 pNewDesc->addEntry(VirtualSystemDescriptionType_Product,
    3575                                     "",
    3576                                     vsysThis.strProduct,
    3577                                     vsysThis.strProduct);
    3578 
    3579             /* VM Vendor */
    3580             if (!vsysThis.strVendor.isEmpty())
    3581                 pNewDesc->addEntry(VirtualSystemDescriptionType_Vendor,
    3582                                     "",
    3583                                     vsysThis.strVendor,
    3584                                     vsysThis.strVendor);
    3585 
    3586             /* VM Version */
    3587             if (!vsysThis.strVersion.isEmpty())
    3588                 pNewDesc->addEntry(VirtualSystemDescriptionType_Version,
    3589                                     "",
    3590                                     vsysThis.strVersion,
    3591                                     vsysThis.strVersion);
    3592 
    3593             /* VM ProductUrl */
    3594             if (!vsysThis.strProductUrl.isEmpty())
    3595                 pNewDesc->addEntry(VirtualSystemDescriptionType_ProductUrl,
    3596                                     "",
    3597                                     vsysThis.strProductUrl,
    3598                                     vsysThis.strProductUrl);
    3599 
    3600             /* VM VendorUrl */
    3601             if (!vsysThis.strVendorUrl.isEmpty())
    3602                 pNewDesc->addEntry(VirtualSystemDescriptionType_VendorUrl,
    3603                                     "",
    3604                                     vsysThis.strVendorUrl,
    3605                                     vsysThis.strVendorUrl);
    3606 
    3607             /* VM description */
    3608             if (!vsysThis.strDescription.isEmpty())
    3609                 pNewDesc->addEntry(VirtualSystemDescriptionType_Description,
    3610                                     "",
    3611                                     vsysThis.strDescription,
    3612                                     vsysThis.strDescription);
    3613 
    3614             /* VM license */
    3615             if (!vsysThis.strLicenseText.isEmpty())
    3616                 pNewDesc->addEntry(VirtualSystemDescriptionType_License,
    3617                                     "",
    3618                                     vsysThis.strLicenseText,
    3619                                     vsysThis.strLicenseText);
    3620 
    3621             /* Now that we know the OS type, get our internal defaults based on that. */
    3622             ComPtr<IGuestOSType> pGuestOSType;
    3623             rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), pGuestOSType.asOutParam());
    3624             if (FAILED(rc)) throw rc;
    3625 
    3626             /* CPU count */
    3627             ULONG cpuCountVBox = vsysThis.cCPUs;
    3628             /* Check for the constrains */
    3629             if (cpuCountVBox > SchemaDefs::MaxCPUCount)
    3630             {
    3631                 addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
    3632                            vsysThis.strName.c_str(), cpuCountVBox, SchemaDefs::MaxCPUCount);
    3633                 cpuCountVBox = SchemaDefs::MaxCPUCount;
    3634             }
    3635             if (vsysThis.cCPUs == 0)
    3636                 cpuCountVBox = 1;
    3637             pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
    3638                                "",
    3639                                Utf8StrFmt("%RI32", (uint32_t)vsysThis.cCPUs),
    3640                                Utf8StrFmt("%RI32", (uint32_t)cpuCountVBox));
    3641 
    3642             /* RAM */
    3643             uint64_t ullMemSizeVBox = vsysThis.ullMemorySize / _1M;
    3644             /* Check for the constrains */
    3645             if (ullMemSizeVBox != 0 &&
    3646                 (ullMemSizeVBox < MM_RAM_MIN_IN_MB ||
    3647                  ullMemSizeVBox > MM_RAM_MAX_IN_MB))
    3648             {
    3649                 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."),
    3650                               vsysThis.strName.c_str(), ullMemSizeVBox, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
    3651                 ullMemSizeVBox = RT_MIN(RT_MAX(ullMemSizeVBox, MM_RAM_MIN_IN_MB), MM_RAM_MAX_IN_MB);
    3652             }
    3653             if (vsysThis.ullMemorySize == 0)
    3654             {
    3655                 /* If the RAM of the OVF is zero, use our predefined values */
    3656                 ULONG memSizeVBox2;
    3657                 rc = pGuestOSType->COMGETTER(RecommendedRAM)(&memSizeVBox2);
    3658                 if (FAILED(rc)) throw rc;
    3659                 /* VBox stores that in MByte */
    3660                 ullMemSizeVBox = (uint64_t)memSizeVBox2;
    3661             }
    3662             pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
    3663                                "",
    3664                                Utf8StrFmt("%RI64", (uint64_t)vsysThis.ullMemorySize),
    3665                                Utf8StrFmt("%RI64", (uint64_t)ullMemSizeVBox));
    3666 
    3667             /* Audio */
    3668             if (!vsysThis.strSoundCardType.isEmpty())
    3669                 /* Currently we set the AC97 always.
    3670                    @todo: figure out the hardware which could be possible */
    3671                 pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
    3672                                    "",
    3673                                    vsysThis.strSoundCardType,
    3674                                    Utf8StrFmt("%RI32", (uint32_t)AudioControllerType_AC97));
    3675 
    3676 #ifdef VBOX_WITH_USB
    3677             /* USB Controller */
    3678             if (vsysThis.fHasUsbController)
    3679                 pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
    3680 #endif /* VBOX_WITH_USB */
    3681 
    3682             /* Network Controller */
    3683             size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size();
    3684             if (cEthernetAdapters > 0)
    3685             {
    3686                 /* Check for the constrains */
    3687                 if (cEthernetAdapters > SchemaDefs::NetworkAdapterCount)
    3688                     addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
    3689                                   vsysThis.strName.c_str(), cEthernetAdapters, SchemaDefs::NetworkAdapterCount);
    3690 
    3691                 /* Get the default network adapter type for the selected guest OS */
    3692                 NetworkAdapterType_T defaultAdapterVBox = NetworkAdapterType_Am79C970A;
    3693                 rc = pGuestOSType->COMGETTER(AdapterType)(&defaultAdapterVBox);
    3694                 if (FAILED(rc)) throw rc;
    3695 
    3696                 EthernetAdaptersList::const_iterator itEA;
    3697                 /* Iterate through all abstract networks. We support 8 network
    3698                  * adapters at the maximum, so the first 8 will be added only. */
    3699                 size_t a = 0;
    3700                 for (itEA = vsysThis.llEthernetAdapters.begin();
    3701                      itEA != vsysThis.llEthernetAdapters.end() && a < SchemaDefs::NetworkAdapterCount;
    3702                      ++itEA, ++a)
    3703                 {
    3704                     const EthernetAdapter &ea = *itEA; // logical network to connect to
    3705                     Utf8Str strNetwork = ea.strNetworkName;
    3706                     // make sure it's one of these two
    3707                     if (    (strNetwork.compare("Null", Utf8Str::CaseInsensitive))
    3708                          && (strNetwork.compare("NAT", Utf8Str::CaseInsensitive))
    3709                          && (strNetwork.compare("Bridged", Utf8Str::CaseInsensitive))
    3710                          && (strNetwork.compare("Internal", Utf8Str::CaseInsensitive))
    3711                          && (strNetwork.compare("HostOnly", Utf8Str::CaseInsensitive))
    3712                        )
    3713                         strNetwork = "Bridged";     // VMware assumes this is the default apparently
    3714 
    3715                     /* Figure out the hardware type */
    3716                     NetworkAdapterType_T nwAdapterVBox = defaultAdapterVBox;
    3717                     if (!ea.strAdapterType.compare("PCNet32", Utf8Str::CaseInsensitive))
    3718                     {
    3719                         /* If the default adapter is already one of the two
    3720                          * PCNet adapters use the default one. If not use the
    3721                          * Am79C970A as fallback. */
    3722                         if (!(defaultAdapterVBox == NetworkAdapterType_Am79C970A ||
    3723                               defaultAdapterVBox == NetworkAdapterType_Am79C973))
    3724                             nwAdapterVBox = NetworkAdapterType_Am79C970A;
    3725                     }
    3726 #ifdef VBOX_WITH_E1000
    3727                     /* VMWare accidentally write this with VirtualCenter 3.5,
    3728                        so make sure in this case always to use the VMWare one */
    3729                     else if (!ea.strAdapterType.compare("E10000", Utf8Str::CaseInsensitive))
    3730                         nwAdapterVBox = NetworkAdapterType_I82545EM;
    3731                     else if (!ea.strAdapterType.compare("E1000", Utf8Str::CaseInsensitive))
    3732                     {
    3733                         /* Check if this OVF was written by VirtualBox */
    3734                         if (Utf8Str(vsysThis.strVirtualSystemType).contains("virtualbox", Utf8Str::CaseInsensitive))
    3735                         {
    3736                             /* If the default adapter is already one of the three
    3737                              * E1000 adapters use the default one. If not use the
    3738                              * I82545EM as fallback. */
    3739                             if (!(defaultAdapterVBox == NetworkAdapterType_I82540EM ||
    3740                                   defaultAdapterVBox == NetworkAdapterType_I82543GC ||
    3741                                   defaultAdapterVBox == NetworkAdapterType_I82545EM))
    3742                             nwAdapterVBox = NetworkAdapterType_I82540EM;
    3743                         }
    3744                         else
    3745                             /* Always use this one since it's what VMware uses */
    3746                             nwAdapterVBox = NetworkAdapterType_I82545EM;
    3747                     }
    3748 #endif /* VBOX_WITH_E1000 */
    3749 
    3750                     pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
    3751                                        "",      // ref
    3752                                        ea.strNetworkName,      // orig
    3753                                        Utf8StrFmt("%RI32", (uint32_t)nwAdapterVBox),   // conf
    3754                                        0,
    3755                                        Utf8StrFmt("type=%s", strNetwork.c_str()));       // extra conf
    3756                 }
    3757             }
    3758 
    3759             /* Floppy Drive */
    3760             if (vsysThis.fHasFloppyDrive)
    3761                 pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy, "", "", "");
    3762 
    3763             /* CD Drive */
    3764             if (vsysThis.fHasCdromDrive)
    3765                 pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");
    3766 
    3767             /* Hard disk Controller */
    3768             uint16_t cIDEused = 0;
    3769             uint16_t cSATAused = 0; NOREF(cSATAused);
    3770             uint16_t cSCSIused = 0; NOREF(cSCSIused);
    3771             ControllersMap::const_iterator hdcIt;
    3772             /* Iterate through all hard disk controllers */
    3773             for (hdcIt = vsysThis.mapControllers.begin();
    3774                  hdcIt != vsysThis.mapControllers.end();
    3775                  ++hdcIt)
    3776             {
    3777                 const HardDiskController &hdc = hdcIt->second;
    3778                 Utf8Str strControllerID = Utf8StrFmt("%RI32", (uint32_t)hdc.idController);
    3779 
    3780                 switch (hdc.system)
    3781                 {
    3782                     case HardDiskController::IDE:
    3783                         {
    3784                             /* Check for the constrains */
    3785                             /* @todo: I'm very confused! Are these bits *one* controller or
    3786                                is every port/bus declared as an extra controller. */
    3787                             if (cIDEused < 4)
    3788                             {
    3789                                 // @todo: figure out the IDE types
    3790                                 /* Use PIIX4 as default */
    3791                                 Utf8Str strType = "PIIX4";
    3792                                 if (!hdc.strControllerType.compare("PIIX3", Utf8Str::CaseInsensitive))
    3793                                     strType = "PIIX3";
    3794                                 else if (!hdc.strControllerType.compare("ICH6", Utf8Str::CaseInsensitive))
    3795                                     strType = "ICH6";
    3796                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
    3797                                                    strControllerID,
    3798                                                    hdc.strControllerType,
    3799                                                    strType);
    3800                             }
    3801                             else
    3802                             {
    3803                                 /* Warn only once */
    3804                                 if (cIDEused == 1)
    3805                                     addWarning(tr("The virtual \"%s\" system requests support for more than one IDE controller, but VirtualBox has support for only one."),
    3806                                                vsysThis.strName.c_str());
    3807 
    3808                             }
    3809                             ++cIDEused;
    3810                             break;
    3811                         }
    3812 
    3813                     case HardDiskController::SATA:
    3814                         {
    3815 #ifdef VBOX_WITH_AHCI
    3816                             /* Check for the constrains */
    3817                             if (cSATAused < 1)
    3818                             {
    3819                                 // @todo: figure out the SATA types
    3820                                 /* We only support a plain AHCI controller, so use them always */
    3821                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
    3822                                                    strControllerID,
    3823                                                    hdc.strControllerType,
    3824                                                    "AHCI");
    3825                             }
    3826                             else
    3827                             {
    3828                                 /* Warn only once */
    3829                                 if (cSATAused == 1)
    3830                                     addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"),
    3831                                                vsysThis.strName.c_str());
    3832 
    3833                             }
    3834                             ++cSATAused;
    3835                             break;
    3836 #else /* !VBOX_WITH_AHCI */
    3837                             addWarning(tr("The virtual system \"%s\" requests at least one SATA controller but this version of VirtualBox does not provide a SATA controller emulation"),
    3838                                       vsysThis.strName.c_str());
    3839 #endif /* !VBOX_WITH_AHCI */
    3840                         }
    3841 
    3842                     case HardDiskController::SCSI:
    3843                         {
    3844 #ifdef VBOX_WITH_LSILOGIC
    3845                             /* Check for the constrains */
    3846                             if (cSCSIused < 1)
    3847                             {
    3848                                 Utf8Str hdcController = "LsiLogic";
    3849                                 if (!hdc.strControllerType.compare("BusLogic", Utf8Str::CaseInsensitive))
    3850                                     hdcController = "BusLogic";
    3851                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
    3852                                                    strControllerID,
    3853                                                    hdc.strControllerType,
    3854                                                    hdcController);
    3855                             }
    3856                             else
    3857                                 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."),
    3858                                            vsysThis.strName.c_str(),
    3859                                            hdc.strControllerType.c_str(),
    3860                                            strControllerID.c_str());
    3861                             ++cSCSIused;
    3862                             break;
    3863 #else /* !VBOX_WITH_LSILOGIC */
    3864                             addWarning(tr("The virtual system \"%s\" requests at least one SATA controller but this version of VirtualBox does not provide a SCSI controller emulation"),
    3865                                        vsysThis.strName.c_str());
    3866 #endif /* !VBOX_WITH_LSILOGIC */
    3867                         }
    3868                 }
    3869             }
    3870 
    3871             /* Hard disks */
    3872             if (vsysThis.mapVirtualDisks.size() > 0)
    3873             {
    3874                 VirtualDisksMap::const_iterator itVD;
    3875                 /* Iterate through all hard disks ()*/
    3876                 for (itVD = vsysThis.mapVirtualDisks.begin();
    3877                      itVD != vsysThis.mapVirtualDisks.end();
    3878                      ++itVD)
    3879                 {
    3880                     const VirtualDisk &hd = itVD->second;
    3881                     /* Get the associated disk image */
    3882                     const DiskImage &di = m->pReader->m_mapDisks[hd.strDiskId];
    3883 
    3884                     // @todo:
    3885                     //  - figure out all possible vmdk formats we also support
    3886                     //  - figure out if there is a url specifier for vhd already
    3887                     //  - we need a url specifier for the vdi format
    3888                     if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
    3889                         || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
    3890                     {
    3891                         /* If the href is empty use the VM name as filename */
    3892                         Utf8Str strFilename = di.strHref;
    3893                         if (!strFilename.length())
    3894                             strFilename = Utf8StrFmt("%s.vmdk", nameVBox.c_str());
    3895                         /* Construct a unique target path */
    3896                         Utf8StrFmt strPath("%ls%c%s",
    3897                                            bstrDefaultHardDiskLocation.raw(),
    3898                                            RTPATH_DELIMITER,
    3899                                            strFilename.c_str());
    3900                         searchUniqueDiskImageFilePath(strPath);
    3901 
    3902                         /* find the description for the hard disk controller
    3903                          * that has the same ID as hd.idController */
    3904                         const VirtualSystemDescriptionEntry *pController;
    3905                         if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
    3906                             throw setError(E_FAIL,
    3907                                            tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"),
    3908                                            hd.idController,
    3909                                            di.strHref.c_str());
    3910 
    3911                         /* controller to attach to, and the bus within that controller */
    3912                         Utf8StrFmt strExtraConfig("controller=%RI16;channel=%RI16",
    3913                                                   pController->ulIndex,
    3914                                                   hd.ulAddressOnParent);
    3915                         ULONG ulSize = 0;
    3916                         if (di.iCapacity != -1)
    3917                             ulSize = (ULONG)(di.iCapacity / _1M);
    3918                         else if (di.iPopulatedSize != -1)
    3919                             ulSize = (ULONG)(di.iPopulatedSize / _1M);
    3920                         else if (di.iSize != -1)
    3921                             ulSize = (ULONG)(di.iSize / _1M);
    3922                         if (ulSize == 0)
    3923                             ulSize = 10000;         // assume 10 GB, this is for the progress bar only anyway
    3924                         pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
    3925                                            hd.strDiskId,
    3926                                            di.strHref,
    3927                                            strPath,
    3928                                            ulSize,
    3929                                            strExtraConfig);
    3930                     }
    3931                     else
    3932                         throw setError(VBOX_E_FILE_ERROR,
    3933                                        tr("Unsupported format for virtual disk image in OVF: \"%s\"", di.strFormat.c_str()));
    3934                 }
    3935             }
    3936 
    3937             m->virtualSystemDescriptions.push_back(pNewDesc);
    3938         }
    3939     }
    3940     catch (HRESULT aRC)
    3941     {
    3942         /* On error we clear the list & return */
    3943         m->virtualSystemDescriptions.clear();
    3944         rc = aRC;
    3945     }
    3946 
    3947     // reset the appliance state
    3948     alock.acquire();
    3949     m->state = Data::ApplianceIdle;
    3950 
    3951     return rc;
    3952 }
    3953 
    3954 /**
    3955  * Public method implementation.
    3956  * @param aProgress
    3957  * @return
    3958  */
    3959 STDMETHODIMP Appliance::ImportMachines(IProgress **aProgress)
    3960 {
    3961     CheckComArgOutPointerValid(aProgress);
    3962 
    3963     AutoCaller autoCaller(this);
    3964     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3965 
    3966     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3967 
    3968     // do not allow entering this method if the appliance is busy reading or writing
    3969     if (!isApplianceIdle())
    3970         return E_ACCESSDENIED;
    3971 
    3972     if (!m->pReader)
    3973         return setError(E_FAIL,
    3974                         tr("Cannot import machines without reading it first (call read() before importMachines())"));
    3975 
    3976     ComObjPtr<Progress> progress;
    3977     HRESULT rc = S_OK;
    3978     try
    3979     {
    3980         rc = importImpl(m->locInfo, progress);
    3981     }
    3982     catch (HRESULT aRC)
    3983     {
    3984         rc = aRC;
    3985     }
    3986 
    3987     if (SUCCEEDED(rc))
    3988         /* Return progress to the caller */
    3989         progress.queryInterfaceTo(aProgress);
    3990 
    3991     return rc;
    3992 }
    3993 
    3994 STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
    3995 {
    3996     CheckComArgOutPointerValid(aExplorer);
    3997 
    3998     AutoCaller autoCaller(this);
    3999     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4000 
    4001     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4002 
    4003     ComObjPtr<VFSExplorer> explorer;
    4004     HRESULT rc = S_OK;
    4005     try
    4006     {
    4007         Utf8Str uri(aURI);
    4008         /* Check which kind of export the user has requested */
    4009         LocationInfo li;
    4010         parseURI(uri, li);
    4011         /* Create the explorer object */
    4012         explorer.createObject();
    4013         rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
    4014     }
    4015     catch (HRESULT aRC)
    4016     {
    4017         rc = aRC;
    4018     }
    4019 
    4020     if (SUCCEEDED(rc))
    4021         /* Return explorer to the caller */
    4022         explorer.queryInterfaceTo(aExplorer);
    4023 
    4024     return rc;
    4025 }
    4026 
    4027 STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress)
    4028 {
    4029     if (!path) return E_POINTER;
    4030     CheckComArgOutPointerValid(aProgress);
    4031 
    4032     AutoCaller autoCaller(this);
    4033     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4034 
    4035     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4036 
    4037     // do not allow entering this method if the appliance is busy reading or writing
    4038     if (!isApplianceIdle())
    4039         return E_ACCESSDENIED;
    4040 
    4041     // see if we can handle this file; for now we insist it has an ".ovf" extension
    4042     Utf8Str strPath = path;
    4043     if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    4044         return setError(VBOX_E_FILE_ERROR,
    4045                         tr("Appliance file must have .ovf extension"));
    4046 
    4047     Utf8Str strFormat(format);
    4048     TaskExportOVF::OVFFormat ovfF;
    4049     if (strFormat == "ovf-0.9")
    4050         ovfF = TaskExportOVF::OVF_0_9;
    4051     else if (strFormat == "ovf-1.0")
    4052         ovfF = TaskExportOVF::OVF_1_0;
    4053     else
    4054         return setError(VBOX_E_FILE_ERROR,
    4055                         tr("Invalid format \"%s\" specified"), strFormat.c_str());
    4056 
    4057     ComObjPtr<Progress> progress;
    4058     HRESULT rc = S_OK;
    4059     try
    4060     {
    4061         /* Parse all necessary info out of the URI */
    4062         parseURI(strPath, m->locInfo);
    4063         rc = writeImpl(ovfF, m->locInfo, progress);
    4064     }
    4065     catch (HRESULT aRC)
    4066     {
    4067         rc = aRC;
    4068     }
    4069 
    4070     if (SUCCEEDED(rc))
    4071         /* Return progress to the caller */
    4072         progress.queryInterfaceTo(aProgress);
    4073 
    4074     return rc;
    4075 }
    4076 
    4077 /**
    4078 * Public method implementation.
    4079  * @return
    4080  */
    4081 STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
    4082 {
    4083     if (ComSafeArrayOutIsNull(aWarnings))
    4084         return E_POINTER;
    4085 
    4086     AutoCaller autoCaller(this);
    4087     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4088 
    4089     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4090 
    4091     com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
    4092 
    4093     list<Utf8Str>::const_iterator it;
    4094     size_t i = 0;
    4095     for (it = m->llWarnings.begin();
    4096          it != m->llWarnings.end();
    4097          ++it, ++i)
    4098     {
    4099         Bstr bstr = *it;
    4100         bstr.cloneTo(&sfaWarnings[i]);
    4101     }
    4102 
    4103     sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
    41042840
    41052841    return S_OK;
     
    44853221}
    44863222
    4487 ////////////////////////////////////////////////////////////////////////////////
    4488 //
    4489 // IMachine public methods
    4490 //
    4491 ////////////////////////////////////////////////////////////////////////////////
    4492 
    4493 // This code is here so we won't have to include the appliance headers in the
    4494 // IMachine implementation, and we also need to access private appliance data.
    4495 
    4496 /**
    4497 * Public method implementation.
    4498 * @param appliance
    4499 * @return
    4500 */
    4501 
    4502 STDMETHODIMP Machine::Export(IAppliance *aAppliance, IVirtualSystemDescription **aDescription)
    4503 {
    4504     HRESULT rc = S_OK;
    4505 
    4506     if (!aAppliance)
    4507         return E_POINTER;
    4508 
    4509     AutoCaller autoCaller(this);
    4510     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4511 
    4512     ComObjPtr<VirtualSystemDescription> pNewDesc;
    4513 
    4514     try
    4515     {
    4516         Bstr bstrName1;
    4517         Bstr bstrDescription;
    4518         Bstr bstrGuestOSType;
    4519         uint32_t cCPUs;
    4520         uint32_t ulMemSizeMB;
    4521         BOOL fUSBEnabled;
    4522         BOOL fAudioEnabled;
    4523         AudioControllerType_T audioController;
    4524 
    4525         ComPtr<IUSBController> pUsbController;
    4526         ComPtr<IAudioAdapter> pAudioAdapter;
    4527 
    4528         // first, call the COM methods, as they request locks
    4529         rc = COMGETTER(USBController)(pUsbController.asOutParam());
    4530         if (FAILED(rc))
    4531             fUSBEnabled = false;
    4532         else
    4533             rc = pUsbController->COMGETTER(Enabled)(&fUSBEnabled);
    4534 
    4535         // request the machine lock while acessing internal members
    4536         AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
    4537 
    4538         pAudioAdapter = mAudioAdapter;
    4539         rc = pAudioAdapter->COMGETTER(Enabled)(&fAudioEnabled);
    4540         if (FAILED(rc)) throw rc;
    4541         rc = pAudioAdapter->COMGETTER(AudioController)(&audioController);
    4542         if (FAILED(rc)) throw rc;
    4543 
    4544         // get name
    4545         bstrName1 = mUserData->mName;
    4546         // get description
    4547         bstrDescription = mUserData->mDescription;
    4548         // get guest OS
    4549         bstrGuestOSType = mUserData->mOSTypeId;
    4550         // CPU count
    4551         cCPUs = mHWData->mCPUCount;
    4552         // memory size in MB
    4553         ulMemSizeMB = mHWData->mMemorySize;
    4554         // VRAM size?
    4555         // BIOS settings?
    4556         // 3D acceleration enabled?
    4557         // hardware virtualization enabled?
    4558         // nested paging enabled?
    4559         // HWVirtExVPIDEnabled?
    4560         // PAEEnabled?
    4561         // snapshotFolder?
    4562         // VRDPServer?
    4563 
    4564         // create a new virtual system
    4565         rc = pNewDesc.createObject();
    4566         if (FAILED(rc)) throw rc;
    4567         rc = pNewDesc->init();
    4568         if (FAILED(rc)) throw rc;
    4569 
    4570         /* Guest OS type */
    4571         Utf8Str strOsTypeVBox(bstrGuestOSType);
    4572         CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str());
    4573         pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
    4574                            "",
    4575                            Utf8StrFmt("%RI32", cim),
    4576                            strOsTypeVBox);
    4577 
    4578         /* VM name */
    4579         Utf8Str strVMName(bstrName1);
    4580         pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
    4581                            "",
    4582                            strVMName,
    4583                            strVMName);
    4584 
    4585         // description
    4586         Utf8Str strDescription(bstrDescription);
    4587         pNewDesc->addEntry(VirtualSystemDescriptionType_Description,
    4588                            "",
    4589                            strDescription,
    4590                            strDescription);
    4591 
    4592         /* CPU count*/
    4593         Utf8Str strCpuCount = Utf8StrFmt("%RI32", cCPUs);
    4594         pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
    4595                            "",
    4596                            strCpuCount,
    4597                            strCpuCount);
    4598 
    4599         /* Memory */
    4600         Utf8Str strMemory = Utf8StrFmt("%RI64", (uint64_t)ulMemSizeMB * _1M);
    4601         pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
    4602                            "",
    4603                            strMemory,
    4604                            strMemory);
    4605 
    4606         int32_t lIDEControllerIndex = 0;
    4607         int32_t lSATAControllerIndex = 0;
    4608         int32_t lSCSIControllerIndex = 0;
    4609 
    4610         /* Fetch all available storage controllers */
    4611         com::SafeIfaceArray<IStorageController> nwControllers;
    4612         rc = COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(nwControllers));
    4613         if (FAILED(rc)) throw rc;
    4614 
    4615         ComPtr<IStorageController> pIDEController;
    4616 #ifdef VBOX_WITH_AHCI
    4617         ComPtr<IStorageController> pSATAController;
    4618 #endif /* VBOX_WITH_AHCI */
    4619 #ifdef VBOX_WITH_LSILOGIC
    4620         ComPtr<IStorageController> pSCSIController;
    4621 #endif /* VBOX_WITH_LSILOGIC */
    4622         for (size_t j = 0; j < nwControllers.size(); ++j)
    4623         {
    4624             StorageBus_T eType;
    4625             rc = nwControllers[j]->COMGETTER(Bus)(&eType);
    4626             if (FAILED(rc)) throw rc;
    4627             if (   eType == StorageBus_IDE
    4628                 && pIDEController.isNull())
    4629                 pIDEController = nwControllers[j];
    4630 #ifdef VBOX_WITH_AHCI
    4631             else if (   eType == StorageBus_SATA
    4632                      && pSATAController.isNull())
    4633                 pSATAController = nwControllers[j];
    4634 #endif /* VBOX_WITH_AHCI */
    4635 #ifdef VBOX_WITH_LSILOGIC
    4636             else if (   eType == StorageBus_SCSI
    4637                      && pSATAController.isNull())
    4638                 pSCSIController = nwControllers[j];
    4639 #endif /* VBOX_WITH_LSILOGIC */
    4640         }
    4641 
    4642 //     <const name="HardDiskControllerIDE" value="6" />
    4643         if (!pIDEController.isNull())
    4644         {
    4645             Utf8Str strVbox;
    4646             StorageControllerType_T ctlr;
    4647             rc = pIDEController->COMGETTER(ControllerType)(&ctlr);
    4648             if (FAILED(rc)) throw rc;
    4649             switch(ctlr)
    4650             {
    4651                 case StorageControllerType_PIIX3: strVbox = "PIIX3"; break;
    4652                 case StorageControllerType_PIIX4: strVbox = "PIIX4"; break;
    4653                 case StorageControllerType_ICH6: strVbox = "ICH6"; break;
    4654             }
    4655 
    4656             if (strVbox.length())
    4657             {
    4658                 lIDEControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
    4659                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
    4660                                    Utf8StrFmt("%d", lIDEControllerIndex),
    4661                                    strVbox,
    4662                                    strVbox);
    4663             }
    4664         }
    4665 
    4666 #ifdef VBOX_WITH_AHCI
    4667 //     <const name="HardDiskControllerSATA" value="7" />
    4668         if (!pSATAController.isNull())
    4669         {
    4670             Utf8Str strVbox = "AHCI";
    4671             lSATAControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
    4672             pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
    4673                                Utf8StrFmt("%d", lSATAControllerIndex),
    4674                                strVbox,
    4675                                strVbox);
    4676         }
    4677 #endif // VBOX_WITH_AHCI
    4678 
    4679 #ifdef VBOX_WITH_LSILOGIC
    4680 //     <const name="HardDiskControllerSCSI" value="8" />
    4681         if (!pSCSIController.isNull())
    4682         {
    4683             StorageControllerType_T ctlr;
    4684             rc = pSCSIController->COMGETTER(ControllerType)(&ctlr);
    4685             if (SUCCEEDED(rc))
    4686             {
    4687                 Utf8Str strVbox = "LsiLogic";       // the default in VBox
    4688                 switch(ctlr)
    4689                 {
    4690                     case StorageControllerType_LsiLogic: strVbox = "LsiLogic"; break;
    4691                     case StorageControllerType_BusLogic: strVbox = "BusLogic"; break;
    4692                 }
    4693                 lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
    4694                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
    4695                                    Utf8StrFmt("%d", lSCSIControllerIndex),
    4696                                    strVbox,
    4697                                    strVbox);
    4698             }
    4699             else
    4700                 throw rc;
    4701         }
    4702 #endif // VBOX_WITH_LSILOGIC
    4703 
    4704 //     <const name="HardDiskImage" value="9" />
    4705 //     <const name="Floppy" value="18" />
    4706 //     <const name="CDROM" value="19" />
    4707 
    4708         MediaData::AttachmentList::iterator itA;
    4709         for (itA = mMediaData->mAttachments.begin();
    4710              itA != mMediaData->mAttachments.end();
    4711              ++itA)
    4712         {
    4713             ComObjPtr<MediumAttachment> pHDA = *itA;
    4714 
    4715             // the attachment's data
    4716             ComPtr<IMedium> pMedium;
    4717             ComPtr<IStorageController> ctl;
    4718             Bstr controllerName;
    4719 
    4720             rc = pHDA->COMGETTER(Controller)(controllerName.asOutParam());
    4721             if (FAILED(rc)) throw rc;
    4722 
    4723             rc = GetStorageControllerByName(controllerName, ctl.asOutParam());
    4724             if (FAILED(rc)) throw rc;
    4725 
    4726             StorageBus_T storageBus;
    4727             DeviceType_T deviceType;
    4728             LONG lChannel;
    4729             LONG lDevice;
    4730 
    4731             rc = ctl->COMGETTER(Bus)(&storageBus);
    4732             if (FAILED(rc)) throw rc;
    4733 
    4734             rc = pHDA->COMGETTER(Type)(&deviceType);
    4735             if (FAILED(rc)) throw rc;
    4736 
    4737             rc = pHDA->COMGETTER(Medium)(pMedium.asOutParam());
    4738             if (FAILED(rc)) throw rc;
    4739 
    4740             rc = pHDA->COMGETTER(Port)(&lChannel);
    4741             if (FAILED(rc)) throw rc;
    4742 
    4743             rc = pHDA->COMGETTER(Device)(&lDevice);
    4744             if (FAILED(rc)) throw rc;
    4745 
    4746             Utf8Str strTargetVmdkName;
    4747             Utf8Str strLocation;
    4748             ULONG64 ullSize = 0;
    4749 
    4750             if (    deviceType == DeviceType_HardDisk
    4751                  && pMedium
    4752                )
    4753             {
    4754                 Bstr bstrLocation;
    4755                 rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam());
    4756                 if (FAILED(rc)) throw rc;
    4757                 strLocation = bstrLocation;
    4758 
    4759                 Bstr bstrName;
    4760                 rc = pMedium->COMGETTER(Name)(bstrName.asOutParam());
    4761                 if (FAILED(rc)) throw rc;
    4762 
    4763                 strTargetVmdkName = bstrName;
    4764                 strTargetVmdkName.stripExt();
    4765                 strTargetVmdkName.append(".vmdk");
    4766 
    4767                 // we need the size of the image so we can give it to addEntry();
    4768                 // later, on export, the progress weight will be based on this.
    4769                 // pMedium can be a differencing image though; in that case, we
    4770                 // need to use the size of the base instead.
    4771                 ComPtr<IMedium> pBaseMedium;
    4772                 rc = pMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
    4773                         // returns pMedium if there are no diff images
    4774                 if (FAILED(rc)) throw rc;
    4775 
    4776                 // force reading state, or else size will be returned as 0
    4777                 MediumState_T ms;
    4778                 rc = pBaseMedium->RefreshState(&ms);
    4779                 if (FAILED(rc)) throw rc;
    4780 
    4781                 rc = pBaseMedium->COMGETTER(Size)(&ullSize);
    4782                 if (FAILED(rc)) throw rc;
    4783             }
    4784 
    4785             // and how this translates to the virtual system
    4786             int32_t lControllerVsys = 0;
    4787             LONG lChannelVsys;
    4788 
    4789             switch (storageBus)
    4790             {
    4791                 case StorageBus_IDE:
    4792                     // this is the exact reverse to what we're doing in Appliance::taskThreadImportMachines,
    4793                     // and it must be updated when that is changed!
    4794 
    4795                     if (lChannel == 0 && lDevice == 0)      // primary master
    4796                         lChannelVsys = 0;
    4797                     else if (lChannel == 0 && lDevice == 1) // primary slave
    4798                         lChannelVsys = 1;
    4799                     else if (lChannel == 1 && lDevice == 0) // secondary master; by default this is the CD-ROM but as of VirtualBox 3.1 that can change
    4800                         lChannelVsys = 2;
    4801                     else if (lChannel == 1 && lDevice == 1) // secondary slave
    4802                         lChannelVsys = 3;
    4803                     else
    4804                         throw setError(VBOX_E_NOT_SUPPORTED,
    4805                                     tr("Cannot handle medium attachment: channel is %d, device is %d"), lChannel, lDevice);
    4806 
    4807                     lControllerVsys = lIDEControllerIndex;
    4808                 break;
    4809 
    4810                 case StorageBus_SATA:
    4811                     lChannelVsys = lChannel;        // should be between 0 and 29
    4812                     lControllerVsys = lSATAControllerIndex;
    4813                 break;
    4814 
    4815                 case StorageBus_SCSI:
    4816                     lChannelVsys = lChannel;        // should be between 0 and 15
    4817                     lControllerVsys = lSCSIControllerIndex;
    4818                 break;
    4819 
    4820                 case StorageBus_Floppy:
    4821                     lChannelVsys = 0;
    4822                     lControllerVsys = 0;
    4823                 break;
    4824 
    4825                 default:
    4826                     throw setError(VBOX_E_NOT_SUPPORTED,
    4827                                 tr("Cannot handle medium attachment: storageBus is %d, channel is %d, device is %d"), storageBus, lChannel, lDevice);
    4828                 break;
    4829             }
    4830 
    4831             Utf8StrFmt strExtra("controller=%RI32;channel=%RI32", lControllerVsys, lChannelVsys);
    4832             Utf8Str strEmpty;
    4833 
    4834             switch (deviceType)
    4835             {
    4836                 case DeviceType_HardDisk:
    4837                     Log(("Adding VirtualSystemDescriptionType_HardDiskImage, disk size: %RI64\n", ullSize));
    4838                     pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
    4839                                        strTargetVmdkName,   // disk ID: let's use the name
    4840                                        strTargetVmdkName,   // OVF value:
    4841                                        strLocation, // vbox value: media path
    4842                                        (uint32_t)(ullSize / _1M),
    4843                                        strExtra);
    4844                 break;
    4845 
    4846                 case DeviceType_DVD:
    4847                     pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM,
    4848                                        strEmpty,   // disk ID
    4849                                        strEmpty,   // OVF value
    4850                                        strEmpty, // vbox value
    4851                                        1,           // ulSize
    4852                                        strExtra);
    4853                 break;
    4854 
    4855                 case DeviceType_Floppy:
    4856                     pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy,
    4857                                        strEmpty,      // disk ID
    4858                                        strEmpty,      // OVF value
    4859                                        strEmpty,      // vbox value
    4860                                        1,       // ulSize
    4861                                        strExtra);
    4862                 break;
    4863             }
    4864         }
    4865 
    4866 //     <const name="NetworkAdapter" />
    4867         size_t a;
    4868         for (a = 0;
    4869              a < SchemaDefs::NetworkAdapterCount;
    4870              ++a)
    4871         {
    4872             ComPtr<INetworkAdapter> pNetworkAdapter;
    4873             BOOL fEnabled;
    4874             NetworkAdapterType_T adapterType;
    4875             NetworkAttachmentType_T attachmentType;
    4876 
    4877             rc = GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
    4878             if (FAILED(rc)) throw rc;
    4879             /* Enable the network card & set the adapter type */
    4880             rc = pNetworkAdapter->COMGETTER(Enabled)(&fEnabled);
    4881             if (FAILED(rc)) throw rc;
    4882 
    4883             if (fEnabled)
    4884             {
    4885                 Utf8Str strAttachmentType;
    4886 
    4887                 rc = pNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
    4888                 if (FAILED(rc)) throw rc;
    4889 
    4890                 rc = pNetworkAdapter->COMGETTER(AttachmentType)(&attachmentType);
    4891                 if (FAILED(rc)) throw rc;
    4892 
    4893                 switch (attachmentType)
    4894                 {
    4895                     case NetworkAttachmentType_Null:
    4896                         strAttachmentType = "Null";
    4897                     break;
    4898 
    4899                     case NetworkAttachmentType_NAT:
    4900                         strAttachmentType = "NAT";
    4901                     break;
    4902 
    4903                     case NetworkAttachmentType_Bridged:
    4904                         strAttachmentType = "Bridged";
    4905                     break;
    4906 
    4907                     case NetworkAttachmentType_Internal:
    4908                         strAttachmentType = "Internal";
    4909                     break;
    4910 
    4911                     case NetworkAttachmentType_HostOnly:
    4912                         strAttachmentType = "HostOnly";
    4913                     break;
    4914                 }
    4915 
    4916                 pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
    4917                                    "",      // ref
    4918                                    strAttachmentType,      // orig
    4919                                    Utf8StrFmt("%RI32", (uint32_t)adapterType),   // conf
    4920                                    0,
    4921                                    Utf8StrFmt("type=%s", strAttachmentType.c_str()));       // extra conf
    4922             }
    4923         }
    4924 
    4925 //     <const name="USBController"  />
    4926 #ifdef VBOX_WITH_USB
    4927         if (fUSBEnabled)
    4928             pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
    4929 #endif /* VBOX_WITH_USB */
    4930 
    4931 //     <const name="SoundCard"  />
    4932         if (fAudioEnabled)
    4933         {
    4934             pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
    4935                                "",
    4936                                "ensoniq1371",       // this is what OVFTool writes and VMware supports
    4937                                Utf8StrFmt("%RI32", audioController));
    4938         }
    4939 
    4940         // finally, add the virtual system to the appliance
    4941         Appliance *pAppliance = static_cast<Appliance*>(aAppliance);
    4942         AutoCaller autoCaller1(pAppliance);
    4943         if (FAILED(autoCaller1.rc())) return autoCaller1.rc();
    4944 
    4945         /* We return the new description to the caller */
    4946         ComPtr<IVirtualSystemDescription> copy(pNewDesc);
    4947         copy.queryInterfaceTo(aDescription);
    4948 
    4949         AutoWriteLock alock(pAppliance COMMA_LOCKVAL_SRC_POS);
    4950 
    4951         pAppliance->m->virtualSystemDescriptions.push_back(pNewDesc);
    4952     }
    4953     catch(HRESULT arc)
    4954     {
    4955         rc = arc;
    4956     }
    4957 
    4958     return rc;
    4959 }
    4960 
    4961 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
  • trunk/src/VBox/Main/ApplianceImplExport.cpp

    r27797 r27829  
    4545#include "Logging.h"
    4646
     47#include "ApplianceImplPrivate.h"
     48
    4749using namespace std;
    48 
    49 ////////////////////////////////////////////////////////////////////////////////
    50 //
    51 // Appliance data definition
    52 //
    53 ////////////////////////////////////////////////////////////////////////////////
    54 
    55 /* Describe a location for the import/export. The location could be a file on a
    56  * local hard disk or a remote target based on the supported inet protocols. */
    57 struct Appliance::LocationInfo
    58 {
    59     LocationInfo()
    60       : storageType(VFSType_File) {}
    61     VFSType_T storageType; /* Which type of storage should be handled */
    62     Utf8Str strPath;       /* File path for the import/export */
    63     Utf8Str strHostname;   /* Hostname on remote storage locations (could be empty) */
    64     Utf8Str strUsername;   /* Username on remote storage locations (could be empty) */
    65     Utf8Str strPassword;   /* Password on remote storage locations (could be empty) */
    66 };
    67 
    68 // opaque private instance data of Appliance class
    69 struct Appliance::Data
    70 {
    71     enum ApplianceState { ApplianceIdle, ApplianceImporting, ApplianceExporting };
    72 
    73     Data()
    74       : state(ApplianceIdle),
    75         pReader(NULL)
    76     {
    77     }
    78 
    79     ~Data()
    80     {
    81         if (pReader)
    82         {
    83             delete pReader;
    84             pReader = NULL;
    85         }
    86     }
    87 
    88     ApplianceState  state;
    89 
    90     LocationInfo    locInfo;       // location info for the currently processed OVF
    91 
    92     OVFReader       *pReader;
    93 
    94     bool            fBusyWriting;          // state protection; while this is true nobody else can call methods
    95 
    96     list< ComObjPtr<VirtualSystemDescription> >
    97                     virtualSystemDescriptions;
    98 
    99     list<Utf8Str>   llWarnings;
    100 
    101     ULONG           ulWeightPerOperation;
    102     Utf8Str         strOVFSHA1Digest;
    103 };
    104 
    105 struct VirtualSystemDescription::Data
    106 {
    107     list<VirtualSystemDescriptionEntry> llDescriptions;
    108 };
    10950
    11051////////////////////////////////////////////////////////////////////////////////
     
    11455////////////////////////////////////////////////////////////////////////////////
    11556
    116 static const struct
    117 {
    118     CIMOSType_T     cim;
    119     const char      *pcszVbox;
    120 }
    121 g_osTypes[] =
    122 {
    123     { CIMOSType_CIMOS_Unknown,                              SchemaDefs_OSTypeId_Other },
    124     { CIMOSType_CIMOS_OS2,                                  SchemaDefs_OSTypeId_OS2 },
    125     { CIMOSType_CIMOS_MSDOS,                                SchemaDefs_OSTypeId_DOS },
    126     { CIMOSType_CIMOS_WIN3x,                                SchemaDefs_OSTypeId_Windows31 },
    127     { CIMOSType_CIMOS_WIN95,                                SchemaDefs_OSTypeId_Windows95 },
    128     { CIMOSType_CIMOS_WIN98,                                SchemaDefs_OSTypeId_Windows98 },
    129     { CIMOSType_CIMOS_WINNT,                                SchemaDefs_OSTypeId_WindowsNT4 },
    130     { CIMOSType_CIMOS_NetWare,                              SchemaDefs_OSTypeId_Netware },
    131     { CIMOSType_CIMOS_NovellOES,                            SchemaDefs_OSTypeId_Netware },
    132     { CIMOSType_CIMOS_Solaris,                              SchemaDefs_OSTypeId_OpenSolaris },
    133     { CIMOSType_CIMOS_SunOS,                                SchemaDefs_OSTypeId_OpenSolaris },
    134     { CIMOSType_CIMOS_FreeBSD,                              SchemaDefs_OSTypeId_FreeBSD },
    135     { CIMOSType_CIMOS_NetBSD,                               SchemaDefs_OSTypeId_NetBSD },
    136     { CIMOSType_CIMOS_QNX,                                  SchemaDefs_OSTypeId_QNX },
    137     { CIMOSType_CIMOS_Windows2000,                          SchemaDefs_OSTypeId_Windows2000 },
    138     { CIMOSType_CIMOS_WindowsMe,                            SchemaDefs_OSTypeId_WindowsMe },
    139     { CIMOSType_CIMOS_OpenBSD,                              SchemaDefs_OSTypeId_OpenBSD },
    140     { CIMOSType_CIMOS_WindowsXP,                            SchemaDefs_OSTypeId_WindowsXP },
    141     { CIMOSType_CIMOS_WindowsXPEmbedded,                    SchemaDefs_OSTypeId_WindowsXP },
    142     { CIMOSType_CIMOS_WindowsEmbeddedforPointofService,     SchemaDefs_OSTypeId_WindowsXP },
    143     { CIMOSType_CIMOS_MicrosoftWindowsServer2003,           SchemaDefs_OSTypeId_Windows2003 },
    144     { CIMOSType_CIMOS_MicrosoftWindowsServer2003_64,        SchemaDefs_OSTypeId_Windows2003_64 },
    145     { CIMOSType_CIMOS_WindowsXP_64,                         SchemaDefs_OSTypeId_WindowsXP_64 },
    146     { CIMOSType_CIMOS_WindowsVista,                         SchemaDefs_OSTypeId_WindowsVista },
    147     { CIMOSType_CIMOS_WindowsVista_64,                      SchemaDefs_OSTypeId_WindowsVista_64 },
    148     { CIMOSType_CIMOS_MicrosoftWindowsServer2008,           SchemaDefs_OSTypeId_Windows2008 },
    149     { CIMOSType_CIMOS_MicrosoftWindowsServer2008_64,        SchemaDefs_OSTypeId_Windows2008_64 },
    150     { CIMOSType_CIMOS_FreeBSD_64,                           SchemaDefs_OSTypeId_FreeBSD_64 },
    151     { CIMOSType_CIMOS_RedHatEnterpriseLinux,                SchemaDefs_OSTypeId_RedHat },
    152     { CIMOSType_CIMOS_RedHatEnterpriseLinux_64,             SchemaDefs_OSTypeId_RedHat_64 },
    153     { CIMOSType_CIMOS_Solaris_64,                           SchemaDefs_OSTypeId_OpenSolaris_64 },
    154     { CIMOSType_CIMOS_SUSE,                                 SchemaDefs_OSTypeId_OpenSUSE },
    155     { CIMOSType_CIMOS_SLES,                                 SchemaDefs_OSTypeId_OpenSUSE },
    156     { CIMOSType_CIMOS_NovellLinuxDesktop,                   SchemaDefs_OSTypeId_OpenSUSE },
    157     { CIMOSType_CIMOS_SUSE_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
    158     { CIMOSType_CIMOS_SLES_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
    159     { CIMOSType_CIMOS_LINUX,                                SchemaDefs_OSTypeId_Linux },
    160     { CIMOSType_CIMOS_SunJavaDesktopSystem,                 SchemaDefs_OSTypeId_Linux },
    161     { CIMOSType_CIMOS_TurboLinux,                           SchemaDefs_OSTypeId_Linux},
    162 
    163     //                { CIMOSType_CIMOS_TurboLinux_64, },
    164 
    165     { CIMOSType_CIMOS_Mandriva,                             SchemaDefs_OSTypeId_Mandriva },
    166     { CIMOSType_CIMOS_Mandriva_64,                          SchemaDefs_OSTypeId_Mandriva_64 },
    167     { CIMOSType_CIMOS_Ubuntu,                               SchemaDefs_OSTypeId_Ubuntu },
    168     { CIMOSType_CIMOS_Ubuntu_64,                            SchemaDefs_OSTypeId_Ubuntu_64 },
    169     { CIMOSType_CIMOS_Debian,                               SchemaDefs_OSTypeId_Debian },
    170     { CIMOSType_CIMOS_Debian_64,                            SchemaDefs_OSTypeId_Debian_64 },
    171     { CIMOSType_CIMOS_Linux_2_4_x,                          SchemaDefs_OSTypeId_Linux24 },
    172     { CIMOSType_CIMOS_Linux_2_4_x_64,                       SchemaDefs_OSTypeId_Linux24_64 },
    173     { CIMOSType_CIMOS_Linux_2_6_x,                          SchemaDefs_OSTypeId_Linux26 },
    174     { CIMOSType_CIMOS_Linux_2_6_x_64,                       SchemaDefs_OSTypeId_Linux26_64 },
    175     { CIMOSType_CIMOS_Linux_64,                             SchemaDefs_OSTypeId_Linux26_64 }
    176 };
    177 
    178 /* Pattern structure for matching the OS type description field */
    179 struct osTypePattern
    180 {
    181     const char *pcszPattern;
    182     const char *pcszVbox;
    183 };
    184 
    185 /* These are the 32-Bit ones. They are sorted by priority. */
    186 static const osTypePattern g_osTypesPattern[] =
    187 {
    188     {"Windows NT",    SchemaDefs_OSTypeId_WindowsNT4},
    189     {"Windows XP",    SchemaDefs_OSTypeId_WindowsXP},
    190     {"Windows 2000",  SchemaDefs_OSTypeId_Windows2000},
    191     {"Windows 2003",  SchemaDefs_OSTypeId_Windows2003},
    192     {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista},
    193     {"Windows 2008",  SchemaDefs_OSTypeId_Windows2008},
    194     {"SUSE",          SchemaDefs_OSTypeId_OpenSUSE},
    195     {"Novell",        SchemaDefs_OSTypeId_OpenSUSE},
    196     {"Red Hat",       SchemaDefs_OSTypeId_RedHat},
    197     {"Mandriva",      SchemaDefs_OSTypeId_Mandriva},
    198     {"Ubuntu",        SchemaDefs_OSTypeId_Ubuntu},
    199     {"Debian",        SchemaDefs_OSTypeId_Debian},
    200     {"QNX",           SchemaDefs_OSTypeId_QNX},
    201     {"Linux 2.4",     SchemaDefs_OSTypeId_Linux24},
    202     {"Linux 2.6",     SchemaDefs_OSTypeId_Linux26},
    203     {"Linux",         SchemaDefs_OSTypeId_Linux},
    204     {"OpenSolaris",   SchemaDefs_OSTypeId_OpenSolaris},
    205     {"Solaris",       SchemaDefs_OSTypeId_OpenSolaris},
    206     {"FreeBSD",       SchemaDefs_OSTypeId_FreeBSD},
    207     {"NetBSD",        SchemaDefs_OSTypeId_NetBSD},
    208     {"Windows 95",    SchemaDefs_OSTypeId_Windows95},
    209     {"Windows 98",    SchemaDefs_OSTypeId_Windows98},
    210     {"Windows Me",    SchemaDefs_OSTypeId_WindowsMe},
    211     {"Windows 3.",    SchemaDefs_OSTypeId_Windows31},
    212     {"DOS",           SchemaDefs_OSTypeId_DOS},
    213     {"OS2",           SchemaDefs_OSTypeId_OS2}
    214 };
    215 
    216 /* These are the 64-Bit ones. They are sorted by priority. */
    217 static const osTypePattern g_osTypesPattern64[] =
    218 {
    219     {"Windows XP",    SchemaDefs_OSTypeId_WindowsXP_64},
    220     {"Windows 2003",  SchemaDefs_OSTypeId_Windows2003_64},
    221     {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista_64},
    222     {"Windows 2008",  SchemaDefs_OSTypeId_Windows2008_64},
    223     {"SUSE",          SchemaDefs_OSTypeId_OpenSUSE_64},
    224     {"Novell",        SchemaDefs_OSTypeId_OpenSUSE_64},
    225     {"Red Hat",       SchemaDefs_OSTypeId_RedHat_64},
    226     {"Mandriva",      SchemaDefs_OSTypeId_Mandriva_64},
    227     {"Ubuntu",        SchemaDefs_OSTypeId_Ubuntu_64},
    228     {"Debian",        SchemaDefs_OSTypeId_Debian_64},
    229     {"Linux 2.4",     SchemaDefs_OSTypeId_Linux24_64},
    230     {"Linux 2.6",     SchemaDefs_OSTypeId_Linux26_64},
    231     {"Linux",         SchemaDefs_OSTypeId_Linux26_64},
    232     {"OpenSolaris",   SchemaDefs_OSTypeId_OpenSolaris_64},
    233     {"Solaris",       SchemaDefs_OSTypeId_OpenSolaris_64},
    234     {"FreeBSD",       SchemaDefs_OSTypeId_FreeBSD_64},
    235 };
    236 
    237 /**
    238  * Private helper func that suggests a VirtualBox guest OS type
    239  * for the given OVF operating system type.
    240  * @param osTypeVBox
    241  * @param c
    242  * @param cStr
    243  */
    244 static void convertCIMOSType2VBoxOSType(Utf8Str &strType, CIMOSType_T c, const Utf8Str &cStr)
    245 {
    246     /* First check if the type is other/other_64 */
    247     if (c == CIMOSType_CIMOS_Other)
    248     {
    249         for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern); ++i)
    250             if (cStr.contains (g_osTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive))
    251             {
    252                 strType = g_osTypesPattern[i].pcszVbox;
    253                 return;
    254             }
    255     }
    256     else if (c == CIMOSType_CIMOS_Other_64)
    257     {
    258         for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern64); ++i)
    259             if (cStr.contains (g_osTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive))
    260             {
    261                 strType = g_osTypesPattern64[i].pcszVbox;
    262                 return;
    263             }
    264     }
    265 
    266     for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
    267     {
    268         if (c == g_osTypes[i].cim)
    269         {
    270             strType = g_osTypes[i].pcszVbox;
    271             return;
    272         }
    273     }
    274 
    275     strType = SchemaDefs_OSTypeId_Other;
    276 }
    277 
    278 /**
    279  * Private helper func that suggests a VirtualBox guest OS type
    280  * for the given OVF operating system type.
    281  * @param osTypeVBox
    282  * @param c
    283  */
    284 static CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
    285 {
    286     for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
    287     {
    288         if (!RTStrICmp(pcszVbox, g_osTypes[i].pcszVbox))
    289             return g_osTypes[i].cim;
    290     }
    291 
    292     return CIMOSType_CIMOS_Other;
    293 }
    294 
    29557////////////////////////////////////////////////////////////////////////////////
    29658//
    297 // IVirtualBox public methods
     59// IMachine public methods
    29860//
    29961////////////////////////////////////////////////////////////////////////////////
    30062
    30163// This code is here so we won't have to include the appliance headers in the
    302 // IVirtualBox implementation.
     64// IMachine implementation, and we also need to access private appliance data.
    30365
    30466/**
    305  * Implementation for IVirtualBox::createAppliance.
    306  *
    307  * @param anAppliance IAppliance object created if S_OK is returned.
    308  * @return S_OK or error.
    309  */
    310 STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
     67* Public method implementation.
     68* @param appliance
     69* @return
     70*/
     71
     72STDMETHODIMP Machine::Export(IAppliance *aAppliance, IVirtualSystemDescription **aDescription)
    31173{
    312     HRESULT rc;
    313 
    314     ComObjPtr<Appliance> appliance;
    315     appliance.createObject();
    316     rc = appliance->init(this);
    317 
    318     if (SUCCEEDED(rc))
    319         appliance.queryInterfaceTo(anAppliance);
     74    HRESULT rc = S_OK;
     75
     76    if (!aAppliance)
     77        return E_POINTER;
     78
     79    AutoCaller autoCaller(this);
     80    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     81
     82    ComObjPtr<VirtualSystemDescription> pNewDesc;
     83
     84    try
     85    {
     86        Bstr bstrName1;
     87        Bstr bstrDescription;
     88        Bstr bstrGuestOSType;
     89        uint32_t cCPUs;
     90        uint32_t ulMemSizeMB;
     91        BOOL fUSBEnabled;
     92        BOOL fAudioEnabled;
     93        AudioControllerType_T audioController;
     94
     95        ComPtr<IUSBController> pUsbController;
     96        ComPtr<IAudioAdapter> pAudioAdapter;
     97
     98        // first, call the COM methods, as they request locks
     99        rc = COMGETTER(USBController)(pUsbController.asOutParam());
     100        if (FAILED(rc))
     101            fUSBEnabled = false;
     102        else
     103            rc = pUsbController->COMGETTER(Enabled)(&fUSBEnabled);
     104
     105        // request the machine lock while acessing internal members
     106        AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
     107
     108        pAudioAdapter = mAudioAdapter;
     109        rc = pAudioAdapter->COMGETTER(Enabled)(&fAudioEnabled);
     110        if (FAILED(rc)) throw rc;
     111        rc = pAudioAdapter->COMGETTER(AudioController)(&audioController);
     112        if (FAILED(rc)) throw rc;
     113
     114        // get name
     115        bstrName1 = mUserData->mName;
     116        // get description
     117        bstrDescription = mUserData->mDescription;
     118        // get guest OS
     119        bstrGuestOSType = mUserData->mOSTypeId;
     120        // CPU count
     121        cCPUs = mHWData->mCPUCount;
     122        // memory size in MB
     123        ulMemSizeMB = mHWData->mMemorySize;
     124        // VRAM size?
     125        // BIOS settings?
     126        // 3D acceleration enabled?
     127        // hardware virtualization enabled?
     128        // nested paging enabled?
     129        // HWVirtExVPIDEnabled?
     130        // PAEEnabled?
     131        // snapshotFolder?
     132        // VRDPServer?
     133
     134        // create a new virtual system
     135        rc = pNewDesc.createObject();
     136        if (FAILED(rc)) throw rc;
     137        rc = pNewDesc->init();
     138        if (FAILED(rc)) throw rc;
     139
     140        /* Guest OS type */
     141        Utf8Str strOsTypeVBox(bstrGuestOSType);
     142        CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str());
     143        pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
     144                           "",
     145                           Utf8StrFmt("%RI32", cim),
     146                           strOsTypeVBox);
     147
     148        /* VM name */
     149        Utf8Str strVMName(bstrName1);
     150        pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
     151                           "",
     152                           strVMName,
     153                           strVMName);
     154
     155        // description
     156        Utf8Str strDescription(bstrDescription);
     157        pNewDesc->addEntry(VirtualSystemDescriptionType_Description,
     158                           "",
     159                           strDescription,
     160                           strDescription);
     161
     162        /* CPU count*/
     163        Utf8Str strCpuCount = Utf8StrFmt("%RI32", cCPUs);
     164        pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
     165                           "",
     166                           strCpuCount,
     167                           strCpuCount);
     168
     169        /* Memory */
     170        Utf8Str strMemory = Utf8StrFmt("%RI64", (uint64_t)ulMemSizeMB * _1M);
     171        pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
     172                           "",
     173                           strMemory,
     174                           strMemory);
     175
     176        int32_t lIDEControllerIndex = 0;
     177        int32_t lSATAControllerIndex = 0;
     178        int32_t lSCSIControllerIndex = 0;
     179
     180        /* Fetch all available storage controllers */
     181        com::SafeIfaceArray<IStorageController> nwControllers;
     182        rc = COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(nwControllers));
     183        if (FAILED(rc)) throw rc;
     184
     185        ComPtr<IStorageController> pIDEController;
     186#ifdef VBOX_WITH_AHCI
     187        ComPtr<IStorageController> pSATAController;
     188#endif /* VBOX_WITH_AHCI */
     189#ifdef VBOX_WITH_LSILOGIC
     190        ComPtr<IStorageController> pSCSIController;
     191#endif /* VBOX_WITH_LSILOGIC */
     192        for (size_t j = 0; j < nwControllers.size(); ++j)
     193        {
     194            StorageBus_T eType;
     195            rc = nwControllers[j]->COMGETTER(Bus)(&eType);
     196            if (FAILED(rc)) throw rc;
     197            if (   eType == StorageBus_IDE
     198                && pIDEController.isNull())
     199                pIDEController = nwControllers[j];
     200#ifdef VBOX_WITH_AHCI
     201            else if (   eType == StorageBus_SATA
     202                     && pSATAController.isNull())
     203                pSATAController = nwControllers[j];
     204#endif /* VBOX_WITH_AHCI */
     205#ifdef VBOX_WITH_LSILOGIC
     206            else if (   eType == StorageBus_SCSI
     207                     && pSATAController.isNull())
     208                pSCSIController = nwControllers[j];
     209#endif /* VBOX_WITH_LSILOGIC */
     210        }
     211
     212//     <const name="HardDiskControllerIDE" value="6" />
     213        if (!pIDEController.isNull())
     214        {
     215            Utf8Str strVbox;
     216            StorageControllerType_T ctlr;
     217            rc = pIDEController->COMGETTER(ControllerType)(&ctlr);
     218            if (FAILED(rc)) throw rc;
     219            switch(ctlr)
     220            {
     221                case StorageControllerType_PIIX3: strVbox = "PIIX3"; break;
     222                case StorageControllerType_PIIX4: strVbox = "PIIX4"; break;
     223                case StorageControllerType_ICH6: strVbox = "ICH6"; break;
     224            }
     225
     226            if (strVbox.length())
     227            {
     228                lIDEControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
     229                pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
     230                                   Utf8StrFmt("%d", lIDEControllerIndex),
     231                                   strVbox,
     232                                   strVbox);
     233            }
     234        }
     235
     236#ifdef VBOX_WITH_AHCI
     237//     <const name="HardDiskControllerSATA" value="7" />
     238        if (!pSATAController.isNull())
     239        {
     240            Utf8Str strVbox = "AHCI";
     241            lSATAControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
     242            pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
     243                               Utf8StrFmt("%d", lSATAControllerIndex),
     244                               strVbox,
     245                               strVbox);
     246        }
     247#endif // VBOX_WITH_AHCI
     248
     249#ifdef VBOX_WITH_LSILOGIC
     250//     <const name="HardDiskControllerSCSI" value="8" />
     251        if (!pSCSIController.isNull())
     252        {
     253            StorageControllerType_T ctlr;
     254            rc = pSCSIController->COMGETTER(ControllerType)(&ctlr);
     255            if (SUCCEEDED(rc))
     256            {
     257                Utf8Str strVbox = "LsiLogic";       // the default in VBox
     258                switch(ctlr)
     259                {
     260                    case StorageControllerType_LsiLogic: strVbox = "LsiLogic"; break;
     261                    case StorageControllerType_BusLogic: strVbox = "BusLogic"; break;
     262                }
     263                lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
     264                pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
     265                                   Utf8StrFmt("%d", lSCSIControllerIndex),
     266                                   strVbox,
     267                                   strVbox);
     268            }
     269            else
     270                throw rc;
     271        }
     272#endif // VBOX_WITH_LSILOGIC
     273
     274//     <const name="HardDiskImage" value="9" />
     275//     <const name="Floppy" value="18" />
     276//     <const name="CDROM" value="19" />
     277
     278        MediaData::AttachmentList::iterator itA;
     279        for (itA = mMediaData->mAttachments.begin();
     280             itA != mMediaData->mAttachments.end();
     281             ++itA)
     282        {
     283            ComObjPtr<MediumAttachment> pHDA = *itA;
     284
     285            // the attachment's data
     286            ComPtr<IMedium> pMedium;
     287            ComPtr<IStorageController> ctl;
     288            Bstr controllerName;
     289
     290            rc = pHDA->COMGETTER(Controller)(controllerName.asOutParam());
     291            if (FAILED(rc)) throw rc;
     292
     293            rc = GetStorageControllerByName(controllerName, ctl.asOutParam());
     294            if (FAILED(rc)) throw rc;
     295
     296            StorageBus_T storageBus;
     297            DeviceType_T deviceType;
     298            LONG lChannel;
     299            LONG lDevice;
     300
     301            rc = ctl->COMGETTER(Bus)(&storageBus);
     302            if (FAILED(rc)) throw rc;
     303
     304            rc = pHDA->COMGETTER(Type)(&deviceType);
     305            if (FAILED(rc)) throw rc;
     306
     307            rc = pHDA->COMGETTER(Medium)(pMedium.asOutParam());
     308            if (FAILED(rc)) throw rc;
     309
     310            rc = pHDA->COMGETTER(Port)(&lChannel);
     311            if (FAILED(rc)) throw rc;
     312
     313            rc = pHDA->COMGETTER(Device)(&lDevice);
     314            if (FAILED(rc)) throw rc;
     315
     316            Utf8Str strTargetVmdkName;
     317            Utf8Str strLocation;
     318            ULONG64 ullSize = 0;
     319
     320            if (    deviceType == DeviceType_HardDisk
     321                 && pMedium
     322               )
     323            {
     324                Bstr bstrLocation;
     325                rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam());
     326                if (FAILED(rc)) throw rc;
     327                strLocation = bstrLocation;
     328
     329                Bstr bstrName;
     330                rc = pMedium->COMGETTER(Name)(bstrName.asOutParam());
     331                if (FAILED(rc)) throw rc;
     332
     333                strTargetVmdkName = bstrName;
     334                strTargetVmdkName.stripExt();
     335                strTargetVmdkName.append(".vmdk");
     336
     337                // we need the size of the image so we can give it to addEntry();
     338                // later, on export, the progress weight will be based on this.
     339                // pMedium can be a differencing image though; in that case, we
     340                // need to use the size of the base instead.
     341                ComPtr<IMedium> pBaseMedium;
     342                rc = pMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
     343                        // returns pMedium if there are no diff images
     344                if (FAILED(rc)) throw rc;
     345
     346                // force reading state, or else size will be returned as 0
     347                MediumState_T ms;
     348                rc = pBaseMedium->RefreshState(&ms);
     349                if (FAILED(rc)) throw rc;
     350
     351                rc = pBaseMedium->COMGETTER(Size)(&ullSize);
     352                if (FAILED(rc)) throw rc;
     353            }
     354
     355            // and how this translates to the virtual system
     356            int32_t lControllerVsys = 0;
     357            LONG lChannelVsys;
     358
     359            switch (storageBus)
     360            {
     361                case StorageBus_IDE:
     362                    // this is the exact reverse to what we're doing in Appliance::taskThreadImportMachines,
     363                    // and it must be updated when that is changed!
     364
     365                    if (lChannel == 0 && lDevice == 0)      // primary master
     366                        lChannelVsys = 0;
     367                    else if (lChannel == 0 && lDevice == 1) // primary slave
     368                        lChannelVsys = 1;
     369                    else if (lChannel == 1 && lDevice == 0) // secondary master; by default this is the CD-ROM but as of VirtualBox 3.1 that can change
     370                        lChannelVsys = 2;
     371                    else if (lChannel == 1 && lDevice == 1) // secondary slave
     372                        lChannelVsys = 3;
     373                    else
     374                        throw setError(VBOX_E_NOT_SUPPORTED,
     375                                    tr("Cannot handle medium attachment: channel is %d, device is %d"), lChannel, lDevice);
     376
     377                    lControllerVsys = lIDEControllerIndex;
     378                break;
     379
     380                case StorageBus_SATA:
     381                    lChannelVsys = lChannel;        // should be between 0 and 29
     382                    lControllerVsys = lSATAControllerIndex;
     383                break;
     384
     385                case StorageBus_SCSI:
     386                    lChannelVsys = lChannel;        // should be between 0 and 15
     387                    lControllerVsys = lSCSIControllerIndex;
     388                break;
     389
     390                case StorageBus_Floppy:
     391                    lChannelVsys = 0;
     392                    lControllerVsys = 0;
     393                break;
     394
     395                default:
     396                    throw setError(VBOX_E_NOT_SUPPORTED,
     397                                tr("Cannot handle medium attachment: storageBus is %d, channel is %d, device is %d"), storageBus, lChannel, lDevice);
     398                break;
     399            }
     400
     401            Utf8StrFmt strExtra("controller=%RI32;channel=%RI32", lControllerVsys, lChannelVsys);
     402            Utf8Str strEmpty;
     403
     404            switch (deviceType)
     405            {
     406                case DeviceType_HardDisk:
     407                    Log(("Adding VirtualSystemDescriptionType_HardDiskImage, disk size: %RI64\n", ullSize));
     408                    pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
     409                                       strTargetVmdkName,   // disk ID: let's use the name
     410                                       strTargetVmdkName,   // OVF value:
     411                                       strLocation, // vbox value: media path
     412                                       (uint32_t)(ullSize / _1M),
     413                                       strExtra);
     414                break;
     415
     416                case DeviceType_DVD:
     417                    pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM,
     418                                       strEmpty,   // disk ID
     419                                       strEmpty,   // OVF value
     420                                       strEmpty, // vbox value
     421                                       1,           // ulSize
     422                                       strExtra);
     423                break;
     424
     425                case DeviceType_Floppy:
     426                    pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy,
     427                                       strEmpty,      // disk ID
     428                                       strEmpty,      // OVF value
     429                                       strEmpty,      // vbox value
     430                                       1,       // ulSize
     431                                       strExtra);
     432                break;
     433            }
     434        }
     435
     436//     <const name="NetworkAdapter" />
     437        size_t a;
     438        for (a = 0;
     439             a < SchemaDefs::NetworkAdapterCount;
     440             ++a)
     441        {
     442            ComPtr<INetworkAdapter> pNetworkAdapter;
     443            BOOL fEnabled;
     444            NetworkAdapterType_T adapterType;
     445            NetworkAttachmentType_T attachmentType;
     446
     447            rc = GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
     448            if (FAILED(rc)) throw rc;
     449            /* Enable the network card & set the adapter type */
     450            rc = pNetworkAdapter->COMGETTER(Enabled)(&fEnabled);
     451            if (FAILED(rc)) throw rc;
     452
     453            if (fEnabled)
     454            {
     455                Utf8Str strAttachmentType;
     456
     457                rc = pNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
     458                if (FAILED(rc)) throw rc;
     459
     460                rc = pNetworkAdapter->COMGETTER(AttachmentType)(&attachmentType);
     461                if (FAILED(rc)) throw rc;
     462
     463                switch (attachmentType)
     464                {
     465                    case NetworkAttachmentType_Null:
     466                        strAttachmentType = "Null";
     467                    break;
     468
     469                    case NetworkAttachmentType_NAT:
     470                        strAttachmentType = "NAT";
     471                    break;
     472
     473                    case NetworkAttachmentType_Bridged:
     474                        strAttachmentType = "Bridged";
     475                    break;
     476
     477                    case NetworkAttachmentType_Internal:
     478                        strAttachmentType = "Internal";
     479                    break;
     480
     481                    case NetworkAttachmentType_HostOnly:
     482                        strAttachmentType = "HostOnly";
     483                    break;
     484                }
     485
     486                pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
     487                                   "",      // ref
     488                                   strAttachmentType,      // orig
     489                                   Utf8StrFmt("%RI32", (uint32_t)adapterType),   // conf
     490                                   0,
     491                                   Utf8StrFmt("type=%s", strAttachmentType.c_str()));       // extra conf
     492            }
     493        }
     494
     495//     <const name="USBController"  />
     496#ifdef VBOX_WITH_USB
     497        if (fUSBEnabled)
     498            pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
     499#endif /* VBOX_WITH_USB */
     500
     501//     <const name="SoundCard"  />
     502        if (fAudioEnabled)
     503            pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
     504                               "",
     505                               "ensoniq1371",       // this is what OVFTool writes and VMware supports
     506                               Utf8StrFmt("%RI32", audioController));
     507
     508        // finally, add the virtual system to the appliance
     509        Appliance *pAppliance = static_cast<Appliance*>(aAppliance);
     510        AutoCaller autoCaller1(pAppliance);
     511        if (FAILED(autoCaller1.rc())) return autoCaller1.rc();
     512
     513        /* We return the new description to the caller */
     514        ComPtr<IVirtualSystemDescription> copy(pNewDesc);
     515        copy.queryInterfaceTo(aDescription);
     516
     517        AutoWriteLock alock(pAppliance COMMA_LOCKVAL_SRC_POS);
     518
     519        pAppliance->m->virtualSystemDescriptions.push_back(pNewDesc);
     520    }
     521    catch(HRESULT arc)
     522    {
     523        rc = arc;
     524    }
    320525
    321526    return rc;
     
    324529////////////////////////////////////////////////////////////////////////////////
    325530//
    326 // Appliance constructor / destructor
     531// IAppliance public methods
    327532//
    328533////////////////////////////////////////////////////////////////////////////////
    329534
    330 Appliance::Appliance()
    331     : mVirtualBox(NULL)
    332 {
    333 }
    334 
    335 Appliance::~Appliance()
    336 {
    337 }
    338 
    339535/**
    340  * Appliance COM initializer.
    341  * @param
     536 * Public method implementation.
     537 * @param format
     538 * @param path
     539 * @param aProgress
    342540 * @return
    343541 */
    344 HRESULT Appliance::init(VirtualBox *aVirtualBox)
     542STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress)
    345543{
    346     /* Enclose the state transition NotReady->InInit->Ready */
    347     AutoInitSpan autoInitSpan(this);
    348     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    349 
    350     /* Weak reference to a VirtualBox object */
    351     unconst(mVirtualBox) = aVirtualBox;
    352 
    353     // initialize data
    354     m = new Data;
    355 
    356     /* Confirm a successful initialization */
    357     autoInitSpan.setSucceeded();
    358 
    359     return S_OK;
    360 }
    361 
    362 /**
    363  * Appliance COM uninitializer.
    364  * @return
    365  */
    366 void Appliance::uninit()
    367 {
    368     /* Enclose the state transition Ready->InUninit->NotReady */
    369     AutoUninitSpan autoUninitSpan(this);
    370     if (autoUninitSpan.uninitDone())
    371         return;
    372 
    373     delete m;
    374     m = NULL;
     544    if (!path) return E_POINTER;
     545    CheckComArgOutPointerValid(aProgress);
     546
     547    AutoCaller autoCaller(this);
     548    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     549
     550    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     551
     552    // do not allow entering this method if the appliance is busy reading or writing
     553    if (!isApplianceIdle())
     554        return E_ACCESSDENIED;
     555
     556    // see if we can handle this file; for now we insist it has an ".ovf" extension
     557    Utf8Str strPath = path;
     558    if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
     559        return setError(VBOX_E_FILE_ERROR,
     560                        tr("Appliance file must have .ovf extension"));
     561
     562    Utf8Str strFormat(format);
     563    TaskExportOVF::OVFFormat ovfF;
     564    if (strFormat == "ovf-0.9")
     565        ovfF = TaskExportOVF::OVF_0_9;
     566    else if (strFormat == "ovf-1.0")
     567        ovfF = TaskExportOVF::OVF_1_0;
     568    else
     569        return setError(VBOX_E_FILE_ERROR,
     570                        tr("Invalid format \"%s\" specified"), strFormat.c_str());
     571
     572    ComObjPtr<Progress> progress;
     573    HRESULT rc = S_OK;
     574    try
     575    {
     576        /* Parse all necessary info out of the URI */
     577        parseURI(strPath, m->locInfo);
     578        rc = writeImpl(ovfF, m->locInfo, progress);
     579    }
     580    catch (HRESULT aRC)
     581    {
     582        rc = aRC;
     583    }
     584
     585    if (SUCCEEDED(rc))
     586        /* Return progress to the caller */
     587        progress.queryInterfaceTo(aProgress);
     588
     589    return rc;
    375590}
    376591
     
    382597
    383598/**
    384  * Returns true if the appliance is in "idle" state. This should always be the
    385  * case unless an import or export is currently in progress. Similar to machine
    386  * states, this permits the Appliance implementation code to let go of the
    387  * Appliance object lock while a time-consuming disk conversion is in progress
    388  * without exposing the appliance to conflicting calls.
     599 * Implementation for writing out the OVF to disk. This starts a new thread which will call
     600 * Appliance::taskThreadWriteOVF(). This is in a separate private method because it is used
     601 * from two locations:
    389602 *
    390  * This sets an error on "this" (the appliance) and returns false if the appliance
    391  * is busy. The caller should then return E_ACCESSDENIED.
     603 * 1) from the public Appliance::Write().
     604 * 2) from Appliance::writeS3(), which got called from a previous instance of Appliance::taskThreadWriteOVF().
    392605 *
    393  * Must be called from under the object lock!
    394  *
    395  * @return
    396  */
    397 bool Appliance::isApplianceIdle() const
    398 {
    399     if (m->state == Data::ApplianceImporting)
    400         setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy importing files");
    401     else if (m->state == Data::ApplianceExporting)
    402         setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy exporting files");
    403     else
    404         return true;
    405 
    406     return false;
    407 }
    408 
    409 HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
    410 {
    411     IMachine *machine = NULL;
    412     char *tmpName = RTStrDup(aName.c_str());
    413     int i = 1;
    414     /* @todo: Maybe too cost-intensive; try to find a lighter way */
    415     while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
    416     {
    417         RTStrFree(tmpName);
    418         RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
    419         ++i;
    420     }
    421     aName = tmpName;
    422     RTStrFree(tmpName);
    423 
    424     return S_OK;
    425 }
    426 
    427 HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
    428 {
    429     IMedium *harddisk = NULL;
    430     char *tmpName = RTStrDup(aName.c_str());
    431     int i = 1;
    432     /* Check if the file exists or if a file with this path is registered
    433      * already */
    434     /* @todo: Maybe too cost-intensive; try to find a lighter way */
    435     while (RTPathExists(tmpName) ||
    436            mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
    437     {
    438         RTStrFree(tmpName);
    439         char *tmpDir = RTStrDup(aName.c_str());
    440         RTPathStripFilename(tmpDir);;
    441         char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
    442         RTPathStripExt(tmpFile);
    443         const char *tmpExt = RTPathExt(aName.c_str());
    444         RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
    445         RTStrFree(tmpFile);
    446         RTStrFree(tmpDir);
    447         ++i;
    448     }
    449     aName = tmpName;
    450     RTStrFree(tmpName);
    451 
    452     return S_OK;
    453 }
    454 
    455 /**
    456  * Called from the import and export background threads to synchronize the second
    457  * background disk thread's progress object with the current progress object so
    458  * that the user interface sees progress correctly and that cancel signals are
    459  * passed on to the second thread.
    460  * @param pProgressThis Progress object of the current thread.
    461  * @param pProgressAsync Progress object of asynchronous task running in background.
    462  */
    463 void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
    464                                      ComPtr<IProgress> &pProgressAsync)
    465 {
    466     HRESULT rc;
    467 
    468     // now loop until the asynchronous operation completes and then report its result
    469     BOOL fCompleted;
    470     BOOL fCanceled;
    471     ULONG currentPercent;
    472     while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
    473     {
    474         rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
    475         if (FAILED(rc)) throw rc;
    476         if (fCanceled)
    477         {
    478             pProgressAsync->Cancel();
    479             break;
    480         }
    481 
    482         rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
    483         if (FAILED(rc)) throw rc;
    484         if (!pProgressThis.isNull())
    485             pProgressThis->SetCurrentOperationProgress(currentPercent);
    486         if (fCompleted)
    487             break;
    488 
    489         /* Make sure the loop is not too tight */
    490         rc = pProgressAsync->WaitForCompletion(100);
    491         if (FAILED(rc)) throw rc;
    492     }
    493     // report result of asynchronous operation
    494     LONG iRc;
    495     rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
    496     if (FAILED(rc)) throw rc;
    497 
    498 
    499     // if the thread of the progress object has an error, then
    500     // retrieve the error info from there, or it'll be lost
    501     if (FAILED(iRc))
    502     {
    503         ProgressErrorInfo info(pProgressAsync);
    504         Utf8Str str(info.getText());
    505         const char *pcsz = str.c_str();
    506         HRESULT rc2 = setError(iRc, pcsz);
    507         throw rc2;
    508     }
    509 }
    510 
    511 void Appliance::addWarning(const char* aWarning, ...)
    512 {
    513     va_list args;
    514     va_start(args, aWarning);
    515     Utf8StrFmtVA str(aWarning, args);
    516     va_end(args);
    517     m->llWarnings.push_back(str);
    518 }
    519 
    520 void Appliance::disksWeight(uint32_t &ulTotalMB, uint32_t &cDisks) const
    521 {
    522     ulTotalMB = 0;
    523     cDisks = 0;
    524     /* Weigh the disk images according to their sizes */
    525     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    526     for (it = m->virtualSystemDescriptions.begin();
    527          it != m->virtualSystemDescriptions.end();
    528          ++it)
    529     {
    530         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    531         /* One for every hard disk of the Virtual System */
    532         std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    533         std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    534         for (itH = avsdeHDs.begin();
    535              itH != avsdeHDs.end();
    536              ++itH)
    537         {
    538             const VirtualSystemDescriptionEntry *pHD = *itH;
    539             ulTotalMB += pHD->ulSizeMB;
    540             ++cDisks;
    541         }
    542     }
    543 
    544 }
    545 
    546 HRESULT Appliance::setUpProgressFS(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    547 {
    548     HRESULT rc;
    549 
    550     /* Create the progress object */
    551     pProgress.createObject();
    552 
    553     /* Weigh the disk images according to their sizes */
    554     uint32_t ulTotalMB;
    555     uint32_t cDisks;
    556     disksWeight(ulTotalMB, cDisks);
    557 
    558     ULONG cOperations = 1 + cDisks;     // one op per disk plus 1 for the XML
    559 
    560     ULONG ulTotalOperationsWeight;
    561     if (ulTotalMB)
    562     {
    563         m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1  / 100);    // use 1% of the progress for the XML
    564         ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
    565     }
    566     else
    567     {
    568         // no disks to export:
    569         ulTotalOperationsWeight = 1;
    570         m->ulWeightPerOperation = 1;
    571     }
    572 
    573     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    574          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    575 
    576     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    577                          bstrDescription,
    578                          TRUE /* aCancelable */,
    579                          cOperations, // ULONG cOperations,
    580                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    581                          bstrDescription, // CBSTR bstrFirstOperationDescription,
    582                          m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
    583     return rc;
    584 }
    585 
    586 HRESULT Appliance::setUpProgressImportS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    587 {
    588     HRESULT rc;
    589 
    590     /* Create the progress object */
    591     pProgress.createObject();
    592 
    593     /* Weigh the disk images according to their sizes */
    594     uint32_t ulTotalMB;
    595     uint32_t cDisks;
    596     disksWeight(ulTotalMB, cDisks);
    597 
    598     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 */
    599 
    600     ULONG ulTotalOperationsWeight = ulTotalMB;
    601     if (!ulTotalOperationsWeight)
    602         // no disks to export:
    603         ulTotalOperationsWeight = 1;
    604 
    605     ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50  / 100);  // use 50% for import
    606     ulTotalOperationsWeight += ulImportWeight;
    607 
    608     m->ulWeightPerOperation = ulImportWeight; /* save for using later */
    609 
    610     ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1  / 100);  // use 0.1% for init
    611     ulTotalOperationsWeight += ulInitWeight;
    612 
    613     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    614          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    615 
    616     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    617                          bstrDescription,
    618                          TRUE /* aCancelable */,
    619                          cOperations, // ULONG cOperations,
    620                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    621                          Bstr(tr("Init")), // CBSTR bstrFirstOperationDescription,
    622                          ulInitWeight); // ULONG ulFirstOperationWeight,
    623     return rc;
    624 }
    625 
    626 HRESULT Appliance::setUpProgressWriteS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    627 {
    628     HRESULT rc;
    629 
    630     /* Create the progress object */
    631     pProgress.createObject();
    632 
    633     /* Weigh the disk images according to their sizes */
    634     uint32_t ulTotalMB;
    635     uint32_t cDisks;
    636     disksWeight(ulTotalMB, cDisks);
    637 
    638     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 */
    639 
    640     ULONG ulTotalOperationsWeight;
    641     if (ulTotalMB)
    642     {
    643         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)
    644         ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
    645     }
    646     else
    647     {
    648         // no disks to export:
    649         ulTotalOperationsWeight = 1;
    650         m->ulWeightPerOperation = 1;
    651     }
    652     ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
    653     ulTotalOperationsWeight += ulOVFCreationWeight;
    654 
    655     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    656          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    657 
    658     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    659                          bstrDescription,
    660                          TRUE /* aCancelable */,
    661                          cOperations, // ULONG cOperations,
    662                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    663                          bstrDescription, // CBSTR bstrFirstOperationDescription,
    664                          ulOVFCreationWeight); // ULONG ulFirstOperationWeight,
    665     return rc;
    666 }
    667 
    668 void Appliance::parseURI(Utf8Str strUri, LocationInfo &locInfo) const
    669 {
    670     /* Check the URI for the protocol */
    671     if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
    672     {
    673         locInfo.storageType = VFSType_File;
    674         strUri = strUri.substr(sizeof("file://") - 1);
    675     }
    676     else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
    677     {
    678         locInfo.storageType = VFSType_S3;
    679         strUri = strUri.substr(sizeof("SunCloud://") - 1);
    680     }
    681     else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
    682     {
    683         locInfo.storageType = VFSType_S3;
    684         strUri = strUri.substr(sizeof("S3://") - 1);
    685     }
    686     else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
    687         throw E_NOTIMPL;
    688 
    689     /* Not necessary on a file based URI */
    690     if (locInfo.storageType != VFSType_File)
    691     {
    692         size_t uppos = strUri.find("@"); /* username:password combo */
    693         if (uppos != Utf8Str::npos)
    694         {
    695             locInfo.strUsername = strUri.substr(0, uppos);
    696             strUri = strUri.substr(uppos + 1);
    697             size_t upos = locInfo.strUsername.find(":");
    698             if (upos != Utf8Str::npos)
    699             {
    700                 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
    701                 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
    702             }
    703         }
    704         size_t hpos = strUri.find("/"); /* hostname part */
    705         if (hpos != Utf8Str::npos)
    706         {
    707             locInfo.strHostname = strUri.substr(0, hpos);
    708             strUri = strUri.substr(hpos);
    709         }
    710     }
    711 
    712     locInfo.strPath = strUri;
    713 }
    714 
    715 void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket) const
    716 {
    717     /* Buckets are S3 specific. So parse the bucket out of the file path */
    718     if (!aPath.startsWith("/"))
    719         throw setError(E_INVALIDARG,
    720                        tr("The path '%s' must start with /"), aPath.c_str());
    721     size_t bpos = aPath.find("/", 1);
    722     if (bpos != Utf8Str::npos)
    723     {
    724         aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
    725         aPath = aPath.substr(bpos); /* The rest of the file path */
    726     }
    727     /* If there is no bucket name provided reject it */
    728     if (aBucket.isEmpty())
    729         throw setError(E_INVALIDARG,
    730                        tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
    731 }
    732 
    733 Utf8Str Appliance::manifestFileName(Utf8Str aPath) const
    734 {
    735     /* Get the name part */
    736     char *pszMfName = RTStrDup(RTPathFilename(aPath.c_str()));
    737     /* Strip any extensions */
    738     RTPathStripExt(pszMfName);
    739     /* Path without the filename */
    740     aPath.stripFilename();
    741     /* Format the manifest path */
    742     Utf8StrFmt strMfFile("%s/%s.mf", aPath.c_str(), pszMfName);
    743     RTStrFree(pszMfName);
    744     return strMfFile;
    745 }
    746 
    747 struct Appliance::TaskOVF
    748 {
    749     TaskOVF(Appliance *aThat)
    750       : pAppliance(aThat),
    751         rc(S_OK)
    752     {}
    753 
    754     static int updateProgress(unsigned uPercent, void *pvUser);
    755 
    756     LocationInfo locInfo;
    757     Appliance *pAppliance;
    758     ComObjPtr<Progress> progress;
    759     HRESULT rc;
    760 };
    761 
    762 struct Appliance::TaskImportOVF : Appliance::TaskOVF
    763 {
    764     enum TaskType
    765     {
    766         Read,
    767         Import
    768     };
    769 
    770     TaskImportOVF(Appliance *aThat)
    771         : TaskOVF(aThat),
    772           taskType(Read)
    773     {}
    774 
    775     int startThread();
    776 
    777     TaskType taskType;
    778 };
    779 
    780 struct Appliance::TaskExportOVF : Appliance::TaskOVF
    781 {
    782     enum OVFFormat
    783     {
    784         unspecified,
    785         OVF_0_9,
    786         OVF_1_0
    787     };
    788     enum TaskType
    789     {
    790         Write
    791     };
    792 
    793     TaskExportOVF(Appliance *aThat)
    794         : TaskOVF(aThat),
    795           taskType(Write)
    796     {}
    797 
    798     int startThread();
    799 
    800     TaskType taskType;
    801     OVFFormat enFormat;
    802 };
    803 
    804 struct MyHardDiskAttachment
    805 {
    806     Bstr                bstrUuid;
    807     ComPtr<IMachine>    pMachine;
    808     Bstr                controllerType;
    809     int32_t             lChannel;
    810     int32_t             lDevice;
    811 };
    812 
    813 /* static */
    814 int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
    815 {
    816     Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
    817 
    818     if (    pTask
    819          && !pTask->progress.isNull())
    820     {
    821         BOOL fCanceled;
    822         pTask->progress->COMGETTER(Canceled)(&fCanceled);
    823         if (fCanceled)
    824             return -1;
    825         pTask->progress->SetCurrentOperationProgress(uPercent);
    826     }
    827     return VINF_SUCCESS;
    828 }
    829 
    830 HRESULT Appliance::readImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    831 {
    832     /* Initialize our worker task */
    833     std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
    834     /* What should the task do */
    835     task->taskType = TaskImportOVF::Read;
    836     /* Copy the current location info to the task */
    837     task->locInfo = aLocInfo;
    838 
    839     BstrFmt bstrDesc = BstrFmt(tr("Read appliance '%s'"),
    840                                aLocInfo.strPath.c_str());
    841     HRESULT rc;
    842     /* Create the progress object */
    843     aProgress.createObject();
    844     if (task->locInfo.storageType == VFSType_File)
    845     {
    846         /* 1 operation only */
    847         rc = aProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    848                              bstrDesc,
    849                              TRUE /* aCancelable */);
    850     }
    851     else
    852     {
    853         /* 4/5 is downloading, 1/5 is reading */
    854         rc = aProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    855                              bstrDesc,
    856                              TRUE /* aCancelable */,
    857                              2, // ULONG cOperations,
    858                              5, // ULONG ulTotalOperationsWeight,
    859                              BstrFmt(tr("Download appliance '%s'"),
    860                                      aLocInfo.strPath.c_str()), // CBSTR bstrFirstOperationDescription,
    861                              4); // ULONG ulFirstOperationWeight,
    862     }
    863     if (FAILED(rc)) throw rc;
    864 
    865     task->progress = aProgress;
    866 
    867     rc = task->startThread();
    868     if (FAILED(rc)) throw rc;
    869 
    870     /* Don't destruct on success */
    871     task.release();
    872 
    873     return rc;
    874 }
    875 
    876 /**
    877  * Implementation of the import code. This gets called from the public Appliance::ImportMachines()
    878  * method as well as Appliance::importS3().
     606 * @param aFormat
    879607 * @param aLocInfo
    880608 * @param aProgress
    881609 * @return
    882610 */
    883 HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    884 {
    885     /* Initialize our worker task */
    886     std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
    887     /* What should the task do */
    888     task->taskType = TaskImportOVF::Import;
    889     /* Copy the current location info to the task */
    890     task->locInfo = aLocInfo;
    891 
    892     Bstr progressDesc = BstrFmt(tr("Import appliance '%s'"),
    893                                 aLocInfo.strPath.c_str());
    894 
    895     HRESULT rc = S_OK;
    896 
    897     /* todo: This progress init stuff should be done a little bit more generic */
    898     if (task->locInfo.storageType == VFSType_File)
    899         rc = setUpProgressFS(aProgress, progressDesc);
    900     else
    901         rc = setUpProgressImportS3(aProgress, progressDesc);
    902     if (FAILED(rc)) throw rc;
    903 
    904     task->progress = aProgress;
    905 
    906     rc = task->startThread();
    907     if (FAILED(rc)) throw rc;
    908 
    909     /* Don't destruct on success */
    910     task.release();
    911 
    912     return rc;
    913 }
    914 
    915 /**
    916  * Worker thread implementation for Read() (ovf reader).
    917  * @param aThread
    918  * @param pvUser
    919  */
    920 /* static */
    921 DECLCALLBACK(int) Appliance::taskThreadImportOVF(RTTHREAD /* aThread */, void *pvUser)
    922 {
    923     std::auto_ptr<TaskImportOVF> task(static_cast<TaskImportOVF*>(pvUser));
    924     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    925 
    926     Appliance *pAppliance = task->pAppliance;
    927 
    928     LogFlowFuncEnter();
    929     LogFlowFunc(("Appliance %p\n", pAppliance));
    930 
    931     HRESULT rc = S_OK;
    932 
    933     switch (task->taskType)
    934     {
    935         case TaskImportOVF::Read:
    936         {
    937             if (task->locInfo.storageType == VFSType_File)
    938                 rc = pAppliance->readFS(task.get());
    939             else if (task->locInfo.storageType == VFSType_S3)
    940                 rc = pAppliance->readS3(task.get());
    941             break;
    942         }
    943         case TaskImportOVF::Import:
    944         {
    945             if (task->locInfo.storageType == VFSType_File)
    946                 rc = pAppliance->importFS(task.get());
    947             else if (task->locInfo.storageType == VFSType_S3)
    948                 rc = pAppliance->importS3(task.get());
    949             break;
    950         }
    951     }
    952 
    953     LogFlowFunc(("rc=%Rhrc\n", rc));
    954     LogFlowFuncLeave();
    955 
    956     return VINF_SUCCESS;
    957 }
    958 
    959 int Appliance::TaskImportOVF::startThread()
    960 {
    961     int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOVF, this,
    962                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    963                              "Appliance::Task");
    964 
    965     ComAssertMsgRCRet(vrc,
    966                       ("Could not create taskThreadImportOVF (%Rrc)\n", vrc), E_FAIL);
    967 
    968     return S_OK;
    969 }
    970 
    971 int Appliance::readFS(TaskImportOVF *pTask)
    972 {
    973     LogFlowFuncEnter();
    974     LogFlowFunc(("Appliance %p\n", this));
    975 
    976     AutoCaller autoCaller(this);
    977     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    978 
    979     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    980 
    981     HRESULT rc = S_OK;
    982 
    983     try
    984     {
    985         /* Read & parse the XML structure of the OVF file */
    986         m->pReader = new OVFReader(pTask->locInfo.strPath);
    987         /* Create the SHA1 sum of the OVF file for later validation */
    988         char *pszDigest;
    989         int vrc = RTSha1Digest(pTask->locInfo.strPath.c_str(), &pszDigest);
    990         if (RT_FAILURE(vrc))
    991             throw setError(VBOX_E_FILE_ERROR,
    992                            tr("Couldn't calculate SHA1 digest for file '%s' (%Rrc)"),
    993                            RTPathFilename(pTask->locInfo.strPath.c_str()), vrc);
    994         m->strOVFSHA1Digest = pszDigest;
    995         RTStrFree(pszDigest);
    996     }
    997     catch(xml::Error &x)
    998     {
    999         rc = setError(VBOX_E_FILE_ERROR,
    1000                       x.what());
    1001     }
    1002     catch(HRESULT aRC)
    1003     {
    1004         rc = aRC;
    1005     }
    1006 
    1007     pTask->rc = rc;
    1008 
    1009     if (!pTask->progress.isNull())
    1010         pTask->progress->notifyComplete(rc);
    1011 
    1012     LogFlowFunc(("rc=%Rhrc\n", rc));
    1013     LogFlowFuncLeave();
    1014 
    1015     return VINF_SUCCESS;
    1016 }
    1017 
    1018 int Appliance::readS3(TaskImportOVF *pTask)
    1019 {
    1020     LogFlowFuncEnter();
    1021     LogFlowFunc(("Appliance %p\n", this));
    1022 
    1023     AutoCaller autoCaller(this);
    1024     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1025 
    1026     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    1027 
    1028     HRESULT rc = S_OK;
    1029     int vrc = VINF_SUCCESS;
    1030     RTS3 hS3 = NIL_RTS3;
    1031     char szOSTmpDir[RTPATH_MAX];
    1032     RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
    1033     /* The template for the temporary directory created below */
    1034     char *pszTmpDir;
    1035     RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
    1036     list< pair<Utf8Str, ULONG> > filesList;
    1037     Utf8Str strTmpOvf;
    1038 
    1039     try
    1040     {
    1041         /* Extract the bucket */
    1042         Utf8Str tmpPath = pTask->locInfo.strPath;
    1043         Utf8Str bucket;
    1044         parseBucket(tmpPath, bucket);
    1045 
    1046         /* We need a temporary directory which we can put the OVF file & all
    1047          * disk images in */
    1048         vrc = RTDirCreateTemp(pszTmpDir);
    1049         if (RT_FAILURE(vrc))
    1050             throw setError(VBOX_E_FILE_ERROR,
    1051                            tr("Cannot create temporary directory '%s'"), pszTmpDir);
    1052 
    1053         /* The temporary name of the target OVF file */
    1054         strTmpOvf = Utf8StrFmt("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str()));
    1055 
    1056         /* Next we have to download the OVF */
    1057         vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
    1058         if(RT_FAILURE(vrc))
    1059             throw setError(VBOX_E_IPRT_ERROR,
    1060                            tr("Cannot create S3 service handler"));
    1061         RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
    1062 
    1063         /* Get it */
    1064         char *pszFilename = RTPathFilename(strTmpOvf.c_str());
    1065         vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strTmpOvf.c_str());
    1066         if (RT_FAILURE(vrc))
    1067         {
    1068             if(vrc == VERR_S3_CANCELED)
    1069                 throw S_OK; /* todo: !!!!!!!!!!!!! */
    1070             else if(vrc == VERR_S3_ACCESS_DENIED)
    1071                 throw setError(E_ACCESSDENIED,
    1072                                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);
    1073             else if(vrc == VERR_S3_NOT_FOUND)
    1074                 throw setError(VBOX_E_FILE_ERROR,
    1075                                tr("Cannot download file '%s' from S3 storage server (File not found)"), pszFilename);
    1076             else
    1077                 throw setError(VBOX_E_IPRT_ERROR,
    1078                                tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
    1079         }
    1080 
    1081         /* Close the connection early */
    1082         RTS3Destroy(hS3);
    1083         hS3 = NIL_RTS3;
    1084 
    1085         if (!pTask->progress.isNull())
    1086             pTask->progress->SetNextOperation(Bstr(tr("Reading")), 1);
    1087 
    1088         /* Prepare the temporary reading of the OVF */
    1089         ComObjPtr<Progress> progress;
    1090         LocationInfo li;
    1091         li.strPath = strTmpOvf;
    1092         /* Start the reading from the fs */
    1093         rc = readImpl(li, progress);
    1094         if (FAILED(rc)) throw rc;
    1095 
    1096         /* Unlock the appliance for the reading thread */
    1097         appLock.release();
    1098         /* Wait until the reading is done, but report the progress back to the
    1099            caller */
    1100         ComPtr<IProgress> progressInt(progress);
    1101         waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
    1102 
    1103         /* Again lock the appliance for the next steps */
    1104         appLock.acquire();
    1105     }
    1106     catch(HRESULT aRC)
    1107     {
    1108         rc = aRC;
    1109     }
    1110     /* Cleanup */
    1111     RTS3Destroy(hS3);
    1112     /* Delete all files which where temporary created */
    1113     if (RTPathExists(strTmpOvf.c_str()))
    1114     {
    1115         vrc = RTFileDelete(strTmpOvf.c_str());
    1116         if(RT_FAILURE(vrc))
    1117             rc = setError(VBOX_E_FILE_ERROR,
    1118                           tr("Cannot delete file '%s' (%Rrc)"), strTmpOvf.c_str(), vrc);
    1119     }
    1120     /* Delete the temporary directory */
    1121     if (RTPathExists(pszTmpDir))
    1122     {
    1123         vrc = RTDirRemove(pszTmpDir);
    1124         if(RT_FAILURE(vrc))
    1125             rc = setError(VBOX_E_FILE_ERROR,
    1126                           tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
    1127     }
    1128     if (pszTmpDir)
    1129         RTStrFree(pszTmpDir);
    1130 
    1131     pTask->rc = rc;
    1132 
    1133     if (!pTask->progress.isNull())
    1134         pTask->progress->notifyComplete(rc);
    1135 
    1136     LogFlowFunc(("rc=%Rhrc\n", rc));
    1137     LogFlowFuncLeave();
    1138 
    1139     return VINF_SUCCESS;
    1140 }
    1141 
    1142 int Appliance::importFS(TaskImportOVF *pTask)
    1143 {
    1144     LogFlowFuncEnter();
    1145     LogFlowFunc(("Appliance %p\n", this));
    1146 
    1147     AutoCaller autoCaller(this);
    1148     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1149 
    1150     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    1151 
    1152     if (!isApplianceIdle())
    1153         return VERR_ACCESS_DENIED;
    1154 
    1155     // Change the appliance state so we can safely leave the lock while doing time-consuming
    1156     // disk imports; also the below method calls do all kinds of locking which conflicts with
    1157     // the appliance object lock
    1158     m->state = Data::ApplianceImporting;
    1159     appLock.release();
    1160 
    1161     HRESULT rc = S_OK;
    1162 
    1163     // rollback for errors:
    1164     // a list of images that we created/imported
    1165     list<MyHardDiskAttachment> llHardDiskAttachments;
    1166     list< ComPtr<IMedium> > llHardDisksCreated;
    1167     list<Bstr> llMachinesRegistered;            // list of string UUIDs
    1168 
    1169     ComPtr<ISession> session;
    1170     bool fSessionOpen = false;
    1171     rc = session.createInprocObject(CLSID_Session);
    1172     if (FAILED(rc)) return rc;
    1173 
    1174     const OVFReader &reader = *m->pReader;
    1175     // this is safe to access because this thread only gets started
    1176     // if pReader != NULL
    1177 
    1178     /* If an manifest file exists, verify the content. Therefore we need all
    1179      * files which are referenced by the OVF & the OVF itself */
    1180     Utf8Str strMfFile = manifestFileName(pTask->locInfo.strPath);
    1181     list<Utf8Str> filesList;
    1182     if (RTPathExists(strMfFile.c_str()))
    1183     {
    1184         Utf8Str strSrcDir(pTask->locInfo.strPath);
    1185         strSrcDir.stripFilename();
    1186         /* Add every disks of every virtual system to an internal list */
    1187         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    1188         for (it = m->virtualSystemDescriptions.begin();
    1189              it != m->virtualSystemDescriptions.end();
    1190              ++it)
    1191         {
    1192             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    1193             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    1194             std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    1195             for (itH = avsdeHDs.begin();
    1196                  itH != avsdeHDs.end();
    1197                  ++itH)
    1198             {
    1199                 VirtualSystemDescriptionEntry *vsdeHD = *itH;
    1200                 /* Find the disk from the OVF's disk list */
    1201                 DiskImagesMap::const_iterator itDiskImage = reader.m_mapDisks.find(vsdeHD->strRef);
    1202                 const DiskImage &di = itDiskImage->second;
    1203                 Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
    1204                 filesList.push_back(strSrcFilePath);
    1205             }
    1206         }
    1207         /* Create the test list */
    1208         PRTMANIFESTTEST pTestList = (PRTMANIFESTTEST)RTMemAllocZ(sizeof(RTMANIFESTTEST)*(filesList.size()+1));
    1209         pTestList[0].pszTestFile = (char*)pTask->locInfo.strPath.c_str();
    1210         pTestList[0].pszTestDigest = (char*)m->strOVFSHA1Digest.c_str();
    1211         int vrc = VINF_SUCCESS;
    1212         size_t i = 1;
    1213         list<Utf8Str>::const_iterator it1;
    1214         for (it1 = filesList.begin();
    1215              it1 != filesList.end();
    1216              ++it1, ++i)
    1217         {
    1218             char* pszDigest;
    1219             vrc = RTSha1Digest((*it1).c_str(), &pszDigest);
    1220             pTestList[i].pszTestFile = (char*)(*it1).c_str();
    1221             pTestList[i].pszTestDigest = pszDigest;
    1222         }
    1223         size_t cIndexOnError;
    1224         vrc = RTManifestVerify(strMfFile.c_str(), pTestList, filesList.size() + 1, &cIndexOnError);
    1225         if (vrc == VERR_MANIFEST_DIGEST_MISMATCH)
    1226             rc = setError(VBOX_E_FILE_ERROR,
    1227                           tr("The SHA1 digest of '%s' doesn't match to the one in '%s'"),
    1228                           RTPathFilename(pTestList[cIndexOnError].pszTestFile),
    1229                           RTPathFilename(strMfFile.c_str()));
    1230         else if (RT_FAILURE(vrc))
    1231             rc = setError(VBOX_E_FILE_ERROR,
    1232                           tr("Couldn't verify the content of '%s' against the available files (%Rrc)"),
    1233                           RTPathFilename(strMfFile.c_str()),
    1234                           vrc);
    1235         /* Cleanup */
    1236         for (size_t j = 1;
    1237              j < filesList.size();
    1238              ++j)
    1239             RTStrFree(pTestList[j].pszTestDigest);
    1240         RTMemFree(pTestList);
    1241         if (FAILED(rc))
    1242         {
    1243             /* Return on error */
    1244             pTask->rc = rc;
    1245 
    1246             if (!pTask->progress.isNull())
    1247                 pTask->progress->notifyComplete(rc);
    1248             return rc;
    1249         }
    1250     }
    1251 
    1252     list<VirtualSystem>::const_iterator it;
    1253     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
    1254     /* Iterate through all virtual systems of that appliance */
    1255     size_t i = 0;
    1256     for (it = reader.m_llVirtualSystems.begin(),
    1257          it1 = m->virtualSystemDescriptions.begin();
    1258          it != reader.m_llVirtualSystems.end();
    1259          ++it, ++it1, ++i)
    1260     {
    1261         const VirtualSystem &vsysThis = *it;
    1262         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it1);
    1263 
    1264         ComPtr<IMachine> pNewMachine;
    1265 
    1266         /* Catch possible errors */
    1267         try
    1268         {
    1269             /* Guest OS type */
    1270             std::list<VirtualSystemDescriptionEntry*> vsdeOS;
    1271             vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
    1272             if (vsdeOS.size() < 1)
    1273                 throw setError(VBOX_E_FILE_ERROR,
    1274                                tr("Missing guest OS type"));
    1275             const Utf8Str &strOsTypeVBox = vsdeOS.front()->strVbox;
    1276 
    1277             /* Now that we know the base system get our internal defaults based on that. */
    1278             ComPtr<IGuestOSType> osType;
    1279             rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam());
    1280             if (FAILED(rc)) throw rc;
    1281 
    1282             /* Create the machine */
    1283             /* First get the name */
    1284             std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
    1285             if (vsdeName.size() < 1)
    1286                 throw setError(VBOX_E_FILE_ERROR,
    1287                                tr("Missing VM name"));
    1288             const Utf8Str &strNameVBox = vsdeName.front()->strVbox;
    1289             rc = mVirtualBox->CreateMachine(Bstr(strNameVBox), Bstr(strOsTypeVBox),
    1290                                                  Bstr(), Bstr(), FALSE,
    1291                                                  pNewMachine.asOutParam());
    1292             if (FAILED(rc)) throw rc;
    1293 
    1294             // and the description
    1295             std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
    1296             if (vsdeDescription.size())
    1297             {
    1298                 const Utf8Str &strDescription = vsdeDescription.front()->strVbox;
    1299                 rc = pNewMachine->COMSETTER(Description)(Bstr(strDescription));
    1300                 if (FAILED(rc)) throw rc;
    1301             }
    1302 
    1303             /* CPU count */
    1304             std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU);
    1305             ComAssertMsgThrow(vsdeCPU.size() == 1, ("CPU count missing"), E_FAIL);
    1306             const Utf8Str &cpuVBox = vsdeCPU.front()->strVbox;
    1307             ULONG tmpCount = (ULONG)RTStrToUInt64(cpuVBox.c_str());
    1308             rc = pNewMachine->COMSETTER(CPUCount)(tmpCount);
    1309             if (FAILED(rc)) throw rc;
    1310             bool fEnableIOApic = false;
    1311             /* We need HWVirt & IO-APIC if more than one CPU is requested */
    1312             if (tmpCount > 1)
    1313             {
    1314                 rc = pNewMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, TRUE);
    1315                 if (FAILED(rc)) throw rc;
    1316 
    1317                 fEnableIOApic = true;
    1318             }
    1319 
    1320             /* RAM */
    1321             std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
    1322             ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL);
    1323             const Utf8Str &memoryVBox = vsdeRAM.front()->strVbox;
    1324             ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str());
    1325             rc = pNewMachine->COMSETTER(MemorySize)(tt);
    1326             if (FAILED(rc)) throw rc;
    1327 
    1328             /* VRAM */
    1329             /* Get the recommended VRAM for this guest OS type */
    1330             ULONG vramVBox;
    1331             rc = osType->COMGETTER(RecommendedVRAM)(&vramVBox);
    1332             if (FAILED(rc)) throw rc;
    1333 
    1334             /* Set the VRAM */
    1335             rc = pNewMachine->COMSETTER(VRAMSize)(vramVBox);
    1336             if (FAILED(rc)) throw rc;
    1337 
    1338             /* I/O APIC: so far we have no setting for this. Enable it if we
    1339               import a Windows VM because if if Windows was installed without IOAPIC,
    1340               it will not mind finding an one later on, but if Windows was installed
    1341               _with_ an IOAPIC, it will bluescreen if it's not found */
    1342             Bstr bstrFamilyId;
    1343             rc = osType->COMGETTER(FamilyId)(bstrFamilyId.asOutParam());
    1344             if (FAILED(rc)) throw rc;
    1345 
    1346             Utf8Str strFamilyId(bstrFamilyId);
    1347             if (strFamilyId == "Windows")
    1348                 fEnableIOApic = true;
    1349 
    1350             /* If IP-APIC should be enabled could be have different reasons.
    1351                See CPU count & the Win test above. Here we enable it if it was
    1352                previously requested. */
    1353             if (fEnableIOApic)
    1354             {
    1355                 ComPtr<IBIOSSettings> pBIOSSettings;
    1356                 rc = pNewMachine->COMGETTER(BIOSSettings)(pBIOSSettings.asOutParam());
    1357                 if (FAILED(rc)) throw rc;
    1358 
    1359                 rc = pBIOSSettings->COMSETTER(IOAPICEnabled)(TRUE);
    1360                 if (FAILED(rc)) throw rc;
    1361             }
    1362 
    1363             /* Audio Adapter */
    1364             std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
    1365             /* @todo: we support one audio adapter only */
    1366             if (vsdeAudioAdapter.size() > 0)
    1367             {
    1368                 const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strVbox;
    1369                 if (audioAdapterVBox.compare("null", Utf8Str::CaseInsensitive) != 0)
    1370                 {
    1371                     uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str());
    1372                     ComPtr<IAudioAdapter> audioAdapter;
    1373                     rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
    1374                     if (FAILED(rc)) throw rc;
    1375                     rc = audioAdapter->COMSETTER(Enabled)(true);
    1376                     if (FAILED(rc)) throw rc;
    1377                     rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio));
    1378                     if (FAILED(rc)) throw rc;
    1379                 }
    1380             }
    1381 
    1382 #ifdef VBOX_WITH_USB
    1383             /* USB Controller */
    1384             std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
    1385             // USB support is enabled if there's at least one such entry; to disable USB support,
    1386             // the type of the USB item would have been changed to "ignore"
    1387             bool fUSBEnabled = vsdeUSBController.size() > 0;
    1388 
    1389             ComPtr<IUSBController> usbController;
    1390             rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
    1391             if (FAILED(rc)) throw rc;
    1392             rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
    1393             if (FAILED(rc)) throw rc;
    1394 #endif /* VBOX_WITH_USB */
    1395 
    1396             /* Change the network adapters */
    1397             std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
    1398             if (vsdeNW.size() == 0)
    1399             {
    1400                 /* No network adapters, so we have to disable our default one */
    1401                 ComPtr<INetworkAdapter> nwVBox;
    1402                 rc = pNewMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
    1403                 if (FAILED(rc)) throw rc;
    1404                 rc = nwVBox->COMSETTER(Enabled)(false);
    1405                 if (FAILED(rc)) throw rc;
    1406             }
    1407             else
    1408             {
    1409                 list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
    1410                 /* Iterate through all network cards. We support 8 network adapters
    1411                  * at the maximum. (@todo: warn if there are more!) */
    1412                 size_t a = 0;
    1413                 for (nwIt = vsdeNW.begin();
    1414                      (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
    1415                      ++nwIt, ++a)
    1416                 {
    1417                     const VirtualSystemDescriptionEntry* pvsys = *nwIt;
    1418 
    1419                     const Utf8Str &nwTypeVBox = pvsys->strVbox;
    1420                     uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
    1421                     ComPtr<INetworkAdapter> pNetworkAdapter;
    1422                     rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
    1423                     if (FAILED(rc)) throw rc;
    1424                     /* Enable the network card & set the adapter type */
    1425                     rc = pNetworkAdapter->COMSETTER(Enabled)(true);
    1426                     if (FAILED(rc)) throw rc;
    1427                     rc = pNetworkAdapter->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
    1428                     if (FAILED(rc)) throw rc;
    1429 
    1430                     // default is NAT; change to "bridged" if extra conf says so
    1431                     if (!pvsys->strExtraConfig.compare("type=Bridged", Utf8Str::CaseInsensitive))
    1432                     {
    1433                         /* Attach to the right interface */
    1434                         rc = pNetworkAdapter->AttachToBridgedInterface();
    1435                         if (FAILED(rc)) throw rc;
    1436                         ComPtr<IHost> host;
    1437                         rc = mVirtualBox->COMGETTER(Host)(host.asOutParam());
    1438                         if (FAILED(rc)) throw rc;
    1439                         com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
    1440                         rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
    1441                         if (FAILED(rc)) throw rc;
    1442                         /* We search for the first host network interface which
    1443                          * is usable for bridged networking */
    1444                         for (size_t j = 0;
    1445                              j < nwInterfaces.size();
    1446                              ++j)
    1447                         {
    1448                             HostNetworkInterfaceType_T itype;
    1449                             rc = nwInterfaces[j]->COMGETTER(InterfaceType)(&itype);
    1450                             if (FAILED(rc)) throw rc;
    1451                             if (itype == HostNetworkInterfaceType_Bridged)
    1452                             {
    1453                                 Bstr name;
    1454                                 rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam());
    1455                                 if (FAILED(rc)) throw rc;
    1456                                 /* Set the interface name to attach to */
    1457                                 pNetworkAdapter->COMSETTER(HostInterface)(name);
    1458                                 if (FAILED(rc)) throw rc;
    1459                                 break;
    1460                             }
    1461                         }
    1462                     }
    1463                     /* Next test for host only interfaces */
    1464                     else if (!pvsys->strExtraConfig.compare("type=HostOnly", Utf8Str::CaseInsensitive))
    1465                     {
    1466                         /* Attach to the right interface */
    1467                         rc = pNetworkAdapter->AttachToHostOnlyInterface();
    1468                         if (FAILED(rc)) throw rc;
    1469                         ComPtr<IHost> host;
    1470                         rc = mVirtualBox->COMGETTER(Host)(host.asOutParam());
    1471                         if (FAILED(rc)) throw rc;
    1472                         com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
    1473                         rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
    1474                         if (FAILED(rc)) throw rc;
    1475                         /* We search for the first host network interface which
    1476                          * is usable for host only networking */
    1477                         for (size_t j = 0;
    1478                              j < nwInterfaces.size();
    1479                              ++j)
    1480                         {
    1481                             HostNetworkInterfaceType_T itype;
    1482                             rc = nwInterfaces[j]->COMGETTER(InterfaceType)(&itype);
    1483                             if (FAILED(rc)) throw rc;
    1484                             if (itype == HostNetworkInterfaceType_HostOnly)
    1485                             {
    1486                                 Bstr name;
    1487                                 rc = nwInterfaces[j]->COMGETTER(Name)(name.asOutParam());
    1488                                 if (FAILED(rc)) throw rc;
    1489                                 /* Set the interface name to attach to */
    1490                                 pNetworkAdapter->COMSETTER(HostInterface)(name);
    1491                                 if (FAILED(rc)) throw rc;
    1492                                 break;
    1493                             }
    1494                         }
    1495                     }
    1496                 }
    1497             }
    1498 
    1499             /* Hard disk controller IDE */
    1500             std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
    1501             if (vsdeHDCIDE.size() > 1)
    1502                 throw setError(VBOX_E_FILE_ERROR,
    1503                                tr("Too many IDE controllers in OVF; import facility only supports one"));
    1504             if (vsdeHDCIDE.size() == 1)
    1505             {
    1506                 ComPtr<IStorageController> pController;
    1507                 rc = pNewMachine->AddStorageController(Bstr("IDE Controller"), StorageBus_IDE, pController.asOutParam());
    1508                 if (FAILED(rc)) throw rc;
    1509 
    1510                 const char *pcszIDEType = vsdeHDCIDE.front()->strVbox.c_str();
    1511                 if (!strcmp(pcszIDEType, "PIIX3"))
    1512                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3);
    1513                 else if (!strcmp(pcszIDEType, "PIIX4"))
    1514                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX4);
    1515                 else if (!strcmp(pcszIDEType, "ICH6"))
    1516                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_ICH6);
    1517                 else
    1518                     throw setError(VBOX_E_FILE_ERROR,
    1519                                    tr("Invalid IDE controller type \"%s\""),
    1520                                    pcszIDEType);
    1521                 if (FAILED(rc)) throw rc;
    1522             }
    1523 #ifdef VBOX_WITH_AHCI
    1524             /* Hard disk controller SATA */
    1525             std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
    1526             if (vsdeHDCSATA.size() > 1)
    1527                 throw setError(VBOX_E_FILE_ERROR,
    1528                                tr("Too many SATA controllers in OVF; import facility only supports one"));
    1529             if (vsdeHDCSATA.size() > 0)
    1530             {
    1531                 ComPtr<IStorageController> pController;
    1532                 const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVbox;
    1533                 if (hdcVBox == "AHCI")
    1534                 {
    1535                     rc = pNewMachine->AddStorageController(Bstr("SATA Controller"), StorageBus_SATA, pController.asOutParam());
    1536                     if (FAILED(rc)) throw rc;
    1537                 }
    1538                 else
    1539                     throw setError(VBOX_E_FILE_ERROR,
    1540                                    tr("Invalid SATA controller type \"%s\""),
    1541                                    hdcVBox.c_str());
    1542             }
    1543 #endif /* VBOX_WITH_AHCI */
    1544 
    1545 #ifdef VBOX_WITH_LSILOGIC
    1546             /* Hard disk controller SCSI */
    1547             std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
    1548             if (vsdeHDCSCSI.size() > 1)
    1549                 throw setError(VBOX_E_FILE_ERROR,
    1550                                tr("Too many SCSI controllers in OVF; import facility only supports one"));
    1551             if (vsdeHDCSCSI.size() > 0)
    1552             {
    1553                 ComPtr<IStorageController> pController;
    1554                 StorageControllerType_T controllerType;
    1555                 const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVbox;
    1556                 if (hdcVBox == "LsiLogic")
    1557                     controllerType = StorageControllerType_LsiLogic;
    1558                 else if (hdcVBox == "BusLogic")
    1559                     controllerType = StorageControllerType_BusLogic;
    1560                 else
    1561                     throw setError(VBOX_E_FILE_ERROR,
    1562                                    tr("Invalid SCSI controller type \"%s\""),
    1563                                    hdcVBox.c_str());
    1564 
    1565                 rc = pNewMachine->AddStorageController(Bstr("SCSI Controller"), StorageBus_SCSI, pController.asOutParam());
    1566                 if (FAILED(rc)) throw rc;
    1567                 rc = pController->COMSETTER(ControllerType)(controllerType);
    1568                 if (FAILED(rc)) throw rc;
    1569             }
    1570 #endif /* VBOX_WITH_LSILOGIC */
    1571 
    1572             /* Now its time to register the machine before we add any hard disks */
    1573             rc = mVirtualBox->RegisterMachine(pNewMachine);
    1574             if (FAILED(rc)) throw rc;
    1575 
    1576             Bstr bstrNewMachineId;
    1577             rc = pNewMachine->COMGETTER(Id)(bstrNewMachineId.asOutParam());
    1578             if (FAILED(rc)) throw rc;
    1579 
    1580             // store new machine for roll-back in case of errors
    1581             llMachinesRegistered.push_back(bstrNewMachineId);
    1582 
    1583             // Add floppies and CD-ROMs to the appropriate controllers.
    1584             std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
    1585             if (vsdeFloppy.size() > 1)
    1586                 throw setError(VBOX_E_FILE_ERROR,
    1587                                tr("Too many floppy controllers in OVF; import facility only supports one"));
    1588             std::list<VirtualSystemDescriptionEntry*> vsdeCDROM = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM);
    1589             if (    (vsdeFloppy.size() > 0)
    1590                  || (vsdeCDROM.size() > 0)
    1591                )
    1592             {
    1593                 // If there's an error here we need to close the session, so
    1594                 // we need another try/catch block.
    1595 
    1596                 try
    1597                 {
    1598                     /* In order to attach things we need to open a session
    1599                      * for the new machine */
    1600                     rc = mVirtualBox->OpenSession(session, bstrNewMachineId);
    1601                     if (FAILED(rc)) throw rc;
    1602                     fSessionOpen = true;
    1603 
    1604                     ComPtr<IMachine> sMachine;
    1605                     rc = session->COMGETTER(Machine)(sMachine.asOutParam());
    1606                     if (FAILED(rc)) throw rc;
    1607 
    1608                     // floppy first
    1609                     if (vsdeFloppy.size() == 1)
    1610                     {
    1611                         ComPtr<IStorageController> pController;
    1612                         rc = sMachine->AddStorageController(Bstr("Floppy Controller"), StorageBus_Floppy, pController.asOutParam());
    1613                         if (FAILED(rc)) throw rc;
    1614 
    1615                         Bstr bstrName;
    1616                         rc = pController->COMGETTER(Name)(bstrName.asOutParam());
    1617                         if (FAILED(rc)) throw rc;
    1618 
    1619                         // this is for rollback later
    1620                         MyHardDiskAttachment mhda;
    1621                         mhda.bstrUuid = bstrNewMachineId;
    1622                         mhda.pMachine = pNewMachine;
    1623                         mhda.controllerType = bstrName;
    1624                         mhda.lChannel = 0;
    1625                         mhda.lDevice = 0;
    1626 
    1627                         Log(("Attaching floppy\n"));
    1628 
    1629                         rc = sMachine->AttachDevice(mhda.controllerType,
    1630                                                     mhda.lChannel,
    1631                                                     mhda.lDevice,
    1632                                                     DeviceType_Floppy,
    1633                                                     NULL);
    1634                         if (FAILED(rc)) throw rc;
    1635 
    1636                         llHardDiskAttachments.push_back(mhda);
    1637                     }
    1638 
    1639 
    1640                     // CD-ROMs next
    1641                     for (std::list<VirtualSystemDescriptionEntry*>::const_iterator jt = vsdeCDROM.begin();
    1642                          jt != vsdeCDROM.end();
    1643                          ++jt)
    1644                     {
    1645                         // for now always attach to secondary master on IDE controller;
    1646                         // there seems to be no useful information in OVF where else to
    1647                         // attach jt (@todo test with latest versions of OVF software)
    1648 
    1649                         // find the IDE controller
    1650                         const HardDiskController *pController = NULL;
    1651                         for (ControllersMap::const_iterator kt = vsysThis.mapControllers.begin();
    1652                              kt != vsysThis.mapControllers.end();
    1653                              ++kt)
    1654                         {
    1655                             if (kt->second.system == HardDiskController::IDE)
    1656                             {
    1657                                 pController = &kt->second;
    1658                             }
    1659                         }
    1660 
    1661                         if (!pController)
    1662                             throw setError(VBOX_E_FILE_ERROR,
    1663                                            tr("OVF wants a CD-ROM drive but cannot find IDE controller, which is required in this version of VirtualBox"));
    1664 
    1665                         // this is for rollback later
    1666                         MyHardDiskAttachment mhda;
    1667                         mhda.bstrUuid = bstrNewMachineId;
    1668                         mhda.pMachine = pNewMachine;
    1669 
    1670                         ConvertDiskAttachmentValues(*pController,
    1671                                                     2,     // interpreted as secondary master
    1672                                                     mhda.controllerType,        // Bstr
    1673                                                     mhda.lChannel,
    1674                                                     mhda.lDevice);
    1675 
    1676                         Log(("Attaching CD-ROM to channel %d on device %d\n", mhda.lChannel, mhda.lDevice));
    1677 
    1678                         rc = sMachine->AttachDevice(mhda.controllerType,
    1679                                                     mhda.lChannel,
    1680                                                     mhda.lDevice,
    1681                                                     DeviceType_DVD,
    1682                                                     NULL);
    1683                         if (FAILED(rc)) throw rc;
    1684 
    1685                         llHardDiskAttachments.push_back(mhda);
    1686                     } // end for (itHD = avsdeHDs.begin();
    1687 
    1688                     rc = sMachine->SaveSettings();
    1689                     if (FAILED(rc)) throw rc;
    1690 
    1691                     // only now that we're done with all disks, close the session
    1692                     rc = session->Close();
    1693                     if (FAILED(rc)) throw rc;
    1694                     fSessionOpen = false;
    1695                 }
    1696                 catch(HRESULT /* aRC */)
    1697                 {
    1698                     if (fSessionOpen)
    1699                         session->Close();
    1700 
    1701                     throw;
    1702                 }
    1703             }
    1704 
    1705             /* Create the hard disks & connect them to the appropriate controllers. */
    1706             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    1707             if (avsdeHDs.size() > 0)
    1708             {
    1709                 // If there's an error here we need to close the session, so
    1710                 // we need another try/catch block.
    1711                 ComPtr<IMedium> srcHdVBox;
    1712                 bool fSourceHdNeedsClosing = false;
    1713 
    1714                 try
    1715                 {
    1716                     /* In order to attach hard disks we need to open a session
    1717                      * for the new machine */
    1718                     rc = mVirtualBox->OpenSession(session, bstrNewMachineId);
    1719                     if (FAILED(rc)) throw rc;
    1720                     fSessionOpen = true;
    1721 
    1722                     /* The disk image has to be on the same place as the OVF file. So
    1723                      * strip the filename out of the full file path. */
    1724                     Utf8Str strSrcDir(pTask->locInfo.strPath);
    1725                     strSrcDir.stripFilename();
    1726 
    1727                     /* Iterate over all given disk images */
    1728                     list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
    1729                     for (itHD = avsdeHDs.begin();
    1730                          itHD != avsdeHDs.end();
    1731                          ++itHD)
    1732                     {
    1733                         VirtualSystemDescriptionEntry *vsdeHD = *itHD;
    1734 
    1735                         /* Check if the destination file exists already or the
    1736                          * destination path is empty. */
    1737                         if (    vsdeHD->strVbox.isEmpty()
    1738                              || RTPathExists(vsdeHD->strVbox.c_str())
    1739                            )
    1740                             /* This isn't allowed */
    1741                             throw setError(VBOX_E_FILE_ERROR,
    1742                                            tr("Destination file '%s' exists",
    1743                                               vsdeHD->strVbox.c_str()));
    1744 
    1745                         /* Find the disk from the OVF's disk list */
    1746                         DiskImagesMap::const_iterator itDiskImage = reader.m_mapDisks.find(vsdeHD->strRef);
    1747                         /* vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
    1748                            in the virtual system's disks map under that ID and also in the global images map. */
    1749                         VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
    1750 
    1751                         if (    itDiskImage == reader.m_mapDisks.end()
    1752                              || itVirtualDisk == vsysThis.mapVirtualDisks.end()
    1753                            )
    1754                             throw setError(E_FAIL,
    1755                                            tr("Internal inconsistency looking up disk images."));
    1756 
    1757                         const DiskImage &di = itDiskImage->second;
    1758                         const VirtualDisk &vd = itVirtualDisk->second;
    1759 
    1760                         /* Make sure all target directories exists */
    1761                         rc = VirtualBox::ensureFilePathExists(vsdeHD->strVbox.c_str());
    1762                         if (FAILED(rc))
    1763                             throw rc;
    1764 
    1765                         // subprogress object for hard disk
    1766                         ComPtr<IProgress> pProgress2;
    1767 
    1768                         ComPtr<IMedium> dstHdVBox;
    1769                         /* If strHref is empty we have to create a new file */
    1770                         if (di.strHref.isEmpty())
    1771                         {
    1772                             /* Which format to use? */
    1773                             Bstr srcFormat = L"VDI";
    1774                             if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
    1775                                 || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
    1776                                 srcFormat = L"VMDK";
    1777                             /* Create an empty hard disk */
    1778                             rc = mVirtualBox->CreateHardDisk(srcFormat, Bstr(vsdeHD->strVbox), dstHdVBox.asOutParam());
    1779                             if (FAILED(rc)) throw rc;
    1780 
    1781                             /* Create a dynamic growing disk image with the given capacity */
    1782                             rc = dstHdVBox->CreateBaseStorage(di.iCapacity / _1M, MediumVariant_Standard, pProgress2.asOutParam());
    1783                             if (FAILED(rc)) throw rc;
    1784 
    1785                             /* Advance to the next operation */
    1786                             if (!pTask->progress.isNull())
    1787                                 pTask->progress->SetNextOperation(BstrFmt(tr("Creating virtual disk image '%s'"), vsdeHD->strVbox.c_str()),
    1788                                                                  vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally
    1789                         }
    1790                         else
    1791                         {
    1792                             /* Construct the source file path */
    1793                             Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
    1794                             /* Check if the source file exists */
    1795                             if (!RTPathExists(strSrcFilePath.c_str()))
    1796                                 /* This isn't allowed */
    1797                                 throw setError(VBOX_E_FILE_ERROR,
    1798                                                tr("Source virtual disk image file '%s' doesn't exist"),
    1799                                                   strSrcFilePath.c_str());
    1800 
    1801                             /* Clone the disk image (this is necessary cause the id has
    1802                              * to be recreated for the case the same hard disk is
    1803                              * attached already from a previous import) */
    1804 
    1805                             /* First open the existing disk image */
    1806                             rc = mVirtualBox->OpenHardDisk(Bstr(strSrcFilePath),
    1807                                                            AccessMode_ReadOnly,
    1808                                                            false,
    1809                                                            NULL,
    1810                                                            false,
    1811                                                            NULL,
    1812                                                            srcHdVBox.asOutParam());
    1813                             if (FAILED(rc)) throw rc;
    1814                             fSourceHdNeedsClosing = true;
    1815 
    1816                             /* We need the format description of the source disk image */
    1817                             Bstr srcFormat;
    1818                             rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
    1819                             if (FAILED(rc)) throw rc;
    1820                             /* Create a new hard disk interface for the destination disk image */
    1821                             rc = mVirtualBox->CreateHardDisk(srcFormat, Bstr(vsdeHD->strVbox), dstHdVBox.asOutParam());
    1822                             if (FAILED(rc)) throw rc;
    1823                             /* Clone the source disk image */
    1824                             rc = srcHdVBox->CloneTo(dstHdVBox, MediumVariant_Standard, NULL, pProgress2.asOutParam());
    1825                             if (FAILED(rc)) throw rc;
    1826 
    1827                             /* Advance to the next operation */
    1828                             if (!pTask->progress.isNull())
    1829                                 pTask->progress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), strSrcFilePath.c_str()),
    1830                                                                  vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
    1831                         }
    1832 
    1833                         // now wait for the background disk operation to complete; this throws HRESULTs on error
    1834                         waitForAsyncProgress(pTask->progress, pProgress2);
    1835 
    1836                         if (fSourceHdNeedsClosing)
    1837                         {
    1838                             rc = srcHdVBox->Close();
    1839                             if (FAILED(rc)) throw rc;
    1840                             fSourceHdNeedsClosing = false;
    1841                         }
    1842 
    1843                         llHardDisksCreated.push_back(dstHdVBox);
    1844                         /* Now use the new uuid to attach the disk image to our new machine */
    1845                         ComPtr<IMachine> sMachine;
    1846                         rc = session->COMGETTER(Machine)(sMachine.asOutParam());
    1847                         if (FAILED(rc)) throw rc;
    1848                         Bstr hdId;
    1849                         rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());
    1850                         if (FAILED(rc)) throw rc;
    1851 
    1852                         /* For now we assume we have one controller of every type only */
    1853                         HardDiskController hdc = (*vsysThis.mapControllers.find(vd.idController)).second;
    1854 
    1855                         // this is for rollback later
    1856                         MyHardDiskAttachment mhda;
    1857                         mhda.bstrUuid = bstrNewMachineId;
    1858                         mhda.pMachine = pNewMachine;
    1859 
    1860                         ConvertDiskAttachmentValues(hdc,
    1861                                                     vd.ulAddressOnParent,
    1862                                                     mhda.controllerType,        // Bstr
    1863                                                     mhda.lChannel,
    1864                                                     mhda.lDevice);
    1865 
    1866                         Log(("Attaching disk %s to channel %d on device %d\n", vsdeHD->strVbox.c_str(), mhda.lChannel, mhda.lDevice));
    1867 
    1868                         rc = sMachine->AttachDevice(mhda.controllerType,
    1869                                                     mhda.lChannel,
    1870                                                     mhda.lDevice,
    1871                                                     DeviceType_HardDisk,
    1872                                                     hdId);
    1873                         if (FAILED(rc)) throw rc;
    1874 
    1875                         llHardDiskAttachments.push_back(mhda);
    1876 
    1877                         rc = sMachine->SaveSettings();
    1878                         if (FAILED(rc)) throw rc;
    1879                     } // end for (itHD = avsdeHDs.begin();
    1880 
    1881                     // only now that we're done with all disks, close the session
    1882                     rc = session->Close();
    1883                     if (FAILED(rc)) throw rc;
    1884                     fSessionOpen = false;
    1885                 }
    1886                 catch(HRESULT /* aRC */)
    1887                 {
    1888                     if (fSourceHdNeedsClosing)
    1889                         srcHdVBox->Close();
    1890 
    1891                     if (fSessionOpen)
    1892                         session->Close();
    1893 
    1894                     throw;
    1895                 }
    1896             }
    1897         }
    1898         catch(HRESULT aRC)
    1899         {
    1900             rc = aRC;
    1901         }
    1902 
    1903         if (FAILED(rc))
    1904             break;
    1905 
    1906     } // for (it = pAppliance->m->llVirtualSystems.begin(),
    1907 
    1908     if (FAILED(rc))
    1909     {
    1910         // with _whatever_ error we've had, do a complete roll-back of
    1911         // machines and disks we've created; unfortunately this is
    1912         // not so trivially done...
    1913 
    1914         HRESULT rc2;
    1915         // detach all hard disks from all machines we created
    1916         list<MyHardDiskAttachment>::iterator itM;
    1917         for (itM = llHardDiskAttachments.begin();
    1918              itM != llHardDiskAttachments.end();
    1919              ++itM)
    1920         {
    1921             const MyHardDiskAttachment &mhda = *itM;
    1922             Bstr bstrUuid(mhda.bstrUuid);           // make a copy, Windows can't handle const Bstr
    1923             rc2 = mVirtualBox->OpenSession(session, bstrUuid);
    1924             if (SUCCEEDED(rc2))
    1925             {
    1926                 ComPtr<IMachine> sMachine;
    1927                 rc2 = session->COMGETTER(Machine)(sMachine.asOutParam());
    1928                 if (SUCCEEDED(rc2))
    1929                 {
    1930                     rc2 = sMachine->DetachDevice(Bstr(mhda.controllerType), mhda.lChannel, mhda.lDevice);
    1931                     rc2 = sMachine->SaveSettings();
    1932                 }
    1933                 session->Close();
    1934             }
    1935         }
    1936 
    1937         // now clean up all hard disks we created
    1938         list< ComPtr<IMedium> >::iterator itHD;
    1939         for (itHD = llHardDisksCreated.begin();
    1940              itHD != llHardDisksCreated.end();
    1941              ++itHD)
    1942         {
    1943             ComPtr<IMedium> pDisk = *itHD;
    1944             ComPtr<IProgress> pProgress;
    1945             rc2 = pDisk->DeleteStorage(pProgress.asOutParam());
    1946             rc2 = pProgress->WaitForCompletion(-1);
    1947         }
    1948 
    1949         // finally, deregister and remove all machines
    1950         list<Bstr>::iterator itID;
    1951         for (itID = llMachinesRegistered.begin();
    1952              itID != llMachinesRegistered.end();
    1953              ++itID)
    1954         {
    1955             Bstr bstrGuid = *itID;      // make a copy, Windows can't handle const Bstr
    1956             ComPtr<IMachine> failedMachine;
    1957             rc2 = mVirtualBox->UnregisterMachine(bstrGuid, failedMachine.asOutParam());
    1958             if (SUCCEEDED(rc2))
    1959                 rc2 = failedMachine->DeleteSettings();
    1960         }
    1961     }
    1962 
    1963     // restore the appliance state
    1964     appLock.acquire();
    1965     m->state = Data::ApplianceIdle;
    1966 
    1967     pTask->rc = rc;
    1968 
    1969     if (!pTask->progress.isNull())
    1970         pTask->progress->notifyComplete(rc);
    1971 
    1972     LogFlowFunc(("rc=%Rhrc\n", rc));
    1973     LogFlowFuncLeave();
    1974 
    1975     return VINF_SUCCESS;
    1976 }
    1977 
    1978 /**
    1979  * Helper that converts VirtualSystem attachment values into VirtualBox attachment values.
    1980  * Throws HRESULT values on errors!
    1981  *
    1982  * @param hdc
    1983  * @param vd
    1984  * @param mhda
    1985  */
    1986 void Appliance::ConvertDiskAttachmentValues(const HardDiskController &hdc,
    1987                                             uint32_t ulAddressOnParent,
    1988                                             Bstr &controllerType,
    1989                                             int32_t &lChannel,
    1990                                             int32_t &lDevice)
    1991 {
    1992     switch (hdc.system)
    1993     {
    1994         case HardDiskController::IDE:
    1995             // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
    1996             // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
    1997             // the device number can be either 0 or 1, to specify the master or the slave device,
    1998             // respectively. For the secondary IDE controller, the device number is always 1 because
    1999             // the master device is reserved for the CD-ROM drive.
    2000             controllerType = Bstr("IDE Controller");
    2001             switch (ulAddressOnParent)
    2002             {
    2003                 case 0:     // interpret this as primary master
    2004                     lChannel = (long)0;
    2005                     lDevice = (long)0;
    2006                 break;
    2007 
    2008                 case 1:     // interpret this as primary slave
    2009                     lChannel = (long)0;
    2010                     lDevice = (long)1;
    2011                 break;
    2012 
    2013                 case 2:     // interpret this as secondary master
    2014                     lChannel = (long)1;
    2015                     lDevice = (long)0;
    2016                 break;
    2017 
    2018                 case 3:     // interpret this as secondary slave
    2019                     lChannel = (long)1;
    2020                     lDevice = (long)1;
    2021                 break;
    2022 
    2023                 default:
    2024                     throw setError(VBOX_E_NOT_SUPPORTED,
    2025                                     tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), ulAddressOnParent);
    2026                 break;
    2027             }
    2028         break;
    2029 
    2030         case HardDiskController::SATA:
    2031             controllerType = Bstr("SATA Controller");
    2032             lChannel = (long)ulAddressOnParent;
    2033             lDevice = (long)0;
    2034         break;
    2035 
    2036         case HardDiskController::SCSI:
    2037             controllerType = Bstr("SCSI Controller");
    2038             lChannel = (long)ulAddressOnParent;
    2039             lDevice = (long)0;
    2040         break;
    2041 
    2042         default: break;
    2043     }
    2044 }
    2045 
    2046 int Appliance::importS3(TaskImportOVF *pTask)
    2047 {
    2048     LogFlowFuncEnter();
    2049     LogFlowFunc(("Appliance %p\n", this));
    2050 
    2051     AutoCaller autoCaller(this);
    2052     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2053 
    2054     AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
    2055 
    2056     int vrc = VINF_SUCCESS;
    2057     RTS3 hS3 = NIL_RTS3;
    2058     char szOSTmpDir[RTPATH_MAX];
    2059     RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
    2060     /* The template for the temporary directory created below */
    2061     char *pszTmpDir;
    2062     RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
    2063     list< pair<Utf8Str, ULONG> > filesList;
    2064 
    2065     HRESULT rc = S_OK;
    2066     try
    2067     {
    2068         /* Extract the bucket */
    2069         Utf8Str tmpPath = pTask->locInfo.strPath;
    2070         Utf8Str bucket;
    2071         parseBucket(tmpPath, bucket);
    2072 
    2073         /* We need a temporary directory which we can put the all disk images
    2074          * in */
    2075         vrc = RTDirCreateTemp(pszTmpDir);
    2076         if (RT_FAILURE(vrc))
    2077             throw setError(VBOX_E_FILE_ERROR,
    2078                            tr("Cannot create temporary directory '%s'"), pszTmpDir);
    2079 
    2080         /* Add every disks of every virtual system to an internal list */
    2081         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    2082         for (it = m->virtualSystemDescriptions.begin();
    2083              it != m->virtualSystemDescriptions.end();
    2084              ++it)
    2085         {
    2086             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    2087             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    2088             std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    2089             for (itH = avsdeHDs.begin();
    2090                  itH != avsdeHDs.end();
    2091                  ++itH)
    2092             {
    2093                 const Utf8Str &strTargetFile = (*itH)->strOvf;
    2094                 if (!strTargetFile.isEmpty())
    2095                 {
    2096                     /* The temporary name of the target disk file */
    2097                     Utf8StrFmt strTmpDisk("%s/%s", pszTmpDir, RTPathFilename(strTargetFile.c_str()));
    2098                     filesList.push_back(pair<Utf8Str, ULONG>(strTmpDisk, (*itH)->ulSizeMB));
    2099                 }
    2100             }
    2101         }
    2102 
    2103         /* Next we have to download the disk images */
    2104         vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
    2105         if(RT_FAILURE(vrc))
    2106             throw setError(VBOX_E_IPRT_ERROR,
    2107                            tr("Cannot create S3 service handler"));
    2108         RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
    2109 
    2110         /* Download all files */
    2111         for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    2112         {
    2113             const pair<Utf8Str, ULONG> &s = (*it1);
    2114             const Utf8Str &strSrcFile = s.first;
    2115             /* Construct the source file name */
    2116             char *pszFilename = RTPathFilename(strSrcFile.c_str());
    2117             /* Advance to the next operation */
    2118             if (!pTask->progress.isNull())
    2119                 pTask->progress->SetNextOperation(BstrFmt(tr("Downloading file '%s'"), pszFilename), s.second);
    2120 
    2121             vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strSrcFile.c_str());
    2122             if (RT_FAILURE(vrc))
    2123             {
    2124                 if(vrc == VERR_S3_CANCELED)
    2125                     throw S_OK; /* todo: !!!!!!!!!!!!! */
    2126                 else if(vrc == VERR_S3_ACCESS_DENIED)
    2127                     throw setError(E_ACCESSDENIED,
    2128                                    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);
    2129                 else if(vrc == VERR_S3_NOT_FOUND)
    2130                     throw setError(VBOX_E_FILE_ERROR,
    2131                                    tr("Cannot download file '%s' from S3 storage server (File not found)"), pszFilename);
    2132                 else
    2133                     throw setError(VBOX_E_IPRT_ERROR,
    2134                                    tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
    2135             }
    2136         }
    2137 
    2138         /* Provide a OVF file (haven't to exist) so the import routine can
    2139          * figure out where the disk images/manifest file are located. */
    2140         Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath.c_str()));
    2141         /* Now check if there is an manifest file. This is optional. */
    2142         Utf8Str strManifestFile = manifestFileName(strTmpOvf);
    2143         char *pszFilename = RTPathFilename(strManifestFile.c_str());
    2144         if (!pTask->progress.isNull())
    2145             pTask->progress->SetNextOperation(BstrFmt(tr("Downloading file '%s'"), pszFilename), 1);
    2146 
    2147         /* Try to download it. If the error is VERR_S3_NOT_FOUND, it isn't fatal. */
    2148         vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strManifestFile.c_str());
    2149         if (RT_SUCCESS(vrc))
    2150             filesList.push_back(pair<Utf8Str, ULONG>(strManifestFile, 0));
    2151         else if (RT_FAILURE(vrc))
    2152         {
    2153             if(vrc == VERR_S3_CANCELED)
    2154                 throw S_OK; /* todo: !!!!!!!!!!!!! */
    2155             else if(vrc == VERR_S3_NOT_FOUND)
    2156                 vrc = VINF_SUCCESS; /* Not found is ok */
    2157             else if(vrc == VERR_S3_ACCESS_DENIED)
    2158                 throw setError(E_ACCESSDENIED,
    2159                                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);
    2160             else
    2161                 throw setError(VBOX_E_IPRT_ERROR,
    2162                                tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
    2163         }
    2164 
    2165         /* Close the connection early */
    2166         RTS3Destroy(hS3);
    2167         hS3 = NIL_RTS3;
    2168 
    2169         if (!pTask->progress.isNull())
    2170             pTask->progress->SetNextOperation(BstrFmt(tr("Importing appliance")), m->ulWeightPerOperation);
    2171 
    2172         ComObjPtr<Progress> progress;
    2173         /* Import the whole temporary OVF & the disk images */
    2174         LocationInfo li;
    2175         li.strPath = strTmpOvf;
    2176         rc = importImpl(li, progress);
    2177         if (FAILED(rc)) throw rc;
    2178 
    2179         /* Unlock the appliance for the fs import thread */
    2180         appLock.release();
    2181         /* Wait until the import is done, but report the progress back to the
    2182            caller */
    2183         ComPtr<IProgress> progressInt(progress);
    2184         waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
    2185 
    2186         /* Again lock the appliance for the next steps */
    2187         appLock.acquire();
    2188     }
    2189     catch(HRESULT aRC)
    2190     {
    2191         rc = aRC;
    2192     }
    2193     /* Cleanup */
    2194     RTS3Destroy(hS3);
    2195     /* Delete all files which where temporary created */
    2196     for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    2197     {
    2198         const char *pszFilePath = (*it1).first.c_str();
    2199         if (RTPathExists(pszFilePath))
    2200         {
    2201             vrc = RTFileDelete(pszFilePath);
    2202             if(RT_FAILURE(vrc))
    2203                 rc = setError(VBOX_E_FILE_ERROR,
    2204                               tr("Cannot delete file '%s' (%Rrc)"), pszFilePath, vrc);
    2205         }
    2206     }
    2207     /* Delete the temporary directory */
    2208     if (RTPathExists(pszTmpDir))
    2209     {
    2210         vrc = RTDirRemove(pszTmpDir);
    2211         if(RT_FAILURE(vrc))
    2212             rc = setError(VBOX_E_FILE_ERROR,
    2213                           tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
    2214     }
    2215     if (pszTmpDir)
    2216         RTStrFree(pszTmpDir);
    2217 
    2218     pTask->rc = rc;
    2219 
    2220     if (!pTask->progress.isNull())
    2221         pTask->progress->notifyComplete(rc);
    2222 
    2223     LogFlowFunc(("rc=%Rhrc\n", rc));
    2224     LogFlowFuncLeave();
    2225 
    2226     return VINF_SUCCESS;
    2227 }
    2228 
    2229611HRESULT Appliance::writeImpl(int aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
    2230612{
     
    2266648}
    2267649
     650/**
     651 * Thread function for the thread started in Appliance::writeImpl(). This will in turn
     652 * call Appliance::writeFS() or Appliance::writeS3().
     653 * @param
     654 * @param pvUser
     655 * @return
     656 */
    2268657DECLCALLBACK(int) Appliance::taskThreadWriteOVF(RTTHREAD /* aThread */, void *pvUser)
    2269658{
     
    2296685}
    2297686
    2298 int Appliance::TaskExportOVF::startThread()
    2299 {
    2300     int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this,
    2301                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    2302                              "Appliance::Task");
    2303 
    2304     ComAssertMsgRCRet(vrc,
    2305                       ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL);
    2306 
    2307     return S_OK;
    2308 }
    2309 
     687/**
     688 * Actual worker code for writing out OVF to disk. This is called from Appliance::taskThreadWriteOVF()
     689 * and therefore runs on the OVF write worker thread. This runs in two contexts:
     690 *
     691 * 1) in a first worker thread; in that case, Appliance::Write() called Appliance::writeImpl();
     692 *
     693 * 2) in a second worker thread; in that case, Appliance::Write() called Appliance::writeImpl(), which
     694 *    called Appliance::writeS3(), which called Appliance::writeImpl(), which then called this. In other
     695 *    words, to write to the cloud, the first worker thread first starts a second worker thread to create
     696 *    temporary files and then uploads them to the S3 cloud server.
     697 *
     698 * @param pTask
     699 * @return
     700 */
    2310701int Appliance::writeFS(TaskExportOVF *pTask)
    2311702{
     
    31621553}
    31631554
     1555/**
     1556 * Worker code for writing out OVF to the cloud. This is called from Appliance::taskThreadWriteOVF()
     1557 * in S3 mode and therefore runs on the OVF write worker thread. This then starts a second worker
     1558 * thread to create temporary files (see Appliance::writeFS()).
     1559 *
     1560 * @param pTask
     1561 * @return
     1562 */
    31641563int Appliance::writeS3(TaskExportOVF *pTask)
    31651564{
     
    33281727}
    33291728
    3330 ////////////////////////////////////////////////////////////////////////////////
    3331 //
    3332 // IAppliance public methods
    3333 //
    3334 ////////////////////////////////////////////////////////////////////////////////
    3335 
    3336 /**
    3337  * Public method implementation.
    3338  * @param
    3339  * @return
    3340  */
    3341 STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
    3342 {
    3343     if (!aPath)
    3344         return E_POINTER;
    3345 
    3346     AutoCaller autoCaller(this);
    3347     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3348 
    3349     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3350 
    3351     if (!isApplianceIdle())
    3352         return E_ACCESSDENIED;
    3353 
    3354     Bstr bstrPath(m->locInfo.strPath);
    3355     bstrPath.cloneTo(aPath);
    3356 
    3357     return S_OK;
    3358 }
    3359 
    3360 /**
    3361  * Public method implementation.
    3362  * @param
    3363  * @return
    3364  */
    3365 STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
    3366 {
    3367     CheckComArgOutSafeArrayPointerValid(aDisks);
    3368 
    3369     AutoCaller autoCaller(this);
    3370     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3371 
    3372     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3373 
    3374     if (!isApplianceIdle())
    3375         return E_ACCESSDENIED;
    3376 
    3377     if (m->pReader) // OVFReader instantiated?
    3378     {
    3379         size_t c = m->pReader->m_mapDisks.size();
    3380         com::SafeArray<BSTR> sfaDisks(c);
    3381 
    3382         DiskImagesMap::const_iterator it;
    3383         size_t i = 0;
    3384         for (it = m->pReader->m_mapDisks.begin();
    3385              it != m->pReader->m_mapDisks.end();
    3386              ++it, ++i)
    3387         {
    3388             // create a string representing this disk
    3389             const DiskImage &d = it->second;
    3390             char *psz = NULL;
    3391             RTStrAPrintf(&psz,
    3392                          "%s\t"
    3393                          "%RI64\t"
    3394                          "%RI64\t"
    3395                          "%s\t"
    3396                          "%s\t"
    3397                          "%RI64\t"
    3398                          "%RI64\t"
    3399                          "%s",
    3400                          d.strDiskId.c_str(),
    3401                          d.iCapacity,
    3402                          d.iPopulatedSize,
    3403                          d.strFormat.c_str(),
    3404                          d.strHref.c_str(),
    3405                          d.iSize,
    3406                          d.iChunkSize,
    3407                          d.strCompression.c_str());
    3408             Utf8Str utf(psz);
    3409             Bstr bstr(utf);
    3410             // push to safearray
    3411             bstr.cloneTo(&sfaDisks[i]);
    3412             RTStrFree(psz);
    3413         }
    3414 
    3415         sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
    3416     }
    3417 
    3418     return S_OK;
    3419 }
    3420 
    3421 /**
    3422  * Public method implementation.
    3423  * @param
    3424  * @return
    3425  */
    3426 STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
    3427 {
    3428     CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
    3429 
    3430     AutoCaller autoCaller(this);
    3431     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3432 
    3433     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3434 
    3435     if (!isApplianceIdle())
    3436         return E_ACCESSDENIED;
    3437 
    3438     SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
    3439     sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
    3440 
    3441     return S_OK;
    3442 }
    3443 
    3444 /**
    3445  * Public method implementation.
    3446  * @param path
    3447  * @return
    3448  */
    3449 STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress)
    3450 {
    3451     if (!path) return E_POINTER;
    3452     CheckComArgOutPointerValid(aProgress);
    3453 
    3454     AutoCaller autoCaller(this);
    3455     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3456 
    3457     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3458 
    3459     if (!isApplianceIdle())
    3460         return E_ACCESSDENIED;
    3461 
    3462     if (m->pReader)
    3463     {
    3464         delete m->pReader;
    3465         m->pReader = NULL;
    3466     }
    3467 
    3468     // see if we can handle this file; for now we insist it has an ".ovf" extension
    3469     Utf8Str strPath (path);
    3470     if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    3471         return setError(VBOX_E_FILE_ERROR,
    3472                         tr("Appliance file must have .ovf extension"));
    3473 
    3474     ComObjPtr<Progress> progress;
    3475     HRESULT rc = S_OK;
    3476     try
    3477     {
    3478         /* Parse all necessary info out of the URI */
    3479         parseURI(strPath, m->locInfo);
    3480         rc = readImpl(m->locInfo, progress);
    3481     }
    3482     catch (HRESULT aRC)
    3483     {
    3484         rc = aRC;
    3485     }
    3486 
    3487     if (SUCCEEDED(rc))
    3488         /* Return progress to the caller */
    3489         progress.queryInterfaceTo(aProgress);
    3490 
    3491     return S_OK;
    3492 }
    3493 
    3494 /**
    3495  * Public method implementation.
    3496  * @return
    3497  */
    3498 STDMETHODIMP Appliance::Interpret()
    3499 {
    3500     // @todo:
    3501     //  - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
    3502     //  - Appropriate handle errors like not supported file formats
    3503     AutoCaller autoCaller(this);
    3504     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3505 
    3506     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3507 
    3508     if (!isApplianceIdle())
    3509         return E_ACCESSDENIED;
    3510 
    3511     HRESULT rc = S_OK;
    3512 
    3513     /* Clear any previous virtual system descriptions */
    3514     m->virtualSystemDescriptions.clear();
    3515 
    3516     /* We need the default path for storing disk images */
    3517     ComPtr<ISystemProperties> systemProps;
    3518     rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
    3519     if (FAILED(rc)) return rc;
    3520     Bstr bstrDefaultHardDiskLocation;
    3521     rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskLocation.asOutParam());
    3522     if (FAILED(rc)) return rc;
    3523 
    3524     if (!m->pReader)
    3525         return setError(E_FAIL,
    3526                         tr("Cannot interpret appliance without reading it first (call read() before interpret())"));
    3527 
    3528     // Change the appliance state so we can safely leave the lock while doing time-consuming
    3529     // disk imports; also the below method calls do all kinds of locking which conflicts with
    3530     // the appliance object lock
    3531     m->state = Data::ApplianceImporting;
    3532     alock.release();
    3533 
    3534     /* Try/catch so we can clean up on error */
    3535     try
    3536     {
    3537         list<VirtualSystem>::const_iterator it;
    3538         /* Iterate through all virtual systems */
    3539         for (it = m->pReader->m_llVirtualSystems.begin();
    3540              it != m->pReader->m_llVirtualSystems.end();
    3541              ++it)
    3542         {
    3543             const VirtualSystem &vsysThis = *it;
    3544 
    3545             ComObjPtr<VirtualSystemDescription> pNewDesc;
    3546             rc = pNewDesc.createObject();
    3547             if (FAILED(rc)) throw rc;
    3548             rc = pNewDesc->init();
    3549             if (FAILED(rc)) throw rc;
    3550 
    3551             /* Guest OS type */
    3552             Utf8Str strOsTypeVBox,
    3553                     strCIMOSType = Utf8StrFmt("%RI32", (uint32_t)vsysThis.cimos);
    3554             convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos, vsysThis.strCimosDesc);
    3555             pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
    3556                                "",
    3557                                strCIMOSType,
    3558                                strOsTypeVBox);
    3559 
    3560             /* VM name */
    3561             /* If the there isn't any name specified create a default one out of
    3562              * the OS type */
    3563             Utf8Str nameVBox = vsysThis.strName;
    3564             if (nameVBox.isEmpty())
    3565                 nameVBox = strOsTypeVBox;
    3566             searchUniqueVMName(nameVBox);
    3567             pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
    3568                                "",
    3569                                vsysThis.strName,
    3570                                nameVBox);
    3571 
    3572             /* VM Product */
    3573             if (!vsysThis.strProduct.isEmpty())
    3574                 pNewDesc->addEntry(VirtualSystemDescriptionType_Product,
    3575                                     "",
    3576                                     vsysThis.strProduct,
    3577                                     vsysThis.strProduct);
    3578 
    3579             /* VM Vendor */
    3580             if (!vsysThis.strVendor.isEmpty())
    3581                 pNewDesc->addEntry(VirtualSystemDescriptionType_Vendor,
    3582                                     "",
    3583                                     vsysThis.strVendor,
    3584                                     vsysThis.strVendor);
    3585 
    3586             /* VM Version */
    3587             if (!vsysThis.strVersion.isEmpty())
    3588                 pNewDesc->addEntry(VirtualSystemDescriptionType_Version,
    3589                                     "",
    3590                                     vsysThis.strVersion,
    3591                                     vsysThis.strVersion);
    3592 
    3593             /* VM ProductUrl */
    3594             if (!vsysThis.strProductUrl.isEmpty())
    3595                 pNewDesc->addEntry(VirtualSystemDescriptionType_ProductUrl,
    3596                                     "",
    3597                                     vsysThis.strProductUrl,
    3598                                     vsysThis.strProductUrl);
    3599 
    3600             /* VM VendorUrl */
    3601             if (!vsysThis.strVendorUrl.isEmpty())
    3602                 pNewDesc->addEntry(VirtualSystemDescriptionType_VendorUrl,
    3603                                     "",
    3604                                     vsysThis.strVendorUrl,
    3605                                     vsysThis.strVendorUrl);
    3606 
    3607             /* VM description */
    3608             if (!vsysThis.strDescription.isEmpty())
    3609                 pNewDesc->addEntry(VirtualSystemDescriptionType_Description,
    3610                                     "",
    3611                                     vsysThis.strDescription,
    3612                                     vsysThis.strDescription);
    3613 
    3614             /* VM license */
    3615             if (!vsysThis.strLicenseText.isEmpty())
    3616                 pNewDesc->addEntry(VirtualSystemDescriptionType_License,
    3617                                     "",
    3618                                     vsysThis.strLicenseText,
    3619                                     vsysThis.strLicenseText);
    3620 
    3621             /* Now that we know the OS type, get our internal defaults based on that. */
    3622             ComPtr<IGuestOSType> pGuestOSType;
    3623             rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), pGuestOSType.asOutParam());
    3624             if (FAILED(rc)) throw rc;
    3625 
    3626             /* CPU count */
    3627             ULONG cpuCountVBox = vsysThis.cCPUs;
    3628             /* Check for the constrains */
    3629             if (cpuCountVBox > SchemaDefs::MaxCPUCount)
    3630             {
    3631                 addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
    3632                            vsysThis.strName.c_str(), cpuCountVBox, SchemaDefs::MaxCPUCount);
    3633                 cpuCountVBox = SchemaDefs::MaxCPUCount;
    3634             }
    3635             if (vsysThis.cCPUs == 0)
    3636                 cpuCountVBox = 1;
    3637             pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
    3638                                "",
    3639                                Utf8StrFmt("%RI32", (uint32_t)vsysThis.cCPUs),
    3640                                Utf8StrFmt("%RI32", (uint32_t)cpuCountVBox));
    3641 
    3642             /* RAM */
    3643             uint64_t ullMemSizeVBox = vsysThis.ullMemorySize / _1M;
    3644             /* Check for the constrains */
    3645             if (ullMemSizeVBox != 0 &&
    3646                 (ullMemSizeVBox < MM_RAM_MIN_IN_MB ||
    3647                  ullMemSizeVBox > MM_RAM_MAX_IN_MB))
    3648             {
    3649                 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."),
    3650                               vsysThis.strName.c_str(), ullMemSizeVBox, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
    3651                 ullMemSizeVBox = RT_MIN(RT_MAX(ullMemSizeVBox, MM_RAM_MIN_IN_MB), MM_RAM_MAX_IN_MB);
    3652             }
    3653             if (vsysThis.ullMemorySize == 0)
    3654             {
    3655                 /* If the RAM of the OVF is zero, use our predefined values */
    3656                 ULONG memSizeVBox2;
    3657                 rc = pGuestOSType->COMGETTER(RecommendedRAM)(&memSizeVBox2);
    3658                 if (FAILED(rc)) throw rc;
    3659                 /* VBox stores that in MByte */
    3660                 ullMemSizeVBox = (uint64_t)memSizeVBox2;
    3661             }
    3662             pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
    3663                                "",
    3664                                Utf8StrFmt("%RI64", (uint64_t)vsysThis.ullMemorySize),
    3665                                Utf8StrFmt("%RI64", (uint64_t)ullMemSizeVBox));
    3666 
    3667             /* Audio */
    3668             if (!vsysThis.strSoundCardType.isEmpty())
    3669                 /* Currently we set the AC97 always.
    3670                    @todo: figure out the hardware which could be possible */
    3671                 pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
    3672                                    "",
    3673                                    vsysThis.strSoundCardType,
    3674                                    Utf8StrFmt("%RI32", (uint32_t)AudioControllerType_AC97));
    3675 
    3676 #ifdef VBOX_WITH_USB
    3677             /* USB Controller */
    3678             if (vsysThis.fHasUsbController)
    3679                 pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
    3680 #endif /* VBOX_WITH_USB */
    3681 
    3682             /* Network Controller */
    3683             size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size();
    3684             if (cEthernetAdapters > 0)
    3685             {
    3686                 /* Check for the constrains */
    3687                 if (cEthernetAdapters > SchemaDefs::NetworkAdapterCount)
    3688                     addWarning(tr("The virtual system \"%s\" claims support for %zu network adapters, but VirtualBox has support for max %u network adapter only."),
    3689                                   vsysThis.strName.c_str(), cEthernetAdapters, SchemaDefs::NetworkAdapterCount);
    3690 
    3691                 /* Get the default network adapter type for the selected guest OS */
    3692                 NetworkAdapterType_T defaultAdapterVBox = NetworkAdapterType_Am79C970A;
    3693                 rc = pGuestOSType->COMGETTER(AdapterType)(&defaultAdapterVBox);
    3694                 if (FAILED(rc)) throw rc;
    3695 
    3696                 EthernetAdaptersList::const_iterator itEA;
    3697                 /* Iterate through all abstract networks. We support 8 network
    3698                  * adapters at the maximum, so the first 8 will be added only. */
    3699                 size_t a = 0;
    3700                 for (itEA = vsysThis.llEthernetAdapters.begin();
    3701                      itEA != vsysThis.llEthernetAdapters.end() && a < SchemaDefs::NetworkAdapterCount;
    3702                      ++itEA, ++a)
    3703                 {
    3704                     const EthernetAdapter &ea = *itEA; // logical network to connect to
    3705                     Utf8Str strNetwork = ea.strNetworkName;
    3706                     // make sure it's one of these two
    3707                     if (    (strNetwork.compare("Null", Utf8Str::CaseInsensitive))
    3708                          && (strNetwork.compare("NAT", Utf8Str::CaseInsensitive))
    3709                          && (strNetwork.compare("Bridged", Utf8Str::CaseInsensitive))
    3710                          && (strNetwork.compare("Internal", Utf8Str::CaseInsensitive))
    3711                          && (strNetwork.compare("HostOnly", Utf8Str::CaseInsensitive))
    3712                        )
    3713                         strNetwork = "Bridged";     // VMware assumes this is the default apparently
    3714 
    3715                     /* Figure out the hardware type */
    3716                     NetworkAdapterType_T nwAdapterVBox = defaultAdapterVBox;
    3717                     if (!ea.strAdapterType.compare("PCNet32", Utf8Str::CaseInsensitive))
    3718                     {
    3719                         /* If the default adapter is already one of the two
    3720                          * PCNet adapters use the default one. If not use the
    3721                          * Am79C970A as fallback. */
    3722                         if (!(defaultAdapterVBox == NetworkAdapterType_Am79C970A ||
    3723                               defaultAdapterVBox == NetworkAdapterType_Am79C973))
    3724                             nwAdapterVBox = NetworkAdapterType_Am79C970A;
    3725                     }
    3726 #ifdef VBOX_WITH_E1000
    3727                     /* VMWare accidentally write this with VirtualCenter 3.5,
    3728                        so make sure in this case always to use the VMWare one */
    3729                     else if (!ea.strAdapterType.compare("E10000", Utf8Str::CaseInsensitive))
    3730                         nwAdapterVBox = NetworkAdapterType_I82545EM;
    3731                     else if (!ea.strAdapterType.compare("E1000", Utf8Str::CaseInsensitive))
    3732                     {
    3733                         /* Check if this OVF was written by VirtualBox */
    3734                         if (Utf8Str(vsysThis.strVirtualSystemType).contains("virtualbox", Utf8Str::CaseInsensitive))
    3735                         {
    3736                             /* If the default adapter is already one of the three
    3737                              * E1000 adapters use the default one. If not use the
    3738                              * I82545EM as fallback. */
    3739                             if (!(defaultAdapterVBox == NetworkAdapterType_I82540EM ||
    3740                                   defaultAdapterVBox == NetworkAdapterType_I82543GC ||
    3741                                   defaultAdapterVBox == NetworkAdapterType_I82545EM))
    3742                             nwAdapterVBox = NetworkAdapterType_I82540EM;
    3743                         }
    3744                         else
    3745                             /* Always use this one since it's what VMware uses */
    3746                             nwAdapterVBox = NetworkAdapterType_I82545EM;
    3747                     }
    3748 #endif /* VBOX_WITH_E1000 */
    3749 
    3750                     pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
    3751                                        "",      // ref
    3752                                        ea.strNetworkName,      // orig
    3753                                        Utf8StrFmt("%RI32", (uint32_t)nwAdapterVBox),   // conf
    3754                                        0,
    3755                                        Utf8StrFmt("type=%s", strNetwork.c_str()));       // extra conf
    3756                 }
    3757             }
    3758 
    3759             /* Floppy Drive */
    3760             if (vsysThis.fHasFloppyDrive)
    3761                 pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy, "", "", "");
    3762 
    3763             /* CD Drive */
    3764             if (vsysThis.fHasCdromDrive)
    3765                 pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");
    3766 
    3767             /* Hard disk Controller */
    3768             uint16_t cIDEused = 0;
    3769             uint16_t cSATAused = 0; NOREF(cSATAused);
    3770             uint16_t cSCSIused = 0; NOREF(cSCSIused);
    3771             ControllersMap::const_iterator hdcIt;
    3772             /* Iterate through all hard disk controllers */
    3773             for (hdcIt = vsysThis.mapControllers.begin();
    3774                  hdcIt != vsysThis.mapControllers.end();
    3775                  ++hdcIt)
    3776             {
    3777                 const HardDiskController &hdc = hdcIt->second;
    3778                 Utf8Str strControllerID = Utf8StrFmt("%RI32", (uint32_t)hdc.idController);
    3779 
    3780                 switch (hdc.system)
    3781                 {
    3782                     case HardDiskController::IDE:
    3783                         {
    3784                             /* Check for the constrains */
    3785                             /* @todo: I'm very confused! Are these bits *one* controller or
    3786                                is every port/bus declared as an extra controller. */
    3787                             if (cIDEused < 4)
    3788                             {
    3789                                 // @todo: figure out the IDE types
    3790                                 /* Use PIIX4 as default */
    3791                                 Utf8Str strType = "PIIX4";
    3792                                 if (!hdc.strControllerType.compare("PIIX3", Utf8Str::CaseInsensitive))
    3793                                     strType = "PIIX3";
    3794                                 else if (!hdc.strControllerType.compare("ICH6", Utf8Str::CaseInsensitive))
    3795                                     strType = "ICH6";
    3796                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
    3797                                                    strControllerID,
    3798                                                    hdc.strControllerType,
    3799                                                    strType);
    3800                             }
    3801                             else
    3802                             {
    3803                                 /* Warn only once */
    3804                                 if (cIDEused == 1)
    3805                                     addWarning(tr("The virtual \"%s\" system requests support for more than one IDE controller, but VirtualBox has support for only one."),
    3806                                                vsysThis.strName.c_str());
    3807 
    3808                             }
    3809                             ++cIDEused;
    3810                             break;
    3811                         }
    3812 
    3813                     case HardDiskController::SATA:
    3814                         {
    3815 #ifdef VBOX_WITH_AHCI
    3816                             /* Check for the constrains */
    3817                             if (cSATAused < 1)
    3818                             {
    3819                                 // @todo: figure out the SATA types
    3820                                 /* We only support a plain AHCI controller, so use them always */
    3821                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
    3822                                                    strControllerID,
    3823                                                    hdc.strControllerType,
    3824                                                    "AHCI");
    3825                             }
    3826                             else
    3827                             {
    3828                                 /* Warn only once */
    3829                                 if (cSATAused == 1)
    3830                                     addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"),
    3831                                                vsysThis.strName.c_str());
    3832 
    3833                             }
    3834                             ++cSATAused;
    3835                             break;
    3836 #else /* !VBOX_WITH_AHCI */
    3837                             addWarning(tr("The virtual system \"%s\" requests at least one SATA controller but this version of VirtualBox does not provide a SATA controller emulation"),
    3838                                       vsysThis.strName.c_str());
    3839 #endif /* !VBOX_WITH_AHCI */
    3840                         }
    3841 
    3842                     case HardDiskController::SCSI:
    3843                         {
    3844 #ifdef VBOX_WITH_LSILOGIC
    3845                             /* Check for the constrains */
    3846                             if (cSCSIused < 1)
    3847                             {
    3848                                 Utf8Str hdcController = "LsiLogic";
    3849                                 if (!hdc.strControllerType.compare("BusLogic", Utf8Str::CaseInsensitive))
    3850                                     hdcController = "BusLogic";
    3851                                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
    3852                                                    strControllerID,
    3853                                                    hdc.strControllerType,
    3854                                                    hdcController);
    3855                             }
    3856                             else
    3857                                 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."),
    3858                                            vsysThis.strName.c_str(),
    3859                                            hdc.strControllerType.c_str(),
    3860                                            strControllerID.c_str());
    3861                             ++cSCSIused;
    3862                             break;
    3863 #else /* !VBOX_WITH_LSILOGIC */
    3864                             addWarning(tr("The virtual system \"%s\" requests at least one SATA controller but this version of VirtualBox does not provide a SCSI controller emulation"),
    3865                                        vsysThis.strName.c_str());
    3866 #endif /* !VBOX_WITH_LSILOGIC */
    3867                         }
    3868                 }
    3869             }
    3870 
    3871             /* Hard disks */
    3872             if (vsysThis.mapVirtualDisks.size() > 0)
    3873             {
    3874                 VirtualDisksMap::const_iterator itVD;
    3875                 /* Iterate through all hard disks ()*/
    3876                 for (itVD = vsysThis.mapVirtualDisks.begin();
    3877                      itVD != vsysThis.mapVirtualDisks.end();
    3878                      ++itVD)
    3879                 {
    3880                     const VirtualDisk &hd = itVD->second;
    3881                     /* Get the associated disk image */
    3882                     const DiskImage &di = m->pReader->m_mapDisks[hd.strDiskId];
    3883 
    3884                     // @todo:
    3885                     //  - figure out all possible vmdk formats we also support
    3886                     //  - figure out if there is a url specifier for vhd already
    3887                     //  - we need a url specifier for the vdi format
    3888                     if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
    3889                         || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
    3890                     {
    3891                         /* If the href is empty use the VM name as filename */
    3892                         Utf8Str strFilename = di.strHref;
    3893                         if (!strFilename.length())
    3894                             strFilename = Utf8StrFmt("%s.vmdk", nameVBox.c_str());
    3895                         /* Construct a unique target path */
    3896                         Utf8StrFmt strPath("%ls%c%s",
    3897                                            bstrDefaultHardDiskLocation.raw(),
    3898                                            RTPATH_DELIMITER,
    3899                                            strFilename.c_str());
    3900                         searchUniqueDiskImageFilePath(strPath);
    3901 
    3902                         /* find the description for the hard disk controller
    3903                          * that has the same ID as hd.idController */
    3904                         const VirtualSystemDescriptionEntry *pController;
    3905                         if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
    3906                             throw setError(E_FAIL,
    3907                                            tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"),
    3908                                            hd.idController,
    3909                                            di.strHref.c_str());
    3910 
    3911                         /* controller to attach to, and the bus within that controller */
    3912                         Utf8StrFmt strExtraConfig("controller=%RI16;channel=%RI16",
    3913                                                   pController->ulIndex,
    3914                                                   hd.ulAddressOnParent);
    3915                         ULONG ulSize = 0;
    3916                         if (di.iCapacity != -1)
    3917                             ulSize = (ULONG)(di.iCapacity / _1M);
    3918                         else if (di.iPopulatedSize != -1)
    3919                             ulSize = (ULONG)(di.iPopulatedSize / _1M);
    3920                         else if (di.iSize != -1)
    3921                             ulSize = (ULONG)(di.iSize / _1M);
    3922                         if (ulSize == 0)
    3923                             ulSize = 10000;         // assume 10 GB, this is for the progress bar only anyway
    3924                         pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
    3925                                            hd.strDiskId,
    3926                                            di.strHref,
    3927                                            strPath,
    3928                                            ulSize,
    3929                                            strExtraConfig);
    3930                     }
    3931                     else
    3932                         throw setError(VBOX_E_FILE_ERROR,
    3933                                        tr("Unsupported format for virtual disk image in OVF: \"%s\"", di.strFormat.c_str()));
    3934                 }
    3935             }
    3936 
    3937             m->virtualSystemDescriptions.push_back(pNewDesc);
    3938         }
    3939     }
    3940     catch (HRESULT aRC)
    3941     {
    3942         /* On error we clear the list & return */
    3943         m->virtualSystemDescriptions.clear();
    3944         rc = aRC;
    3945     }
    3946 
    3947     // reset the appliance state
    3948     alock.acquire();
    3949     m->state = Data::ApplianceIdle;
    3950 
    3951     return rc;
    3952 }
    3953 
    3954 /**
    3955  * Public method implementation.
    3956  * @param aProgress
    3957  * @return
    3958  */
    3959 STDMETHODIMP Appliance::ImportMachines(IProgress **aProgress)
    3960 {
    3961     CheckComArgOutPointerValid(aProgress);
    3962 
    3963     AutoCaller autoCaller(this);
    3964     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3965 
    3966     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3967 
    3968     // do not allow entering this method if the appliance is busy reading or writing
    3969     if (!isApplianceIdle())
    3970         return E_ACCESSDENIED;
    3971 
    3972     if (!m->pReader)
    3973         return setError(E_FAIL,
    3974                         tr("Cannot import machines without reading it first (call read() before importMachines())"));
    3975 
    3976     ComObjPtr<Progress> progress;
    3977     HRESULT rc = S_OK;
    3978     try
    3979     {
    3980         rc = importImpl(m->locInfo, progress);
    3981     }
    3982     catch (HRESULT aRC)
    3983     {
    3984         rc = aRC;
    3985     }
    3986 
    3987     if (SUCCEEDED(rc))
    3988         /* Return progress to the caller */
    3989         progress.queryInterfaceTo(aProgress);
    3990 
    3991     return rc;
    3992 }
    3993 
    3994 STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
    3995 {
    3996     CheckComArgOutPointerValid(aExplorer);
    3997 
    3998     AutoCaller autoCaller(this);
    3999     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4000 
    4001     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4002 
    4003     ComObjPtr<VFSExplorer> explorer;
    4004     HRESULT rc = S_OK;
    4005     try
    4006     {
    4007         Utf8Str uri(aURI);
    4008         /* Check which kind of export the user has requested */
    4009         LocationInfo li;
    4010         parseURI(uri, li);
    4011         /* Create the explorer object */
    4012         explorer.createObject();
    4013         rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
    4014     }
    4015     catch (HRESULT aRC)
    4016     {
    4017         rc = aRC;
    4018     }
    4019 
    4020     if (SUCCEEDED(rc))
    4021         /* Return explorer to the caller */
    4022         explorer.queryInterfaceTo(aExplorer);
    4023 
    4024     return rc;
    4025 }
    4026 
    4027 STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress)
    4028 {
    4029     if (!path) return E_POINTER;
    4030     CheckComArgOutPointerValid(aProgress);
    4031 
    4032     AutoCaller autoCaller(this);
    4033     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4034 
    4035     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4036 
    4037     // do not allow entering this method if the appliance is busy reading or writing
    4038     if (!isApplianceIdle())
    4039         return E_ACCESSDENIED;
    4040 
    4041     // see if we can handle this file; for now we insist it has an ".ovf" extension
    4042     Utf8Str strPath = path;
    4043     if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    4044         return setError(VBOX_E_FILE_ERROR,
    4045                         tr("Appliance file must have .ovf extension"));
    4046 
    4047     Utf8Str strFormat(format);
    4048     TaskExportOVF::OVFFormat ovfF;
    4049     if (strFormat == "ovf-0.9")
    4050         ovfF = TaskExportOVF::OVF_0_9;
    4051     else if (strFormat == "ovf-1.0")
    4052         ovfF = TaskExportOVF::OVF_1_0;
    4053     else
    4054         return setError(VBOX_E_FILE_ERROR,
    4055                         tr("Invalid format \"%s\" specified"), strFormat.c_str());
    4056 
    4057     ComObjPtr<Progress> progress;
    4058     HRESULT rc = S_OK;
    4059     try
    4060     {
    4061         /* Parse all necessary info out of the URI */
    4062         parseURI(strPath, m->locInfo);
    4063         rc = writeImpl(ovfF, m->locInfo, progress);
    4064     }
    4065     catch (HRESULT aRC)
    4066     {
    4067         rc = aRC;
    4068     }
    4069 
    4070     if (SUCCEEDED(rc))
    4071         /* Return progress to the caller */
    4072         progress.queryInterfaceTo(aProgress);
    4073 
    4074     return rc;
    4075 }
    4076 
    4077 /**
    4078 * Public method implementation.
    4079  * @return
    4080  */
    4081 STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
    4082 {
    4083     if (ComSafeArrayOutIsNull(aWarnings))
    4084         return E_POINTER;
    4085 
    4086     AutoCaller autoCaller(this);
    4087     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4088 
    4089     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4090 
    4091     com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
    4092 
    4093     list<Utf8Str>::const_iterator it;
    4094     size_t i = 0;
    4095     for (it = m->llWarnings.begin();
    4096          it != m->llWarnings.end();
    4097          ++it, ++i)
    4098     {
    4099         Bstr bstr = *it;
    4100         bstr.cloneTo(&sfaWarnings[i]);
    4101     }
    4102 
    4103     sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
    4104 
    4105     return S_OK;
    4106 }
    4107 
    4108 ////////////////////////////////////////////////////////////////////////////////
    4109 //
    4110 // IVirtualSystemDescription constructor / destructor
    4111 //
    4112 ////////////////////////////////////////////////////////////////////////////////
    4113 
    4114 DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
    4115 
    4116 /**
    4117  * COM initializer.
    4118  * @return
    4119  */
    4120 HRESULT VirtualSystemDescription::init()
    4121 {
    4122     /* Enclose the state transition NotReady->InInit->Ready */
    4123     AutoInitSpan autoInitSpan(this);
    4124     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    4125 
    4126     /* Initialize data */
    4127     m = new Data();
    4128 
    4129     /* Confirm a successful initialization */
    4130     autoInitSpan.setSucceeded();
    4131     return S_OK;
    4132 }
    4133 
    4134 /**
    4135 * COM uninitializer.
    4136 */
    4137 
    4138 void VirtualSystemDescription::uninit()
    4139 {
    4140     delete m;
    4141     m = NULL;
    4142 }
    4143 
    4144 ////////////////////////////////////////////////////////////////////////////////
    4145 //
    4146 // IVirtualSystemDescription public methods
    4147 //
    4148 ////////////////////////////////////////////////////////////////////////////////
    4149 
    4150 /**
    4151  * Public method implementation.
    4152  * @param
    4153  * @return
    4154  */
    4155 STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
    4156 {
    4157     if (!aCount)
    4158         return E_POINTER;
    4159 
    4160     AutoCaller autoCaller(this);
    4161     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4162 
    4163     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4164 
    4165     *aCount = (ULONG)m->llDescriptions.size();
    4166 
    4167     return S_OK;
    4168 }
    4169 
    4170 /**
    4171  * Public method implementation.
    4172  * @return
    4173  */
    4174 STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
    4175                                                       ComSafeArrayOut(BSTR, aRefs),
    4176                                                       ComSafeArrayOut(BSTR, aOrigValues),
    4177                                                       ComSafeArrayOut(BSTR, aVboxValues),
    4178                                                       ComSafeArrayOut(BSTR, aExtraConfigValues))
    4179 {
    4180     if (ComSafeArrayOutIsNull(aTypes) ||
    4181         ComSafeArrayOutIsNull(aRefs) ||
    4182         ComSafeArrayOutIsNull(aOrigValues) ||
    4183         ComSafeArrayOutIsNull(aVboxValues) ||
    4184         ComSafeArrayOutIsNull(aExtraConfigValues))
    4185         return E_POINTER;
    4186 
    4187     AutoCaller autoCaller(this);
    4188     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4189 
    4190     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4191 
    4192     ULONG c = (ULONG)m->llDescriptions.size();
    4193     com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
    4194     com::SafeArray<BSTR> sfaRefs(c);
    4195     com::SafeArray<BSTR> sfaOrigValues(c);
    4196     com::SafeArray<BSTR> sfaVboxValues(c);
    4197     com::SafeArray<BSTR> sfaExtraConfigValues(c);
    4198 
    4199     list<VirtualSystemDescriptionEntry>::const_iterator it;
    4200     size_t i = 0;
    4201     for (it = m->llDescriptions.begin();
    4202          it != m->llDescriptions.end();
    4203          ++it, ++i)
    4204     {
    4205         const VirtualSystemDescriptionEntry &vsde = (*it);
    4206 
    4207         sfaTypes[i] = vsde.type;
    4208 
    4209         Bstr bstr = vsde.strRef;
    4210         bstr.cloneTo(&sfaRefs[i]);
    4211 
    4212         bstr = vsde.strOvf;
    4213         bstr.cloneTo(&sfaOrigValues[i]);
    4214 
    4215         bstr = vsde.strVbox;
    4216         bstr.cloneTo(&sfaVboxValues[i]);
    4217 
    4218         bstr = vsde.strExtraConfig;
    4219         bstr.cloneTo(&sfaExtraConfigValues[i]);
    4220     }
    4221 
    4222     sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
    4223     sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
    4224     sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
    4225     sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
    4226     sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
    4227 
    4228     return S_OK;
    4229 }
    4230 
    4231 /**
    4232  * Public method implementation.
    4233  * @return
    4234  */
    4235 STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
    4236                                                             ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
    4237                                                             ComSafeArrayOut(BSTR, aRefs),
    4238                                                             ComSafeArrayOut(BSTR, aOrigValues),
    4239                                                             ComSafeArrayOut(BSTR, aVboxValues),
    4240                                                             ComSafeArrayOut(BSTR, aExtraConfigValues))
    4241 {
    4242     if (ComSafeArrayOutIsNull(aTypes) ||
    4243         ComSafeArrayOutIsNull(aRefs) ||
    4244         ComSafeArrayOutIsNull(aOrigValues) ||
    4245         ComSafeArrayOutIsNull(aVboxValues) ||
    4246         ComSafeArrayOutIsNull(aExtraConfigValues))
    4247         return E_POINTER;
    4248 
    4249     AutoCaller autoCaller(this);
    4250     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4251 
    4252     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4253 
    4254     std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
    4255     ULONG c = (ULONG)vsd.size();
    4256     com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
    4257     com::SafeArray<BSTR> sfaRefs(c);
    4258     com::SafeArray<BSTR> sfaOrigValues(c);
    4259     com::SafeArray<BSTR> sfaVboxValues(c);
    4260     com::SafeArray<BSTR> sfaExtraConfigValues(c);
    4261 
    4262     list<VirtualSystemDescriptionEntry*>::const_iterator it;
    4263     size_t i = 0;
    4264     for (it = vsd.begin();
    4265          it != vsd.end();
    4266          ++it, ++i)
    4267     {
    4268         const VirtualSystemDescriptionEntry *vsde = (*it);
    4269 
    4270         sfaTypes[i] = vsde->type;
    4271 
    4272         Bstr bstr = vsde->strRef;
    4273         bstr.cloneTo(&sfaRefs[i]);
    4274 
    4275         bstr = vsde->strOvf;
    4276         bstr.cloneTo(&sfaOrigValues[i]);
    4277 
    4278         bstr = vsde->strVbox;
    4279         bstr.cloneTo(&sfaVboxValues[i]);
    4280 
    4281         bstr = vsde->strExtraConfig;
    4282         bstr.cloneTo(&sfaExtraConfigValues[i]);
    4283     }
    4284 
    4285     sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
    4286     sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
    4287     sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
    4288     sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
    4289     sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
    4290 
    4291     return S_OK;
    4292 }
    4293 
    4294 /**
    4295  * Public method implementation.
    4296  * @return
    4297  */
    4298 STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
    4299                                                        VirtualSystemDescriptionValueType_T aWhich,
    4300                                                        ComSafeArrayOut(BSTR, aValues))
    4301 {
    4302     if (ComSafeArrayOutIsNull(aValues))
    4303         return E_POINTER;
    4304 
    4305     AutoCaller autoCaller(this);
    4306     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4307 
    4308     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4309 
    4310     std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
    4311     com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
    4312 
    4313     list<VirtualSystemDescriptionEntry*>::const_iterator it;
    4314     size_t i = 0;
    4315     for (it = vsd.begin();
    4316          it != vsd.end();
    4317          ++it, ++i)
    4318     {
    4319         const VirtualSystemDescriptionEntry *vsde = (*it);
    4320 
    4321         Bstr bstr;
    4322         switch (aWhich)
    4323         {
    4324             case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
    4325             case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
    4326             case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVbox; break;
    4327             case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfig; break;
    4328         }
    4329 
    4330         bstr.cloneTo(&sfaValues[i]);
    4331     }
    4332 
    4333     sfaValues.detachTo(ComSafeArrayOutArg(aValues));
    4334 
    4335     return S_OK;
    4336 }
    4337 
    4338 /**
    4339  * Public method implementation.
    4340  * @return
    4341  */
    4342 STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
    4343                                                       ComSafeArrayIn(IN_BSTR, argVboxValues),
    4344                                                       ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
    4345 {
    4346 #ifndef RT_OS_WINDOWS
    4347     NOREF(aEnabledSize);
    4348 #endif /* RT_OS_WINDOWS */
    4349 
    4350     CheckComArgSafeArrayNotNull(aEnabled);
    4351     CheckComArgSafeArrayNotNull(argVboxValues);
    4352     CheckComArgSafeArrayNotNull(argExtraConfigValues);
    4353 
    4354     AutoCaller autoCaller(this);
    4355     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4356 
    4357     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4358 
    4359     com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
    4360     com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
    4361     com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
    4362 
    4363     if (    (sfaEnabled.size() != m->llDescriptions.size())
    4364          || (sfaVboxValues.size() != m->llDescriptions.size())
    4365          || (sfaExtraConfigValues.size() != m->llDescriptions.size())
    4366        )
    4367         return E_INVALIDARG;
    4368 
    4369     list<VirtualSystemDescriptionEntry>::iterator it;
    4370     size_t i = 0;
    4371     for (it = m->llDescriptions.begin();
    4372          it != m->llDescriptions.end();
    4373          ++it, ++i)
    4374     {
    4375         VirtualSystemDescriptionEntry& vsde = *it;
    4376 
    4377         if (sfaEnabled[i])
    4378         {
    4379             vsde.strVbox = sfaVboxValues[i];
    4380             vsde.strExtraConfig = sfaExtraConfigValues[i];
    4381         }
    4382         else
    4383             vsde.type = VirtualSystemDescriptionType_Ignore;
    4384     }
    4385 
    4386     return S_OK;
    4387 }
    4388 
    4389 /**
    4390  * Public method implementation.
    4391  * @return
    4392  */
    4393 STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
    4394                                                       IN_BSTR aVboxValue,
    4395                                                       IN_BSTR aExtraConfigValue)
    4396 {
    4397     AutoCaller autoCaller(this);
    4398     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4399 
    4400     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4401 
    4402     addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
    4403 
    4404     return S_OK;
    4405 }
    4406 
    4407 /**
    4408  * Internal method; adds a new description item to the member list.
    4409  * @param aType Type of description for the new item.
    4410  * @param strRef Reference item; only used with hard disk controllers.
    4411  * @param aOrigValue Corresponding original value from OVF.
    4412  * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
    4413  * @param ulSizeMB Weight for IProgress
    4414  * @param strExtraConfig Extra configuration; meaning dependent on type.
    4415  */
    4416 void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
    4417                                         const Utf8Str &strRef,
    4418                                         const Utf8Str &aOrigValue,
    4419                                         const Utf8Str &aAutoValue,
    4420                                         uint32_t ulSizeMB,
    4421                                         const Utf8Str &strExtraConfig /*= ""*/)
    4422 {
    4423     VirtualSystemDescriptionEntry vsde;
    4424     vsde.ulIndex = (uint32_t)m->llDescriptions.size();      // each entry gets an index so the client side can reference them
    4425     vsde.type = aType;
    4426     vsde.strRef = strRef;
    4427     vsde.strOvf = aOrigValue;
    4428     vsde.strVbox = aAutoValue;
    4429     vsde.strExtraConfig = strExtraConfig;
    4430     vsde.ulSizeMB = ulSizeMB;
    4431 
    4432     m->llDescriptions.push_back(vsde);
    4433 }
    4434 
    4435 /**
    4436  * Private method; returns a list of description items containing all the items from the member
    4437  * description items of this virtual system that match the given type.
    4438  * @param aType
    4439  * @return
    4440  */
    4441 std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
    4442 {
    4443     std::list<VirtualSystemDescriptionEntry*> vsd;
    4444 
    4445     list<VirtualSystemDescriptionEntry>::iterator it;
    4446     for (it = m->llDescriptions.begin();
    4447          it != m->llDescriptions.end();
    4448          ++it)
    4449     {
    4450         if (it->type == aType)
    4451             vsd.push_back(&(*it));
    4452     }
    4453 
    4454     return vsd;
    4455 }
    4456 
    4457 /**
    4458  * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
    4459  * the given reference ID. Useful when needing the controller for a particular
    4460  * virtual disk.
    4461  * @param id
    4462  * @return
    4463  */
    4464 const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
    4465 {
    4466     Utf8Str strRef = Utf8StrFmt("%RI32", id);
    4467     list<VirtualSystemDescriptionEntry>::const_iterator it;
    4468     for (it = m->llDescriptions.begin();
    4469          it != m->llDescriptions.end();
    4470          ++it)
    4471     {
    4472         const VirtualSystemDescriptionEntry &d = *it;
    4473         switch (d.type)
    4474         {
    4475             case VirtualSystemDescriptionType_HardDiskControllerIDE:
    4476             case VirtualSystemDescriptionType_HardDiskControllerSATA:
    4477             case VirtualSystemDescriptionType_HardDiskControllerSCSI:
    4478                 if (d.strRef == strRef)
    4479                     return &d;
    4480             break;
    4481         }
    4482     }
    4483 
    4484     return NULL;
    4485 }
    4486 
    4487 ////////////////////////////////////////////////////////////////////////////////
    4488 //
    4489 // IMachine public methods
    4490 //
    4491 ////////////////////////////////////////////////////////////////////////////////
    4492 
    4493 // This code is here so we won't have to include the appliance headers in the
    4494 // IMachine implementation, and we also need to access private appliance data.
    4495 
    4496 /**
    4497 * Public method implementation.
    4498 * @param appliance
    4499 * @return
    4500 */
    4501 
    4502 STDMETHODIMP Machine::Export(IAppliance *aAppliance, IVirtualSystemDescription **aDescription)
    4503 {
    4504     HRESULT rc = S_OK;
    4505 
    4506     if (!aAppliance)
    4507         return E_POINTER;
    4508 
    4509     AutoCaller autoCaller(this);
    4510     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4511 
    4512     ComObjPtr<VirtualSystemDescription> pNewDesc;
    4513 
    4514     try
    4515     {
    4516         Bstr bstrName1;
    4517         Bstr bstrDescription;
    4518         Bstr bstrGuestOSType;
    4519         uint32_t cCPUs;
    4520         uint32_t ulMemSizeMB;
    4521         BOOL fUSBEnabled;
    4522         BOOL fAudioEnabled;
    4523         AudioControllerType_T audioController;
    4524 
    4525         ComPtr<IUSBController> pUsbController;
    4526         ComPtr<IAudioAdapter> pAudioAdapter;
    4527 
    4528         // first, call the COM methods, as they request locks
    4529         rc = COMGETTER(USBController)(pUsbController.asOutParam());
    4530         if (FAILED(rc))
    4531             fUSBEnabled = false;
    4532         else
    4533             rc = pUsbController->COMGETTER(Enabled)(&fUSBEnabled);
    4534 
    4535         // request the machine lock while acessing internal members
    4536         AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
    4537 
    4538         pAudioAdapter = mAudioAdapter;
    4539         rc = pAudioAdapter->COMGETTER(Enabled)(&fAudioEnabled);
    4540         if (FAILED(rc)) throw rc;
    4541         rc = pAudioAdapter->COMGETTER(AudioController)(&audioController);
    4542         if (FAILED(rc)) throw rc;
    4543 
    4544         // get name
    4545         bstrName1 = mUserData->mName;
    4546         // get description
    4547         bstrDescription = mUserData->mDescription;
    4548         // get guest OS
    4549         bstrGuestOSType = mUserData->mOSTypeId;
    4550         // CPU count
    4551         cCPUs = mHWData->mCPUCount;
    4552         // memory size in MB
    4553         ulMemSizeMB = mHWData->mMemorySize;
    4554         // VRAM size?
    4555         // BIOS settings?
    4556         // 3D acceleration enabled?
    4557         // hardware virtualization enabled?
    4558         // nested paging enabled?
    4559         // HWVirtExVPIDEnabled?
    4560         // PAEEnabled?
    4561         // snapshotFolder?
    4562         // VRDPServer?
    4563 
    4564         // create a new virtual system
    4565         rc = pNewDesc.createObject();
    4566         if (FAILED(rc)) throw rc;
    4567         rc = pNewDesc->init();
    4568         if (FAILED(rc)) throw rc;
    4569 
    4570         /* Guest OS type */
    4571         Utf8Str strOsTypeVBox(bstrGuestOSType);
    4572         CIMOSType_T cim = convertVBoxOSType2CIMOSType(strOsTypeVBox.c_str());
    4573         pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
    4574                            "",
    4575                            Utf8StrFmt("%RI32", cim),
    4576                            strOsTypeVBox);
    4577 
    4578         /* VM name */
    4579         Utf8Str strVMName(bstrName1);
    4580         pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
    4581                            "",
    4582                            strVMName,
    4583                            strVMName);
    4584 
    4585         // description
    4586         Utf8Str strDescription(bstrDescription);
    4587         pNewDesc->addEntry(VirtualSystemDescriptionType_Description,
    4588                            "",
    4589                            strDescription,
    4590                            strDescription);
    4591 
    4592         /* CPU count*/
    4593         Utf8Str strCpuCount = Utf8StrFmt("%RI32", cCPUs);
    4594         pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
    4595                            "",
    4596                            strCpuCount,
    4597                            strCpuCount);
    4598 
    4599         /* Memory */
    4600         Utf8Str strMemory = Utf8StrFmt("%RI64", (uint64_t)ulMemSizeMB * _1M);
    4601         pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
    4602                            "",
    4603                            strMemory,
    4604                            strMemory);
    4605 
    4606         int32_t lIDEControllerIndex = 0;
    4607         int32_t lSATAControllerIndex = 0;
    4608         int32_t lSCSIControllerIndex = 0;
    4609 
    4610         /* Fetch all available storage controllers */
    4611         com::SafeIfaceArray<IStorageController> nwControllers;
    4612         rc = COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(nwControllers));
    4613         if (FAILED(rc)) throw rc;
    4614 
    4615         ComPtr<IStorageController> pIDEController;
    4616 #ifdef VBOX_WITH_AHCI
    4617         ComPtr<IStorageController> pSATAController;
    4618 #endif /* VBOX_WITH_AHCI */
    4619 #ifdef VBOX_WITH_LSILOGIC
    4620         ComPtr<IStorageController> pSCSIController;
    4621 #endif /* VBOX_WITH_LSILOGIC */
    4622         for (size_t j = 0; j < nwControllers.size(); ++j)
    4623         {
    4624             StorageBus_T eType;
    4625             rc = nwControllers[j]->COMGETTER(Bus)(&eType);
    4626             if (FAILED(rc)) throw rc;
    4627             if (   eType == StorageBus_IDE
    4628                 && pIDEController.isNull())
    4629                 pIDEController = nwControllers[j];
    4630 #ifdef VBOX_WITH_AHCI
    4631             else if (   eType == StorageBus_SATA
    4632                      && pSATAController.isNull())
    4633                 pSATAController = nwControllers[j];
    4634 #endif /* VBOX_WITH_AHCI */
    4635 #ifdef VBOX_WITH_LSILOGIC
    4636             else if (   eType == StorageBus_SCSI
    4637                      && pSATAController.isNull())
    4638                 pSCSIController = nwControllers[j];
    4639 #endif /* VBOX_WITH_LSILOGIC */
    4640         }
    4641 
    4642 //     <const name="HardDiskControllerIDE" value="6" />
    4643         if (!pIDEController.isNull())
    4644         {
    4645             Utf8Str strVbox;
    4646             StorageControllerType_T ctlr;
    4647             rc = pIDEController->COMGETTER(ControllerType)(&ctlr);
    4648             if (FAILED(rc)) throw rc;
    4649             switch(ctlr)
    4650             {
    4651                 case StorageControllerType_PIIX3: strVbox = "PIIX3"; break;
    4652                 case StorageControllerType_PIIX4: strVbox = "PIIX4"; break;
    4653                 case StorageControllerType_ICH6: strVbox = "ICH6"; break;
    4654             }
    4655 
    4656             if (strVbox.length())
    4657             {
    4658                 lIDEControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
    4659                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
    4660                                    Utf8StrFmt("%d", lIDEControllerIndex),
    4661                                    strVbox,
    4662                                    strVbox);
    4663             }
    4664         }
    4665 
    4666 #ifdef VBOX_WITH_AHCI
    4667 //     <const name="HardDiskControllerSATA" value="7" />
    4668         if (!pSATAController.isNull())
    4669         {
    4670             Utf8Str strVbox = "AHCI";
    4671             lSATAControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
    4672             pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
    4673                                Utf8StrFmt("%d", lSATAControllerIndex),
    4674                                strVbox,
    4675                                strVbox);
    4676         }
    4677 #endif // VBOX_WITH_AHCI
    4678 
    4679 #ifdef VBOX_WITH_LSILOGIC
    4680 //     <const name="HardDiskControllerSCSI" value="8" />
    4681         if (!pSCSIController.isNull())
    4682         {
    4683             StorageControllerType_T ctlr;
    4684             rc = pSCSIController->COMGETTER(ControllerType)(&ctlr);
    4685             if (SUCCEEDED(rc))
    4686             {
    4687                 Utf8Str strVbox = "LsiLogic";       // the default in VBox
    4688                 switch(ctlr)
    4689                 {
    4690                     case StorageControllerType_LsiLogic: strVbox = "LsiLogic"; break;
    4691                     case StorageControllerType_BusLogic: strVbox = "BusLogic"; break;
    4692                 }
    4693                 lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size();
    4694                 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
    4695                                    Utf8StrFmt("%d", lSCSIControllerIndex),
    4696                                    strVbox,
    4697                                    strVbox);
    4698             }
    4699             else
    4700                 throw rc;
    4701         }
    4702 #endif // VBOX_WITH_LSILOGIC
    4703 
    4704 //     <const name="HardDiskImage" value="9" />
    4705 //     <const name="Floppy" value="18" />
    4706 //     <const name="CDROM" value="19" />
    4707 
    4708         MediaData::AttachmentList::iterator itA;
    4709         for (itA = mMediaData->mAttachments.begin();
    4710              itA != mMediaData->mAttachments.end();
    4711              ++itA)
    4712         {
    4713             ComObjPtr<MediumAttachment> pHDA = *itA;
    4714 
    4715             // the attachment's data
    4716             ComPtr<IMedium> pMedium;
    4717             ComPtr<IStorageController> ctl;
    4718             Bstr controllerName;
    4719 
    4720             rc = pHDA->COMGETTER(Controller)(controllerName.asOutParam());
    4721             if (FAILED(rc)) throw rc;
    4722 
    4723             rc = GetStorageControllerByName(controllerName, ctl.asOutParam());
    4724             if (FAILED(rc)) throw rc;
    4725 
    4726             StorageBus_T storageBus;
    4727             DeviceType_T deviceType;
    4728             LONG lChannel;
    4729             LONG lDevice;
    4730 
    4731             rc = ctl->COMGETTER(Bus)(&storageBus);
    4732             if (FAILED(rc)) throw rc;
    4733 
    4734             rc = pHDA->COMGETTER(Type)(&deviceType);
    4735             if (FAILED(rc)) throw rc;
    4736 
    4737             rc = pHDA->COMGETTER(Medium)(pMedium.asOutParam());
    4738             if (FAILED(rc)) throw rc;
    4739 
    4740             rc = pHDA->COMGETTER(Port)(&lChannel);
    4741             if (FAILED(rc)) throw rc;
    4742 
    4743             rc = pHDA->COMGETTER(Device)(&lDevice);
    4744             if (FAILED(rc)) throw rc;
    4745 
    4746             Utf8Str strTargetVmdkName;
    4747             Utf8Str strLocation;
    4748             ULONG64 ullSize = 0;
    4749 
    4750             if (    deviceType == DeviceType_HardDisk
    4751                  && pMedium
    4752                )
    4753             {
    4754                 Bstr bstrLocation;
    4755                 rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam());
    4756                 if (FAILED(rc)) throw rc;
    4757                 strLocation = bstrLocation;
    4758 
    4759                 Bstr bstrName;
    4760                 rc = pMedium->COMGETTER(Name)(bstrName.asOutParam());
    4761                 if (FAILED(rc)) throw rc;
    4762 
    4763                 strTargetVmdkName = bstrName;
    4764                 strTargetVmdkName.stripExt();
    4765                 strTargetVmdkName.append(".vmdk");
    4766 
    4767                 // we need the size of the image so we can give it to addEntry();
    4768                 // later, on export, the progress weight will be based on this.
    4769                 // pMedium can be a differencing image though; in that case, we
    4770                 // need to use the size of the base instead.
    4771                 ComPtr<IMedium> pBaseMedium;
    4772                 rc = pMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
    4773                         // returns pMedium if there are no diff images
    4774                 if (FAILED(rc)) throw rc;
    4775 
    4776                 // force reading state, or else size will be returned as 0
    4777                 MediumState_T ms;
    4778                 rc = pBaseMedium->RefreshState(&ms);
    4779                 if (FAILED(rc)) throw rc;
    4780 
    4781                 rc = pBaseMedium->COMGETTER(Size)(&ullSize);
    4782                 if (FAILED(rc)) throw rc;
    4783             }
    4784 
    4785             // and how this translates to the virtual system
    4786             int32_t lControllerVsys = 0;
    4787             LONG lChannelVsys;
    4788 
    4789             switch (storageBus)
    4790             {
    4791                 case StorageBus_IDE:
    4792                     // this is the exact reverse to what we're doing in Appliance::taskThreadImportMachines,
    4793                     // and it must be updated when that is changed!
    4794 
    4795                     if (lChannel == 0 && lDevice == 0)      // primary master
    4796                         lChannelVsys = 0;
    4797                     else if (lChannel == 0 && lDevice == 1) // primary slave
    4798                         lChannelVsys = 1;
    4799                     else if (lChannel == 1 && lDevice == 0) // secondary master; by default this is the CD-ROM but as of VirtualBox 3.1 that can change
    4800                         lChannelVsys = 2;
    4801                     else if (lChannel == 1 && lDevice == 1) // secondary slave
    4802                         lChannelVsys = 3;
    4803                     else
    4804                         throw setError(VBOX_E_NOT_SUPPORTED,
    4805                                     tr("Cannot handle medium attachment: channel is %d, device is %d"), lChannel, lDevice);
    4806 
    4807                     lControllerVsys = lIDEControllerIndex;
    4808                 break;
    4809 
    4810                 case StorageBus_SATA:
    4811                     lChannelVsys = lChannel;        // should be between 0 and 29
    4812                     lControllerVsys = lSATAControllerIndex;
    4813                 break;
    4814 
    4815                 case StorageBus_SCSI:
    4816                     lChannelVsys = lChannel;        // should be between 0 and 15
    4817                     lControllerVsys = lSCSIControllerIndex;
    4818                 break;
    4819 
    4820                 case StorageBus_Floppy:
    4821                     lChannelVsys = 0;
    4822                     lControllerVsys = 0;
    4823                 break;
    4824 
    4825                 default:
    4826                     throw setError(VBOX_E_NOT_SUPPORTED,
    4827                                 tr("Cannot handle medium attachment: storageBus is %d, channel is %d, device is %d"), storageBus, lChannel, lDevice);
    4828                 break;
    4829             }
    4830 
    4831             Utf8StrFmt strExtra("controller=%RI32;channel=%RI32", lControllerVsys, lChannelVsys);
    4832             Utf8Str strEmpty;
    4833 
    4834             switch (deviceType)
    4835             {
    4836                 case DeviceType_HardDisk:
    4837                     Log(("Adding VirtualSystemDescriptionType_HardDiskImage, disk size: %RI64\n", ullSize));
    4838                     pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
    4839                                        strTargetVmdkName,   // disk ID: let's use the name
    4840                                        strTargetVmdkName,   // OVF value:
    4841                                        strLocation, // vbox value: media path
    4842                                        (uint32_t)(ullSize / _1M),
    4843                                        strExtra);
    4844                 break;
    4845 
    4846                 case DeviceType_DVD:
    4847                     pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM,
    4848                                        strEmpty,   // disk ID
    4849                                        strEmpty,   // OVF value
    4850                                        strEmpty, // vbox value
    4851                                        1,           // ulSize
    4852                                        strExtra);
    4853                 break;
    4854 
    4855                 case DeviceType_Floppy:
    4856                     pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy,
    4857                                        strEmpty,      // disk ID
    4858                                        strEmpty,      // OVF value
    4859                                        strEmpty,      // vbox value
    4860                                        1,       // ulSize
    4861                                        strExtra);
    4862                 break;
    4863             }
    4864         }
    4865 
    4866 //     <const name="NetworkAdapter" />
    4867         size_t a;
    4868         for (a = 0;
    4869              a < SchemaDefs::NetworkAdapterCount;
    4870              ++a)
    4871         {
    4872             ComPtr<INetworkAdapter> pNetworkAdapter;
    4873             BOOL fEnabled;
    4874             NetworkAdapterType_T adapterType;
    4875             NetworkAttachmentType_T attachmentType;
    4876 
    4877             rc = GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
    4878             if (FAILED(rc)) throw rc;
    4879             /* Enable the network card & set the adapter type */
    4880             rc = pNetworkAdapter->COMGETTER(Enabled)(&fEnabled);
    4881             if (FAILED(rc)) throw rc;
    4882 
    4883             if (fEnabled)
    4884             {
    4885                 Utf8Str strAttachmentType;
    4886 
    4887                 rc = pNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
    4888                 if (FAILED(rc)) throw rc;
    4889 
    4890                 rc = pNetworkAdapter->COMGETTER(AttachmentType)(&attachmentType);
    4891                 if (FAILED(rc)) throw rc;
    4892 
    4893                 switch (attachmentType)
    4894                 {
    4895                     case NetworkAttachmentType_Null:
    4896                         strAttachmentType = "Null";
    4897                     break;
    4898 
    4899                     case NetworkAttachmentType_NAT:
    4900                         strAttachmentType = "NAT";
    4901                     break;
    4902 
    4903                     case NetworkAttachmentType_Bridged:
    4904                         strAttachmentType = "Bridged";
    4905                     break;
    4906 
    4907                     case NetworkAttachmentType_Internal:
    4908                         strAttachmentType = "Internal";
    4909                     break;
    4910 
    4911                     case NetworkAttachmentType_HostOnly:
    4912                         strAttachmentType = "HostOnly";
    4913                     break;
    4914                 }
    4915 
    4916                 pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
    4917                                    "",      // ref
    4918                                    strAttachmentType,      // orig
    4919                                    Utf8StrFmt("%RI32", (uint32_t)adapterType),   // conf
    4920                                    0,
    4921                                    Utf8StrFmt("type=%s", strAttachmentType.c_str()));       // extra conf
    4922             }
    4923         }
    4924 
    4925 //     <const name="USBController"  />
    4926 #ifdef VBOX_WITH_USB
    4927         if (fUSBEnabled)
    4928             pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
    4929 #endif /* VBOX_WITH_USB */
    4930 
    4931 //     <const name="SoundCard"  />
    4932         if (fAudioEnabled)
    4933         {
    4934             pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
    4935                                "",
    4936                                "ensoniq1371",       // this is what OVFTool writes and VMware supports
    4937                                Utf8StrFmt("%RI32", audioController));
    4938         }
    4939 
    4940         // finally, add the virtual system to the appliance
    4941         Appliance *pAppliance = static_cast<Appliance*>(aAppliance);
    4942         AutoCaller autoCaller1(pAppliance);
    4943         if (FAILED(autoCaller1.rc())) return autoCaller1.rc();
    4944 
    4945         /* We return the new description to the caller */
    4946         ComPtr<IVirtualSystemDescription> copy(pNewDesc);
    4947         copy.queryInterfaceTo(aDescription);
    4948 
    4949         AutoWriteLock alock(pAppliance COMMA_LOCKVAL_SRC_POS);
    4950 
    4951         pAppliance->m->virtualSystemDescriptions.push_back(pNewDesc);
    4952     }
    4953     catch(HRESULT arc)
    4954     {
    4955         rc = arc;
    4956     }
    4957 
    4958     return rc;
    4959 }
    4960 
    4961 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
  • trunk/src/VBox/Main/Makefile.kmk

    r27741 r27829  
    291291        VirtualBoxImpl.cpp \
    292292        ApplianceImpl.cpp \
     293        ApplianceImplExport.cpp \
    293294        xml/ovfreader.cpp \
    294295        VFSExplorerImpl.cpp \
Note: See TracChangeset for help on using the changeset viewer.

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