VirtualBox

Ignore:
Timestamp:
Jul 15, 2009 3:00:34 PM (15 years ago)
Author:
vboxsync
Message:

OVF: Added remote OVF downloading.

File:
1 edited

Legend:

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

    r21588 r21612  
    5050////////////////////////////////////////////////////////////////////////////////
    5151
     52/* Describe a location for the import/export. The location could be a file on a
     53 * local hard disk or a remote target based on the supported inet protocols. */
     54struct Appliance::LocationInfo
     55{
     56    LocationInfo()
     57      : storageType(VFSType_File) {}
     58    VFSType_T storageType; /* Which type of storage should be handled */
     59    Utf8Str strPath;       /* File path for the import/export */
     60    Utf8Str strHostname;   /* Hostname on remote storage locations (could be empty) */
     61    Utf8Str strUsername;   /* Username on remote storage locations (could be empty) */
     62    Utf8Str strPassword;   /* Password on remote storage locations (could be empty) */
     63};
     64
    5265// opaque private instance data of Appliance class
    5366struct Appliance::Data
    5467{
     68        Data()
     69          : pReader(NULL) {}
     70
     71        ~Data()
     72        {
     73            if (pReader)
     74            {
     75                delete pReader;
     76                pReader = NULL;
     77            }
     78        }
     79
     80    LocationInfo locInfo; /* The location info for the currently processed OVF */
     81
    5582    OVFReader *pReader;
    5683
    57     list< ComObjPtr<VirtualSystemDescription> > virtualSystemDescriptions; //
     84    list< ComObjPtr<VirtualSystemDescription> > virtualSystemDescriptions;
    5885
    5986    list<Utf8Str> llWarnings;
    6087
    61     ULONG                   ulWeightPerOperation;   // for progress calculations
    62 
    63     Data()
    64         : pReader(NULL)
    65     {
    66     }
    67 
    68     ~Data()
    69     {
    70         if (pReader)
    71         {
    72             delete pReader;
    73             pReader = NULL;
    74         }
    75     }
     88    ULONG ulWeightPerOperation;
    7689};
    7790
     
    92105    const char      *pcszVbox;
    93106}
    94     g_osTypes[] =
    95     {
    96         { CIMOSType_CIMOS_Unknown,                              SchemaDefs_OSTypeId_Other },
    97         { CIMOSType_CIMOS_OS2,                                  SchemaDefs_OSTypeId_OS2 },
    98         { CIMOSType_CIMOS_MSDOS,                                SchemaDefs_OSTypeId_DOS },
    99         { CIMOSType_CIMOS_WIN3x,                                SchemaDefs_OSTypeId_Windows31 },
    100         { CIMOSType_CIMOS_WIN95,                                SchemaDefs_OSTypeId_Windows95 },
    101         { CIMOSType_CIMOS_WIN98,                                SchemaDefs_OSTypeId_Windows98 },
    102         { CIMOSType_CIMOS_WINNT,                                SchemaDefs_OSTypeId_WindowsNT4 },
    103         { CIMOSType_CIMOS_NetWare,                              SchemaDefs_OSTypeId_Netware },
    104         { CIMOSType_CIMOS_NovellOES,                            SchemaDefs_OSTypeId_Netware },
    105         { CIMOSType_CIMOS_Solaris,                              SchemaDefs_OSTypeId_OpenSolaris },
    106         { CIMOSType_CIMOS_SunOS,                                SchemaDefs_OSTypeId_OpenSolaris },
    107         { CIMOSType_CIMOS_FreeBSD,                              SchemaDefs_OSTypeId_FreeBSD },
    108         { CIMOSType_CIMOS_NetBSD,                               SchemaDefs_OSTypeId_NetBSD },
    109         { CIMOSType_CIMOS_QNX,                                  SchemaDefs_OSTypeId_QNX },
    110         { CIMOSType_CIMOS_Windows2000,                          SchemaDefs_OSTypeId_Windows2000 },
    111         { CIMOSType_CIMOS_WindowsMe,                            SchemaDefs_OSTypeId_WindowsMe },
    112         { CIMOSType_CIMOS_OpenBSD,                              SchemaDefs_OSTypeId_OpenBSD },
    113         { CIMOSType_CIMOS_WindowsXP,                            SchemaDefs_OSTypeId_WindowsXP },
    114         { CIMOSType_CIMOS_WindowsXPEmbedded,                    SchemaDefs_OSTypeId_WindowsXP },
    115         { CIMOSType_CIMOS_WindowsEmbeddedforPointofService,     SchemaDefs_OSTypeId_WindowsXP },
    116         { CIMOSType_CIMOS_MicrosoftWindowsServer2003,           SchemaDefs_OSTypeId_Windows2003 },
    117         { CIMOSType_CIMOS_MicrosoftWindowsServer2003_64,        SchemaDefs_OSTypeId_Windows2003_64 },
    118         { CIMOSType_CIMOS_WindowsXP_64,                         SchemaDefs_OSTypeId_WindowsXP_64 },
    119         { CIMOSType_CIMOS_WindowsVista,                         SchemaDefs_OSTypeId_WindowsVista },
    120         { CIMOSType_CIMOS_WindowsVista_64,                      SchemaDefs_OSTypeId_WindowsVista_64 },
    121         { CIMOSType_CIMOS_MicrosoftWindowsServer2008,           SchemaDefs_OSTypeId_Windows2008 },
    122         { CIMOSType_CIMOS_MicrosoftWindowsServer2008_64,        SchemaDefs_OSTypeId_Windows2008_64 },
    123         { CIMOSType_CIMOS_FreeBSD_64,                           SchemaDefs_OSTypeId_FreeBSD_64 },
    124         { CIMOSType_CIMOS_RedHatEnterpriseLinux,                SchemaDefs_OSTypeId_RedHat },
    125         { CIMOSType_CIMOS_RedHatEnterpriseLinux_64,             SchemaDefs_OSTypeId_RedHat_64 },
    126         { CIMOSType_CIMOS_Solaris_64,                           SchemaDefs_OSTypeId_OpenSolaris_64 },
    127         { CIMOSType_CIMOS_SUSE,                                 SchemaDefs_OSTypeId_OpenSUSE },
    128         { CIMOSType_CIMOS_SLES,                                 SchemaDefs_OSTypeId_OpenSUSE },
    129         { CIMOSType_CIMOS_NovellLinuxDesktop,                   SchemaDefs_OSTypeId_OpenSUSE },
    130         { CIMOSType_CIMOS_SUSE_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
    131         { CIMOSType_CIMOS_SLES_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
    132         { CIMOSType_CIMOS_LINUX,                                SchemaDefs_OSTypeId_Linux },
    133         { CIMOSType_CIMOS_SunJavaDesktopSystem,                 SchemaDefs_OSTypeId_Linux },
    134         { CIMOSType_CIMOS_TurboLinux,                           SchemaDefs_OSTypeId_Linux},
    135 
    136             //                { CIMOSType_CIMOS_TurboLinux_64, },
    137 
    138         { CIMOSType_CIMOS_Mandriva,                             SchemaDefs_OSTypeId_Mandriva },
    139         { CIMOSType_CIMOS_Mandriva_64,                          SchemaDefs_OSTypeId_Mandriva_64 },
    140         { CIMOSType_CIMOS_Ubuntu,                               SchemaDefs_OSTypeId_Ubuntu },
    141         { CIMOSType_CIMOS_Ubuntu_64,                            SchemaDefs_OSTypeId_Ubuntu_64 },
    142         { CIMOSType_CIMOS_Debian,                               SchemaDefs_OSTypeId_Debian },
    143         { CIMOSType_CIMOS_Debian_64,                            SchemaDefs_OSTypeId_Debian_64 },
    144         { CIMOSType_CIMOS_Linux_2_4_x,                          SchemaDefs_OSTypeId_Linux24 },
    145         { CIMOSType_CIMOS_Linux_2_4_x_64,                       SchemaDefs_OSTypeId_Linux24_64 },
    146         { CIMOSType_CIMOS_Linux_2_6_x,                          SchemaDefs_OSTypeId_Linux26 },
    147         { CIMOSType_CIMOS_Linux_2_6_x_64,                       SchemaDefs_OSTypeId_Linux26_64 },
    148         { CIMOSType_CIMOS_Linux_64,                             SchemaDefs_OSTypeId_Linux26_64 }
     107g_osTypes[] =
     108{
     109    { CIMOSType_CIMOS_Unknown,                              SchemaDefs_OSTypeId_Other },
     110    { CIMOSType_CIMOS_OS2,                                  SchemaDefs_OSTypeId_OS2 },
     111    { CIMOSType_CIMOS_MSDOS,                                SchemaDefs_OSTypeId_DOS },
     112    { CIMOSType_CIMOS_WIN3x,                                SchemaDefs_OSTypeId_Windows31 },
     113    { CIMOSType_CIMOS_WIN95,                                SchemaDefs_OSTypeId_Windows95 },
     114    { CIMOSType_CIMOS_WIN98,                                SchemaDefs_OSTypeId_Windows98 },
     115    { CIMOSType_CIMOS_WINNT,                                SchemaDefs_OSTypeId_WindowsNT4 },
     116    { CIMOSType_CIMOS_NetWare,                              SchemaDefs_OSTypeId_Netware },
     117    { CIMOSType_CIMOS_NovellOES,                            SchemaDefs_OSTypeId_Netware },
     118    { CIMOSType_CIMOS_Solaris,                              SchemaDefs_OSTypeId_OpenSolaris },
     119    { CIMOSType_CIMOS_SunOS,                                SchemaDefs_OSTypeId_OpenSolaris },
     120    { CIMOSType_CIMOS_FreeBSD,                              SchemaDefs_OSTypeId_FreeBSD },
     121    { CIMOSType_CIMOS_NetBSD,                               SchemaDefs_OSTypeId_NetBSD },
     122    { CIMOSType_CIMOS_QNX,                                  SchemaDefs_OSTypeId_QNX },
     123    { CIMOSType_CIMOS_Windows2000,                          SchemaDefs_OSTypeId_Windows2000 },
     124    { CIMOSType_CIMOS_WindowsMe,                            SchemaDefs_OSTypeId_WindowsMe },
     125    { CIMOSType_CIMOS_OpenBSD,                              SchemaDefs_OSTypeId_OpenBSD },
     126    { CIMOSType_CIMOS_WindowsXP,                            SchemaDefs_OSTypeId_WindowsXP },
     127    { CIMOSType_CIMOS_WindowsXPEmbedded,                    SchemaDefs_OSTypeId_WindowsXP },
     128    { CIMOSType_CIMOS_WindowsEmbeddedforPointofService,     SchemaDefs_OSTypeId_WindowsXP },
     129    { CIMOSType_CIMOS_MicrosoftWindowsServer2003,           SchemaDefs_OSTypeId_Windows2003 },
     130    { CIMOSType_CIMOS_MicrosoftWindowsServer2003_64,        SchemaDefs_OSTypeId_Windows2003_64 },
     131    { CIMOSType_CIMOS_WindowsXP_64,                         SchemaDefs_OSTypeId_WindowsXP_64 },
     132    { CIMOSType_CIMOS_WindowsVista,                         SchemaDefs_OSTypeId_WindowsVista },
     133    { CIMOSType_CIMOS_WindowsVista_64,                      SchemaDefs_OSTypeId_WindowsVista_64 },
     134    { CIMOSType_CIMOS_MicrosoftWindowsServer2008,           SchemaDefs_OSTypeId_Windows2008 },
     135    { CIMOSType_CIMOS_MicrosoftWindowsServer2008_64,        SchemaDefs_OSTypeId_Windows2008_64 },
     136    { CIMOSType_CIMOS_FreeBSD_64,                           SchemaDefs_OSTypeId_FreeBSD_64 },
     137    { CIMOSType_CIMOS_RedHatEnterpriseLinux,                SchemaDefs_OSTypeId_RedHat },
     138    { CIMOSType_CIMOS_RedHatEnterpriseLinux_64,             SchemaDefs_OSTypeId_RedHat_64 },
     139    { CIMOSType_CIMOS_Solaris_64,                           SchemaDefs_OSTypeId_OpenSolaris_64 },
     140    { CIMOSType_CIMOS_SUSE,                                 SchemaDefs_OSTypeId_OpenSUSE },
     141    { CIMOSType_CIMOS_SLES,                                 SchemaDefs_OSTypeId_OpenSUSE },
     142    { CIMOSType_CIMOS_NovellLinuxDesktop,                   SchemaDefs_OSTypeId_OpenSUSE },
     143    { CIMOSType_CIMOS_SUSE_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
     144    { CIMOSType_CIMOS_SLES_64,                              SchemaDefs_OSTypeId_OpenSUSE_64 },
     145    { CIMOSType_CIMOS_LINUX,                                SchemaDefs_OSTypeId_Linux },
     146    { CIMOSType_CIMOS_SunJavaDesktopSystem,                 SchemaDefs_OSTypeId_Linux },
     147    { CIMOSType_CIMOS_TurboLinux,                           SchemaDefs_OSTypeId_Linux},
     148
     149    //                { CIMOSType_CIMOS_TurboLinux_64, },
     150
     151    { CIMOSType_CIMOS_Mandriva,                             SchemaDefs_OSTypeId_Mandriva },
     152    { CIMOSType_CIMOS_Mandriva_64,                          SchemaDefs_OSTypeId_Mandriva_64 },
     153    { CIMOSType_CIMOS_Ubuntu,                               SchemaDefs_OSTypeId_Ubuntu },
     154    { CIMOSType_CIMOS_Ubuntu_64,                            SchemaDefs_OSTypeId_Ubuntu_64 },
     155    { CIMOSType_CIMOS_Debian,                               SchemaDefs_OSTypeId_Debian },
     156    { CIMOSType_CIMOS_Debian_64,                            SchemaDefs_OSTypeId_Debian_64 },
     157    { CIMOSType_CIMOS_Linux_2_4_x,                          SchemaDefs_OSTypeId_Linux24 },
     158    { CIMOSType_CIMOS_Linux_2_4_x_64,                       SchemaDefs_OSTypeId_Linux24_64 },
     159    { CIMOSType_CIMOS_Linux_2_6_x,                          SchemaDefs_OSTypeId_Linux26 },
     160    { CIMOSType_CIMOS_Linux_2_6_x_64,                       SchemaDefs_OSTypeId_Linux26_64 },
     161    { CIMOSType_CIMOS_Linux_64,                             SchemaDefs_OSTypeId_Linux26_64 }
    149162};
    150163
    151 /* Pattern structure for matching the os type description field */
     164/* Pattern structure for matching the OS type description field */
    152165struct osTypePattern
    153166{
     
    302315
    303316DEFINE_EMPTY_CTOR_DTOR(Appliance)
    304 struct shutup {};
    305317
    306318/**
     
    339351////////////////////////////////////////////////////////////////////////////////
    340352//
     353// Appliance private methods
     354//
     355////////////////////////////////////////////////////////////////////////////////
     356
     357HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
     358{
     359    IMachine *machine = NULL;
     360    char *tmpName = RTStrDup(aName.c_str());
     361    int i = 1;
     362    /* @todo: Maybe too cost-intensive; try to find a lighter way */
     363    while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
     364    {
     365        RTStrFree(tmpName);
     366        RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
     367        ++i;
     368    }
     369    aName = tmpName;
     370    RTStrFree(tmpName);
     371
     372    return S_OK;
     373}
     374
     375HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
     376{
     377    IHardDisk *harddisk = NULL;
     378    char *tmpName = RTStrDup(aName.c_str());
     379    int i = 1;
     380    /* Check if the file exists or if a file with this path is registered
     381     * already */
     382    /* @todo: Maybe too cost-intensive; try to find a lighter way */
     383    while (RTPathExists(tmpName) ||
     384           mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
     385    {
     386        RTStrFree(tmpName);
     387        char *tmpDir = RTStrDup(aName.c_str());
     388        RTPathStripFilename(tmpDir);;
     389        char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
     390        RTPathStripExt(tmpFile);
     391        const char *tmpExt = RTPathExt(aName.c_str());
     392        RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
     393        RTStrFree(tmpFile);
     394        RTStrFree(tmpDir);
     395        ++i;
     396    }
     397    aName = tmpName;
     398    RTStrFree(tmpName);
     399
     400    return S_OK;
     401}
     402
     403/**
     404 * Called from the import and export background threads to synchronize the second
     405 * background disk thread's progress object with the current progress object so
     406 * that the user interface sees progress correctly and that cancel signals are
     407 * passed on to the second thread.
     408 * @param pProgressThis Progress object of the current thread.
     409 * @param pProgressAsync Progress object of asynchronous task running in background.
     410 */
     411void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
     412                                     ComPtr<IProgress> &pProgressAsync)
     413{
     414    HRESULT rc;
     415
     416    // now loop until the asynchronous operation completes and then report its result
     417    BOOL fCompleted;
     418    BOOL fCanceled;
     419    ULONG currentPercent;
     420    while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
     421    {
     422        rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
     423        if (FAILED(rc)) throw rc;
     424        if (fCanceled)
     425        {
     426            pProgressAsync->Cancel();
     427            break;
     428        }
     429
     430        rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
     431        if (FAILED(rc)) throw rc;
     432        if (!pProgressThis.isNull())
     433            pProgressThis->setCurrentOperationProgress(currentPercent);
     434        if (fCompleted)
     435            break;
     436
     437        /* Make sure the loop is not too tight */
     438        rc = pProgressAsync->WaitForCompletion(100);
     439        if (FAILED(rc)) throw rc;
     440    }
     441    // report result of asynchronous operation
     442    LONG iRc;
     443    rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
     444    if (FAILED(rc)) throw rc;
     445
     446
     447    // if the thread of the progress object has an error, then
     448    // retrieve the error info from there, or it'll be lost
     449    if (FAILED(iRc))
     450    {
     451        ProgressErrorInfo info(pProgressAsync);
     452        Utf8Str str(info.getText());
     453        const char *pcsz = str.c_str();
     454        HRESULT rc2 = setError(iRc, pcsz);
     455        throw rc2;
     456    }
     457}
     458
     459void Appliance::addWarning(const char* aWarning, ...)
     460{
     461    va_list args;
     462    va_start(args, aWarning);
     463    Utf8StrFmtVA str(aWarning, args);
     464    va_end(args);
     465    m->llWarnings.push_back(str);
     466}
     467
     468void Appliance::disksWeight(uint32_t &ulTotalMB, uint32_t &cDisks) const
     469{
     470    ulTotalMB = 0;
     471    cDisks = 0;
     472    /* Weigh the disk images according to their sizes */
     473    list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
     474    for (it = m->virtualSystemDescriptions.begin();
     475         it != m->virtualSystemDescriptions.end();
     476         ++it)
     477    {
     478        ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
     479        /* One for every hard disk of the Virtual System */
     480        std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
     481        std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
     482        for (itH = avsdeHDs.begin();
     483             itH != avsdeHDs.end();
     484             ++itH)
     485        {
     486            const VirtualSystemDescriptionEntry *pHD = *itH;
     487            ulTotalMB += pHD->ulSizeMB;
     488            ++cDisks;
     489        }
     490    }
     491
     492}
     493
     494HRESULT Appliance::setUpProgressFS(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
     495{
     496    HRESULT rc;
     497
     498    /* Create the progress object */
     499    pProgress.createObject();
     500
     501    /* Weigh the disk images according to their sizes */
     502    uint32_t ulTotalMB;
     503    uint32_t cDisks;
     504    disksWeight(ulTotalMB, cDisks);
     505
     506    ULONG cOperations = 1 + cDisks;     // one op per disk plus 1 for the XML
     507
     508    ULONG ulTotalOperationsWeight;
     509    if (ulTotalMB)
     510    {
     511        m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1  / 100);    // use 1% of the progress for the XML
     512        ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
     513    }
     514    else
     515    {
     516        // no disks to export:
     517        ulTotalOperationsWeight = 1;
     518        m->ulWeightPerOperation = 1;
     519    }
     520
     521    Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
     522         ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
     523
     524    rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
     525                         bstrDescription,
     526                         TRUE /* aCancelable */,
     527                         cOperations, // ULONG cOperations,
     528                         ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
     529                         bstrDescription, // CBSTR bstrFirstOperationDescription,
     530                         m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
     531    return rc;
     532}
     533
     534HRESULT Appliance::setUpProgressImportS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
     535{
     536    HRESULT rc;
     537
     538    /* Create the progress object */
     539    pProgress.createObject();
     540
     541    /* Weigh the disk images according to their sizes */
     542    uint32_t ulTotalMB;
     543    uint32_t cDisks;
     544    disksWeight(ulTotalMB, cDisks);
     545
     546    ULONG cOperations = 1 + 1 + cDisks;     // one op per disk plus 1 for init & 1 plus for the import */
     547
     548    ULONG ulTotalOperationsWeight = ulTotalMB;
     549    if (!ulTotalOperationsWeight)
     550        // no disks to export:
     551        ulTotalOperationsWeight = 1;
     552
     553    ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50  / 100);  // use 50% for import
     554    ulTotalOperationsWeight += ulImportWeight;
     555
     556    m->ulWeightPerOperation = ulImportWeight; /* save for using later */
     557
     558    ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1  / 100);  // use 0.1% for init
     559    ulTotalOperationsWeight += ulInitWeight;
     560
     561    Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
     562         ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
     563
     564    rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
     565                         bstrDescription,
     566                         TRUE /* aCancelable */,
     567                         cOperations, // ULONG cOperations,
     568                         ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
     569                         Bstr(tr("Init")), // CBSTR bstrFirstOperationDescription,
     570                         ulInitWeight); // ULONG ulFirstOperationWeight,
     571    return rc;
     572}
     573
     574HRESULT Appliance::setUpProgressWriteS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
     575{
     576    HRESULT rc;
     577
     578    /* Create the progress object */
     579    pProgress.createObject();
     580
     581    /* Weigh the disk images according to their sizes */
     582    uint32_t ulTotalMB;
     583    uint32_t cDisks;
     584    disksWeight(ulTotalMB, cDisks);
     585
     586    ULONG cOperations = 1 + 1 + cDisks;     // one op per disk plus 1 for the OVF & 1 plus to the temporary creation */
     587
     588    ULONG ulTotalOperationsWeight;
     589    if (ulTotalMB)
     590    {
     591        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)
     592        ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
     593    }
     594    else
     595    {
     596        // no disks to export:
     597        ulTotalOperationsWeight = 1;
     598        m->ulWeightPerOperation = 1;
     599    }
     600    ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
     601    ulTotalOperationsWeight += ulOVFCreationWeight;
     602
     603    Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
     604         ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
     605
     606    rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
     607                         bstrDescription,
     608                         TRUE /* aCancelable */,
     609                         cOperations, // ULONG cOperations,
     610                         ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
     611                         bstrDescription, // CBSTR bstrFirstOperationDescription,
     612                         ulOVFCreationWeight); // ULONG ulFirstOperationWeight,
     613    return rc;
     614}
     615
     616void Appliance::parseURI(Utf8Str strUri, LocationInfo &locInfo) const
     617{
     618    /* Check the URI for the protocol */
     619    if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
     620    {
     621        locInfo.storageType = VFSType_File;
     622        strUri = strUri.substr(sizeof("file://") - 1);
     623    }
     624    else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
     625    {
     626        locInfo.storageType = VFSType_S3;
     627        strUri = strUri.substr(sizeof("SunCloud://") - 1);
     628    }
     629    else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
     630    {
     631        locInfo.storageType = VFSType_S3;
     632        strUri = strUri.substr(sizeof("S3://") - 1);
     633    }
     634    else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
     635        throw E_NOTIMPL;
     636
     637    /* Not necessary on a file based URI */
     638    if (locInfo.storageType != VFSType_File)
     639    {
     640        size_t uppos = strUri.find("@"); /* username:password combo */
     641        if (uppos != Utf8Str::npos)
     642        {
     643            locInfo.strUsername = strUri.substr(0, uppos);
     644            strUri = strUri.substr(uppos + 1);
     645            size_t upos = locInfo.strUsername.find(":");
     646            if (upos != Utf8Str::npos)
     647            {
     648                locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
     649                locInfo.strUsername = locInfo.strUsername.substr(0, upos);
     650            }
     651        }
     652        size_t hpos = strUri.find("/"); /* hostname part */
     653        if (hpos != Utf8Str::npos)
     654        {
     655            locInfo.strHostname = strUri.substr(0, hpos);
     656            strUri = strUri.substr(hpos);
     657        }
     658    }
     659
     660    locInfo.strPath = strUri;
     661}
     662
     663void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket) const
     664{
     665    /* Buckets are S3 specific. So parse the bucket out of the file path */
     666    if (!aPath.startsWith("/"))
     667        throw setError(E_INVALIDARG,
     668                       tr("The path '%s' must start with /"), aPath.c_str());
     669    size_t bpos = aPath.find("/", 1);
     670    if (bpos != Utf8Str::npos)
     671    {
     672        aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
     673        aPath = aPath.substr(bpos); /* The rest of the file path */
     674    }
     675    /* If there is no bucket name provided reject it */
     676    if (aBucket.isEmpty())
     677        throw setError(E_INVALIDARG,
     678                       tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
     679}
     680
     681struct Appliance::TaskOVF
     682{
     683    TaskOVF(Appliance *aThat)
     684      : pAppliance(aThat)
     685      , rc(S_OK) {}
     686
     687    static int updateProgress(unsigned uPercent, void *pvUser);
     688
     689    LocationInfo locInfo;
     690    Appliance *pAppliance;
     691    ComObjPtr<Progress> progress;
     692    HRESULT rc;
     693};
     694
     695struct Appliance::TaskImportOVF: Appliance::TaskOVF
     696{
     697    enum TaskType
     698    {
     699        Read,
     700        Import
     701    };
     702
     703    TaskImportOVF(Appliance *aThat)
     704        : TaskOVF(aThat)
     705        , taskType(Read) {}
     706
     707    int startThread();
     708
     709    TaskType taskType;
     710};
     711
     712struct Appliance::TaskExportOVF: Appliance::TaskOVF
     713{
     714    enum OVFFormat
     715    {
     716        unspecified,
     717        OVF_0_9,
     718        OVF_1_0
     719    };
     720    enum TaskType
     721    {
     722        Write
     723    };
     724
     725    TaskExportOVF(Appliance *aThat)
     726        : TaskOVF(aThat)
     727        , taskType(Write) {}
     728
     729    int startThread();
     730
     731    TaskType taskType;
     732    OVFFormat enFormat;
     733};
     734
     735struct MyHardDiskAttachment
     736{
     737    Guid    uuid;
     738    ComPtr<IMachine> pMachine;
     739    Bstr    controllerType;
     740    int32_t lChannel;
     741    int32_t lDevice;
     742};
     743
     744/* static */
     745int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
     746{
     747    Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
     748
     749    if (pTask &&
     750        !pTask->progress.isNull())
     751    {
     752        BOOL fCanceled;
     753        pTask->progress->COMGETTER(Canceled)(&fCanceled);
     754        if (fCanceled)
     755            return -1;
     756        pTask->progress->setCurrentOperationProgress(uPercent);
     757    }
     758    return VINF_SUCCESS;
     759}
     760
     761HRESULT Appliance::readImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
     762{
     763    /* Initialize our worker task */
     764    std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
     765    /* What should the task do */
     766    task->taskType = TaskImportOVF::Read;
     767    /* Copy the current location info to the task */
     768    task->locInfo = aLocInfo;
     769
     770    BstrFmt bstrDesc = BstrFmt(tr("Read appliance '%s'"),
     771                               aLocInfo.strPath.c_str());
     772    HRESULT rc;
     773    /* Create the progress object */
     774    aProgress.createObject();
     775    if (task->locInfo.storageType == VFSType_File)
     776    {
     777        /* 1 operation only */
     778        rc = aProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
     779                             bstrDesc,
     780                             TRUE /* aCancelable */);
     781    }
     782    else
     783    {
     784        /* 4/5 is downloading, 1/5 is reading */
     785        rc = aProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
     786                             bstrDesc,
     787                             TRUE /* aCancelable */,
     788                             2, // ULONG cOperations,
     789                             5, // ULONG ulTotalOperationsWeight,
     790                             BstrFmt(tr("Download appliance '%s'"),
     791                                     aLocInfo.strPath.c_str()), // CBSTR bstrFirstOperationDescription,
     792                             4); // ULONG ulFirstOperationWeight,
     793    }
     794    if (FAILED(rc)) throw rc;
     795
     796    task->progress = aProgress;
     797
     798    rc = task->startThread();
     799    CheckComRCThrowRC(rc);
     800
     801    /* Don't destruct on success */
     802    task.release();
     803
     804    return rc;
     805}
     806
     807HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
     808{
     809    /* Initialize our worker task */
     810    std::auto_ptr<TaskImportOVF> task(new TaskImportOVF(this));
     811    /* What should the task do */
     812    task->taskType = TaskImportOVF::Import;
     813    /* Copy the current location info to the task */
     814    task->locInfo = aLocInfo;
     815
     816    Bstr progressDesc = BstrFmt(tr("Import appliance '%s'"),
     817                                aLocInfo.strPath.c_str());
     818
     819    HRESULT rc = S_OK;
     820
     821    /* todo: This progress init stuff should be done a little bit more generic */
     822    if (task->locInfo.storageType == VFSType_File)
     823        rc = setUpProgressFS(aProgress, progressDesc);
     824    else
     825        rc = setUpProgressImportS3(aProgress, progressDesc);
     826    if (FAILED(rc)) throw rc;
     827
     828    task->progress = aProgress;
     829
     830    rc = task->startThread();
     831    CheckComRCThrowRC(rc);
     832
     833    /* Don't destruct on success */
     834    task.release();
     835
     836    return rc;
     837}
     838
     839/**
     840 * Worker thread implementation for Read() (ovf reader).
     841 * @param aThread
     842 * @param pvUser
     843 */
     844/* static */
     845DECLCALLBACK(int) Appliance::taskThreadImportOVF(RTTHREAD /* aThread */, void *pvUser)
     846{
     847    std::auto_ptr<TaskImportOVF> task(static_cast<TaskImportOVF*>(pvUser));
     848    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
     849
     850    Appliance *pAppliance = task->pAppliance;
     851
     852    LogFlowFuncEnter();
     853    LogFlowFunc(("Appliance %p\n", pAppliance));
     854
     855    HRESULT rc = S_OK;
     856
     857    switch(task->taskType)
     858    {
     859        case TaskImportOVF::Read:
     860        {
     861            if (task->locInfo.storageType == VFSType_File)
     862                rc = pAppliance->readFS(task.get());
     863            else if (task->locInfo.storageType == VFSType_S3)
     864                rc = pAppliance->readS3(task.get());
     865            break;
     866        }
     867        case TaskImportOVF::Import:
     868        {
     869            if (task->locInfo.storageType == VFSType_File)
     870                rc = pAppliance->importFS(task.get());
     871            else if (task->locInfo.storageType == VFSType_S3)
     872                rc = pAppliance->importS3(task.get());
     873            break;
     874        }
     875    }
     876
     877    LogFlowFunc(("rc=%Rhrc\n", rc));
     878    LogFlowFuncLeave();
     879
     880    return VINF_SUCCESS;
     881}
     882
     883int Appliance::TaskImportOVF::startThread()
     884{
     885    int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOVF, this,
     886                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
     887                             "Appliance::Task");
     888
     889    ComAssertMsgRCRet(vrc,
     890                      ("Could not create taskThreadImportOVF (%Rrc)\n", vrc), E_FAIL);
     891
     892    return S_OK;
     893}
     894
     895int Appliance::readFS(TaskImportOVF *pTask)
     896{
     897    LogFlowFuncEnter();
     898    LogFlowFunc(("Appliance %p\n", this));
     899
     900    AutoCaller autoCaller(this);
     901    CheckComRCReturnRC(autoCaller.rc());
     902
     903    AutoWriteLock appLock(this);
     904
     905    HRESULT rc = S_OK;
     906
     907    try
     908    {
     909        m->pReader = new OVFReader(pTask->locInfo.strPath);
     910    }
     911    catch(xml::Error &x)
     912    {
     913        rc = setError(VBOX_E_FILE_ERROR,
     914                      x.what());
     915    }
     916
     917    pTask->rc = rc;
     918
     919    if (!pTask->progress.isNull())
     920        pTask->progress->notifyComplete(rc);
     921
     922    LogFlowFunc(("rc=%Rhrc\n", rc));
     923    LogFlowFuncLeave();
     924
     925    return VINF_SUCCESS;
     926}
     927
     928int Appliance::readS3(TaskImportOVF *pTask)
     929{
     930    LogFlowFuncEnter();
     931    LogFlowFunc(("Appliance %p\n", this));
     932
     933    AutoCaller autoCaller(this);
     934    CheckComRCReturnRC(autoCaller.rc());
     935
     936    AutoWriteLock appLock(this);
     937
     938    HRESULT rc = S_OK;
     939    int vrc = VINF_SUCCESS;
     940    RTS3 hS3 = NIL_RTS3;
     941    char szOSTmpDir[RTPATH_MAX];
     942    RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
     943    /* The template for the temporary directory created below */
     944    char *pszTmpDir;
     945    RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
     946    list< pair<Utf8Str, ULONG> > filesList;
     947    Utf8Str strTmpOvf;
     948
     949    try
     950    {
     951        /* Extract the bucket */
     952        Utf8Str tmpPath = pTask->locInfo.strPath;
     953        Utf8Str bucket;
     954        parseBucket(tmpPath, bucket);
     955
     956        /* We need a temporary directory which we can put the OVF file & all
     957         * disk images in */
     958        vrc = RTDirCreateTemp(pszTmpDir);
     959        if (RT_FAILURE(rc))
     960            throw setError(VBOX_E_FILE_ERROR,
     961                           tr("Cannot create temporary directory '%s'"), pszTmpDir);
     962
     963        /* The temporary name of the target OVF file */
     964        strTmpOvf = Utf8StrFmt("%s/%s", pszTmpDir, RTPathFilename(tmpPath));
     965
     966        /* Next we have to download the OVF */
     967        vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
     968        if(RT_FAILURE(vrc))
     969            throw setError(VBOX_E_IPRT_ERROR,
     970                           tr("Cannot create S3 service handler"));
     971        RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
     972
     973        /* Get it */
     974        char *pszFilename = RTPathFilename(strTmpOvf.c_str());
     975        vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strTmpOvf.c_str());
     976        if (RT_FAILURE(vrc))
     977        {
     978            if(vrc == VERR_S3_CANCELED)
     979                throw S_OK; /* todo: !!!!!!!!!!!!! */
     980            else if(vrc == VERR_S3_ACCESS_DENIED)
     981                throw setError(E_ACCESSDENIED,
     982                               tr("Cannot download file '%s' from S3 storage server (Access denied)"), pszFilename);
     983            else if(vrc == VERR_S3_NOT_FOUND)
     984                throw setError(VBOX_E_FILE_ERROR,
     985                               tr("Cannot download file '%s' from S3 storage server (File not found)"), pszFilename);
     986            else
     987                throw setError(VBOX_E_IPRT_ERROR,
     988                               tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
     989        }
     990
     991        /* Close the connection early */
     992        RTS3Destroy(hS3);
     993        hS3 = NIL_RTS3;
     994
     995        if (!pTask->progress.isNull())
     996            pTask->progress->setNextOperation(Bstr(tr("Reading")), 1);
     997
     998        /* Prepare the temporary reading of the OVF */
     999        ComObjPtr<Progress> progress;
     1000        LocationInfo li;
     1001        li.strPath = strTmpOvf;
     1002        /* Start the reading from the fs */
     1003        rc = readImpl(li, progress);
     1004        if (FAILED(rc)) throw rc;
     1005
     1006        /* Unlock the appliance for the reading thread */
     1007        appLock.unlock();
     1008        /* Wait until the reading is done, but report the progress back to the
     1009           caller */
     1010        ComPtr<IProgress> progressInt(progress);
     1011        waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
     1012
     1013        /* Again lock the appliance for the next steps */
     1014        appLock.lock();
     1015    }
     1016    catch(HRESULT aRC)
     1017    {
     1018        rc = aRC;
     1019    }
     1020    /* Cleanup */
     1021    RTS3Destroy(hS3);
     1022    /* Delete all files which where temporary created */
     1023    if (RTPathExists(strTmpOvf.c_str()))
     1024    {
     1025        vrc = RTFileDelete(strTmpOvf.c_str());
     1026        if(RT_FAILURE(vrc))
     1027            rc = setError(VBOX_E_FILE_ERROR,
     1028                          tr("Cannot delete file '%s' (%Rrc)"), strTmpOvf.c_str(), vrc);
     1029    }
     1030    /* Delete the temporary directory */
     1031    if (RTPathExists(pszTmpDir))
     1032    {
     1033        vrc = RTDirRemove(pszTmpDir);
     1034        if(RT_FAILURE(vrc))
     1035            rc = setError(VBOX_E_FILE_ERROR,
     1036                          tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
     1037    }
     1038    if (pszTmpDir)
     1039        RTStrFree(pszTmpDir);
     1040
     1041    pTask->rc = rc;
     1042
     1043    if (!pTask->progress.isNull())
     1044        pTask->progress->notifyComplete(rc);
     1045
     1046    LogFlowFunc(("rc=%Rhrc\n", rc));
     1047    LogFlowFuncLeave();
     1048
     1049    return VINF_SUCCESS;
     1050}
     1051
     1052int Appliance::importFS(TaskImportOVF *pTask)
     1053{
     1054    LogFlowFuncEnter();
     1055    LogFlowFunc(("Appliance %p\n", this));
     1056
     1057    AutoCaller autoCaller(this);
     1058    CheckComRCReturnRC(autoCaller.rc());
     1059
     1060    AutoWriteLock appLock(this);
     1061
     1062    HRESULT rc = S_OK;
     1063
     1064    // rollback for errors:
     1065    // a list of images that we created/imported
     1066    list<MyHardDiskAttachment> llHardDiskAttachments;
     1067    list< ComPtr<IHardDisk> > llHardDisksCreated;
     1068    list<Guid> llMachinesRegistered;
     1069
     1070    ComPtr<ISession> session;
     1071    bool fSessionOpen = false;
     1072    rc = session.createInprocObject(CLSID_Session);
     1073    CheckComRCReturnRC(rc);
     1074
     1075    const OVFReader reader = *m->pReader;
     1076        // this is safe to access because this thread only gets started
     1077        // if pReader != NULL
     1078
     1079    list<VirtualSystem>::const_iterator it;
     1080    list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
     1081    /* Iterate through all virtual systems of that appliance */
     1082    size_t i = 0;
     1083    for (it = reader.m_llVirtualSystems.begin(),
     1084            it1 = m->virtualSystemDescriptions.begin();
     1085         it != reader.m_llVirtualSystems.end();
     1086         ++it, ++it1, ++i)
     1087    {
     1088        const VirtualSystem &vsysThis = *it;
     1089        ComObjPtr<VirtualSystemDescription> vsdescThis = (*it1);
     1090
     1091        ComPtr<IMachine> pNewMachine;
     1092
     1093        /* Catch possible errors */
     1094        try
     1095        {
     1096            /* Guest OS type */
     1097            std::list<VirtualSystemDescriptionEntry*> vsdeOS;
     1098            vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
     1099            if (vsdeOS.size() < 1)
     1100                throw setError(VBOX_E_FILE_ERROR,
     1101                               tr("Missing guest OS type"));
     1102            const Utf8Str &strOsTypeVBox = vsdeOS.front()->strVbox;
     1103
     1104            /* Now that we know the base system get our internal defaults based on that. */
     1105            ComPtr<IGuestOSType> osType;
     1106            rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam());
     1107            if (FAILED(rc)) throw rc;
     1108
     1109            /* Create the machine */
     1110            /* First get the name */
     1111            std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
     1112            if (vsdeName.size() < 1)
     1113                throw setError(VBOX_E_FILE_ERROR,
     1114                               tr("Missing VM name"));
     1115            const Utf8Str &strNameVBox = vsdeName.front()->strVbox;
     1116            rc = mVirtualBox->CreateMachine(Bstr(strNameVBox), Bstr(strOsTypeVBox),
     1117                                                 Bstr(), Bstr(),
     1118                                                 pNewMachine.asOutParam());
     1119            if (FAILED(rc)) throw rc;
     1120
     1121            // and the description
     1122            std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
     1123            if (vsdeDescription.size())
     1124            {
     1125                const Utf8Str &strDescription = vsdeDescription.front()->strVbox;
     1126                rc = pNewMachine->COMSETTER(Description)(Bstr(strDescription));
     1127                if (FAILED(rc)) throw rc;
     1128            }
     1129
     1130            /* CPU count */
     1131            std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType (VirtualSystemDescriptionType_CPU);
     1132            ComAssertMsgThrow(vsdeCPU.size() == 1, ("CPU count missing"), E_FAIL);
     1133            const Utf8Str &cpuVBox = vsdeCPU.front()->strVbox;
     1134            ULONG tmpCount = (ULONG)RTStrToUInt64(cpuVBox.c_str());
     1135            rc = pNewMachine->COMSETTER(CPUCount)(tmpCount);
     1136            if (FAILED(rc)) throw rc;
     1137            bool fEnableIOApic = false;
     1138            /* We need HWVirt & IO-APIC if more than one CPU is requested */
     1139            if (tmpCount > 1)
     1140            {
     1141                rc = pNewMachine->COMSETTER(HWVirtExEnabled)(TRUE);
     1142                if (FAILED(rc)) throw rc;
     1143
     1144                fEnableIOApic = true;
     1145            }
     1146
     1147            /* RAM */
     1148            std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
     1149            ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL);
     1150            const Utf8Str &memoryVBox = vsdeRAM.front()->strVbox;
     1151            ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str());
     1152            rc = pNewMachine->COMSETTER(MemorySize)(tt);
     1153            if (FAILED(rc)) throw rc;
     1154
     1155            /* VRAM */
     1156            /* Get the recommended VRAM for this guest OS type */
     1157            ULONG vramVBox;
     1158            rc = osType->COMGETTER(RecommendedVRAM)(&vramVBox);
     1159            if (FAILED(rc)) throw rc;
     1160
     1161            /* Set the VRAM */
     1162            rc = pNewMachine->COMSETTER(VRAMSize)(vramVBox);
     1163            if (FAILED(rc)) throw rc;
     1164
     1165            /* I/O APIC: so far we have no setting for this. Enable it if we
     1166              import a Windows VM because if if Windows was installed without IOAPIC,
     1167              it will not mind finding an one later on, but if Windows was installed
     1168              _with_ an IOAPIC, it will bluescreen if it's not found */
     1169            Bstr bstrFamilyId;
     1170            rc = osType->COMGETTER(FamilyId)(bstrFamilyId.asOutParam());
     1171            if (FAILED(rc)) throw rc;
     1172
     1173            Utf8Str strFamilyId(bstrFamilyId);
     1174            if (strFamilyId == "Windows")
     1175                fEnableIOApic = true;
     1176
     1177            /* If IP-APIC should be enabled could be have different reasons.
     1178               See CPU count & the Win test above. Here we enable it if it was
     1179               previously requested. */
     1180            if (fEnableIOApic)
     1181            {
     1182                ComPtr<IBIOSSettings> pBIOSSettings;
     1183                rc = pNewMachine->COMGETTER(BIOSSettings)(pBIOSSettings.asOutParam());
     1184                if (FAILED(rc)) throw rc;
     1185
     1186                rc = pBIOSSettings->COMSETTER(IOAPICEnabled)(TRUE);
     1187                if (FAILED(rc)) throw rc;
     1188            }
     1189
     1190            /* Audio Adapter */
     1191            std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
     1192            /* @todo: we support one audio adapter only */
     1193            if (vsdeAudioAdapter.size() > 0)
     1194            {
     1195                const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strVbox;
     1196                if (audioAdapterVBox.compare("null", Utf8Str::CaseInsensitive) != 0)
     1197                {
     1198                    uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str());
     1199                    ComPtr<IAudioAdapter> audioAdapter;
     1200                    rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
     1201                    if (FAILED(rc)) throw rc;
     1202                    rc = audioAdapter->COMSETTER(Enabled)(true);
     1203                    if (FAILED(rc)) throw rc;
     1204                    rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio));
     1205                    if (FAILED(rc)) throw rc;
     1206                }
     1207            }
     1208
     1209#ifdef VBOX_WITH_USB
     1210            /* USB Controller */
     1211            std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
     1212            // USB support is enabled if there's at least one such entry; to disable USB support,
     1213            // the type of the USB item would have been changed to "ignore"
     1214            bool fUSBEnabled = vsdeUSBController.size() > 0;
     1215
     1216            ComPtr<IUSBController> usbController;
     1217            rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
     1218            if (FAILED(rc)) throw rc;
     1219            rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
     1220            if (FAILED(rc)) throw rc;
     1221#endif /* VBOX_WITH_USB */
     1222
     1223            /* Change the network adapters */
     1224            std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
     1225            if (vsdeNW.size() == 0)
     1226            {
     1227                /* No network adapters, so we have to disable our default one */
     1228                ComPtr<INetworkAdapter> nwVBox;
     1229                rc = pNewMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
     1230                if (FAILED(rc)) throw rc;
     1231                rc = nwVBox->COMSETTER(Enabled)(false);
     1232                if (FAILED(rc)) throw rc;
     1233            }
     1234            else
     1235            {
     1236                list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
     1237                /* Iterate through all network cards. We support 8 network adapters
     1238                 * at the maximum. (@todo: warn if there are more!) */
     1239                size_t a = 0;
     1240                for (nwIt = vsdeNW.begin();
     1241                     (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
     1242                     ++nwIt, ++a)
     1243                {
     1244                    const VirtualSystemDescriptionEntry* pvsys = *nwIt;
     1245
     1246                    const Utf8Str &nwTypeVBox = pvsys->strVbox;
     1247                    uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
     1248                    ComPtr<INetworkAdapter> pNetworkAdapter;
     1249                    rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
     1250                    if (FAILED(rc)) throw rc;
     1251                    /* Enable the network card & set the adapter type */
     1252                    rc = pNetworkAdapter->COMSETTER(Enabled)(true);
     1253                    if (FAILED(rc)) throw rc;
     1254                    rc = pNetworkAdapter->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
     1255                    if (FAILED(rc)) throw rc;
     1256
     1257                    // default is NAT; change to "bridged" if extra conf says so
     1258                    if (!pvsys->strExtraConfig.compare("type=Bridged", Utf8Str::CaseInsensitive))
     1259                    {
     1260                        /* Attach to the right interface */
     1261                        rc = pNetworkAdapter->AttachToBridgedInterface();
     1262                        if (FAILED(rc)) throw rc;
     1263                        ComPtr<IHost> host;
     1264                        rc = mVirtualBox->COMGETTER(Host)(host.asOutParam());
     1265                        if (FAILED(rc)) throw rc;
     1266                        com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
     1267                        rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
     1268                        if (FAILED(rc)) throw rc;
     1269                        /* We search for the first host network interface which
     1270                         * is usable for bridged networking */
     1271                        for (size_t i=0; i < nwInterfaces.size(); ++i)
     1272                        {
     1273                            HostNetworkInterfaceType_T itype;
     1274                            rc = nwInterfaces[i]->COMGETTER(InterfaceType)(&itype);
     1275                            if (FAILED(rc)) throw rc;
     1276                            if (itype == HostNetworkInterfaceType_Bridged)
     1277                            {
     1278                                Bstr name;
     1279                                rc = nwInterfaces[i]->COMGETTER(Name)(name.asOutParam());
     1280                                if (FAILED(rc)) throw rc;
     1281                                /* Set the interface name to attach to */
     1282                                pNetworkAdapter->COMSETTER(HostInterface)(name);
     1283                                if (FAILED(rc)) throw rc;
     1284                                break;
     1285                            }
     1286                        }
     1287                    }
     1288                    /* Next test for host only interfaces */
     1289                    else if (!pvsys->strExtraConfig.compare("type=HostOnly", Utf8Str::CaseInsensitive))
     1290                    {
     1291                        /* Attach to the right interface */
     1292                        rc = pNetworkAdapter->AttachToHostOnlyInterface();
     1293                        if (FAILED(rc)) throw rc;
     1294                        ComPtr<IHost> host;
     1295                        rc = mVirtualBox->COMGETTER(Host)(host.asOutParam());
     1296                        if (FAILED(rc)) throw rc;
     1297                        com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
     1298                        rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
     1299                        if (FAILED(rc)) throw rc;
     1300                        /* We search for the first host network interface which
     1301                         * is usable for host only networking */
     1302                        for (size_t i=0; i < nwInterfaces.size(); ++i)
     1303                        {
     1304                            HostNetworkInterfaceType_T itype;
     1305                            rc = nwInterfaces[i]->COMGETTER(InterfaceType)(&itype);
     1306                            if (FAILED(rc)) throw rc;
     1307                            if (itype == HostNetworkInterfaceType_HostOnly)
     1308                            {
     1309                                Bstr name;
     1310                                rc = nwInterfaces[i]->COMGETTER(Name)(name.asOutParam());
     1311                                if (FAILED(rc)) throw rc;
     1312                                /* Set the interface name to attach to */
     1313                                pNetworkAdapter->COMSETTER(HostInterface)(name);
     1314                                if (FAILED(rc)) throw rc;
     1315                                break;
     1316                            }
     1317                        }
     1318                    }
     1319                }
     1320            }
     1321
     1322            /* Floppy drive */
     1323            std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
     1324            // Floppy support is enabled if there's at least one such entry; to disable floppy support,
     1325            // the type of the floppy item would have been changed to "ignore"
     1326            bool fFloppyEnabled = vsdeFloppy.size() > 0;
     1327            ComPtr<IFloppyDrive> floppyDrive;
     1328            rc = pNewMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
     1329            if (FAILED(rc)) throw rc;
     1330            rc = floppyDrive->COMSETTER(Enabled)(fFloppyEnabled);
     1331            if (FAILED(rc)) throw rc;
     1332
     1333            /* CDROM drive */
     1334            /* @todo: I can't disable the CDROM. So nothing to do for now */
     1335            // std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_CDROM);
     1336
     1337            /* Hard disk controller IDE */
     1338            std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
     1339            if (vsdeHDCIDE.size() > 1)
     1340                throw setError(VBOX_E_FILE_ERROR,
     1341                               tr("Too many IDE controllers in OVF; VirtualBox only supports one"));
     1342            if (vsdeHDCIDE.size() == 1)
     1343            {
     1344                ComPtr<IStorageController> pController;
     1345                rc = pNewMachine->GetStorageControllerByName(Bstr("IDE"), pController.asOutParam());
     1346                if (FAILED(rc)) throw rc;
     1347
     1348                const char *pcszIDEType = vsdeHDCIDE.front()->strVbox.c_str();
     1349                if (!strcmp(pcszIDEType, "PIIX3"))
     1350                    rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3);
     1351                else if (!strcmp(pcszIDEType, "PIIX4"))
     1352                    rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX4);
     1353                else if (!strcmp(pcszIDEType, "ICH6"))
     1354                    rc = pController->COMSETTER(ControllerType)(StorageControllerType_ICH6);
     1355                else
     1356                    throw setError(VBOX_E_FILE_ERROR,
     1357                                   tr("Invalid IDE controller type \"%s\""),
     1358                                   pcszIDEType);
     1359                if (FAILED(rc)) throw rc;
     1360            }
     1361#ifdef VBOX_WITH_AHCI
     1362            /* Hard disk controller SATA */
     1363            std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
     1364            if (vsdeHDCSATA.size() > 1)
     1365                throw setError(VBOX_E_FILE_ERROR,
     1366                               tr("Too many SATA controllers in OVF; VirtualBox only supports one"));
     1367            if (vsdeHDCSATA.size() > 0)
     1368            {
     1369                ComPtr<IStorageController> pController;
     1370                const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVbox;
     1371                if (hdcVBox == "AHCI")
     1372                {
     1373                    rc = pNewMachine->AddStorageController(Bstr("SATA"), StorageBus_SATA, pController.asOutParam());
     1374                    if (FAILED(rc)) throw rc;
     1375                }
     1376                else
     1377                    throw setError(VBOX_E_FILE_ERROR,
     1378                                   tr("Invalid SATA controller type \"%s\""),
     1379                                   hdcVBox.c_str());
     1380            }
     1381#endif /* VBOX_WITH_AHCI */
     1382
     1383#ifdef VBOX_WITH_LSILOGIC
     1384            /* Hard disk controller SCSI */
     1385            std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
     1386            if (vsdeHDCSCSI.size() > 1)
     1387                throw setError(VBOX_E_FILE_ERROR,
     1388                               tr("Too many SCSI controllers in OVF; VirtualBox only supports one"));
     1389            if (vsdeHDCSCSI.size() > 0)
     1390            {
     1391                ComPtr<IStorageController> pController;
     1392                StorageControllerType_T controllerType;
     1393                const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVbox;
     1394                if (hdcVBox == "LsiLogic")
     1395                    controllerType = StorageControllerType_LsiLogic;
     1396                else if (hdcVBox == "BusLogic")
     1397                    controllerType = StorageControllerType_BusLogic;
     1398                else
     1399                    throw setError(VBOX_E_FILE_ERROR,
     1400                                   tr("Invalid SCSI controller type \"%s\""),
     1401                                   hdcVBox.c_str());
     1402
     1403                rc = pNewMachine->AddStorageController(Bstr("SCSI"), StorageBus_SCSI, pController.asOutParam());
     1404                if (FAILED(rc)) throw rc;
     1405                rc = pController->COMSETTER(ControllerType)(controllerType);
     1406                if (FAILED(rc)) throw rc;
     1407            }
     1408#endif /* VBOX_WITH_LSILOGIC */
     1409
     1410            /* Now its time to register the machine before we add any hard disks */
     1411            rc = mVirtualBox->RegisterMachine(pNewMachine);
     1412            if (FAILED(rc)) throw rc;
     1413
     1414            Bstr newMachineId_;
     1415            rc = pNewMachine->COMGETTER(Id)(newMachineId_.asOutParam());
     1416            if (FAILED(rc)) throw rc;
     1417            Guid newMachineId(newMachineId_);
     1418
     1419            // store new machine for roll-back in case of errors
     1420            llMachinesRegistered.push_back(newMachineId);
     1421
     1422            /* Create the hard disks & connect them to the appropriate controllers. */
     1423            std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
     1424            if (avsdeHDs.size() > 0)
     1425            {
     1426                /* If in the next block an error occur we have to deregister
     1427                   the machine, so make an extra try/catch block. */
     1428                ComPtr<IHardDisk> srcHdVBox;
     1429                bool fSourceHdNeedsClosing = false;
     1430
     1431                try
     1432                {
     1433                    /* In order to attach hard disks we need to open a session
     1434                     * for the new machine */
     1435                    rc = mVirtualBox->OpenSession(session, newMachineId_);
     1436                    if (FAILED(rc)) throw rc;
     1437                    fSessionOpen = true;
     1438
     1439                    /* The disk image has to be on the same place as the OVF file. So
     1440                     * strip the filename out of the full file path. */
     1441                    Utf8Str strSrcDir(pTask->locInfo.strPath);
     1442                    strSrcDir.stripFilename();
     1443
     1444                    /* Iterate over all given disk images */
     1445                    list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
     1446                    for (itHD = avsdeHDs.begin();
     1447                         itHD != avsdeHDs.end();
     1448                         ++itHD)
     1449                    {
     1450                        VirtualSystemDescriptionEntry *vsdeHD = *itHD;
     1451
     1452                        const char *pcszDstFilePath = vsdeHD->strVbox.c_str();
     1453                        /* Check if the destination file exists already or the
     1454                         * destination path is empty. */
     1455                        if (    !(*pcszDstFilePath)
     1456                             || RTPathExists(pcszDstFilePath)
     1457                           )
     1458                            /* This isn't allowed */
     1459                            throw setError(VBOX_E_FILE_ERROR,
     1460                                           tr("Destination file '%s' exists",
     1461                                              pcszDstFilePath));
     1462
     1463                        /* Find the disk from the OVF's disk list */
     1464                        DiskImagesMap::const_iterator itDiskImage = reader.m_mapDisks.find(vsdeHD->strRef);
     1465                        /* vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
     1466                           in the virtual system's disks map under that ID and also in the global images map. */
     1467                        VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
     1468
     1469                        if (    itDiskImage == reader.m_mapDisks.end()
     1470                             || itVirtualDisk == vsysThis.mapVirtualDisks.end()
     1471                           )
     1472                            throw setError(E_FAIL,
     1473                                           tr("Internal inconsistency looking up disk images."));
     1474
     1475                        const DiskImage &di = itDiskImage->second;
     1476                        const VirtualDisk &vd = itVirtualDisk->second;
     1477
     1478                        /* Make sure all target directories exists */
     1479                        rc = VirtualBox::ensureFilePathExists(pcszDstFilePath);
     1480                        if (FAILED(rc))
     1481                            throw rc;
     1482
     1483                        // subprogress object for hard disk
     1484                        ComPtr<IProgress> pProgress2;
     1485
     1486                        ComPtr<IHardDisk> dstHdVBox;
     1487                        /* If strHref is empty we have to create a new file */
     1488                        if (di.strHref.isEmpty())
     1489                        {
     1490                            /* Which format to use? */
     1491                            Bstr srcFormat = L"VDI";
     1492                            if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
     1493                                || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
     1494                                srcFormat = L"VMDK";
     1495                            /* Create an empty hard disk */
     1496                            rc = mVirtualBox->CreateHardDisk(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
     1497                            if (FAILED(rc)) throw rc;
     1498
     1499                            /* Create a dynamic growing disk image with the given capacity */
     1500                            rc = dstHdVBox->CreateBaseStorage(di.iCapacity / _1M, HardDiskVariant_Standard, pProgress2.asOutParam());
     1501                            if (FAILED(rc)) throw rc;
     1502
     1503                            /* Advance to the next operation */
     1504                            if (!pTask->progress.isNull())
     1505                                pTask->progress->setNextOperation(BstrFmt(tr("Creating virtual disk image '%s'"), pcszDstFilePath),
     1506                                                                 vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally
     1507                        }
     1508                        else
     1509                        {
     1510                            /* Construct the source file path */
     1511                            Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
     1512                            /* Check if the source file exists */
     1513                            if (!RTPathExists(strSrcFilePath.c_str()))
     1514                                /* This isn't allowed */
     1515                                throw setError(VBOX_E_FILE_ERROR,
     1516                                               tr("Source virtual disk image file '%s' doesn't exist"),
     1517                                                  strSrcFilePath.c_str());
     1518
     1519                            /* Clone the disk image (this is necessary cause the id has
     1520                             * to be recreated for the case the same hard disk is
     1521                             * attached already from a previous import) */
     1522
     1523                            /* First open the existing disk image */
     1524                            rc = mVirtualBox->OpenHardDisk(Bstr(strSrcFilePath),
     1525                                                           AccessMode_ReadOnly,
     1526                                                           false, Bstr(""), false, Bstr(""),
     1527                                                           srcHdVBox.asOutParam());
     1528                            if (FAILED(rc)) throw rc;
     1529                            fSourceHdNeedsClosing = true;
     1530
     1531                            /* We need the format description of the source disk image */
     1532                            Bstr srcFormat;
     1533                            rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
     1534                            if (FAILED(rc)) throw rc;
     1535                            /* Create a new hard disk interface for the destination disk image */
     1536                            rc = mVirtualBox->CreateHardDisk(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
     1537                            if (FAILED(rc)) throw rc;
     1538                            /* Clone the source disk image */
     1539                            rc = srcHdVBox->CloneTo(dstHdVBox, HardDiskVariant_Standard, NULL, pProgress2.asOutParam());
     1540                            if (FAILED(rc)) throw rc;
     1541
     1542                            /* Advance to the next operation */
     1543                            if (!pTask->progress.isNull())
     1544                                pTask->progress->setNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), strSrcFilePath.c_str()),
     1545                                                                 vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
     1546                        }
     1547
     1548                        // now wait for the background disk operation to complete; this throws HRESULTs on error
     1549                        waitForAsyncProgress(pTask->progress, pProgress2);
     1550
     1551                        if (fSourceHdNeedsClosing)
     1552                        {
     1553                            rc = srcHdVBox->Close();
     1554                            if (FAILED(rc)) throw rc;
     1555                            fSourceHdNeedsClosing = false;
     1556                        }
     1557
     1558                        llHardDisksCreated.push_back(dstHdVBox);
     1559                        /* Now use the new uuid to attach the disk image to our new machine */
     1560                        ComPtr<IMachine> sMachine;
     1561                        rc = session->COMGETTER(Machine)(sMachine.asOutParam());
     1562                        if (FAILED(rc)) throw rc;
     1563                        Bstr hdId;
     1564                        rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());
     1565                        if (FAILED(rc)) throw rc;
     1566
     1567                        /* For now we assume we have one controller of every type only */
     1568                        HardDiskController hdc = (*vsysThis.mapControllers.find(vd.idController)).second;
     1569
     1570                        // this is for rollback later
     1571                        MyHardDiskAttachment mhda;
     1572                        mhda.uuid = newMachineId;
     1573                        mhda.pMachine = pNewMachine;
     1574
     1575                        switch (hdc.system)
     1576                        {
     1577                            case HardDiskController::IDE:
     1578                                // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
     1579                                // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
     1580                                // the device number can be either 0 or 1, to specify the master or the slave device,
     1581                                // respectively. For the secondary IDE controller, the device number is always 1 because
     1582                                // the master device is reserved for the CD-ROM drive.
     1583                                mhda.controllerType = Bstr("IDE");
     1584                                switch (vd.ulAddressOnParent)
     1585                                {
     1586                                    case 0:     // interpret this as primary master
     1587                                        mhda.lChannel = (long)0;
     1588                                        mhda.lDevice = (long)0;
     1589                                    break;
     1590
     1591                                    case 1:     // interpret this as primary slave
     1592                                        mhda.lChannel = (long)0;
     1593                                        mhda.lDevice = (long)1;
     1594                                    break;
     1595
     1596                                    case 2:     // interpret this as secondary slave
     1597                                        mhda.lChannel = (long)1;
     1598                                        mhda.lDevice = (long)1;
     1599                                    break;
     1600
     1601                                    default:
     1602                                        throw setError(VBOX_E_NOT_SUPPORTED,
     1603                                                       tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), vd.ulAddressOnParent);
     1604                                    break;
     1605                                }
     1606                            break;
     1607
     1608                            case HardDiskController::SATA:
     1609                                mhda.controllerType = Bstr("SATA");
     1610                                mhda.lChannel = (long)vd.ulAddressOnParent;
     1611                                mhda.lDevice = (long)0;
     1612                            break;
     1613
     1614                            case HardDiskController::SCSI:
     1615                                mhda.controllerType = Bstr("SCSI");
     1616                                mhda.lChannel = (long)vd.ulAddressOnParent;
     1617                                mhda.lDevice = (long)0;
     1618                            break;
     1619
     1620                            default: break;
     1621                        }
     1622
     1623                        Log(("Attaching disk %s to channel %d on device %d\n", pcszDstFilePath, mhda.lChannel, mhda.lDevice));
     1624
     1625                        rc = sMachine->AttachHardDisk(hdId,
     1626                                                      mhda.controllerType,
     1627                                                      mhda.lChannel,
     1628                                                      mhda.lDevice);
     1629                        if (FAILED(rc)) throw rc;
     1630
     1631                        llHardDiskAttachments.push_back(mhda);
     1632
     1633                        rc = sMachine->SaveSettings();
     1634                        if (FAILED(rc)) throw rc;
     1635                    } // end for (itHD = avsdeHDs.begin();
     1636
     1637                    // only now that we're done with all disks, close the session
     1638                    rc = session->Close();
     1639                    if (FAILED(rc)) throw rc;
     1640                    fSessionOpen = false;
     1641                }
     1642                catch(HRESULT /* aRC */)
     1643                {
     1644                    if (fSourceHdNeedsClosing)
     1645                        srcHdVBox->Close();
     1646
     1647                    if (fSessionOpen)
     1648                        session->Close();
     1649
     1650                    throw;
     1651                }
     1652            }
     1653        }
     1654        catch(HRESULT aRC)
     1655        {
     1656            rc = aRC;
     1657        }
     1658
     1659        if (FAILED(rc))
     1660            break;
     1661
     1662    } // for (it = pAppliance->m->llVirtualSystems.begin(),
     1663
     1664    if (FAILED(rc))
     1665    {
     1666        // with _whatever_ error we've had, do a complete roll-back of
     1667        // machines and disks we've created; unfortunately this is
     1668        // not so trivially done...
     1669
     1670        HRESULT rc2;
     1671        // detach all hard disks from all machines we created
     1672        list<MyHardDiskAttachment>::iterator itM;
     1673        for (itM = llHardDiskAttachments.begin();
     1674             itM != llHardDiskAttachments.end();
     1675             ++itM)
     1676        {
     1677            const MyHardDiskAttachment &mhda = *itM;
     1678            rc2 = mVirtualBox->OpenSession(session, Bstr(mhda.uuid));
     1679            if (SUCCEEDED(rc2))
     1680            {
     1681                ComPtr<IMachine> sMachine;
     1682                rc2 = session->COMGETTER(Machine)(sMachine.asOutParam());
     1683                if (SUCCEEDED(rc2))
     1684                {
     1685                    rc2 = sMachine->DetachHardDisk(Bstr(mhda.controllerType), mhda.lChannel, mhda.lDevice);
     1686                    rc2 = sMachine->SaveSettings();
     1687                }
     1688                session->Close();
     1689            }
     1690        }
     1691
     1692        // now clean up all hard disks we created
     1693        list< ComPtr<IHardDisk> >::iterator itHD;
     1694        for (itHD = llHardDisksCreated.begin();
     1695             itHD != llHardDisksCreated.end();
     1696             ++itHD)
     1697        {
     1698            ComPtr<IHardDisk> pDisk = *itHD;
     1699            ComPtr<IProgress> pProgress;
     1700            rc2 = pDisk->DeleteStorage(pProgress.asOutParam());
     1701            rc2 = pProgress->WaitForCompletion(-1);
     1702        }
     1703
     1704        // finally, deregister and remove all machines
     1705        list<Guid>::iterator itID;
     1706        for (itID = llMachinesRegistered.begin();
     1707             itID != llMachinesRegistered.end();
     1708             ++itID)
     1709        {
     1710            const Guid &guid = *itID;
     1711            ComPtr<IMachine> failedMachine;
     1712            rc2 = mVirtualBox->UnregisterMachine(guid.toUtf16(), failedMachine.asOutParam());
     1713            if (SUCCEEDED(rc2))
     1714                rc2 = failedMachine->DeleteSettings();
     1715        }
     1716    }
     1717
     1718    pTask->rc = rc;
     1719
     1720    if (!pTask->progress.isNull())
     1721        pTask->progress->notifyComplete(rc);
     1722
     1723    LogFlowFunc(("rc=%Rhrc\n", rc));
     1724    LogFlowFuncLeave();
     1725
     1726    return VINF_SUCCESS;
     1727}
     1728
     1729int Appliance::importS3(TaskImportOVF *pTask)
     1730{
     1731    LogFlowFuncEnter();
     1732    LogFlowFunc(("Appliance %p\n", this));
     1733
     1734    AutoCaller autoCaller(this);
     1735    CheckComRCReturnRC(autoCaller.rc());
     1736
     1737    AutoWriteLock appLock(this);
     1738
     1739    int vrc = VINF_SUCCESS;
     1740    RTS3 hS3 = NIL_RTS3;
     1741    char szOSTmpDir[RTPATH_MAX];
     1742    RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
     1743    /* The template for the temporary directory created below */
     1744    char *pszTmpDir;
     1745    RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
     1746    list< pair<Utf8Str, ULONG> > filesList;
     1747
     1748    HRESULT rc = S_OK;
     1749    try
     1750    {
     1751        /* Extract the bucket */
     1752        Utf8Str tmpPath = pTask->locInfo.strPath;
     1753        Utf8Str bucket;
     1754        parseBucket(tmpPath, bucket);
     1755
     1756        /* We need a temporary directory which we can put the all disk images
     1757         * in */
     1758        vrc = RTDirCreateTemp(pszTmpDir);
     1759        if (RT_FAILURE(rc))
     1760            throw setError(VBOX_E_FILE_ERROR,
     1761                           tr("Cannot create temporary directory '%s'"), pszTmpDir);
     1762
     1763        /* Add every disks of every virtual system to an internal list */
     1764        list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
     1765        for (it = m->virtualSystemDescriptions.begin();
     1766             it != m->virtualSystemDescriptions.end();
     1767             ++it)
     1768        {
     1769            ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
     1770            std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
     1771            std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
     1772            for (itH = avsdeHDs.begin();
     1773                 itH != avsdeHDs.end();
     1774                 ++itH)
     1775            {
     1776                const Utf8Str &strTargetFile = (*itH)->strOvf;
     1777                if (!strTargetFile.isEmpty())
     1778                {
     1779                    /* The temporary name of the target disk file */
     1780                    Utf8StrFmt strTmpDisk("%s/%s", pszTmpDir, RTPathFilename(strTargetFile));
     1781                    filesList.push_back(pair<Utf8Str, ULONG>(strTmpDisk, (*itH)->ulSizeMB));
     1782                }
     1783            }
     1784        }
     1785
     1786        /* Next we have to download the disk images */
     1787        vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
     1788        if(RT_FAILURE(vrc))
     1789            throw setError(VBOX_E_IPRT_ERROR,
     1790                           tr("Cannot create S3 service handler"));
     1791        RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
     1792
     1793        /* Download all files */
     1794        for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
     1795        {
     1796            const pair<Utf8Str, ULONG> &s = (*it1);
     1797            const Utf8Str &strSrcFile = s.first;
     1798            /* Construct the source file name */
     1799            char *pszFilename = RTPathFilename(strSrcFile.c_str());
     1800            /* Advance to the next operation */
     1801            if (!pTask->progress.isNull())
     1802                pTask->progress->setNextOperation(BstrFmt(tr("Downloading file '%s'"), pszFilename), s.second);
     1803
     1804            vrc = RTS3GetKey(hS3, bucket.c_str(), pszFilename, strSrcFile.c_str());
     1805            if (RT_FAILURE(vrc))
     1806            {
     1807                if(vrc == VERR_S3_CANCELED)
     1808                    throw S_OK; /* todo: !!!!!!!!!!!!! */
     1809                else if(vrc == VERR_S3_ACCESS_DENIED)
     1810                    throw setError(E_ACCESSDENIED,
     1811                                   tr("Cannot download file '%s' from S3 storage server (Access denied)"), pszFilename);
     1812                else if(vrc == VERR_S3_NOT_FOUND)
     1813                    throw setError(VBOX_E_FILE_ERROR,
     1814                                   tr("Cannot download file '%s' from S3 storage server (File not found)"), pszFilename);
     1815                else
     1816                    throw setError(VBOX_E_IPRT_ERROR,
     1817                                   tr("Cannot download file '%s' from S3 storage server (%Rrc)"), pszFilename, vrc);
     1818            }
     1819        }
     1820
     1821        /* Close the connection early */
     1822        RTS3Destroy(hS3);
     1823        hS3 = NIL_RTS3;
     1824
     1825        if (!pTask->progress.isNull())
     1826            pTask->progress->setNextOperation(BstrFmt(tr("Importing appliance")), m->ulWeightPerOperation);
     1827
     1828        ComObjPtr<Progress> progress;
     1829        /* Import the whole temporary OVF & the disk images */
     1830        LocationInfo li;
     1831        /* Provide a OVF file (haven't to exist) so the import routine can
     1832         * figure out where the disk images are located. */
     1833        Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath));
     1834        li.strPath = strTmpOvf;
     1835        rc = importImpl(li, progress);
     1836        if (FAILED(rc)) throw rc;
     1837
     1838        /* Unlock the appliance for the fs import thread */
     1839        appLock.unlock();
     1840        /* Wait until the import is done, but report the progress back to the
     1841           caller */
     1842        ComPtr<IProgress> progressInt(progress);
     1843        waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
     1844
     1845        /* Again lock the appliance for the next steps */
     1846        appLock.lock();
     1847    }
     1848    catch(HRESULT aRC)
     1849    {
     1850        rc = aRC;
     1851    }
     1852    /* Cleanup */
     1853    RTS3Destroy(hS3);
     1854    /* Delete all files which where temporary created */
     1855    for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
     1856    {
     1857        const char *pszFilePath = (*it1).first.c_str();
     1858        if (RTPathExists(pszFilePath))
     1859        {
     1860            vrc = RTFileDelete(pszFilePath);
     1861            if(RT_FAILURE(vrc))
     1862                rc = setError(VBOX_E_FILE_ERROR,
     1863                              tr("Cannot delete file '%s' (%Rrc)"), pszFilePath, vrc);
     1864        }
     1865    }
     1866    /* Delete the temporary directory */
     1867    if (RTPathExists(pszTmpDir))
     1868    {
     1869        vrc = RTDirRemove(pszTmpDir);
     1870        if(RT_FAILURE(vrc))
     1871            rc = setError(VBOX_E_FILE_ERROR,
     1872                          tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
     1873    }
     1874    if (pszTmpDir)
     1875        RTStrFree(pszTmpDir);
     1876
     1877    pTask->rc = rc;
     1878
     1879    if (!pTask->progress.isNull())
     1880        pTask->progress->notifyComplete(rc);
     1881
     1882    LogFlowFunc(("rc=%Rhrc\n", rc));
     1883    LogFlowFuncLeave();
     1884
     1885    return VINF_SUCCESS;
     1886}
     1887
     1888HRESULT Appliance::writeImpl(int aFormat, const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress)
     1889{
     1890    HRESULT rc = S_OK;
     1891    try
     1892    {
     1893        /* Initialize our worker task */
     1894        std::auto_ptr<TaskExportOVF> task(new TaskExportOVF(this));
     1895        /* What should the task do */
     1896        task->taskType = TaskExportOVF::Write;
     1897        /* The OVF version to write */
     1898        task->enFormat = (TaskExportOVF::OVFFormat)aFormat;
     1899        /* Copy the current location info to the task */
     1900        task->locInfo = aLocInfo;
     1901
     1902        Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"),
     1903                                    task->locInfo.strPath.c_str());
     1904
     1905        /* todo: This progress init stuff should be done a little bit more generic */
     1906        if (task->locInfo.storageType == VFSType_File)
     1907            rc = setUpProgressFS(aProgress, progressDesc);
     1908        else
     1909            rc = setUpProgressWriteS3(aProgress, progressDesc);
     1910
     1911        task->progress = aProgress;
     1912
     1913        rc = task->startThread();
     1914        CheckComRCThrowRC(rc);
     1915
     1916        /* Don't destruct on success */
     1917        task.release();
     1918    }
     1919    catch (HRESULT aRC)
     1920    {
     1921        rc = aRC;
     1922    }
     1923
     1924    return rc;
     1925}
     1926
     1927DECLCALLBACK(int) Appliance::taskThreadWriteOVF(RTTHREAD /* aThread */, void *pvUser)
     1928{
     1929    std::auto_ptr<TaskExportOVF> task(static_cast<TaskExportOVF*>(pvUser));
     1930    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
     1931
     1932    Appliance *pAppliance = task->pAppliance;
     1933
     1934    LogFlowFuncEnter();
     1935    LogFlowFunc(("Appliance %p\n", pAppliance));
     1936
     1937    HRESULT rc = S_OK;
     1938
     1939    switch(task->taskType)
     1940    {
     1941        case TaskExportOVF::Write:
     1942        {
     1943            if (task->locInfo.storageType == VFSType_File)
     1944                rc = pAppliance->writeFS(task.get());
     1945            else if (task->locInfo.storageType == VFSType_S3)
     1946                rc = pAppliance->writeS3(task.get());
     1947            break;
     1948        }
     1949    }
     1950
     1951    LogFlowFunc(("rc=%Rhrc\n", rc));
     1952    LogFlowFuncLeave();
     1953
     1954    return VINF_SUCCESS;
     1955}
     1956
     1957int Appliance::TaskExportOVF::startThread()
     1958{
     1959    int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this,
     1960                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
     1961                             "Appliance::Task");
     1962
     1963    ComAssertMsgRCRet(vrc,
     1964                      ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL);
     1965
     1966    return S_OK;
     1967}
     1968
     1969int Appliance::writeFS(TaskExportOVF *pTask)
     1970{
     1971    LogFlowFuncEnter();
     1972    LogFlowFunc(("Appliance %p\n", this));
     1973
     1974    AutoCaller autoCaller(this);
     1975    CheckComRCReturnRC(autoCaller.rc());
     1976
     1977    AutoWriteLock appLock(this);
     1978
     1979    HRESULT rc = S_OK;
     1980
     1981    try
     1982    {
     1983        xml::Document doc;
     1984        xml::ElementNode *pelmRoot = doc.createRootElement("Envelope");
     1985
     1986        pelmRoot->setAttribute("ovf:version", (pTask->enFormat == TaskExportOVF::OVF_1_0) ? "1.0" : "0.9");
     1987        pelmRoot->setAttribute("xml:lang", "en-US");
     1988
     1989        Utf8Str strNamespace = (pTask->enFormat == TaskExportOVF::OVF_0_9)
     1990            ? "http://www.vmware.com/schema/ovf/1/envelope"     // 0.9
     1991            : "http://schemas.dmtf.org/ovf/envelope/1";         // 1.0
     1992        pelmRoot->setAttribute("xmlns", strNamespace);
     1993        pelmRoot->setAttribute("xmlns:ovf", strNamespace);
     1994
     1995//         pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");
     1996        pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData");
     1997        pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData");
     1998        pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
     1999//         pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
     2000
     2001        // <Envelope>/<References>
     2002        xml::ElementNode *pelmReferences = pelmRoot->createChild("References");     // 0.9 and 1.0
     2003
     2004        /* <Envelope>/<DiskSection>:
     2005            <DiskSection>
     2006                <Info>List of the virtual disks used in the package</Info>
     2007                <Disk ovf:capacity="4294967296" ovf:diskId="lamp" ovf:format="http://www.vmware.com/specifications/vmdk.html#compressed" ovf:populatedSize="1924967692"/>
     2008            </DiskSection> */
     2009        xml::ElementNode *pelmDiskSection;
     2010        if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2011        {
     2012            // <Section xsi:type="ovf:DiskSection_Type">
     2013            pelmDiskSection = pelmRoot->createChild("Section");
     2014            pelmDiskSection->setAttribute("xsi:type", "ovf:DiskSection_Type");
     2015        }
     2016        else
     2017            pelmDiskSection = pelmRoot->createChild("DiskSection");
     2018
     2019        xml::ElementNode *pelmDiskSectionInfo = pelmDiskSection->createChild("Info");
     2020        pelmDiskSectionInfo->addContent("List of the virtual disks used in the package");
     2021        // for now, set up a map so we have a list of unique disk names (to make
     2022        // sure the same disk name is only added once)
     2023        map<Utf8Str, const VirtualSystemDescriptionEntry*> mapDisks;
     2024
     2025        /* <Envelope>/<NetworkSection>:
     2026            <NetworkSection>
     2027                <Info>Logical networks used in the package</Info>
     2028                <Network ovf:name="VM Network">
     2029                    <Description>The network that the LAMP Service will be available on</Description>
     2030                </Network>
     2031            </NetworkSection> */
     2032        xml::ElementNode *pelmNetworkSection;
     2033        if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2034        {
     2035            // <Section xsi:type="ovf:NetworkSection_Type">
     2036            pelmNetworkSection = pelmRoot->createChild("Section");
     2037            pelmNetworkSection->setAttribute("xsi:type", "ovf:NetworkSection_Type");
     2038        }
     2039        else
     2040            pelmNetworkSection = pelmRoot->createChild("NetworkSection");
     2041
     2042        xml::ElementNode *pelmNetworkSectionInfo = pelmNetworkSection->createChild("Info");
     2043        pelmNetworkSectionInfo->addContent("Logical networks used in the package");
     2044        // for now, set up a map so we have a list of unique network names (to make
     2045        // sure the same network name is only added once)
     2046        map<Utf8Str, bool> mapNetworks;
     2047                // we fill this later below when we iterate over the networks
     2048
     2049        // and here come the virtual systems:
     2050
     2051        // write a collection if we have more than one virtual system _and_ we're
     2052        // writing OVF 1.0; otherwise fail since ovftool can't import more than
     2053        // one machine, it seems
     2054        xml::ElementNode *pelmToAddVirtualSystemsTo;
     2055        if (m->virtualSystemDescriptions.size() > 1)
     2056        {
     2057            if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2058                throw setError(VBOX_E_FILE_ERROR,
     2059                               tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0"));
     2060
     2061            pelmToAddVirtualSystemsTo = pelmRoot->createChild("VirtualSystemCollection");
     2062            /* xml::AttributeNode *pattrVirtualSystemCollectionId = */ pelmToAddVirtualSystemsTo->setAttribute("ovf:name", "ExportedVirtualBoxMachines");      // whatever
     2063        }
     2064        else
     2065            pelmToAddVirtualSystemsTo = pelmRoot;       // add virtual system directly under root element
     2066
     2067        uint32_t cDisks = 0;
     2068
     2069        list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
     2070        /* Iterate through all virtual systems of that appliance */
     2071        for (it = m->virtualSystemDescriptions.begin();
     2072             it != m->virtualSystemDescriptions.end();
     2073             ++it)
     2074        {
     2075            ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
     2076
     2077            xml::ElementNode *pelmVirtualSystem;
     2078            if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2079            {
     2080                // <Section xsi:type="ovf:NetworkSection_Type">
     2081                pelmVirtualSystem = pelmToAddVirtualSystemsTo->createChild("Content");
     2082                pelmVirtualSystem->setAttribute("xsi:type", "ovf:VirtualSystem_Type");
     2083            }
     2084            else
     2085                pelmVirtualSystem = pelmToAddVirtualSystemsTo->createChild("VirtualSystem");
     2086
     2087            /*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine");
     2088
     2089            std::list<VirtualSystemDescriptionEntry*> llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
     2090            if (llName.size() != 1)
     2091                throw setError(VBOX_E_NOT_SUPPORTED,
     2092                               tr("Missing VM name"));
     2093            Utf8Str &strVMName = llName.front()->strVbox;
     2094            pelmVirtualSystem->setAttribute("ovf:id", strVMName);
     2095
     2096            // product info
     2097            std::list<VirtualSystemDescriptionEntry*> llProduct = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
     2098            std::list<VirtualSystemDescriptionEntry*> llProductUrl = vsdescThis->findByType(VirtualSystemDescriptionType_ProductUrl);
     2099            std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
     2100            std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
     2101            std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
     2102            bool fProduct = llProduct.size() && !llProduct.front()->strVbox.isEmpty();
     2103            bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVbox.isEmpty();
     2104            bool fVendor = llVendor.size() && !llVendor.front()->strVbox.isEmpty();
     2105            bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVbox.isEmpty();
     2106            bool fVersion = llVersion.size() && !llVersion.front()->strVbox.isEmpty();
     2107            if (fProduct ||
     2108                fProductUrl ||
     2109                fVersion ||
     2110                fVendorUrl ||
     2111                fVersion)
     2112            {
     2113                /* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
     2114                    <Info>Meta-information about the installed software</Info>
     2115                    <Product>VAtest</Product>
     2116                    <Vendor>SUN Microsystems</Vendor>
     2117                    <Version>10.0</Version>
     2118                    <ProductUrl>http://blogs.sun.com/VirtualGuru</ProductUrl>
     2119                    <VendorUrl>http://www.sun.com</VendorUrl>
     2120                </Section> */
     2121                xml::ElementNode *pelmAnnotationSection;
     2122                if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2123                {
     2124                    // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
     2125                    pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
     2126                    pelmAnnotationSection->setAttribute("xsi:type", "ovf:ProductSection_Type");
     2127                }
     2128                else
     2129                    pelmAnnotationSection = pelmVirtualSystem->createChild("ProductSection");
     2130
     2131                pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software");
     2132                if (fProduct)
     2133                    pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVbox);
     2134                if (fVendor)
     2135                    pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVbox);
     2136                if (fVersion)
     2137                    pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVbox);
     2138                if (fProductUrl)
     2139                    pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVbox);
     2140                if (fVendorUrl)
     2141                    pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVbox);
     2142            }
     2143
     2144            // description
     2145            std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
     2146            if (llDescription.size() &&
     2147                !llDescription.front()->strVbox.isEmpty())
     2148            {
     2149                /*  <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
     2150                        <Info>A human-readable annotation</Info>
     2151                        <Annotation>Plan 9</Annotation>
     2152                    </Section> */
     2153                xml::ElementNode *pelmAnnotationSection;
     2154                if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2155                {
     2156                    // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
     2157                    pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
     2158                    pelmAnnotationSection->setAttribute("xsi:type", "ovf:AnnotationSection_Type");
     2159                }
     2160                else
     2161                    pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection");
     2162
     2163                pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation");
     2164                pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVbox);
     2165            }
     2166
     2167            // license
     2168            std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License);
     2169            if (llLicense.size() &&
     2170                !llLicense.front()->strVbox.isEmpty())
     2171            {
     2172                /* <EulaSection>
     2173                   <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
     2174                   <License ovf:msgid="1">License terms can go in here.</License>
     2175                   </EulaSection> */
     2176                xml::ElementNode *pelmEulaSection;
     2177                if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2178                {
     2179                    pelmEulaSection = pelmVirtualSystem->createChild("Section");
     2180                    pelmEulaSection->setAttribute("xsi:type", "ovf:EulaSection_Type");
     2181                }
     2182                else
     2183                    pelmEulaSection = pelmVirtualSystem->createChild("EulaSection");
     2184
     2185                pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system");
     2186                pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVbox);
     2187            }
     2188
     2189            // operating system
     2190            std::list<VirtualSystemDescriptionEntry*> llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
     2191            if (llOS.size() != 1)
     2192                throw setError(VBOX_E_NOT_SUPPORTED,
     2193                               tr("Missing OS type"));
     2194            /*  <OperatingSystemSection ovf:id="82">
     2195                    <Info>Guest Operating System</Info>
     2196                    <Description>Linux 2.6.x</Description>
     2197                </OperatingSystemSection> */
     2198            xml::ElementNode *pelmOperatingSystemSection;
     2199            if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2200            {
     2201                pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section");
     2202                pelmOperatingSystemSection->setAttribute("xsi:type", "ovf:OperatingSystemSection_Type");
     2203            }
     2204            else
     2205                pelmOperatingSystemSection = pelmVirtualSystem->createChild("OperatingSystemSection");
     2206
     2207            pelmOperatingSystemSection->setAttribute("ovf:id", llOS.front()->strOvf);
     2208            pelmOperatingSystemSection->createChild("Info")->addContent("The kind of installed guest operating system");
     2209            Utf8Str strOSDesc;
     2210            convertCIMOSType2VBoxOSType(strOSDesc, (CIMOSType_T)llOS.front()->strOvf.toInt32(), "");
     2211            pelmOperatingSystemSection->createChild("Description")->addContent(strOSDesc);
     2212
     2213            // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso">
     2214            xml::ElementNode *pelmVirtualHardwareSection;
     2215            if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2216            {
     2217                // <Section xsi:type="ovf:VirtualHardwareSection_Type">
     2218                pelmVirtualHardwareSection = pelmVirtualSystem->createChild("Section");
     2219                pelmVirtualHardwareSection->setAttribute("xsi:type", "ovf:VirtualHardwareSection_Type");
     2220            }
     2221            else
     2222                pelmVirtualHardwareSection = pelmVirtualSystem->createChild("VirtualHardwareSection");
     2223
     2224            pelmVirtualHardwareSection->createChild("Info")->addContent("Virtual hardware requirements for a virtual machine");
     2225
     2226            /*  <System>
     2227                    <vssd:Description>Description of the virtual hardware section.</vssd:Description>
     2228                    <vssd:ElementName>vmware</vssd:ElementName>
     2229                    <vssd:InstanceID>1</vssd:InstanceID>
     2230                    <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
     2231                    <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
     2232                </System> */
     2233            xml::ElementNode *pelmSystem = pelmVirtualHardwareSection->createChild("System");
     2234
     2235            pelmSystem->createChild("vssd:ElementName")->addContent("Virtual Hardware Family"); // required OVF 1.0
     2236
     2237            // <vssd:InstanceId>0</vssd:InstanceId>
     2238            if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2239                pelmSystem->createChild("vssd:InstanceId")->addContent("0");
     2240            else // capitalization changed...
     2241                pelmSystem->createChild("vssd:InstanceID")->addContent("0");
     2242
     2243            // <vssd:VirtualSystemIdentifier>VAtest</vssd:VirtualSystemIdentifier>
     2244            pelmSystem->createChild("vssd:VirtualSystemIdentifier")->addContent(strVMName);
     2245            // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
     2246            const char *pcszHardware = "virtualbox-2.2";
     2247            if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2248                // pretend to be vmware compatible then
     2249                pcszHardware = "vmx-6";
     2250            pelmSystem->createChild("vssd:VirtualSystemType")->addContent(pcszHardware);
     2251
     2252            // loop thru all description entries twice; once to write out all
     2253            // devices _except_ disk images, and a second time to assign the
     2254            // disk images; this is because disk images need to reference
     2255            // IDE controllers, and we can't know their instance IDs without
     2256            // assigning them first
     2257
     2258            uint32_t idIDEController = 0;
     2259            int32_t lIDEControllerIndex = 0;
     2260            uint32_t idSATAController = 0;
     2261            int32_t lSATAControllerIndex = 0;
     2262            uint32_t idSCSIController = 0;
     2263            int32_t lSCSIControllerIndex = 0;
     2264
     2265            uint32_t ulInstanceID = 1;
     2266
     2267            for (size_t uLoop = 1;
     2268                 uLoop <= 2;
     2269                 ++uLoop)
     2270            {
     2271                int32_t lIndexThis = 0;
     2272                list<VirtualSystemDescriptionEntry>::const_iterator itD;
     2273                for (itD = vsdescThis->m->llDescriptions.begin();
     2274                    itD != vsdescThis->m->llDescriptions.end();
     2275                    ++itD, ++lIndexThis)
     2276                {
     2277                    const VirtualSystemDescriptionEntry &desc = *itD;
     2278
     2279                    OVFResourceType_T type = (OVFResourceType_T)0;      // if this becomes != 0 then we do stuff
     2280                    Utf8Str strResourceSubType;
     2281
     2282                    Utf8Str strDescription;                             // results in <rasd:Description>...</rasd:Description> block
     2283                    Utf8Str strCaption;                                 // results in <rasd:Caption>...</rasd:Caption> block
     2284
     2285                    uint32_t ulParent = 0;
     2286
     2287                    int32_t lVirtualQuantity = -1;
     2288                    Utf8Str strAllocationUnits;
     2289
     2290                    int32_t lAddress = -1;
     2291                    int32_t lBusNumber = -1;
     2292                    int32_t lAddressOnParent = -1;
     2293
     2294                    int32_t lAutomaticAllocation = -1;                  // 0 means "false", 1 means "true"
     2295                    Utf8Str strConnection;                              // results in <rasd:Connection>...</rasd:Connection> block
     2296                    Utf8Str strHostResource;
     2297
     2298                    uint64_t uTemp;
     2299
     2300                    switch (desc.type)
     2301                    {
     2302                        case VirtualSystemDescriptionType_CPU:
     2303                            /*  <Item>
     2304                                    <rasd:Caption>1 virtual CPU</rasd:Caption>
     2305                                    <rasd:Description>Number of virtual CPUs</rasd:Description>
     2306                                    <rasd:ElementName>virtual CPU</rasd:ElementName>
     2307                                    <rasd:InstanceID>1</rasd:InstanceID>
     2308                                    <rasd:ResourceType>3</rasd:ResourceType>
     2309                                    <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
     2310                                </Item> */
     2311                            if (uLoop == 1)
     2312                            {
     2313                                strDescription = "Number of virtual CPUs";
     2314                                type = OVFResourceType_Processor; // 3
     2315                                desc.strVbox.toInt(uTemp);
     2316                                lVirtualQuantity = uTemp;
     2317                                strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity);     // without this ovftool won't eat the item
     2318                            }
     2319                        break;
     2320
     2321                        case VirtualSystemDescriptionType_Memory:
     2322                            /*  <Item>
     2323                                    <rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
     2324                                    <rasd:Caption>256 MB of memory</rasd:Caption>
     2325                                    <rasd:Description>Memory Size</rasd:Description>
     2326                                    <rasd:ElementName>Memory</rasd:ElementName>
     2327                                    <rasd:InstanceID>2</rasd:InstanceID>
     2328                                    <rasd:ResourceType>4</rasd:ResourceType>
     2329                                    <rasd:VirtualQuantity>256</rasd:VirtualQuantity>
     2330                                </Item> */
     2331                            if (uLoop == 1)
     2332                            {
     2333                                strDescription = "Memory Size";
     2334                                type = OVFResourceType_Memory; // 4
     2335                                desc.strVbox.toInt(uTemp);
     2336                                lVirtualQuantity = (int32_t)(uTemp / _1M);
     2337                                strAllocationUnits = "MegaBytes";
     2338                                strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity);     // without this ovftool won't eat the item
     2339                            }
     2340                        break;
     2341
     2342                        case VirtualSystemDescriptionType_HardDiskControllerIDE:
     2343                            /* <Item>
     2344                                    <rasd:Caption>ideController1</rasd:Caption>
     2345                                    <rasd:Description>IDE Controller</rasd:Description>
     2346                                    <rasd:InstanceId>5</rasd:InstanceId>
     2347                                    <rasd:ResourceType>5</rasd:ResourceType>
     2348                                    <rasd:Address>1</rasd:Address>
     2349                                    <rasd:BusNumber>1</rasd:BusNumber>
     2350                                </Item> */
     2351                            if (uLoop == 1)
     2352                            {
     2353                                strDescription = "IDE Controller";
     2354                                strCaption = "ideController0";
     2355                                type = OVFResourceType_IDEController; // 5
     2356                                strResourceSubType = desc.strVbox;
     2357                                // it seems that OVFTool always writes these two, and since we can only
     2358                                // have one IDE controller, we'll use this as well
     2359                                lAddress = 1;
     2360                                lBusNumber = 1;
     2361
     2362                                // remember this ID
     2363                                idIDEController = ulInstanceID;
     2364                                lIDEControllerIndex = lIndexThis;
     2365                            }
     2366                        break;
     2367
     2368                        case VirtualSystemDescriptionType_HardDiskControllerSATA:
     2369                            /*  <Item>
     2370                                    <rasd:Caption>sataController0</rasd:Caption>
     2371                                    <rasd:Description>SATA Controller</rasd:Description>
     2372                                    <rasd:InstanceId>4</rasd:InstanceId>
     2373                                    <rasd:ResourceType>20</rasd:ResourceType>
     2374                                    <rasd:ResourceSubType>ahci</rasd:ResourceSubType>
     2375                                    <rasd:Address>0</rasd:Address>
     2376                                    <rasd:BusNumber>0</rasd:BusNumber>
     2377                                </Item>
     2378                            */
     2379                            if (uLoop == 1)
     2380                            {
     2381                                strDescription = "SATA Controller";
     2382                                strCaption = "sataController0";
     2383                                type = OVFResourceType_OtherStorageDevice; // 20
     2384                                // it seems that OVFTool always writes these two, and since we can only
     2385                                // have one SATA controller, we'll use this as well
     2386                                lAddress = 0;
     2387                                lBusNumber = 0;
     2388
     2389                                if (    desc.strVbox.isEmpty()      // AHCI is the default in VirtualBox
     2390                                     || (!desc.strVbox.compare("ahci", Utf8Str::CaseInsensitive))
     2391                                   )
     2392                                    strResourceSubType = "AHCI";
     2393                                else
     2394                                    throw setError(VBOX_E_NOT_SUPPORTED,
     2395                                                   tr("Invalid config string \"%s\" in SATA controller"), desc.strVbox.c_str());
     2396
     2397                                // remember this ID
     2398                                idSATAController = ulInstanceID;
     2399                                lSATAControllerIndex = lIndexThis;
     2400                            }
     2401                        break;
     2402
     2403                        case VirtualSystemDescriptionType_HardDiskControllerSCSI:
     2404                            /*  <Item>
     2405                                    <rasd:Caption>scsiController0</rasd:Caption>
     2406                                    <rasd:Description>SCSI Controller</rasd:Description>
     2407                                    <rasd:InstanceId>4</rasd:InstanceId>
     2408                                    <rasd:ResourceType>6</rasd:ResourceType>
     2409                                    <rasd:ResourceSubType>buslogic</rasd:ResourceSubType>
     2410                                    <rasd:Address>0</rasd:Address>
     2411                                    <rasd:BusNumber>0</rasd:BusNumber>
     2412                                </Item>
     2413                            */
     2414                            if (uLoop == 1)
     2415                            {
     2416                                strDescription = "SCSI Controller";
     2417                                strCaption = "scsiController0";
     2418                                type = OVFResourceType_ParallelSCSIHBA; // 6
     2419                                // it seems that OVFTool always writes these two, and since we can only
     2420                                // have one SATA controller, we'll use this as well
     2421                                lAddress = 0;
     2422                                lBusNumber = 0;
     2423
     2424                                if (    desc.strVbox.isEmpty()      // LsiLogic is the default in VirtualBox
     2425                                     || (!desc.strVbox.compare("lsilogic", Utf8Str::CaseInsensitive))
     2426                                   )
     2427                                    strResourceSubType = "lsilogic";
     2428                                else if (!desc.strVbox.compare("buslogic", Utf8Str::CaseInsensitive))
     2429                                    strResourceSubType = "buslogic";
     2430                                else
     2431                                    throw setError(VBOX_E_NOT_SUPPORTED,
     2432                                                   tr("Invalid config string \"%s\" in SCSI controller"), desc.strVbox.c_str());
     2433
     2434                                // remember this ID
     2435                                idSCSIController = ulInstanceID;
     2436                                lSCSIControllerIndex = lIndexThis;
     2437                            }
     2438                        break;
     2439
     2440                        case VirtualSystemDescriptionType_HardDiskImage:
     2441                            /*  <Item>
     2442                                    <rasd:Caption>disk1</rasd:Caption>
     2443                                    <rasd:InstanceId>8</rasd:InstanceId>
     2444                                    <rasd:ResourceType>17</rasd:ResourceType>
     2445                                    <rasd:HostResource>/disk/vmdisk1</rasd:HostResource>
     2446                                    <rasd:Parent>4</rasd:Parent>
     2447                                    <rasd:AddressOnParent>0</rasd:AddressOnParent>
     2448                                </Item> */
     2449                            if (uLoop == 2)
     2450                            {
     2451                                Utf8Str strDiskID = Utf8StrFmt("vmdisk%RI32", ++cDisks);
     2452
     2453                                strDescription = "Disk Image";
     2454                                strCaption = Utf8StrFmt("disk%RI32", cDisks);        // this is not used for anything else
     2455                                type = OVFResourceType_HardDisk; // 17
     2456
     2457                                // the following references the "<Disks>" XML block
     2458                                strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str());
     2459
     2460                                // controller=<index>;channel=<c>
     2461                                size_t pos1 = desc.strExtraConfig.find("controller=");
     2462                                size_t pos2 = desc.strExtraConfig.find("channel=");
     2463                                if (pos1 != Utf8Str::npos)
     2464                                {
     2465                                    int32_t lControllerIndex = -1;
     2466                                    RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos1 + 11, NULL, 0, &lControllerIndex);
     2467                                    if (lControllerIndex == lIDEControllerIndex)
     2468                                        ulParent = idIDEController;
     2469                                    else if (lControllerIndex == lSCSIControllerIndex)
     2470                                        ulParent = idSCSIController;
     2471                                    else if (lControllerIndex == lSATAControllerIndex)
     2472                                        ulParent = idSATAController;
     2473                                }
     2474                                if (pos2 != Utf8Str::npos)
     2475                                    RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos2 + 8, NULL, 0, &lAddressOnParent);
     2476
     2477                                if (    !ulParent
     2478                                     || lAddressOnParent == -1
     2479                                   )
     2480                                    throw setError(VBOX_E_NOT_SUPPORTED,
     2481                                                   tr("Missing or bad extra config string in hard disk image: \"%s\""), desc.strExtraConfig.c_str());
     2482
     2483                                mapDisks[strDiskID] = &desc;
     2484                            }
     2485                        break;
     2486
     2487                        case VirtualSystemDescriptionType_Floppy:
     2488                            if (uLoop == 1)
     2489                            {
     2490                                strDescription = "Floppy Drive";
     2491                                strCaption = "floppy0";         // this is what OVFTool writes
     2492                                type = OVFResourceType_FloppyDrive; // 14
     2493                                lAutomaticAllocation = 0;
     2494                                lAddressOnParent = 0;           // this is what OVFTool writes
     2495                            }
     2496                        break;
     2497
     2498                        case VirtualSystemDescriptionType_CDROM:
     2499                            if (uLoop == 2)
     2500                            {
     2501                                // we can't have a CD without an IDE controller
     2502                                if (!idIDEController)
     2503                                    throw setError(VBOX_E_NOT_SUPPORTED,
     2504                                                   tr("Can't have CD-ROM without IDE controller"));
     2505
     2506                                strDescription = "CD-ROM Drive";
     2507                                strCaption = "cdrom1";          // this is what OVFTool writes
     2508                                type = OVFResourceType_CDDrive; // 15
     2509                                lAutomaticAllocation = 1;
     2510                                ulParent = idIDEController;
     2511                                lAddressOnParent = 0;           // this is what OVFTool writes
     2512                            }
     2513                        break;
     2514
     2515                        case VirtualSystemDescriptionType_NetworkAdapter:
     2516                            /* <Item>
     2517                                    <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
     2518                                    <rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
     2519                                    <rasd:Connection>VM Network</rasd:Connection>
     2520                                    <rasd:ElementName>VM network</rasd:ElementName>
     2521                                    <rasd:InstanceID>3</rasd:InstanceID>
     2522                                    <rasd:ResourceType>10</rasd:ResourceType>
     2523                                </Item> */
     2524                            if (uLoop == 1)
     2525                            {
     2526                                lAutomaticAllocation = 1;
     2527                                strCaption = Utf8StrFmt("Ethernet adapter on '%s'", desc.strOvf.c_str());
     2528                                type = OVFResourceType_EthernetAdapter; // 10
     2529                                /* Set the hardware type to something useful.
     2530                                 * To be compatible with vmware & others we set
     2531                                 * PCNet32 for our PCNet types & E1000 for the
     2532                                 * E1000 cards. */
     2533                                switch (desc.strVbox.toInt32())
     2534                                {
     2535                                    case NetworkAdapterType_Am79C970A:
     2536                                    case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break;
     2537#ifdef VBOX_WITH_E1000
     2538                                    case NetworkAdapterType_I82540EM:
     2539                                    case NetworkAdapterType_I82545EM:
     2540                                    case NetworkAdapterType_I82543GC: strResourceSubType = "E1000"; break;
     2541#endif /* VBOX_WITH_E1000 */
     2542                                }
     2543                                strConnection = desc.strOvf;
     2544
     2545                                mapNetworks[desc.strOvf] = true;
     2546                            }
     2547                        break;
     2548
     2549                        case VirtualSystemDescriptionType_USBController:
     2550                            /*  <Item ovf:required="false">
     2551                                    <rasd:Caption>usb</rasd:Caption>
     2552                                    <rasd:Description>USB Controller</rasd:Description>
     2553                                    <rasd:InstanceId>3</rasd:InstanceId>
     2554                                    <rasd:ResourceType>23</rasd:ResourceType>
     2555                                    <rasd:Address>0</rasd:Address>
     2556                                    <rasd:BusNumber>0</rasd:BusNumber>
     2557                                </Item> */
     2558                            if (uLoop == 1)
     2559                            {
     2560                                strDescription = "USB Controller";
     2561                                strCaption = "usb";
     2562                                type = OVFResourceType_USBController; // 23
     2563                                lAddress = 0;                   // this is what OVFTool writes
     2564                                lBusNumber = 0;                 // this is what OVFTool writes
     2565                            }
     2566                        break;
     2567
     2568                       case VirtualSystemDescriptionType_SoundCard:
     2569                        /*  <Item ovf:required="false">
     2570                                <rasd:Caption>sound</rasd:Caption>
     2571                                <rasd:Description>Sound Card</rasd:Description>
     2572                                <rasd:InstanceId>10</rasd:InstanceId>
     2573                                <rasd:ResourceType>35</rasd:ResourceType>
     2574                                <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
     2575                                <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
     2576                                <rasd:AddressOnParent>3</rasd:AddressOnParent>
     2577                            </Item> */
     2578                            if (uLoop == 1)
     2579                            {
     2580                                strDescription = "Sound Card";
     2581                                strCaption = "sound";
     2582                                type = OVFResourceType_SoundCard; // 35
     2583                                strResourceSubType = desc.strOvf;       // e.g. ensoniq1371
     2584                                lAutomaticAllocation = 0;
     2585                                lAddressOnParent = 3;               // what gives? this is what OVFTool writes
     2586                            }
     2587                        break;
     2588                    }
     2589
     2590                    if (type)
     2591                    {
     2592                        xml::ElementNode *pItem;
     2593
     2594                        pItem = pelmVirtualHardwareSection->createChild("Item");
     2595
     2596                        // NOTE: do not change the order of these items without good reason! While we don't care
     2597                        // about ordering, VMware's ovftool does and fails if the items are not written in
     2598                        // exactly this order, as stupid as it seems.
     2599
     2600                        if (!strCaption.isEmpty())
     2601                        {
     2602                            pItem->createChild("rasd:Caption")->addContent(strCaption);
     2603                            if (pTask->enFormat == TaskExportOVF::OVF_1_0)
     2604                                pItem->createChild("rasd:ElementName")->addContent(strCaption);
     2605                        }
     2606
     2607                        if (!strDescription.isEmpty())
     2608                            pItem->createChild("rasd:Description")->addContent(strDescription);
     2609
     2610                        // <rasd:InstanceID>1</rasd:InstanceID>
     2611                        xml::ElementNode *pelmInstanceID;
     2612                        if (pTask->enFormat == TaskExportOVF::OVF_0_9)
     2613                            pelmInstanceID = pItem->createChild("rasd:InstanceId");
     2614                        else
     2615                            pelmInstanceID = pItem->createChild("rasd:InstanceID");      // capitalization changed...
     2616                        pelmInstanceID->addContent(Utf8StrFmt("%d", ulInstanceID++));
     2617
     2618                        // <rasd:ResourceType>3</rasd:ResourceType>
     2619                        pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type));
     2620                        if (!strResourceSubType.isEmpty())
     2621                            pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType);
     2622
     2623                        if (!strHostResource.isEmpty())
     2624                            pItem->createChild("rasd:HostResource")->addContent(strHostResource);
     2625
     2626                        if (!strAllocationUnits.isEmpty())
     2627                            pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits);
     2628
     2629                        // <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
     2630                        if (lVirtualQuantity != -1)
     2631                            pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity));
     2632
     2633                        if (lAutomaticAllocation != -1)
     2634                            pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" );
     2635
     2636                        if (!strConnection.isEmpty())
     2637                            pItem->createChild("rasd:Connection")->addContent(strConnection);
     2638
     2639                        if (lAddress != -1)
     2640                            pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress));
     2641
     2642                        if (lBusNumber != -1)
     2643                            if (pTask->enFormat == TaskExportOVF::OVF_0_9) // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool compatibility
     2644                                pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber));
     2645
     2646                        if (ulParent)
     2647                            pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent));
     2648                        if (lAddressOnParent != -1)
     2649                            pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent));
     2650                    }
     2651                }
     2652            } // for (size_t uLoop = 0; ...
     2653        }
     2654
     2655        // finally, fill in the network section we set up empty above according
     2656        // to the networks we found with the hardware items
     2657        map<Utf8Str, bool>::const_iterator itN;
     2658        for (itN = mapNetworks.begin();
     2659             itN != mapNetworks.end();
     2660             ++itN)
     2661        {
     2662            const Utf8Str &strNetwork = itN->first;
     2663            xml::ElementNode *pelmNetwork = pelmNetworkSection->createChild("Network");
     2664            pelmNetwork->setAttribute("ovf:name", strNetwork.c_str());
     2665            pelmNetwork->createChild("Description")->addContent("Logical network used by this appliance.");
     2666        }
     2667
     2668        map<Utf8Str, const VirtualSystemDescriptionEntry*>::const_iterator itS;
     2669        uint32_t ulFile = 1;
     2670        for (itS = mapDisks.begin();
     2671             itS != mapDisks.end();
     2672             ++itS)
     2673        {
     2674            const Utf8Str &strDiskID = itS->first;
     2675            const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
     2676
     2677            // source path: where the VBox image is
     2678            const Utf8Str &strSrcFilePath = pDiskEntry->strVbox;
     2679            Bstr bstrSrcFilePath(strSrcFilePath);
     2680            if (!RTPathExists(strSrcFilePath.c_str()))
     2681                /* This isn't allowed */
     2682                throw setError(VBOX_E_FILE_ERROR,
     2683                               tr("Source virtual disk image file '%s' doesn't exist"),
     2684                               strSrcFilePath.c_str());
     2685
     2686            // output filename
     2687            const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
     2688            // target path needs to be composed from where the output OVF is
     2689            Utf8Str strTargetFilePath(pTask->locInfo.strPath);
     2690            strTargetFilePath.stripFilename();
     2691            strTargetFilePath.append("/");
     2692            strTargetFilePath.append(strTargetFileNameOnly);
     2693
     2694            // clone the disk:
     2695            ComPtr<IHardDisk> pSourceDisk;
     2696            ComPtr<IHardDisk> pTargetDisk;
     2697            ComPtr<IProgress> pProgress2;
     2698
     2699            Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
     2700            rc = mVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());
     2701            if (FAILED(rc)) throw rc;
     2702
     2703            /* We are always exporting to vmdfk stream optimized for now */
     2704            Bstr bstrSrcFormat = L"VMDK";
     2705
     2706            // create a new hard disk interface for the destination disk image
     2707            Log(("Creating target disk \"%s\"\n", strTargetFilePath.raw()));
     2708            rc = mVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam());
     2709            if (FAILED(rc)) throw rc;
     2710
     2711            // the target disk is now registered and needs to be removed again,
     2712            // both after successful cloning or if anything goes bad!
     2713            try
     2714            {
     2715                // create a flat copy of the source disk image
     2716                rc = pSourceDisk->CloneTo(pTargetDisk, HardDiskVariant_VmdkStreamOptimized, NULL, pProgress2.asOutParam());
     2717                if (FAILED(rc)) throw rc;
     2718
     2719                // advance to the next operation
     2720                if (!pTask->progress.isNull())
     2721                    pTask->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),
     2722                                                     pDiskEntry->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
     2723
     2724                // now wait for the background disk operation to complete; this throws HRESULTs on error
     2725                waitForAsyncProgress(pTask->progress, pProgress2);
     2726            }
     2727            catch (HRESULT rc3)
     2728            {
     2729                // upon error after registering, close the disk or
     2730                // it'll stick in the registry forever
     2731                pTargetDisk->Close();
     2732                throw;
     2733            }
     2734
     2735            // we need the following for the XML
     2736            uint64_t cbFile = 0;        // actual file size
     2737            rc = pTargetDisk->COMGETTER(Size)(&cbFile);
     2738            if (FAILED(rc)) throw rc;
     2739
     2740            ULONG64 cbCapacity = 0;     // size reported to guest
     2741            rc = pTargetDisk->COMGETTER(LogicalSize)(&cbCapacity);
     2742            if (FAILED(rc)) throw rc;
     2743            // capacity is reported in megabytes, so...
     2744            cbCapacity *= _1M;
     2745
     2746            // upon success, close the disk as well
     2747            rc = pTargetDisk->Close();
     2748            if (FAILED(rc)) throw rc;
     2749
     2750            // now handle the XML for the disk:
     2751            Utf8StrFmt strFileRef("file%RI32", ulFile++);
     2752            // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
     2753            xml::ElementNode *pelmFile = pelmReferences->createChild("File");
     2754            pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
     2755            pelmFile->setAttribute("ovf:id", strFileRef);
     2756            pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
     2757
     2758            // add disk to XML Disks section
     2759            // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse"/>
     2760            xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
     2761            pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
     2762            pelmDisk->setAttribute("ovf:diskId", strDiskID);
     2763            pelmDisk->setAttribute("ovf:fileRef", strFileRef);
     2764            pelmDisk->setAttribute("ovf:format", "http://www.vmware.com/specifications/vmdk.html#sparse");      // must be sparse or ovftool chokes
     2765        }
     2766
     2767        // now go write the XML
     2768        xml::XmlFileWriter writer(doc);
     2769        writer.write(pTask->locInfo.strPath.c_str());
     2770    }
     2771    catch(xml::Error &x)
     2772    {
     2773        rc = setError(VBOX_E_FILE_ERROR,
     2774                      x.what());
     2775    }
     2776    catch(HRESULT aRC)
     2777    {
     2778        rc = aRC;
     2779    }
     2780
     2781    pTask->rc = rc;
     2782
     2783    if (!pTask->progress.isNull())
     2784        pTask->progress->notifyComplete(rc);
     2785
     2786    LogFlowFunc(("rc=%Rhrc\n", rc));
     2787    LogFlowFuncLeave();
     2788
     2789    return VINF_SUCCESS;
     2790}
     2791
     2792int Appliance::writeS3(TaskExportOVF *pTask)
     2793{
     2794    LogFlowFuncEnter();
     2795    LogFlowFunc(("Appliance %p\n", this));
     2796
     2797    AutoCaller autoCaller(this);
     2798    CheckComRCReturnRC(autoCaller.rc());
     2799
     2800    HRESULT rc = S_OK;
     2801
     2802    AutoWriteLock appLock(this);
     2803
     2804    int vrc = VINF_SUCCESS;
     2805    RTS3 hS3 = NIL_RTS3;
     2806    char szOSTmpDir[RTPATH_MAX];
     2807    RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
     2808    /* The template for the temporary directory created below */
     2809    char *pszTmpDir;
     2810    RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
     2811    list< pair<Utf8Str, ULONG> > filesList;
     2812
     2813    // todo:
     2814    // - usable error codes
     2815    // - seems snapshot filenames are problematic {uuid}.vdi
     2816    try
     2817    {
     2818        /* Extract the bucket */
     2819        Utf8Str tmpPath = pTask->locInfo.strPath;
     2820        Utf8Str bucket;
     2821        parseBucket(tmpPath, bucket);
     2822
     2823        /* We need a temporary directory which we can put the OVF file & all
     2824         * disk images in */
     2825        vrc = RTDirCreateTemp(pszTmpDir);
     2826        if (RT_FAILURE(rc))
     2827            throw setError(VBOX_E_FILE_ERROR,
     2828                           tr("Cannot create temporary directory '%s'"), pszTmpDir);
     2829
     2830        /* The temporary name of the target OVF file */
     2831        Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath));
     2832
     2833        /* Prepare the temporary writing of the OVF */
     2834        ComObjPtr<Progress> progress;
     2835        /* Create a temporary file based location info for the sub task */
     2836        LocationInfo li;
     2837        li.strPath = strTmpOvf;
     2838        rc = writeImpl(pTask->enFormat, li, progress);
     2839        if (FAILED(rc)) throw rc;
     2840
     2841        /* Unlock the appliance for the writing thread */
     2842        appLock.unlock();
     2843        /* Wait until the writing is done, but report the progress back to the
     2844           caller */
     2845        ComPtr<IProgress> progressInt(progress);
     2846        waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
     2847
     2848        /* Again lock the appliance for the next steps */
     2849        appLock.lock();
     2850
     2851        vrc = RTPathExists(strTmpOvf.c_str()); /* Paranoid check */
     2852        if(RT_FAILURE(vrc))
     2853            throw setError(VBOX_E_FILE_ERROR,
     2854                           tr("Cannot find source file '%s'"), strTmpOvf.c_str());
     2855        /* Add the OVF file */
     2856        filesList.push_back(pair<Utf8Str, ULONG>(strTmpOvf, m->ulWeightPerOperation)); /* Use 1% of the total for the OVF file upload */
     2857
     2858        /* Now add every disks of every virtual system */
     2859        list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
     2860        for (it = m->virtualSystemDescriptions.begin();
     2861             it != m->virtualSystemDescriptions.end();
     2862             ++it)
     2863        {
     2864            ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
     2865            std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
     2866            std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
     2867            for (itH = avsdeHDs.begin();
     2868                 itH != avsdeHDs.end();
     2869                 ++itH)
     2870            {
     2871                const Utf8Str &strTargetFileNameOnly = (*itH)->strOvf;
     2872                /* Target path needs to be composed from where the output OVF is */
     2873                Utf8Str strTargetFilePath(strTmpOvf);
     2874                strTargetFilePath.stripFilename();
     2875                strTargetFilePath.append("/");
     2876                strTargetFilePath.append(strTargetFileNameOnly);
     2877                vrc = RTPathExists(strTargetFilePath.c_str()); /* Paranoid check */
     2878                if(RT_FAILURE(vrc))
     2879                    throw setError(VBOX_E_FILE_ERROR,
     2880                                   tr("Cannot find source file '%s'"), strTargetFilePath.c_str());
     2881                filesList.push_back(pair<Utf8Str, ULONG>(strTargetFilePath, (*itH)->ulSizeMB));
     2882            }
     2883        }
     2884        /* Next we have to upload the OVF & all disk images */
     2885        vrc = RTS3Create(&hS3, pTask->locInfo.strUsername.c_str(), pTask->locInfo.strPassword.c_str(), pTask->locInfo.strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
     2886        if(RT_FAILURE(vrc))
     2887            throw setError(VBOX_E_IPRT_ERROR,
     2888                           tr("Cannot create S3 service handler"));
     2889        RTS3SetProgressCallback(hS3, pTask->updateProgress, &pTask);
     2890
     2891        /* Upload all files */
     2892        for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
     2893        {
     2894            const pair<Utf8Str, ULONG> &s = (*it1);
     2895            char *pszFilename = RTPathFilename(s.first.c_str());
     2896            /* Advance to the next operation */
     2897            if (!pTask->progress.isNull())
     2898                pTask->progress->setNextOperation(BstrFmt(tr("Uploading file '%s'"), pszFilename), s.second);
     2899            vrc = RTS3PutKey(hS3, bucket.c_str(), pszFilename, s.first.c_str());
     2900            if (RT_FAILURE(vrc))
     2901            {
     2902                if(vrc == VERR_S3_CANCELED)
     2903                    break;
     2904                else if(vrc == VERR_S3_ACCESS_DENIED)
     2905                    throw setError(E_ACCESSDENIED,
     2906                                   tr("Cannot upload file '%s' to S3 storage server (Access denied)"), pszFilename);
     2907                else if(vrc == VERR_S3_NOT_FOUND)
     2908                    throw setError(VBOX_E_FILE_ERROR,
     2909                                   tr("Cannot upload file '%s' to S3 storage server (File not found)"), pszFilename);
     2910                else
     2911                    throw setError(VBOX_E_IPRT_ERROR,
     2912                                   tr("Cannot upload file '%s' to S3 storage server (%Rrc)"), pszFilename, vrc);
     2913            }
     2914        }
     2915    }
     2916    catch(HRESULT aRC)
     2917    {
     2918        rc = aRC;
     2919    }
     2920    /* Cleanup */
     2921    RTS3Destroy(hS3);
     2922    /* Delete all files which where temporary created */
     2923    for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
     2924    {
     2925        const char *pszFilePath = (*it1).first.c_str();
     2926        if (RTPathExists(pszFilePath))
     2927        {
     2928            vrc = RTFileDelete(pszFilePath);
     2929            if(RT_FAILURE(vrc))
     2930                rc = setError(VBOX_E_FILE_ERROR,
     2931                              tr("Cannot delete file '%s' (%Rrc)"), pszFilePath, vrc);
     2932        }
     2933    }
     2934    /* Delete the temporary directory */
     2935    if (RTPathExists(pszTmpDir))
     2936    {
     2937        vrc = RTDirRemove(pszTmpDir);
     2938        if(RT_FAILURE(vrc))
     2939            rc = setError(VBOX_E_FILE_ERROR,
     2940                          tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
     2941    }
     2942    if (pszTmpDir)
     2943        RTStrFree(pszTmpDir);
     2944
     2945    pTask->rc = rc;
     2946
     2947    if (!pTask->progress.isNull())
     2948        pTask->progress->notifyComplete(rc);
     2949
     2950    LogFlowFunc(("rc=%Rhrc\n", rc));
     2951    LogFlowFuncLeave();
     2952
     2953    return VINF_SUCCESS;
     2954}
     2955
     2956////////////////////////////////////////////////////////////////////////////////
     2957//
    3412958// IAppliance public methods
    3422959//
     
    3582975    AutoReadLock alock(this);
    3592976
    360     if (m->pReader)     // OVFReader instantiated?
    361     {
    362         Bstr bstrPath(m->pReader->m_strPath);
    363         bstrPath.cloneTo(aPath);
    364     }
    365     else
    366         Bstr("").cloneTo(aPath);
     2977    Bstr bstrPath(m->locInfo.strPath);
     2978    bstrPath.cloneTo(aPath);
    3672979
    3682980    return S_OK;
     
    3913003        size_t i = 0;
    3923004        for (it = m->pReader->m_mapDisks.begin();
    393             it != m->pReader->m_mapDisks.end();
    394             ++it, ++i)
     3005             it != m->pReader->m_mapDisks.end();
     3006             ++it, ++i)
    3953007        {
    3963008            // create a string representing this disk
     
    3983010            char *psz = NULL;
    3993011            RTStrAPrintf(&psz,
    400                         "%s\t"
    401                         "%RI64\t"
    402                         "%RI64\t"
    403                         "%s\t"
    404                         "%s\t"
    405                         "%RI64\t"
    406                         "%RI64\t"
    407                         "%s",
    408                         d.strDiskId.c_str(),
    409                         d.iCapacity,
    410                         d.iPopulatedSize,
    411                         d.strFormat.c_str(),
    412                         d.strHref.c_str(),
    413                         d.iSize,
    414                         d.iChunkSize,
    415                         d.strCompression.c_str());
     3012                         "%s\t"
     3013                         "%RI64\t"
     3014                         "%RI64\t"
     3015                         "%s\t"
     3016                         "%s\t"
     3017                         "%RI64\t"
     3018                         "%RI64\t"
     3019                         "%s",
     3020                         d.strDiskId.c_str(),
     3021                         d.iCapacity,
     3022                         d.iPopulatedSize,
     3023                         d.strFormat.c_str(),
     3024                         d.strHref.c_str(),
     3025                         d.iSize,
     3026                         d.iChunkSize,
     3027                         d.strCompression.c_str());
    4163028            Utf8Str utf(psz);
    4173029            Bstr bstr(utf);
     
    4523064 * @return
    4533065 */
    454 STDMETHODIMP Appliance::Read(IN_BSTR path)
    455 {
    456     if (!path)
    457         return E_POINTER;
     3066STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress)
     3067{
     3068    if (!path) return E_POINTER;
     3069    CheckComArgOutPointerValid(aProgress);
    4583070
    4593071    AutoCaller autoCaller(this);
     
    4633075
    4643076    if (m->pReader)
    465     {
    466         delete m->pReader;
    467         m->pReader = NULL;
    468     }
    469 
    470     Utf8Str strPath(path);
     3077        {
     3078            delete m->pReader;
     3079            m->pReader = NULL;
     3080        }
     3081
    4713082    // see if we can handle this file; for now we insist it has an ".ovf" extension
     3083    Utf8Str strPath (path);
    4723084    if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    4733085        return setError(VBOX_E_FILE_ERROR,
    4743086                        tr("Appliance file must have .ovf extension"));
    4753087
     3088    ComObjPtr<Progress> progress;
     3089    HRESULT rc = S_OK;
    4763090    try
    4773091    {
    478         m->pReader = new OVFReader(strPath);
    479     }
    480     catch(xml::Error &x)
    481     {
    482         return setError(VBOX_E_FILE_ERROR,
    483                         x.what());
    484     }
     3092        /* Parse all necessary info out of the URI */
     3093        parseURI(strPath, m->locInfo);
     3094        rc = readImpl(m->locInfo, progress);
     3095    }
     3096    catch (HRESULT aRC)
     3097    {
     3098        rc = aRC;
     3099    }
     3100
     3101    if (SUCCEEDED(rc))
     3102        /* Return progress to the caller */
     3103        progress.queryInterfaceTo(aProgress);
    4853104
    4863105    return S_OK;
     
    9363555}
    9373556
    938 struct Appliance::TaskImportMachines
    939 {
    940     TaskImportMachines(Appliance *aThat, Progress *aProgress)
    941         : pAppliance(aThat)
    942         , progress(aProgress)
    943         , rc(S_OK)
    944     {}
    945     ~TaskImportMachines() {}
    946 
    947     HRESULT startThread();
    948 
    949     Appliance *pAppliance;
    950     ComObjPtr<Progress> progress;
    951     HRESULT rc;
    952 };
    953 
    954 HRESULT Appliance::TaskImportMachines::startThread()
    955 {
    956     int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportMachines, this,
    957                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    958                              "Appliance::Task");
    959     ComAssertMsgRCRet(vrc,
    960                       ("Could not create taskThreadImportMachines (%Rrc)\n", vrc), E_FAIL);
    961 
    962     return S_OK;
    963 }
    964 
    9653557/**
    9663558 * Public method implementation.
     
    9773569    AutoReadLock(this);
    9783570
    979     HRESULT rc = S_OK;
    980 
    9813571    if (!m->pReader)
    9823572        return setError(E_FAIL,
     
    9843574
    9853575    ComObjPtr<Progress> progress;
     3576    HRESULT rc = S_OK;
    9863577    try
    9873578    {
    988         Bstr progressDesc = BstrFmt(tr("Import appliance '%s'"),
    989                                        m->pReader->m_strPath.raw());
    990         rc = setUpProgress(progress, progressDesc);
    991         if (FAILED(rc)) throw rc;
    992 
    993         /* Initialize our worker task */
    994         std::auto_ptr<TaskImportMachines> task(new TaskImportMachines(this, progress));
    995         //AssertComRCThrowRC (task->autoCaller.rc());
    996 
    997         rc = task->startThread();
    998         if (FAILED(rc)) throw rc;
    999 
    1000         task.release();
     3579        rc = importImpl(m->locInfo, progress);
    10013580    }
    10023581    catch (HRESULT aRC)
     
    10123591}
    10133592
    1014 struct MyHardDiskAttachment
    1015 {
    1016     Guid    uuid;
    1017     ComPtr<IMachine> pMachine;
    1018     Bstr    controllerType;
    1019     int32_t lChannel;
    1020     int32_t lDevice;
    1021 };
    1022 
    1023 /**
    1024  * Worker thread implementation for ImportMachines().
    1025  * @param aThread
    1026  * @param pvUser
    1027  */
    1028 /* static */
    1029 DECLCALLBACK(int) Appliance::taskThreadImportMachines(RTTHREAD /* aThread */, void *pvUser)
    1030 {
    1031     std::auto_ptr<TaskImportMachines> task(static_cast<TaskImportMachines*>(pvUser));
    1032     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    1033 
    1034     Appliance *pAppliance = task->pAppliance;
    1035 
    1036     LogFlowFuncEnter();
    1037     LogFlowFunc(("Appliance %p\n", pAppliance));
    1038 
    1039     AutoCaller autoCaller(pAppliance);
    1040     CheckComRCReturnRC(autoCaller.rc());
    1041 
    1042     AutoWriteLock appLock(pAppliance);
    1043 
    1044     HRESULT rc = S_OK;
    1045 
    1046     ComPtr<IVirtualBox> pVirtualBox(pAppliance->mVirtualBox);
    1047 
    1048     // rollback for errors:
    1049     // a list of images that we created/imported
    1050     list<MyHardDiskAttachment> llHardDiskAttachments;
    1051     list< ComPtr<IHardDisk> > llHardDisksCreated;
    1052     list<Guid> llMachinesRegistered;
    1053 
    1054     ComPtr<ISession> session;
    1055     bool fSessionOpen = false;
    1056     rc = session.createInprocObject(CLSID_Session);
    1057     CheckComRCReturnRC(rc);
    1058 
    1059     const OVFReader reader = *pAppliance->m->pReader;
    1060             // this is safe to access because this thread only gets started
    1061             // if pReader != NULL
    1062 
    1063     list<VirtualSystem>::const_iterator it;
    1064     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
    1065     /* Iterate through all virtual systems of that appliance */
    1066     size_t i = 0;
    1067     for (it = reader.m_llVirtualSystems.begin(),
    1068             it1 = pAppliance->m->virtualSystemDescriptions.begin();
    1069          it != reader.m_llVirtualSystems.end();
    1070          ++it, ++it1, ++i)
    1071     {
    1072         const VirtualSystem &vsysThis = *it;
    1073         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it1);
    1074 
    1075         ComPtr<IMachine> pNewMachine;
    1076 
    1077         /* Catch possible errors */
    1078         try
    1079         {
    1080             /* Guest OS type */
    1081             std::list<VirtualSystemDescriptionEntry*> vsdeOS;
    1082             vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
    1083             if (vsdeOS.size() < 1)
    1084                 throw setError(VBOX_E_FILE_ERROR,
    1085                                tr("Missing guest OS type"));
    1086             const Utf8Str &strOsTypeVBox = vsdeOS.front()->strVbox;
    1087 
    1088             /* Now that we know the base system get our internal defaults based on that. */
    1089             ComPtr<IGuestOSType> osType;
    1090             rc = pVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam());
    1091             if (FAILED(rc)) throw rc;
    1092 
    1093             /* Create the machine */
    1094             /* First get the name */
    1095             std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
    1096             if (vsdeName.size() < 1)
    1097                 throw setError(VBOX_E_FILE_ERROR,
    1098                                tr("Missing VM name"));
    1099             const Utf8Str &strNameVBox = vsdeName.front()->strVbox;
    1100             rc = pVirtualBox->CreateMachine(Bstr(strNameVBox), Bstr(strOsTypeVBox),
    1101                                                  Bstr(), Bstr(),
    1102                                                  pNewMachine.asOutParam());
    1103             if (FAILED(rc)) throw rc;
    1104 
    1105             // and the description
    1106             std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
    1107             if (vsdeDescription.size())
    1108             {
    1109                 const Utf8Str &strDescription = vsdeDescription.front()->strVbox;
    1110                 rc = pNewMachine->COMSETTER(Description)(Bstr(strDescription));
    1111                 if (FAILED(rc)) throw rc;
    1112             }
    1113 
    1114             /* CPU count */
    1115             std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType (VirtualSystemDescriptionType_CPU);
    1116             ComAssertMsgThrow(vsdeCPU.size() == 1, ("CPU count missing"), E_FAIL);
    1117             const Utf8Str &cpuVBox = vsdeCPU.front()->strVbox;
    1118             ULONG tmpCount = (ULONG)RTStrToUInt64(cpuVBox.c_str());
    1119             rc = pNewMachine->COMSETTER(CPUCount)(tmpCount);
    1120             if (FAILED(rc)) throw rc;
    1121             bool fEnableIOApic = false;
    1122             /* We need HWVirt & IO-APIC if more than one CPU is requested */
    1123             if (tmpCount > 1)
    1124             {
    1125                 rc = pNewMachine->COMSETTER(HWVirtExEnabled)(TRUE);
    1126                 if (FAILED(rc)) throw rc;
    1127 
    1128                 fEnableIOApic = true;
    1129             }
    1130 
    1131             /* RAM */
    1132             std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
    1133             ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL);
    1134             const Utf8Str &memoryVBox = vsdeRAM.front()->strVbox;
    1135             ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str());
    1136             rc = pNewMachine->COMSETTER(MemorySize)(tt);
    1137             if (FAILED(rc)) throw rc;
    1138 
    1139             /* VRAM */
    1140             /* Get the recommended VRAM for this guest OS type */
    1141             ULONG vramVBox;
    1142             rc = osType->COMGETTER(RecommendedVRAM)(&vramVBox);
    1143             if (FAILED(rc)) throw rc;
    1144 
    1145             /* Set the VRAM */
    1146             rc = pNewMachine->COMSETTER(VRAMSize)(vramVBox);
    1147             if (FAILED(rc)) throw rc;
    1148 
    1149             /* I/O APIC: so far we have no setting for this. Enable it if we
    1150               import a Windows VM because if if Windows was installed without IOAPIC,
    1151               it will not mind finding an one later on, but if Windows was installed
    1152               _with_ an IOAPIC, it will bluescreen if it's not found */
    1153             Bstr bstrFamilyId;
    1154             rc = osType->COMGETTER(FamilyId)(bstrFamilyId.asOutParam());
    1155             if (FAILED(rc)) throw rc;
    1156 
    1157             Utf8Str strFamilyId(bstrFamilyId);
    1158             if (strFamilyId == "Windows")
    1159                 fEnableIOApic = true;
    1160 
    1161             /* If IP-APIC should be enabled could be have different reasons.
    1162                See CPU count & the Win test above. Here we enable it if it was
    1163                previously requested. */
    1164             if (fEnableIOApic)
    1165             {
    1166                 ComPtr<IBIOSSettings> pBIOSSettings;
    1167                 rc = pNewMachine->COMGETTER(BIOSSettings)(pBIOSSettings.asOutParam());
    1168                 if (FAILED(rc)) throw rc;
    1169 
    1170                 rc = pBIOSSettings->COMSETTER(IOAPICEnabled)(TRUE);
    1171                 if (FAILED(rc)) throw rc;
    1172             }
    1173 
    1174             /* Audio Adapter */
    1175             std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
    1176             /* @todo: we support one audio adapter only */
    1177             if (vsdeAudioAdapter.size() > 0)
    1178             {
    1179                 const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strVbox;
    1180                 if (audioAdapterVBox.compare("null", Utf8Str::CaseInsensitive) != 0)
    1181                 {
    1182                     uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str());
    1183                     ComPtr<IAudioAdapter> audioAdapter;
    1184                     rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
    1185                     if (FAILED(rc)) throw rc;
    1186                     rc = audioAdapter->COMSETTER(Enabled)(true);
    1187                     if (FAILED(rc)) throw rc;
    1188                     rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio));
    1189                     if (FAILED(rc)) throw rc;
    1190                 }
    1191             }
    1192 
    1193 #ifdef VBOX_WITH_USB
    1194             /* USB Controller */
    1195             std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
    1196             // USB support is enabled if there's at least one such entry; to disable USB support,
    1197             // the type of the USB item would have been changed to "ignore"
    1198             bool fUSBEnabled = vsdeUSBController.size() > 0;
    1199 
    1200             ComPtr<IUSBController> usbController;
    1201             rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
    1202             if (FAILED(rc)) throw rc;
    1203             rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
    1204             if (FAILED(rc)) throw rc;
    1205 #endif /* VBOX_WITH_USB */
    1206 
    1207             /* Change the network adapters */
    1208             std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
    1209             if (vsdeNW.size() == 0)
    1210             {
    1211                 /* No network adapters, so we have to disable our default one */
    1212                 ComPtr<INetworkAdapter> nwVBox;
    1213                 rc = pNewMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
    1214                 if (FAILED(rc)) throw rc;
    1215                 rc = nwVBox->COMSETTER(Enabled)(false);
    1216                 if (FAILED(rc)) throw rc;
    1217             }
    1218             else
    1219             {
    1220                 list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
    1221                 /* Iterate through all network cards. We support 8 network adapters
    1222                  * at the maximum. (@todo: warn if there are more!) */
    1223                 size_t a = 0;
    1224                 for (nwIt = vsdeNW.begin();
    1225                      (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
    1226                      ++nwIt, ++a)
    1227                 {
    1228                     const VirtualSystemDescriptionEntry* pvsys = *nwIt;
    1229 
    1230                     const Utf8Str &nwTypeVBox = pvsys->strVbox;
    1231                     uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
    1232                     ComPtr<INetworkAdapter> pNetworkAdapter;
    1233                     rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam());
    1234                     if (FAILED(rc)) throw rc;
    1235                     /* Enable the network card & set the adapter type */
    1236                     rc = pNetworkAdapter->COMSETTER(Enabled)(true);
    1237                     if (FAILED(rc)) throw rc;
    1238                     rc = pNetworkAdapter->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
    1239                     if (FAILED(rc)) throw rc;
    1240 
    1241                     // default is NAT; change to "bridged" if extra conf says so
    1242                     if (!pvsys->strExtraConfig.compare("type=Bridged", Utf8Str::CaseInsensitive))
    1243                     {
    1244                         /* Attach to the right interface */
    1245                         rc = pNetworkAdapter->AttachToBridgedInterface();
    1246                         if (FAILED(rc)) throw rc;
    1247                         ComPtr<IHost> host;
    1248                         rc = pVirtualBox->COMGETTER(Host)(host.asOutParam());
    1249                         if (FAILED(rc)) throw rc;
    1250                         com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
    1251                         rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
    1252                         if (FAILED(rc)) throw rc;
    1253                         /* We search for the first host network interface which
    1254                          * is usable for bridged networking */
    1255                         for (size_t i=0; i < nwInterfaces.size(); ++i)
    1256                         {
    1257                             HostNetworkInterfaceType_T itype;
    1258                             rc = nwInterfaces[i]->COMGETTER(InterfaceType)(&itype);
    1259                             if (FAILED(rc)) throw rc;
    1260                             if (itype == HostNetworkInterfaceType_Bridged)
    1261                             {
    1262                                 Bstr name;
    1263                                 rc = nwInterfaces[i]->COMGETTER(Name)(name.asOutParam());
    1264                                 if (FAILED(rc)) throw rc;
    1265                                 /* Set the interface name to attach to */
    1266                                 pNetworkAdapter->COMSETTER(HostInterface)(name);
    1267                                 if (FAILED(rc)) throw rc;
    1268                                 break;
    1269                             }
    1270                         }
    1271                     }
    1272                     /* Next test for host only interfaces */
    1273                     else if (!pvsys->strExtraConfig.compare("type=HostOnly", Utf8Str::CaseInsensitive))
    1274                     {
    1275                         /* Attach to the right interface */
    1276                         rc = pNetworkAdapter->AttachToHostOnlyInterface();
    1277                         if (FAILED(rc)) throw rc;
    1278                         ComPtr<IHost> host;
    1279                         rc = pVirtualBox->COMGETTER(Host)(host.asOutParam());
    1280                         if (FAILED(rc)) throw rc;
    1281                         com::SafeIfaceArray<IHostNetworkInterface> nwInterfaces;
    1282                         rc = host->COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(nwInterfaces));
    1283                         if (FAILED(rc)) throw rc;
    1284                         /* We search for the first host network interface which
    1285                          * is usable for host only networking */
    1286                         for (size_t i=0; i < nwInterfaces.size(); ++i)
    1287                         {
    1288                             HostNetworkInterfaceType_T itype;
    1289                             rc = nwInterfaces[i]->COMGETTER(InterfaceType)(&itype);
    1290                             if (FAILED(rc)) throw rc;
    1291                             if (itype == HostNetworkInterfaceType_HostOnly)
    1292                             {
    1293                                 Bstr name;
    1294                                 rc = nwInterfaces[i]->COMGETTER(Name)(name.asOutParam());
    1295                                 if (FAILED(rc)) throw rc;
    1296                                 /* Set the interface name to attach to */
    1297                                 pNetworkAdapter->COMSETTER(HostInterface)(name);
    1298                                 if (FAILED(rc)) throw rc;
    1299                                 break;
    1300                             }
    1301                         }
    1302                     }
    1303                 }
    1304             }
    1305 
    1306             /* Floppy drive */
    1307             std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
    1308             // Floppy support is enabled if there's at least one such entry; to disable floppy support,
    1309             // the type of the floppy item would have been changed to "ignore"
    1310             bool fFloppyEnabled = vsdeFloppy.size() > 0;
    1311             ComPtr<IFloppyDrive> floppyDrive;
    1312             rc = pNewMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
    1313             if (FAILED(rc)) throw rc;
    1314             rc = floppyDrive->COMSETTER(Enabled)(fFloppyEnabled);
    1315             if (FAILED(rc)) throw rc;
    1316 
    1317             /* CDROM drive */
    1318             /* @todo: I can't disable the CDROM. So nothing to do for now */
    1319             // std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_CDROM);
    1320 
    1321             /* Hard disk controller IDE */
    1322             std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
    1323             if (vsdeHDCIDE.size() > 1)
    1324                 throw setError(VBOX_E_FILE_ERROR,
    1325                                tr("Too many IDE controllers in OVF; VirtualBox only supports one"));
    1326             if (vsdeHDCIDE.size() == 1)
    1327             {
    1328                 ComPtr<IStorageController> pController;
    1329                 rc = pNewMachine->GetStorageControllerByName(Bstr("IDE"), pController.asOutParam());
    1330                 if (FAILED(rc)) throw rc;
    1331 
    1332                 const char *pcszIDEType = vsdeHDCIDE.front()->strVbox.c_str();
    1333                 if (!strcmp(pcszIDEType, "PIIX3"))
    1334                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3);
    1335                 else if (!strcmp(pcszIDEType, "PIIX4"))
    1336                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX4);
    1337                 else if (!strcmp(pcszIDEType, "ICH6"))
    1338                     rc = pController->COMSETTER(ControllerType)(StorageControllerType_ICH6);
    1339                 else
    1340                     throw setError(VBOX_E_FILE_ERROR,
    1341                                    tr("Invalid IDE controller type \"%s\""),
    1342                                    pcszIDEType);
    1343                 if (FAILED(rc)) throw rc;
    1344             }
    1345 #ifdef VBOX_WITH_AHCI
    1346             /* Hard disk controller SATA */
    1347             std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
    1348             if (vsdeHDCSATA.size() > 1)
    1349                 throw setError(VBOX_E_FILE_ERROR,
    1350                                tr("Too many SATA controllers in OVF; VirtualBox only supports one"));
    1351             if (vsdeHDCSATA.size() > 0)
    1352             {
    1353                 ComPtr<IStorageController> pController;
    1354                 const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVbox;
    1355                 if (hdcVBox == "AHCI")
    1356                 {
    1357                     rc = pNewMachine->AddStorageController(Bstr("SATA"), StorageBus_SATA, pController.asOutParam());
    1358                     if (FAILED(rc)) throw rc;
    1359                 }
    1360                 else
    1361                     throw setError(VBOX_E_FILE_ERROR,
    1362                                    tr("Invalid SATA controller type \"%s\""),
    1363                                    hdcVBox.c_str());
    1364             }
    1365 #endif /* VBOX_WITH_AHCI */
    1366 
    1367 #ifdef VBOX_WITH_LSILOGIC
    1368             /* Hard disk controller SCSI */
    1369             std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
    1370             if (vsdeHDCSCSI.size() > 1)
    1371                 throw setError(VBOX_E_FILE_ERROR,
    1372                                tr("Too many SCSI controllers in OVF; VirtualBox only supports one"));
    1373             if (vsdeHDCSCSI.size() > 0)
    1374             {
    1375                 ComPtr<IStorageController> pController;
    1376                 StorageControllerType_T controllerType;
    1377                 const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVbox;
    1378                 if (hdcVBox == "LsiLogic")
    1379                     controllerType = StorageControllerType_LsiLogic;
    1380                 else if (hdcVBox == "BusLogic")
    1381                     controllerType = StorageControllerType_BusLogic;
    1382                 else
    1383                     throw setError(VBOX_E_FILE_ERROR,
    1384                                    tr("Invalid SCSI controller type \"%s\""),
    1385                                    hdcVBox.c_str());
    1386 
    1387                 rc = pNewMachine->AddStorageController(Bstr("SCSI"), StorageBus_SCSI, pController.asOutParam());
    1388                 if (FAILED(rc)) throw rc;
    1389                 rc = pController->COMSETTER(ControllerType)(controllerType);
    1390                 if (FAILED(rc)) throw rc;
    1391             }
    1392 #endif /* VBOX_WITH_LSILOGIC */
    1393 
    1394             /* Now its time to register the machine before we add any hard disks */
    1395             rc = pVirtualBox->RegisterMachine(pNewMachine);
    1396             if (FAILED(rc)) throw rc;
    1397 
    1398             Bstr newMachineId_;
    1399             rc = pNewMachine->COMGETTER(Id)(newMachineId_.asOutParam());
    1400             if (FAILED(rc)) throw rc;
    1401             Guid newMachineId(newMachineId_);
    1402 
    1403             // store new machine for roll-back in case of errors
    1404             llMachinesRegistered.push_back(newMachineId);
    1405 
    1406             /* Create the hard disks & connect them to the appropriate controllers. */
    1407             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    1408             if (avsdeHDs.size() > 0)
    1409             {
    1410                 /* If in the next block an error occur we have to deregister
    1411                    the machine, so make an extra try/catch block. */
    1412                 ComPtr<IHardDisk> srcHdVBox;
    1413                 bool fSourceHdNeedsClosing = false;
    1414 
    1415                 try
    1416                 {
    1417                     /* In order to attach hard disks we need to open a session
    1418                      * for the new machine */
    1419                     rc = pVirtualBox->OpenSession(session, newMachineId_);
    1420                     if (FAILED(rc)) throw rc;
    1421                     fSessionOpen = true;
    1422 
    1423                     /* The disk image has to be on the same place as the OVF file. So
    1424                      * strip the filename out of the full file path. */
    1425                     Utf8Str strSrcDir(reader.m_strPath);
    1426                     strSrcDir.stripFilename();
    1427 
    1428                     /* Iterate over all given disk images */
    1429                     list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
    1430                     for (itHD = avsdeHDs.begin();
    1431                          itHD != avsdeHDs.end();
    1432                          ++itHD)
    1433                     {
    1434                         VirtualSystemDescriptionEntry *vsdeHD = *itHD;
    1435 
    1436                         const char *pcszDstFilePath = vsdeHD->strVbox.c_str();
    1437                         /* Check if the destination file exists already or the
    1438                          * destination path is empty. */
    1439                         if (    !(*pcszDstFilePath)
    1440                              || RTPathExists(pcszDstFilePath)
    1441                            )
    1442                             /* This isn't allowed */
    1443                             throw setError(VBOX_E_FILE_ERROR,
    1444                                            tr("Destination file '%s' exists",
    1445                                               pcszDstFilePath));
    1446 
    1447                         /* Find the disk from the OVF's disk list */
    1448                         DiskImagesMap::const_iterator itDiskImage = reader.m_mapDisks.find(vsdeHD->strRef);
    1449                         /* vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
    1450                            in the virtual system's disks map under that ID and also in the global images map. */
    1451                         VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
    1452 
    1453                         if (    itDiskImage == reader.m_mapDisks.end()
    1454                              || itVirtualDisk == vsysThis.mapVirtualDisks.end()
    1455                            )
    1456                             throw setError(E_FAIL,
    1457                                            tr("Internal inconsistency looking up disk images."));
    1458 
    1459                         const DiskImage &di = itDiskImage->second;
    1460                         const VirtualDisk &vd = itVirtualDisk->second;
    1461 
    1462                         /* Make sure all target directories exists */
    1463                         rc = VirtualBox::ensureFilePathExists(pcszDstFilePath);
    1464                         if (FAILED(rc))
    1465                             throw rc;
    1466 
    1467                         // subprogress object for hard disk
    1468                         ComPtr<IProgress> pProgress2;
    1469 
    1470                         ComPtr<IHardDisk> dstHdVBox;
    1471                         /* If strHref is empty we have to create a new file */
    1472                         if (di.strHref.isEmpty())
    1473                         {
    1474                             /* Which format to use? */
    1475                             Bstr srcFormat = L"VDI";
    1476                             if (   di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
    1477                                 || di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
    1478                                 srcFormat = L"VMDK";
    1479                             /* Create an empty hard disk */
    1480                             rc = pVirtualBox->CreateHardDisk(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
    1481                             if (FAILED(rc)) throw rc;
    1482 
    1483                             /* Create a dynamic growing disk image with the given capacity */
    1484                             rc = dstHdVBox->CreateBaseStorage(di.iCapacity / _1M, HardDiskVariant_Standard, pProgress2.asOutParam());
    1485                             if (FAILED(rc)) throw rc;
    1486 
    1487                             /* Advance to the next operation */
    1488                             if (!task->progress.isNull())
    1489                                 task->progress->setNextOperation(BstrFmt(tr("Creating virtual disk image '%s'"), pcszDstFilePath),
    1490                                                                  vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally
    1491                         }
    1492                         else
    1493                         {
    1494                             /* Construct the source file path */
    1495                             Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
    1496                             /* Check if the source file exists */
    1497                             if (!RTPathExists(strSrcFilePath.c_str()))
    1498                                 /* This isn't allowed */
    1499                                 throw setError(VBOX_E_FILE_ERROR,
    1500                                                tr("Source virtual disk image file '%s' doesn't exist"),
    1501                                                   strSrcFilePath.c_str());
    1502 
    1503                             /* Clone the disk image (this is necessary cause the id has
    1504                              * to be recreated for the case the same hard disk is
    1505                              * attached already from a previous import) */
    1506 
    1507                             /* First open the existing disk image */
    1508                             rc = pVirtualBox->OpenHardDisk(Bstr(strSrcFilePath),
    1509                                                            AccessMode_ReadOnly,
    1510                                                            false, Bstr(""), false, Bstr(""),
    1511                                                            srcHdVBox.asOutParam());
    1512                             if (FAILED(rc)) throw rc;
    1513                             fSourceHdNeedsClosing = true;
    1514 
    1515                             /* We need the format description of the source disk image */
    1516                             Bstr srcFormat;
    1517                             rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
    1518                             if (FAILED(rc)) throw rc;
    1519                             /* Create a new hard disk interface for the destination disk image */
    1520                             rc = pVirtualBox->CreateHardDisk(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
    1521                             if (FAILED(rc)) throw rc;
    1522                             /* Clone the source disk image */
    1523                             rc = srcHdVBox->CloneTo(dstHdVBox, HardDiskVariant_Standard, NULL, pProgress2.asOutParam());
    1524                             if (FAILED(rc)) throw rc;
    1525 
    1526                             /* Advance to the next operation */
    1527                             if (!task->progress.isNull())
    1528                                 task->progress->setNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), strSrcFilePath.c_str()),
    1529                                                                  vsdeHD->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
    1530                         }
    1531 
    1532                         // now wait for the background disk operation to complete; this throws HRESULTs on error
    1533                         pAppliance->waitForAsyncProgress(task->progress, pProgress2);
    1534 
    1535                         if (fSourceHdNeedsClosing)
    1536                         {
    1537                             rc = srcHdVBox->Close();
    1538                             if (FAILED(rc)) throw rc;
    1539                             fSourceHdNeedsClosing = false;
    1540                         }
    1541 
    1542                         llHardDisksCreated.push_back(dstHdVBox);
    1543                         /* Now use the new uuid to attach the disk image to our new machine */
    1544                         ComPtr<IMachine> sMachine;
    1545                         rc = session->COMGETTER(Machine)(sMachine.asOutParam());
    1546                         if (FAILED(rc)) throw rc;
    1547                         Bstr hdId;
    1548                         rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());
    1549                         if (FAILED(rc)) throw rc;
    1550 
    1551                         /* For now we assume we have one controller of every type only */
    1552                         HardDiskController hdc = (*vsysThis.mapControllers.find(vd.idController)).second;
    1553 
    1554                         // this is for rollback later
    1555                         MyHardDiskAttachment mhda;
    1556                         mhda.uuid = newMachineId;
    1557                         mhda.pMachine = pNewMachine;
    1558 
    1559                         switch (hdc.system)
    1560                         {
    1561                             case HardDiskController::IDE:
    1562                                 // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
    1563                                 // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
    1564                                 // the device number can be either 0 or 1, to specify the master or the slave device,
    1565                                 // respectively. For the secondary IDE controller, the device number is always 1 because
    1566                                 // the master device is reserved for the CD-ROM drive.
    1567                                 mhda.controllerType = Bstr("IDE");
    1568                                 switch (vd.ulAddressOnParent)
    1569                                 {
    1570                                     case 0:     // interpret this as primary master
    1571                                         mhda.lChannel = (long)0;
    1572                                         mhda.lDevice = (long)0;
    1573                                     break;
    1574 
    1575                                     case 1:     // interpret this as primary slave
    1576                                         mhda.lChannel = (long)0;
    1577                                         mhda.lDevice = (long)1;
    1578                                     break;
    1579 
    1580                                     case 2:     // interpret this as secondary slave
    1581                                         mhda.lChannel = (long)1;
    1582                                         mhda.lDevice = (long)1;
    1583                                     break;
    1584 
    1585                                     default:
    1586                                         throw setError(VBOX_E_NOT_SUPPORTED,
    1587                                                        tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), vd.ulAddressOnParent);
    1588                                     break;
    1589                                 }
    1590                             break;
    1591 
    1592                             case HardDiskController::SATA:
    1593                                 mhda.controllerType = Bstr("SATA");
    1594                                 mhda.lChannel = (long)vd.ulAddressOnParent;
    1595                                 mhda.lDevice = (long)0;
    1596                             break;
    1597 
    1598                             case HardDiskController::SCSI:
    1599                                 mhda.controllerType = Bstr("SCSI");
    1600                                 mhda.lChannel = (long)vd.ulAddressOnParent;
    1601                                 mhda.lDevice = (long)0;
    1602                             break;
    1603 
    1604                             default: break;
    1605                         }
    1606 
    1607                         Log(("Attaching disk %s to channel %d on device %d\n", pcszDstFilePath, mhda.lChannel, mhda.lDevice));
    1608 
    1609                         rc = sMachine->AttachHardDisk(hdId,
    1610                                                       mhda.controllerType,
    1611                                                       mhda.lChannel,
    1612                                                       mhda.lDevice);
    1613                         if (FAILED(rc)) throw rc;
    1614 
    1615                         llHardDiskAttachments.push_back(mhda);
    1616 
    1617                         rc = sMachine->SaveSettings();
    1618                         if (FAILED(rc)) throw rc;
    1619                     } // end for (itHD = avsdeHDs.begin();
    1620 
    1621                     // only now that we're done with all disks, close the session
    1622                     rc = session->Close();
    1623                     if (FAILED(rc)) throw rc;
    1624                     fSessionOpen = false;
    1625                 }
    1626                 catch(HRESULT /* aRC */)
    1627                 {
    1628                     if (fSourceHdNeedsClosing)
    1629                         srcHdVBox->Close();
    1630 
    1631                     if (fSessionOpen)
    1632                         session->Close();
    1633 
    1634                     throw;
    1635                 }
    1636             }
    1637         }
    1638         catch(HRESULT aRC)
    1639         {
    1640             rc = aRC;
    1641         }
    1642 
    1643         if (FAILED(rc))
    1644             break;
    1645 
    1646     } // for (it = pAppliance->m->llVirtualSystems.begin(),
    1647 
    1648     if (FAILED(rc))
    1649     {
    1650         // with _whatever_ error we've had, do a complete roll-back of
    1651         // machines and disks we've created; unfortunately this is
    1652         // not so trivially done...
    1653 
    1654         HRESULT rc2;
    1655         // detach all hard disks from all machines we created
    1656         list<MyHardDiskAttachment>::iterator itM;
    1657         for (itM = llHardDiskAttachments.begin();
    1658              itM != llHardDiskAttachments.end();
    1659              ++itM)
    1660         {
    1661             const MyHardDiskAttachment &mhda = *itM;
    1662             rc2 = pVirtualBox->OpenSession(session, Bstr(mhda.uuid));
    1663             if (SUCCEEDED(rc2))
    1664             {
    1665                 ComPtr<IMachine> sMachine;
    1666                 rc2 = session->COMGETTER(Machine)(sMachine.asOutParam());
    1667                 if (SUCCEEDED(rc2))
    1668                 {
    1669                     rc2 = sMachine->DetachHardDisk(Bstr(mhda.controllerType), mhda.lChannel, mhda.lDevice);
    1670                     rc2 = sMachine->SaveSettings();
    1671                 }
    1672                 session->Close();
    1673             }
    1674         }
    1675 
    1676         // now clean up all hard disks we created
    1677         list< ComPtr<IHardDisk> >::iterator itHD;
    1678         for (itHD = llHardDisksCreated.begin();
    1679              itHD != llHardDisksCreated.end();
    1680              ++itHD)
    1681         {
    1682             ComPtr<IHardDisk> pDisk = *itHD;
    1683             ComPtr<IProgress> pProgress;
    1684             rc2 = pDisk->DeleteStorage(pProgress.asOutParam());
    1685             rc2 = pProgress->WaitForCompletion(-1);
    1686         }
    1687 
    1688         // finally, deregister and remove all machines
    1689         list<Guid>::iterator itID;
    1690         for (itID = llMachinesRegistered.begin();
    1691              itID != llMachinesRegistered.end();
    1692              ++itID)
    1693         {
    1694             const Guid &guid = *itID;
    1695             ComPtr<IMachine> failedMachine;
    1696             rc2 = pVirtualBox->UnregisterMachine(guid.toUtf16(), failedMachine.asOutParam());
    1697             if (SUCCEEDED(rc2))
    1698                 rc2 = failedMachine->DeleteSettings();
    1699         }
    1700     }
    1701 
    1702     task->rc = rc;
    1703 
    1704     if (!task->progress.isNull())
    1705         task->progress->notifyComplete(rc);
    1706 
    1707     LogFlowFunc(("rc=%Rhrc\n", rc));
    1708     LogFlowFuncLeave();
    1709 
    1710     return VINF_SUCCESS;
    1711 }
    1712 
    1713 struct Appliance::TaskWriteOVF
    1714 {
    1715     enum OVFFormat
    1716     {
    1717         unspecified,
    1718         OVF_0_9,
    1719         OVF_1_0
    1720     };
    1721     enum TaskType
    1722     {
    1723         Write
    1724     };
    1725 
    1726     TaskWriteOVF(const Utf8Str &aFile,
    1727                  OVFFormat aFormat,
    1728                  Appliance *aThat)
    1729         : strOutputFile(aFile),
    1730           taskType(Write),
    1731           storageType(VFSType_File),
    1732           enFormat(aFormat),
    1733           pAppliance(aThat),
    1734           rc(S_OK)
    1735     {}
    1736     ~TaskWriteOVF() {}
    1737 
    1738     int startThread();
    1739     static int uploadProgress(unsigned uPercent, void *pvUser);
    1740 
    1741     Utf8Str strOutputFile;
    1742     TaskType taskType;
    1743     VFSType_T storageType;
    1744     Utf8Str filepath;
    1745     Utf8Str hostname;
    1746     Utf8Str username;
    1747     Utf8Str password;
    1748     OVFFormat enFormat;
    1749     Appliance *pAppliance;
    1750     ComObjPtr<Progress> progress;
    1751     HRESULT rc;
    1752 };
    1753 
    1754 int Appliance::TaskWriteOVF::startThread()
    1755 {
    1756     int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this,
    1757                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    1758                              "Appliance::Task");
    1759 
    1760     ComAssertMsgRCRet(vrc,
    1761                       ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL);
    1762 
    1763     return S_OK;
    1764 }
    1765 
    1766 /* static */
    1767 int Appliance::TaskWriteOVF::uploadProgress(unsigned uPercent, void *pvUser)
    1768 {
    1769     Appliance::TaskWriteOVF* pTask = *(Appliance::TaskWriteOVF**)pvUser;
    1770 
    1771     if (pTask &&
    1772         !pTask->progress.isNull())
    1773     {
    1774         BOOL fCanceled;
    1775         pTask->progress->COMGETTER(Canceled)(&fCanceled);
    1776         if (fCanceled)
    1777             return -1;
    1778         pTask->progress->setCurrentOperationProgress(uPercent);
    1779     }
    1780     return VINF_SUCCESS;
    1781 }
    1782 
    17833593STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
    17843594{
    1785     HRESULT rc = S_OK;
    1786 
    17873595    CheckComArgOutPointerValid(aExplorer);
    17883596
     
    17923600    AutoReadLock(this);
    17933601
    1794     Utf8Str uri(aURI);
    1795     /* Check which kind of export the user has requested */
    1796     VFSType_T type = VFSType_File;
    1797     Utf8Str strProtocol = "";
    1798     /* Check the URI for the target format */
    1799     if (uri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
    1800     {
    1801         throw E_NOTIMPL;
    1802 //        type = VFSType_S3;
    1803 //        strProtocol = "SunCloud://";
    1804     }
    1805     else if (uri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
    1806     {
    1807         throw E_NOTIMPL;
    1808 //        type = VFSType_S3;
    1809 //        strProtocol = "S3://";
    1810     }
    1811     else if (uri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
    1812         throw E_NOTIMPL;
    1813 
    1814     Utf8Str strFilepath;
    1815     Utf8Str strHostname;
    1816     Utf8Str strUsername;
    1817     Utf8Str strPassword;
    1818     parseURI(uri, strProtocol, strFilepath, strHostname, strUsername, strPassword);
    1819 
    18203602    ComObjPtr<VFSExplorer> explorer;
    1821     explorer.createObject();
    1822 
    1823     rc = explorer->init(type, strFilepath, strHostname, strUsername, strPassword, mVirtualBox);
     3603    HRESULT rc = S_OK;
     3604    try
     3605    {
     3606        Utf8Str uri(aURI);
     3607        /* Check which kind of export the user has requested */
     3608        LocationInfo li;
     3609        parseURI(uri, li);
     3610        /* Create the explorer object */
     3611        explorer.createObject();
     3612        rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
     3613    }
     3614    catch (HRESULT aRC)
     3615    {
     3616        rc = aRC;
     3617    }
    18243618
    18253619    if (SUCCEEDED(rc))
     
    18323626STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress)
    18333627{
    1834     HRESULT rc = S_OK;
    1835 
     3628    if (!path) return E_POINTER;
    18363629    CheckComArgOutPointerValid(aProgress);
    18373630
     
    18473640                        tr("Appliance file must have .ovf extension"));
    18483641
    1849     ComObjPtr<Progress> progress;
    18503642    Utf8Str strFormat(format);
    1851     TaskWriteOVF::OVFFormat ovfF;
     3643    TaskExportOVF::OVFFormat ovfF;
    18523644    if (strFormat == "ovf-0.9")
    1853         ovfF = TaskWriteOVF::OVF_0_9;
     3645        ovfF = TaskExportOVF::OVF_0_9;
    18543646    else if (strFormat == "ovf-1.0")
    1855         ovfF = TaskWriteOVF::OVF_1_0;
     3647        ovfF = TaskExportOVF::OVF_1_0;
    18563648    else
    18573649        return setError(VBOX_E_FILE_ERROR,
    18583650                        tr("Invalid format \"%s\" specified"), strFormat.c_str());
    18593651
    1860     rc = writeImpl(ovfF, strPath, progress);
     3652    ComObjPtr<Progress> progress;
     3653    HRESULT rc = S_OK;
     3654    try
     3655    {
     3656        /* Parse all necessary info out of the URI */
     3657        parseURI(strPath, m->locInfo);
     3658        rc = writeImpl(ovfF, m->locInfo, progress);
     3659    }
     3660    catch (HRESULT aRC)
     3661    {
     3662        rc = aRC;
     3663    }
    18613664
    18623665    if (SUCCEEDED(rc))
     
    18653668
    18663669    return rc;
    1867 }
    1868 
    1869 void Appliance::parseURI(Utf8Str strUri, const Utf8Str &strProtocol, Utf8Str &strFilepath, Utf8Str &strHostname, Utf8Str &strUsername, Utf8Str &strPassword)
    1870 {
    1871     /* Remove the protocol */
    1872     if (strUri.startsWith(strProtocol, Utf8Str::CaseInsensitive))
    1873         strUri = strUri.substr(strProtocol.length());
    1874     size_t uppos = strUri.find("@");
    1875     if (uppos != Utf8Str::npos)
    1876     {
    1877         strUsername = strUri.substr(0, uppos);
    1878         strUri = strUri.substr(uppos + 1);
    1879         size_t upos = strUsername.find(":");
    1880         if (upos != Utf8Str::npos)
    1881         {
    1882             strPassword = strUsername.substr(upos + 1);
    1883             strUsername = strUsername.substr(0, upos);
    1884         }
    1885     }
    1886     size_t hpos = strUri.find("/");
    1887     if (hpos != Utf8Str::npos)
    1888     {
    1889         strHostname = strUri.substr(0, hpos);
    1890         strUri = strUri.substr(hpos);
    1891     }
    1892     strFilepath = strUri;
    1893 }
    1894 
    1895 HRESULT Appliance::writeImpl(int aFormat,
    1896                              const Utf8Str &aPath,
    1897                              ComObjPtr<Progress> &aProgress)
    1898 {
    1899     HRESULT rc = S_OK;
    1900     try
    1901     {
    1902 //         m->strPath = aPath;
    1903 
    1904         /* Initialize our worker task */
    1905         std::auto_ptr<TaskWriteOVF> task(new TaskWriteOVF(aPath,
    1906                                                           (TaskWriteOVF::OVFFormat)aFormat,
    1907                                                           this));
    1908 
    1909         /* Check which kind of export the user has requested */
    1910         Utf8Str strProtocol = "";
    1911         /* Check the URI for the target format */
    1912         if (aPath.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
    1913         {
    1914             task->storageType = VFSType_S3;
    1915             strProtocol = "SunCloud://";
    1916         }
    1917         else if (aPath.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
    1918         {
    1919             task->storageType = VFSType_S3;
    1920             strProtocol = "S3://";
    1921         }
    1922         else if (aPath.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
    1923             throw E_NOTIMPL;
    1924 
    1925         parseURI(aPath, strProtocol, task->filepath, task->hostname, task->username, task->password);
    1926         Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"),
    1927                                     task->filepath.c_str());
    1928 
    1929         /* todo: This progress init stuff should be done a little bit more generic */
    1930         if (task->storageType == VFSType_S3)
    1931             rc = setUpProgressUpload(aProgress, progressDesc);
    1932         else
    1933             rc = setUpProgress(aProgress, progressDesc);
    1934         if (FAILED(rc)) throw rc;
    1935 
    1936         task->progress = aProgress;
    1937 
    1938         rc = task->startThread();
    1939         CheckComRCThrowRC(rc);
    1940 
    1941         /* Don't destruct on success */
    1942         task.release();
    1943     }
    1944     catch (HRESULT aRC)
    1945     {
    1946         rc = aRC;
    1947     }
    1948 
    1949     return rc;
    1950 }
    1951 
    1952 DECLCALLBACK(int) Appliance::taskThreadWriteOVF(RTTHREAD /* aThread */, void *pvUser)
    1953 {
    1954     std::auto_ptr<TaskWriteOVF> task(static_cast<TaskWriteOVF*>(pvUser));
    1955     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    1956 
    1957     Appliance *pAppliance = task->pAppliance;
    1958 
    1959     LogFlowFuncEnter();
    1960     LogFlowFunc(("Appliance %p\n", pAppliance));
    1961 
    1962     HRESULT rc = S_OK;
    1963 
    1964     switch(task->taskType)
    1965     {
    1966         case TaskWriteOVF::Write:
    1967         {
    1968             if (task->storageType == VFSType_File)
    1969                 rc = pAppliance->writeFS(task.get());
    1970             else if (task->storageType == VFSType_S3)
    1971                 rc = pAppliance->writeS3(task.get());
    1972             break;
    1973         }
    1974     }
    1975 
    1976     LogFlowFunc(("rc=%Rhrc\n", rc));
    1977     LogFlowFuncLeave();
    1978 
    1979     return VINF_SUCCESS;
    1980 }
    1981 
    1982 /**
    1983  * Worker thread implementation for Write() (ovf writer).
    1984  * @param aThread
    1985  * @param pvUser
    1986  */
    1987 /* static */
    1988 int Appliance::writeFS(TaskWriteOVF *pTask)
    1989 {
    1990     LogFlowFuncEnter();
    1991     LogFlowFunc(("Appliance %p\n", this));
    1992 
    1993     AutoCaller autoCaller(this);
    1994     CheckComRCReturnRC(autoCaller.rc());
    1995 
    1996     AutoWriteLock appLock(this);
    1997 
    1998     HRESULT rc = S_OK;
    1999 
    2000     try
    2001     {
    2002         xml::Document doc;
    2003         xml::ElementNode *pelmRoot = doc.createRootElement("Envelope");
    2004 
    2005         pelmRoot->setAttribute("ovf:version", (pTask->enFormat == TaskWriteOVF::OVF_1_0) ? "1.0" : "0.9");
    2006         pelmRoot->setAttribute("xml:lang", "en-US");
    2007 
    2008         Utf8Str strNamespace = (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2009             ? "http://www.vmware.com/schema/ovf/1/envelope"     // 0.9
    2010             : "http://schemas.dmtf.org/ovf/envelope/1";         // 1.0
    2011         pelmRoot->setAttribute("xmlns", strNamespace);
    2012         pelmRoot->setAttribute("xmlns:ovf", strNamespace);
    2013 
    2014 //         pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");
    2015         pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData");
    2016         pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData");
    2017         pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    2018 //         pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
    2019 
    2020         // <Envelope>/<References>
    2021         xml::ElementNode *pelmReferences = pelmRoot->createChild("References");     // 0.9 and 1.0
    2022 
    2023         /* <Envelope>/<DiskSection>:
    2024             <DiskSection>
    2025                 <Info>List of the virtual disks used in the package</Info>
    2026                 <Disk ovf:capacity="4294967296" ovf:diskId="lamp" ovf:format="http://www.vmware.com/specifications/vmdk.html#compressed" ovf:populatedSize="1924967692"/>
    2027             </DiskSection> */
    2028         xml::ElementNode *pelmDiskSection;
    2029         if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2030         {
    2031             // <Section xsi:type="ovf:DiskSection_Type">
    2032             pelmDiskSection = pelmRoot->createChild("Section");
    2033             pelmDiskSection->setAttribute("xsi:type", "ovf:DiskSection_Type");
    2034         }
    2035         else
    2036             pelmDiskSection = pelmRoot->createChild("DiskSection");
    2037 
    2038         xml::ElementNode *pelmDiskSectionInfo = pelmDiskSection->createChild("Info");
    2039         pelmDiskSectionInfo->addContent("List of the virtual disks used in the package");
    2040         // for now, set up a map so we have a list of unique disk names (to make
    2041         // sure the same disk name is only added once)
    2042         map<Utf8Str, const VirtualSystemDescriptionEntry*> mapDisks;
    2043 
    2044         /* <Envelope>/<NetworkSection>:
    2045             <NetworkSection>
    2046                 <Info>Logical networks used in the package</Info>
    2047                 <Network ovf:name="VM Network">
    2048                     <Description>The network that the LAMP Service will be available on</Description>
    2049                 </Network>
    2050             </NetworkSection> */
    2051         xml::ElementNode *pelmNetworkSection;
    2052         if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2053         {
    2054             // <Section xsi:type="ovf:NetworkSection_Type">
    2055             pelmNetworkSection = pelmRoot->createChild("Section");
    2056             pelmNetworkSection->setAttribute("xsi:type", "ovf:NetworkSection_Type");
    2057         }
    2058         else
    2059             pelmNetworkSection = pelmRoot->createChild("NetworkSection");
    2060 
    2061         xml::ElementNode *pelmNetworkSectionInfo = pelmNetworkSection->createChild("Info");
    2062         pelmNetworkSectionInfo->addContent("Logical networks used in the package");
    2063         // for now, set up a map so we have a list of unique network names (to make
    2064         // sure the same network name is only added once)
    2065         map<Utf8Str, bool> mapNetworks;
    2066                 // we fill this later below when we iterate over the networks
    2067 
    2068         // and here come the virtual systems:
    2069 
    2070         // write a collection if we have more than one virtual system _and_ we're
    2071         // writing OVF 1.0; otherwise fail since ovftool can't import more than
    2072         // one machine, it seems
    2073         xml::ElementNode *pelmToAddVirtualSystemsTo;
    2074         if (m->virtualSystemDescriptions.size() > 1)
    2075         {
    2076             if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2077                 throw setError(VBOX_E_FILE_ERROR,
    2078                                tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0"));
    2079 
    2080             pelmToAddVirtualSystemsTo = pelmRoot->createChild("VirtualSystemCollection");
    2081             /* xml::AttributeNode *pattrVirtualSystemCollectionId = */ pelmToAddVirtualSystemsTo->setAttribute("ovf:name", "ExportedVirtualBoxMachines");      // whatever
    2082         }
    2083         else
    2084             pelmToAddVirtualSystemsTo = pelmRoot;       // add virtual system directly under root element
    2085 
    2086         uint32_t cDisks = 0;
    2087 
    2088         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    2089         /* Iterate through all virtual systems of that appliance */
    2090         for (it = m->virtualSystemDescriptions.begin();
    2091              it != m->virtualSystemDescriptions.end();
    2092              ++it)
    2093         {
    2094             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    2095 
    2096             xml::ElementNode *pelmVirtualSystem;
    2097             if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2098             {
    2099                 // <Section xsi:type="ovf:NetworkSection_Type">
    2100                 pelmVirtualSystem = pelmToAddVirtualSystemsTo->createChild("Content");
    2101                 pelmVirtualSystem->setAttribute("xsi:type", "ovf:VirtualSystem_Type");
    2102             }
    2103             else
    2104                 pelmVirtualSystem = pelmToAddVirtualSystemsTo->createChild("VirtualSystem");
    2105 
    2106             /*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine");
    2107 
    2108             std::list<VirtualSystemDescriptionEntry*> llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
    2109             if (llName.size() != 1)
    2110                 throw setError(VBOX_E_NOT_SUPPORTED,
    2111                                tr("Missing VM name"));
    2112             Utf8Str &strVMName = llName.front()->strVbox;
    2113             pelmVirtualSystem->setAttribute("ovf:id", strVMName);
    2114 
    2115             // product info
    2116             std::list<VirtualSystemDescriptionEntry*> llProduct = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
    2117             std::list<VirtualSystemDescriptionEntry*> llProductUrl = vsdescThis->findByType(VirtualSystemDescriptionType_ProductUrl);
    2118             std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
    2119             std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
    2120             std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
    2121             bool fProduct = llProduct.size() && !llProduct.front()->strVbox.isEmpty();
    2122             bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVbox.isEmpty();
    2123             bool fVendor = llVendor.size() && !llVendor.front()->strVbox.isEmpty();
    2124             bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVbox.isEmpty();
    2125             bool fVersion = llVersion.size() && !llVersion.front()->strVbox.isEmpty();
    2126             if (fProduct ||
    2127                 fProductUrl ||
    2128                 fVersion ||
    2129                 fVendorUrl ||
    2130                 fVersion)
    2131             {
    2132                 /* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
    2133                     <Info>Meta-information about the installed software</Info>
    2134                     <Product>VAtest</Product>
    2135                     <Vendor>SUN Microsystems</Vendor>
    2136                     <Version>10.0</Version>
    2137                     <ProductUrl>http://blogs.sun.com/VirtualGuru</ProductUrl>
    2138                     <VendorUrl>http://www.sun.com</VendorUrl>
    2139                 </Section> */
    2140                 xml::ElementNode *pelmAnnotationSection;
    2141                 if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2142                 {
    2143                     // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
    2144                     pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
    2145                     pelmAnnotationSection->setAttribute("xsi:type", "ovf:ProductSection_Type");
    2146                 }
    2147                 else
    2148                     pelmAnnotationSection = pelmVirtualSystem->createChild("ProductSection");
    2149 
    2150                 pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software");
    2151                 if (fProduct)
    2152                     pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVbox);
    2153                 if (fVendor)
    2154                     pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVbox);
    2155                 if (fVersion)
    2156                     pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVbox);
    2157                 if (fProductUrl)
    2158                     pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVbox);
    2159                 if (fVendorUrl)
    2160                     pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVbox);
    2161             }
    2162 
    2163             // description
    2164             std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
    2165             if (llDescription.size() &&
    2166                 !llDescription.front()->strVbox.isEmpty())
    2167             {
    2168                 /*  <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
    2169                         <Info>A human-readable annotation</Info>
    2170                         <Annotation>Plan 9</Annotation>
    2171                     </Section> */
    2172                 xml::ElementNode *pelmAnnotationSection;
    2173                 if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2174                 {
    2175                     // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
    2176                     pelmAnnotationSection = pelmVirtualSystem->createChild("Section");
    2177                     pelmAnnotationSection->setAttribute("xsi:type", "ovf:AnnotationSection_Type");
    2178                 }
    2179                 else
    2180                     pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection");
    2181 
    2182                 pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation");
    2183                 pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVbox);
    2184             }
    2185 
    2186             // license
    2187             std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License);
    2188             if (llLicense.size() &&
    2189                 !llLicense.front()->strVbox.isEmpty())
    2190             {
    2191                 /* <EulaSection>
    2192                    <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
    2193                    <License ovf:msgid="1">License terms can go in here.</License>
    2194                    </EulaSection> */
    2195                 xml::ElementNode *pelmEulaSection;
    2196                 if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2197                 {
    2198                     pelmEulaSection = pelmVirtualSystem->createChild("Section");
    2199                     pelmEulaSection->setAttribute("xsi:type", "ovf:EulaSection_Type");
    2200                 }
    2201                 else
    2202                     pelmEulaSection = pelmVirtualSystem->createChild("EulaSection");
    2203 
    2204                 pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system");
    2205                 pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVbox);
    2206             }
    2207 
    2208             // operating system
    2209             std::list<VirtualSystemDescriptionEntry*> llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
    2210             if (llOS.size() != 1)
    2211                 throw setError(VBOX_E_NOT_SUPPORTED,
    2212                                tr("Missing OS type"));
    2213             /*  <OperatingSystemSection ovf:id="82">
    2214                     <Info>Guest Operating System</Info>
    2215                     <Description>Linux 2.6.x</Description>
    2216                 </OperatingSystemSection> */
    2217             xml::ElementNode *pelmOperatingSystemSection;
    2218             if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2219             {
    2220                 pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section");
    2221                 pelmOperatingSystemSection->setAttribute("xsi:type", "ovf:OperatingSystemSection_Type");
    2222             }
    2223             else
    2224                 pelmOperatingSystemSection = pelmVirtualSystem->createChild("OperatingSystemSection");
    2225 
    2226             pelmOperatingSystemSection->setAttribute("ovf:id", llOS.front()->strOvf);
    2227             pelmOperatingSystemSection->createChild("Info")->addContent("The kind of installed guest operating system");
    2228             Utf8Str strOSDesc;
    2229             convertCIMOSType2VBoxOSType(strOSDesc, (CIMOSType_T)llOS.front()->strOvf.toInt32(), "");
    2230             pelmOperatingSystemSection->createChild("Description")->addContent(strOSDesc);
    2231 
    2232             // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso">
    2233             xml::ElementNode *pelmVirtualHardwareSection;
    2234             if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2235             {
    2236                 // <Section xsi:type="ovf:VirtualHardwareSection_Type">
    2237                 pelmVirtualHardwareSection = pelmVirtualSystem->createChild("Section");
    2238                 pelmVirtualHardwareSection->setAttribute("xsi:type", "ovf:VirtualHardwareSection_Type");
    2239             }
    2240             else
    2241                 pelmVirtualHardwareSection = pelmVirtualSystem->createChild("VirtualHardwareSection");
    2242 
    2243             pelmVirtualHardwareSection->createChild("Info")->addContent("Virtual hardware requirements for a virtual machine");
    2244 
    2245             /*  <System>
    2246                     <vssd:Description>Description of the virtual hardware section.</vssd:Description>
    2247                     <vssd:ElementName>vmware</vssd:ElementName>
    2248                     <vssd:InstanceID>1</vssd:InstanceID>
    2249                     <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
    2250                     <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
    2251                 </System> */
    2252             xml::ElementNode *pelmSystem = pelmVirtualHardwareSection->createChild("System");
    2253 
    2254             pelmSystem->createChild("vssd:ElementName")->addContent("Virtual Hardware Family"); // required OVF 1.0
    2255 
    2256             // <vssd:InstanceId>0</vssd:InstanceId>
    2257             if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2258                 pelmSystem->createChild("vssd:InstanceId")->addContent("0");
    2259             else // capitalization changed...
    2260                 pelmSystem->createChild("vssd:InstanceID")->addContent("0");
    2261 
    2262             // <vssd:VirtualSystemIdentifier>VAtest</vssd:VirtualSystemIdentifier>
    2263             pelmSystem->createChild("vssd:VirtualSystemIdentifier")->addContent(strVMName);
    2264             // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
    2265             const char *pcszHardware = "virtualbox-2.2";
    2266             if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2267                 // pretend to be vmware compatible then
    2268                 pcszHardware = "vmx-6";
    2269             pelmSystem->createChild("vssd:VirtualSystemType")->addContent(pcszHardware);
    2270 
    2271             // loop thru all description entries twice; once to write out all
    2272             // devices _except_ disk images, and a second time to assign the
    2273             // disk images; this is because disk images need to reference
    2274             // IDE controllers, and we can't know their instance IDs without
    2275             // assigning them first
    2276 
    2277             uint32_t idIDEController = 0;
    2278             int32_t lIDEControllerIndex = 0;
    2279             uint32_t idSATAController = 0;
    2280             int32_t lSATAControllerIndex = 0;
    2281             uint32_t idSCSIController = 0;
    2282             int32_t lSCSIControllerIndex = 0;
    2283 
    2284             uint32_t ulInstanceID = 1;
    2285 
    2286             for (size_t uLoop = 1;
    2287                  uLoop <= 2;
    2288                  ++uLoop)
    2289             {
    2290                 int32_t lIndexThis = 0;
    2291                 list<VirtualSystemDescriptionEntry>::const_iterator itD;
    2292                 for (itD = vsdescThis->m->llDescriptions.begin();
    2293                     itD != vsdescThis->m->llDescriptions.end();
    2294                     ++itD, ++lIndexThis)
    2295                 {
    2296                     const VirtualSystemDescriptionEntry &desc = *itD;
    2297 
    2298                     OVFResourceType_T type = (OVFResourceType_T)0;      // if this becomes != 0 then we do stuff
    2299                     Utf8Str strResourceSubType;
    2300 
    2301                     Utf8Str strDescription;                             // results in <rasd:Description>...</rasd:Description> block
    2302                     Utf8Str strCaption;                                 // results in <rasd:Caption>...</rasd:Caption> block
    2303 
    2304                     uint32_t ulParent = 0;
    2305 
    2306                     int32_t lVirtualQuantity = -1;
    2307                     Utf8Str strAllocationUnits;
    2308 
    2309                     int32_t lAddress = -1;
    2310                     int32_t lBusNumber = -1;
    2311                     int32_t lAddressOnParent = -1;
    2312 
    2313                     int32_t lAutomaticAllocation = -1;                  // 0 means "false", 1 means "true"
    2314                     Utf8Str strConnection;                              // results in <rasd:Connection>...</rasd:Connection> block
    2315                     Utf8Str strHostResource;
    2316 
    2317                     uint64_t uTemp;
    2318 
    2319                     switch (desc.type)
    2320                     {
    2321                         case VirtualSystemDescriptionType_CPU:
    2322                             /*  <Item>
    2323                                     <rasd:Caption>1 virtual CPU</rasd:Caption>
    2324                                     <rasd:Description>Number of virtual CPUs</rasd:Description>
    2325                                     <rasd:ElementName>virtual CPU</rasd:ElementName>
    2326                                     <rasd:InstanceID>1</rasd:InstanceID>
    2327                                     <rasd:ResourceType>3</rasd:ResourceType>
    2328                                     <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
    2329                                 </Item> */
    2330                             if (uLoop == 1)
    2331                             {
    2332                                 strDescription = "Number of virtual CPUs";
    2333                                 type = OVFResourceType_Processor; // 3
    2334                                 desc.strVbox.toInt(uTemp);
    2335                                 lVirtualQuantity = uTemp;
    2336                                 strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity);     // without this ovftool won't eat the item
    2337                             }
    2338                         break;
    2339 
    2340                         case VirtualSystemDescriptionType_Memory:
    2341                             /*  <Item>
    2342                                     <rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
    2343                                     <rasd:Caption>256 MB of memory</rasd:Caption>
    2344                                     <rasd:Description>Memory Size</rasd:Description>
    2345                                     <rasd:ElementName>Memory</rasd:ElementName>
    2346                                     <rasd:InstanceID>2</rasd:InstanceID>
    2347                                     <rasd:ResourceType>4</rasd:ResourceType>
    2348                                     <rasd:VirtualQuantity>256</rasd:VirtualQuantity>
    2349                                 </Item> */
    2350                             if (uLoop == 1)
    2351                             {
    2352                                 strDescription = "Memory Size";
    2353                                 type = OVFResourceType_Memory; // 4
    2354                                 desc.strVbox.toInt(uTemp);
    2355                                 lVirtualQuantity = (int32_t)(uTemp / _1M);
    2356                                 strAllocationUnits = "MegaBytes";
    2357                                 strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity);     // without this ovftool won't eat the item
    2358                             }
    2359                         break;
    2360 
    2361                         case VirtualSystemDescriptionType_HardDiskControllerIDE:
    2362                             /* <Item>
    2363                                     <rasd:Caption>ideController1</rasd:Caption>
    2364                                     <rasd:Description>IDE Controller</rasd:Description>
    2365                                     <rasd:InstanceId>5</rasd:InstanceId>
    2366                                     <rasd:ResourceType>5</rasd:ResourceType>
    2367                                     <rasd:Address>1</rasd:Address>
    2368                                     <rasd:BusNumber>1</rasd:BusNumber>
    2369                                 </Item> */
    2370                             if (uLoop == 1)
    2371                             {
    2372                                 strDescription = "IDE Controller";
    2373                                 strCaption = "ideController0";
    2374                                 type = OVFResourceType_IDEController; // 5
    2375                                 strResourceSubType = desc.strVbox;
    2376                                 // it seems that OVFTool always writes these two, and since we can only
    2377                                 // have one IDE controller, we'll use this as well
    2378                                 lAddress = 1;
    2379                                 lBusNumber = 1;
    2380 
    2381                                 // remember this ID
    2382                                 idIDEController = ulInstanceID;
    2383                                 lIDEControllerIndex = lIndexThis;
    2384                             }
    2385                         break;
    2386 
    2387                         case VirtualSystemDescriptionType_HardDiskControllerSATA:
    2388                             /*  <Item>
    2389                                     <rasd:Caption>sataController0</rasd:Caption>
    2390                                     <rasd:Description>SATA Controller</rasd:Description>
    2391                                     <rasd:InstanceId>4</rasd:InstanceId>
    2392                                     <rasd:ResourceType>20</rasd:ResourceType>
    2393                                     <rasd:ResourceSubType>ahci</rasd:ResourceSubType>
    2394                                     <rasd:Address>0</rasd:Address>
    2395                                     <rasd:BusNumber>0</rasd:BusNumber>
    2396                                 </Item>
    2397                             */
    2398                             if (uLoop == 1)
    2399                             {
    2400                                 strDescription = "SATA Controller";
    2401                                 strCaption = "sataController0";
    2402                                 type = OVFResourceType_OtherStorageDevice; // 20
    2403                                 // it seems that OVFTool always writes these two, and since we can only
    2404                                 // have one SATA controller, we'll use this as well
    2405                                 lAddress = 0;
    2406                                 lBusNumber = 0;
    2407 
    2408                                 if (    desc.strVbox.isEmpty()      // AHCI is the default in VirtualBox
    2409                                      || (!desc.strVbox.compare("ahci", Utf8Str::CaseInsensitive))
    2410                                    )
    2411                                     strResourceSubType = "AHCI";
    2412                                 else
    2413                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2414                                                    tr("Invalid config string \"%s\" in SATA controller"), desc.strVbox.c_str());
    2415 
    2416                                 // remember this ID
    2417                                 idSATAController = ulInstanceID;
    2418                                 lSATAControllerIndex = lIndexThis;
    2419                             }
    2420                         break;
    2421 
    2422                         case VirtualSystemDescriptionType_HardDiskControllerSCSI:
    2423                             /*  <Item>
    2424                                     <rasd:Caption>scsiController0</rasd:Caption>
    2425                                     <rasd:Description>SCSI Controller</rasd:Description>
    2426                                     <rasd:InstanceId>4</rasd:InstanceId>
    2427                                     <rasd:ResourceType>6</rasd:ResourceType>
    2428                                     <rasd:ResourceSubType>buslogic</rasd:ResourceSubType>
    2429                                     <rasd:Address>0</rasd:Address>
    2430                                     <rasd:BusNumber>0</rasd:BusNumber>
    2431                                 </Item>
    2432                             */
    2433                             if (uLoop == 1)
    2434                             {
    2435                                 strDescription = "SCSI Controller";
    2436                                 strCaption = "scsiController0";
    2437                                 type = OVFResourceType_ParallelSCSIHBA; // 6
    2438                                 // it seems that OVFTool always writes these two, and since we can only
    2439                                 // have one SATA controller, we'll use this as well
    2440                                 lAddress = 0;
    2441                                 lBusNumber = 0;
    2442 
    2443                                 if (    desc.strVbox.isEmpty()      // LsiLogic is the default in VirtualBox
    2444                                      || (!desc.strVbox.compare("lsilogic", Utf8Str::CaseInsensitive))
    2445                                    )
    2446                                     strResourceSubType = "lsilogic";
    2447                                 else if (!desc.strVbox.compare("buslogic", Utf8Str::CaseInsensitive))
    2448                                     strResourceSubType = "buslogic";
    2449                                 else
    2450                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2451                                                    tr("Invalid config string \"%s\" in SCSI controller"), desc.strVbox.c_str());
    2452 
    2453                                 // remember this ID
    2454                                 idSCSIController = ulInstanceID;
    2455                                 lSCSIControllerIndex = lIndexThis;
    2456                             }
    2457                         break;
    2458 
    2459                         case VirtualSystemDescriptionType_HardDiskImage:
    2460                             /*  <Item>
    2461                                     <rasd:Caption>disk1</rasd:Caption>
    2462                                     <rasd:InstanceId>8</rasd:InstanceId>
    2463                                     <rasd:ResourceType>17</rasd:ResourceType>
    2464                                     <rasd:HostResource>/disk/vmdisk1</rasd:HostResource>
    2465                                     <rasd:Parent>4</rasd:Parent>
    2466                                     <rasd:AddressOnParent>0</rasd:AddressOnParent>
    2467                                 </Item> */
    2468                             if (uLoop == 2)
    2469                             {
    2470                                 Utf8Str strDiskID = Utf8StrFmt("vmdisk%RI32", ++cDisks);
    2471 
    2472                                 strDescription = "Disk Image";
    2473                                 strCaption = Utf8StrFmt("disk%RI32", cDisks);        // this is not used for anything else
    2474                                 type = OVFResourceType_HardDisk; // 17
    2475 
    2476                                 // the following references the "<Disks>" XML block
    2477                                 strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str());
    2478 
    2479                                 // controller=<index>;channel=<c>
    2480                                 size_t pos1 = desc.strExtraConfig.find("controller=");
    2481                                 size_t pos2 = desc.strExtraConfig.find("channel=");
    2482                                 if (pos1 != Utf8Str::npos)
    2483                                 {
    2484                                     int32_t lControllerIndex = -1;
    2485                                     RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos1 + 11, NULL, 0, &lControllerIndex);
    2486                                     if (lControllerIndex == lIDEControllerIndex)
    2487                                         ulParent = idIDEController;
    2488                                     else if (lControllerIndex == lSCSIControllerIndex)
    2489                                         ulParent = idSCSIController;
    2490                                     else if (lControllerIndex == lSATAControllerIndex)
    2491                                         ulParent = idSATAController;
    2492                                 }
    2493                                 if (pos2 != Utf8Str::npos)
    2494                                     RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos2 + 8, NULL, 0, &lAddressOnParent);
    2495 
    2496                                 if (    !ulParent
    2497                                      || lAddressOnParent == -1
    2498                                    )
    2499                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2500                                                    tr("Missing or bad extra config string in hard disk image: \"%s\""), desc.strExtraConfig.c_str());
    2501 
    2502                                 mapDisks[strDiskID] = &desc;
    2503                             }
    2504                         break;
    2505 
    2506                         case VirtualSystemDescriptionType_Floppy:
    2507                             if (uLoop == 1)
    2508                             {
    2509                                 strDescription = "Floppy Drive";
    2510                                 strCaption = "floppy0";         // this is what OVFTool writes
    2511                                 type = OVFResourceType_FloppyDrive; // 14
    2512                                 lAutomaticAllocation = 0;
    2513                                 lAddressOnParent = 0;           // this is what OVFTool writes
    2514                             }
    2515                         break;
    2516 
    2517                         case VirtualSystemDescriptionType_CDROM:
    2518                             if (uLoop == 2)
    2519                             {
    2520                                 // we can't have a CD without an IDE controller
    2521                                 if (!idIDEController)
    2522                                     throw setError(VBOX_E_NOT_SUPPORTED,
    2523                                                    tr("Can't have CD-ROM without IDE controller"));
    2524 
    2525                                 strDescription = "CD-ROM Drive";
    2526                                 strCaption = "cdrom1";          // this is what OVFTool writes
    2527                                 type = OVFResourceType_CDDrive; // 15
    2528                                 lAutomaticAllocation = 1;
    2529                                 ulParent = idIDEController;
    2530                                 lAddressOnParent = 0;           // this is what OVFTool writes
    2531                             }
    2532                         break;
    2533 
    2534                         case VirtualSystemDescriptionType_NetworkAdapter:
    2535                             /* <Item>
    2536                                     <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
    2537                                     <rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
    2538                                     <rasd:Connection>VM Network</rasd:Connection>
    2539                                     <rasd:ElementName>VM network</rasd:ElementName>
    2540                                     <rasd:InstanceID>3</rasd:InstanceID>
    2541                                     <rasd:ResourceType>10</rasd:ResourceType>
    2542                                 </Item> */
    2543                             if (uLoop == 1)
    2544                             {
    2545                                 lAutomaticAllocation = 1;
    2546                                 strCaption = Utf8StrFmt("Ethernet adapter on '%s'", desc.strOvf.c_str());
    2547                                 type = OVFResourceType_EthernetAdapter; // 10
    2548                                 /* Set the hardware type to something useful.
    2549                                  * To be compatible with vmware & others we set
    2550                                  * PCNet32 for our PCNet types & E1000 for the
    2551                                  * E1000 cards. */
    2552                                 switch (desc.strVbox.toInt32())
    2553                                 {
    2554                                     case NetworkAdapterType_Am79C970A:
    2555                                     case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break;
    2556 #ifdef VBOX_WITH_E1000
    2557                                     case NetworkAdapterType_I82540EM:
    2558                                     case NetworkAdapterType_I82545EM:
    2559                                     case NetworkAdapterType_I82543GC: strResourceSubType = "E1000"; break;
    2560 #endif /* VBOX_WITH_E1000 */
    2561                                 }
    2562                                 strConnection = desc.strOvf;
    2563 
    2564                                 mapNetworks[desc.strOvf] = true;
    2565                             }
    2566                         break;
    2567 
    2568                         case VirtualSystemDescriptionType_USBController:
    2569                             /*  <Item ovf:required="false">
    2570                                     <rasd:Caption>usb</rasd:Caption>
    2571                                     <rasd:Description>USB Controller</rasd:Description>
    2572                                     <rasd:InstanceId>3</rasd:InstanceId>
    2573                                     <rasd:ResourceType>23</rasd:ResourceType>
    2574                                     <rasd:Address>0</rasd:Address>
    2575                                     <rasd:BusNumber>0</rasd:BusNumber>
    2576                                 </Item> */
    2577                             if (uLoop == 1)
    2578                             {
    2579                                 strDescription = "USB Controller";
    2580                                 strCaption = "usb";
    2581                                 type = OVFResourceType_USBController; // 23
    2582                                 lAddress = 0;                   // this is what OVFTool writes
    2583                                 lBusNumber = 0;                 // this is what OVFTool writes
    2584                             }
    2585                         break;
    2586 
    2587                        case VirtualSystemDescriptionType_SoundCard:
    2588                         /*  <Item ovf:required="false">
    2589                                 <rasd:Caption>sound</rasd:Caption>
    2590                                 <rasd:Description>Sound Card</rasd:Description>
    2591                                 <rasd:InstanceId>10</rasd:InstanceId>
    2592                                 <rasd:ResourceType>35</rasd:ResourceType>
    2593                                 <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
    2594                                 <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
    2595                                 <rasd:AddressOnParent>3</rasd:AddressOnParent>
    2596                             </Item> */
    2597                             if (uLoop == 1)
    2598                             {
    2599                                 strDescription = "Sound Card";
    2600                                 strCaption = "sound";
    2601                                 type = OVFResourceType_SoundCard; // 35
    2602                                 strResourceSubType = desc.strOvf;       // e.g. ensoniq1371
    2603                                 lAutomaticAllocation = 0;
    2604                                 lAddressOnParent = 3;               // what gives? this is what OVFTool writes
    2605                             }
    2606                         break;
    2607                     }
    2608 
    2609                     if (type)
    2610                     {
    2611                         xml::ElementNode *pItem;
    2612 
    2613                         pItem = pelmVirtualHardwareSection->createChild("Item");
    2614 
    2615                         // NOTE: do not change the order of these items without good reason! While we don't care
    2616                         // about ordering, VMware's ovftool does and fails if the items are not written in
    2617                         // exactly this order, as stupid as it seems.
    2618 
    2619                         if (!strCaption.isEmpty())
    2620                         {
    2621                             pItem->createChild("rasd:Caption")->addContent(strCaption);
    2622                             if (pTask->enFormat == TaskWriteOVF::OVF_1_0)
    2623                                 pItem->createChild("rasd:ElementName")->addContent(strCaption);
    2624                         }
    2625 
    2626                         if (!strDescription.isEmpty())
    2627                             pItem->createChild("rasd:Description")->addContent(strDescription);
    2628 
    2629                         // <rasd:InstanceID>1</rasd:InstanceID>
    2630                         xml::ElementNode *pelmInstanceID;
    2631                         if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    2632                             pelmInstanceID = pItem->createChild("rasd:InstanceId");
    2633                         else
    2634                             pelmInstanceID = pItem->createChild("rasd:InstanceID");      // capitalization changed...
    2635                         pelmInstanceID->addContent(Utf8StrFmt("%d", ulInstanceID++));
    2636 
    2637                         // <rasd:ResourceType>3</rasd:ResourceType>
    2638                         pItem->createChild("rasd:ResourceType")->addContent(Utf8StrFmt("%d", type));
    2639                         if (!strResourceSubType.isEmpty())
    2640                             pItem->createChild("rasd:ResourceSubType")->addContent(strResourceSubType);
    2641 
    2642                         if (!strHostResource.isEmpty())
    2643                             pItem->createChild("rasd:HostResource")->addContent(strHostResource);
    2644 
    2645                         if (!strAllocationUnits.isEmpty())
    2646                             pItem->createChild("rasd:AllocationUnits")->addContent(strAllocationUnits);
    2647 
    2648                         // <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
    2649                         if (lVirtualQuantity != -1)
    2650                             pItem->createChild("rasd:VirtualQuantity")->addContent(Utf8StrFmt("%d", lVirtualQuantity));
    2651 
    2652                         if (lAutomaticAllocation != -1)
    2653                             pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" );
    2654 
    2655                         if (!strConnection.isEmpty())
    2656                             pItem->createChild("rasd:Connection")->addContent(strConnection);
    2657 
    2658                         if (lAddress != -1)
    2659                             pItem->createChild("rasd:Address")->addContent(Utf8StrFmt("%d", lAddress));
    2660 
    2661                         if (lBusNumber != -1)
    2662                             if (pTask->enFormat == TaskWriteOVF::OVF_0_9) // BusNumber is invalid OVF 1.0 so only write it in 0.9 mode for OVFTool compatibility
    2663                                 pItem->createChild("rasd:BusNumber")->addContent(Utf8StrFmt("%d", lBusNumber));
    2664 
    2665                         if (ulParent)
    2666                             pItem->createChild("rasd:Parent")->addContent(Utf8StrFmt("%d", ulParent));
    2667                         if (lAddressOnParent != -1)
    2668                             pItem->createChild("rasd:AddressOnParent")->addContent(Utf8StrFmt("%d", lAddressOnParent));
    2669                     }
    2670                 }
    2671             } // for (size_t uLoop = 0; ...
    2672         }
    2673 
    2674         // finally, fill in the network section we set up empty above according
    2675         // to the networks we found with the hardware items
    2676         map<Utf8Str, bool>::const_iterator itN;
    2677         for (itN = mapNetworks.begin();
    2678              itN != mapNetworks.end();
    2679              ++itN)
    2680         {
    2681             const Utf8Str &strNetwork = itN->first;
    2682             xml::ElementNode *pelmNetwork = pelmNetworkSection->createChild("Network");
    2683             pelmNetwork->setAttribute("ovf:name", strNetwork.c_str());
    2684             pelmNetwork->createChild("Description")->addContent("Logical network used by this appliance.");
    2685         }
    2686 
    2687         map<Utf8Str, const VirtualSystemDescriptionEntry*>::const_iterator itS;
    2688         uint32_t ulFile = 1;
    2689         for (itS = mapDisks.begin();
    2690              itS != mapDisks.end();
    2691              ++itS)
    2692         {
    2693             const Utf8Str &strDiskID = itS->first;
    2694             const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
    2695 
    2696             // source path: where the VBox image is
    2697             const Utf8Str &strSrcFilePath = pDiskEntry->strVbox;
    2698             Bstr bstrSrcFilePath(strSrcFilePath);
    2699             if (!RTPathExists(strSrcFilePath.c_str()))
    2700                 /* This isn't allowed */
    2701                 throw setError(VBOX_E_FILE_ERROR,
    2702                                tr("Source virtual disk image file '%s' doesn't exist"),
    2703                                strSrcFilePath.c_str());
    2704 
    2705             // output filename
    2706             const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
    2707             // target path needs to be composed from where the output OVF is
    2708             Utf8Str strTargetFilePath(pTask->strOutputFile);
    2709             strTargetFilePath.stripFilename();
    2710             strTargetFilePath.append("/");
    2711             strTargetFilePath.append(strTargetFileNameOnly);
    2712 
    2713             // clone the disk:
    2714             ComPtr<IHardDisk> pSourceDisk;
    2715             ComPtr<IHardDisk> pTargetDisk;
    2716             ComPtr<IProgress> pProgress2;
    2717 
    2718             Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
    2719             rc = mVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());
    2720             if (FAILED(rc)) throw rc;
    2721 
    2722             /* We are always exporting to vmdfk stream optimized for now */
    2723             Bstr bstrSrcFormat = L"VMDK";
    2724 
    2725             // create a new hard disk interface for the destination disk image
    2726             Log(("Creating target disk \"%s\"\n", strTargetFilePath.raw()));
    2727             rc = mVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam());
    2728             if (FAILED(rc)) throw rc;
    2729 
    2730             // the target disk is now registered and needs to be removed again,
    2731             // both after successful cloning or if anything goes bad!
    2732             try
    2733             {
    2734                 // create a flat copy of the source disk image
    2735                 rc = pSourceDisk->CloneTo(pTargetDisk, HardDiskVariant_VmdkStreamOptimized, NULL, pProgress2.asOutParam());
    2736                 if (FAILED(rc)) throw rc;
    2737 
    2738                 // advance to the next operation
    2739                 if (!pTask->progress.isNull())
    2740                     pTask->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),
    2741                                                      pDiskEntry->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
    2742 
    2743                 // now wait for the background disk operation to complete; this throws HRESULTs on error
    2744                 waitForAsyncProgress(pTask->progress, pProgress2);
    2745             }
    2746             catch (HRESULT rc3)
    2747             {
    2748                 // upon error after registering, close the disk or
    2749                 // it'll stick in the registry forever
    2750                 pTargetDisk->Close();
    2751                 throw;
    2752             }
    2753 
    2754             // we need the following for the XML
    2755             uint64_t cbFile = 0;        // actual file size
    2756             rc = pTargetDisk->COMGETTER(Size)(&cbFile);
    2757             if (FAILED(rc)) throw rc;
    2758 
    2759             ULONG64 cbCapacity = 0;     // size reported to guest
    2760             rc = pTargetDisk->COMGETTER(LogicalSize)(&cbCapacity);
    2761             if (FAILED(rc)) throw rc;
    2762             // capacity is reported in megabytes, so...
    2763             cbCapacity *= _1M;
    2764 
    2765             // upon success, close the disk as well
    2766             rc = pTargetDisk->Close();
    2767             if (FAILED(rc)) throw rc;
    2768 
    2769             // now handle the XML for the disk:
    2770             Utf8StrFmt strFileRef("file%RI32", ulFile++);
    2771             // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
    2772             xml::ElementNode *pelmFile = pelmReferences->createChild("File");
    2773             pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
    2774             pelmFile->setAttribute("ovf:id", strFileRef);
    2775             pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
    2776 
    2777             // add disk to XML Disks section
    2778             // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse"/>
    2779             xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
    2780             pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
    2781             pelmDisk->setAttribute("ovf:diskId", strDiskID);
    2782             pelmDisk->setAttribute("ovf:fileRef", strFileRef);
    2783             pelmDisk->setAttribute("ovf:format", "http://www.vmware.com/specifications/vmdk.html#sparse");      // must be sparse or ovftool chokes
    2784         }
    2785 
    2786         // now go write the XML
    2787         xml::XmlFileWriter writer(doc);
    2788         writer.write(pTask->strOutputFile.c_str());
    2789     }
    2790     catch(xml::Error &x)
    2791     {
    2792         rc = setError(VBOX_E_FILE_ERROR,
    2793                       x.what());
    2794     }
    2795     catch(HRESULT aRC)
    2796     {
    2797         rc = aRC;
    2798     }
    2799 
    2800     pTask->rc = rc;
    2801 
    2802     if (!pTask->progress.isNull())
    2803         pTask->progress->notifyComplete(rc);
    2804 
    2805     LogFlowFunc(("rc=%Rhrc\n", rc));
    2806     LogFlowFuncLeave();
    2807 
    2808     return VINF_SUCCESS;
    2809 }
    2810 
    2811 /**
    2812  * Worker thread implementation for Upload() (ovf uploader).
    2813  * @param aThread
    2814  * @param pvUser
    2815  */
    2816 /* static */
    2817 int Appliance::writeS3(TaskWriteOVF *pTask)
    2818 {
    2819     LogFlowFuncEnter();
    2820     LogFlowFunc(("Appliance %p\n", this));
    2821 
    2822     AutoCaller autoCaller(this);
    2823     CheckComRCReturnRC(autoCaller.rc());
    2824 
    2825     HRESULT rc = S_OK;
    2826 
    2827     AutoWriteLock appLock(this);
    2828 
    2829     /* Buckets are S3 specific. So parse the bucket out of the file path */
    2830     Utf8Str tmpPath = pTask->filepath;
    2831     if (!tmpPath.startsWith("/"))
    2832         return setError(E_INVALIDARG,
    2833                         tr("The path '%s' must start with /"), tmpPath.c_str());
    2834     Utf8Str bucket;
    2835     size_t bpos = tmpPath.find("/", 1);
    2836     if (bpos != Utf8Str::npos)
    2837     {
    2838         bucket = tmpPath.substr(1, bpos - 1); /* The bucket without any slashes */
    2839         tmpPath = tmpPath.substr(bpos); /* The rest of the file path */
    2840     }
    2841     /* If there is no bucket name provided reject the upload */
    2842     if (bucket.isEmpty())
    2843         return setError(E_INVALIDARG,
    2844                         tr("You doesn't provide a bucket name in the URI"), tmpPath.c_str());
    2845 
    2846     int vrc = VINF_SUCCESS;
    2847     RTS3 hS3 = NULL;
    2848     char szOSTmpDir[RTPATH_MAX];
    2849     RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
    2850     /* The template for the temporary directory created below */
    2851     char *pszTmpDir;
    2852     RTStrAPrintf(&pszTmpDir, "%s"RTPATH_SLASH_STR"vbox-ovf-XXXXXX", szOSTmpDir);
    2853     list< pair<Utf8Str, ULONG> > filesList;
    2854 
    2855     // todo:
    2856     // - getting the tmp directory (especially on win)
    2857     // - usable error codes
    2858     // - seems snapshot filenames are problematic {uuid}.vdi
    2859     try
    2860     {
    2861         /* We need a temporary directory which we can put the OVF file & all
    2862          * disk images in */
    2863         vrc = RTDirCreateTemp(pszTmpDir);
    2864         if (RT_FAILURE(rc))
    2865             throw setError(VBOX_E_FILE_ERROR,
    2866                            tr("Cannot create temporary directory '%s'"), pszTmpDir);
    2867 
    2868         /* The temporary name of the target OVF file */
    2869         Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath));
    2870 
    2871         /* Prepare the temporary writing of the OVF */
    2872         ComObjPtr<Progress> progress;
    2873         rc = writeImpl(pTask->enFormat, strTmpOvf.c_str(), progress);
    2874         if (FAILED(rc)) throw rc;
    2875 
    2876         /* Unlock the appliance for the writing thread */
    2877         appLock.unlock();
    2878         /* Wait until the writing is done, but report the progress back to the
    2879            caller */
    2880         ComPtr<IProgress> progressInt(progress);
    2881         waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
    2882 
    2883         /* Again lock the appliance for the next steps */
    2884         appLock.lock();
    2885 
    2886         vrc = RTPathExists(strTmpOvf.c_str()); /* Paranoid check */
    2887         if(RT_FAILURE(vrc))
    2888             throw setError(VBOX_E_FILE_ERROR,
    2889                            tr("Cannot find source file '%s'"), strTmpOvf.c_str());
    2890         /* Add the OVF file */
    2891         filesList.push_back(pair<Utf8Str, ULONG>(strTmpOvf, m->ulWeightPerOperation)); /* Use 1% of the total for the OVF file upload */
    2892 
    2893         /* Now add every disks of every virtual system */
    2894         list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    2895         for (it = m->virtualSystemDescriptions.begin();
    2896              it != m->virtualSystemDescriptions.end();
    2897              ++it)
    2898         {
    2899             ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    2900             std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    2901             std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    2902             for (itH = avsdeHDs.begin();
    2903                  itH != avsdeHDs.end();
    2904                  ++itH)
    2905             {
    2906                 const Utf8Str &strTargetFileNameOnly = (*itH)->strOvf;
    2907                 /* Target path needs to be composed from where the output OVF is */
    2908                 Utf8Str strTargetFilePath(pTask->strOutputFile);
    2909                 strTargetFilePath.stripFilename();
    2910                 strTargetFilePath.append("/");
    2911                 strTargetFilePath.append(strTargetFileNameOnly);
    2912                 vrc = RTPathExists(strTargetFilePath.c_str()); /* Paranoid check */
    2913                 if(RT_FAILURE(vrc))
    2914                     throw setError(VBOX_E_FILE_ERROR,
    2915                                    tr("Cannot find source file '%s'"), strTargetFilePath.c_str());
    2916                 filesList.push_back(pair<Utf8Str, ULONG>(strTargetFilePath, (*itH)->ulSizeMB));
    2917             }
    2918         }
    2919         /* Next we have to upload the OVF & all disk images */
    2920         vrc = RTS3Create(&hS3, pTask->username.c_str(), pTask->password.c_str(), pTask->hostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
    2921         if(RT_FAILURE(vrc))
    2922             throw setError(VBOX_E_IPRT_ERROR,
    2923                            tr("Cannot create S3 service handler"));
    2924         RTS3SetProgressCallback(hS3, pTask->uploadProgress, &pTask);
    2925 
    2926         /* Upload all files */
    2927         for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    2928         {
    2929             const pair<Utf8Str, ULONG> &s = (*it1);
    2930             char *pszFilename = RTPathFilename(s.first.c_str());
    2931             /* Advance to the next operation */
    2932             if (!pTask->progress.isNull())
    2933                 pTask->progress->setNextOperation(BstrFmt(tr("Uploading file '%s'"), pszFilename), s.second);
    2934             vrc = RTS3PutKey(hS3, bucket.c_str(), pszFilename, s.first.c_str());
    2935             if (RT_FAILURE(vrc))
    2936             {
    2937                 if(vrc == VERR_S3_CANCELED)
    2938                     break;
    2939                 else if(vrc == VERR_S3_ACCESS_DENIED)
    2940                     throw setError(E_ACCESSDENIED,
    2941                                    tr("Cannot upload file '%s' to S3 storage server (Access denied)"), pszFilename);
    2942                 else if(vrc == VERR_S3_NOT_FOUND)
    2943                     throw setError(VBOX_E_FILE_ERROR,
    2944                                    tr("Cannot upload file '%s' to S3 storage server (File not found)"), pszFilename);
    2945                 else
    2946                     throw setError(VBOX_E_IPRT_ERROR,
    2947                                    tr("Cannot upload file '%s' to S3 storage server (%Rrc)"), pszFilename, vrc);
    2948             }
    2949         }
    2950 
    2951     }
    2952     catch(HRESULT aRC)
    2953     {
    2954         rc = aRC;
    2955     }
    2956     /* Cleanup */
    2957     if (hS3)
    2958         RTS3Destroy(hS3);
    2959     /* Delete all files which where temporary created */
    2960     for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
    2961     {
    2962         const pair<Utf8Str, ULONG> &s = (*it1);
    2963         vrc = RTFileDelete(s.first.c_str());
    2964         if(RT_FAILURE(vrc))
    2965             rc = setError(VBOX_E_FILE_ERROR,
    2966                           tr("Cannot delete file '%s' (%Rrc)"), s.first.c_str(), vrc);
    2967     }
    2968     /* Delete the temporary directory */
    2969     if (RTPathExists(pszTmpDir))
    2970     {
    2971         vrc = RTDirRemove(pszTmpDir);
    2972         if(RT_FAILURE(vrc))
    2973             rc = setError(VBOX_E_FILE_ERROR,
    2974                           tr("Cannot delete temporary directory '%s' (%Rrc)"), pszTmpDir, vrc);
    2975     }
    2976     if (pszTmpDir)
    2977         RTStrFree(pszTmpDir);
    2978 
    2979     pTask->rc = rc;
    2980 
    2981     if (!pTask->progress.isNull())
    2982         pTask->progress->notifyComplete(rc);
    2983 
    2984     LogFlowFunc(("rc=%Rhrc\n", rc));
    2985     LogFlowFuncLeave();
    2986 
    2987     return VINF_SUCCESS;
    29883670}
    29893671
     
    30193701}
    30203702
    3021 HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
    3022 {
    3023     IMachine *machine = NULL;
    3024     char *tmpName = RTStrDup(aName.c_str());
    3025     int i = 1;
    3026     /* @todo: Maybe too cost-intensive; try to find a lighter way */
    3027     while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
    3028     {
    3029         RTStrFree(tmpName);
    3030         RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
    3031         ++i;
    3032     }
    3033     aName = tmpName;
    3034     RTStrFree(tmpName);
    3035 
    3036     return S_OK;
    3037 }
    3038 
    3039 HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
    3040 {
    3041     IHardDisk *harddisk = NULL;
    3042     char *tmpName = RTStrDup(aName.c_str());
    3043     int i = 1;
    3044     /* Check if the file exists or if a file with this path is registered
    3045      * already */
    3046     /* @todo: Maybe too cost-intensive; try to find a lighter way */
    3047     while (RTPathExists(tmpName) ||
    3048            mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
    3049     {
    3050         RTStrFree(tmpName);
    3051         char *tmpDir = RTStrDup(aName.c_str());
    3052         RTPathStripFilename(tmpDir);;
    3053         char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
    3054         RTPathStripExt(tmpFile);
    3055         const char *tmpExt = RTPathExt(aName.c_str());
    3056         RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
    3057         RTStrFree(tmpFile);
    3058         RTStrFree(tmpDir);
    3059         ++i;
    3060     }
    3061     aName = tmpName;
    3062     RTStrFree(tmpName);
    3063 
    3064     return S_OK;
    3065 }
    3066 
    3067 /**
    3068  * Sets up the given progress object so that it represents disk images accurately
    3069  * during importMachines() and write().
    3070  * @param pProgress
    3071  * @param bstrDescription
    3072  * @return
    3073  */
    3074 HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    3075 {
    3076     HRESULT rc;
    3077 
    3078     /* Create the progress object */
    3079     pProgress.createObject();
    3080 
    3081     // weigh the disk images according to their sizes
    3082     uint32_t ulTotalMB = 0;
    3083     uint32_t cDisks = 0;
    3084     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    3085     for (it = m->virtualSystemDescriptions.begin();
    3086          it != m->virtualSystemDescriptions.end();
    3087          ++it)
    3088     {
    3089         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    3090         /* One for every hard disk of the Virtual System */
    3091         std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    3092         std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    3093         for (itH = avsdeHDs.begin();
    3094              itH != avsdeHDs.end();
    3095              ++itH)
    3096         {
    3097             const VirtualSystemDescriptionEntry *pHD = *itH;
    3098             ulTotalMB += pHD->ulSizeMB;
    3099             ++cDisks;
    3100         }
    3101     }
    3102 
    3103     ULONG cOperations = 1 + cDisks;     // one op per disk plus 1 for the XML
    3104 
    3105     ULONG ulTotalOperationsWeight;
    3106     if (ulTotalMB)
    3107     {
    3108         m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1  / 100);    // use 1% of the progress for the XML
    3109         ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
    3110     }
    3111     else
    3112     {
    3113         // no disks to export:
    3114         ulTotalOperationsWeight = 1;
    3115         m->ulWeightPerOperation = 1;
    3116     }
    3117 
    3118     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    3119          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    3120 
    3121     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    3122                          bstrDescription,
    3123                          TRUE /* aCancelable */,
    3124                          cOperations, // ULONG cOperations,
    3125                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    3126                          bstrDescription, // CBSTR bstrFirstOperationDescription,
    3127                          m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
    3128     return rc;
    3129 }
    3130 
    3131 HRESULT Appliance::setUpProgressUpload(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
    3132 {
    3133     HRESULT rc;
    3134 
    3135     /* Create the progress object */
    3136     pProgress.createObject();
    3137 
    3138     // weigh the disk images according to their sizes
    3139     uint32_t ulTotalMB = 0;
    3140     uint32_t cDisks = 0;
    3141     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    3142     for (it = m->virtualSystemDescriptions.begin();
    3143          it != m->virtualSystemDescriptions.end();
    3144          ++it)
    3145     {
    3146         ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
    3147         /* One for every hard disk of the Virtual System */
    3148         std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
    3149         std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
    3150         for (itH = avsdeHDs.begin();
    3151              itH != avsdeHDs.end();
    3152              ++itH)
    3153         {
    3154             const VirtualSystemDescriptionEntry *pHD = *itH;
    3155             ulTotalMB += pHD->ulSizeMB;
    3156             ++cDisks;
    3157         }
    3158     }
    3159 
    3160     ULONG cOperations = 1 + 1 + cDisks;     // one op per disk plus 1 for the OVF & 1 plus to the temporary creation */
    3161 
    3162     ULONG ulTotalOperationsWeight;
    3163     if (ulTotalMB)
    3164     {
    3165         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)
    3166         ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
    3167     }
    3168     else
    3169     {
    3170         // no disks to export:
    3171         ulTotalOperationsWeight = 1;
    3172         m->ulWeightPerOperation = 1;
    3173     }
    3174     ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
    3175     ulTotalOperationsWeight += ulOVFCreationWeight;
    3176 
    3177     Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
    3178          ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
    3179 
    3180     rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
    3181                          bstrDescription,
    3182                          TRUE /* aCancelable */,
    3183                          cOperations, // ULONG cOperations,
    3184                          ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
    3185                          bstrDescription, // CBSTR bstrFirstOperationDescription,
    3186                          ulOVFCreationWeight); // ULONG ulFirstOperationWeight,
    3187     return rc;
    3188 }
    3189 
    3190 /**
    3191  * Called from the import and export background threads to synchronize the second
    3192  * background disk thread's progress object with the current progress object so
    3193  * that the user interface sees progress correctly and that cancel signals are
    3194  * passed on to the second thread.
    3195  * @param pProgressThis Progress object of the current thread.
    3196  * @param pProgressAsync Progress object of asynchronous task running in background.
    3197  */
    3198 void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
    3199                                      ComPtr<IProgress> &pProgressAsync)
    3200 {
    3201     HRESULT rc;
    3202 
    3203     // now loop until the asynchronous operation completes and then report its result
    3204     BOOL fCompleted;
    3205     BOOL fCanceled;
    3206     ULONG currentPercent;
    3207     while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
    3208     {
    3209         rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
    3210         if (FAILED(rc)) throw rc;
    3211         if (fCanceled)
    3212         {
    3213             pProgressAsync->Cancel();
    3214             break;
    3215         }
    3216 
    3217         rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
    3218         if (FAILED(rc)) throw rc;
    3219         if (!pProgressThis.isNull())
    3220             pProgressThis->setCurrentOperationProgress(currentPercent);
    3221         if (fCompleted)
    3222             break;
    3223 
    3224         /* Make sure the loop is not too tight */
    3225         rc = pProgressAsync->WaitForCompletion(100);
    3226         if (FAILED(rc)) throw rc;
    3227     }
    3228     // report result of asynchronous operation
    3229     LONG iRc;
    3230     rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
    3231     if (FAILED(rc)) throw rc;
    3232 
    3233 
    3234     // if the thread of the progress object has an error, then
    3235     // retrieve the error info from there, or it'll be lost
    3236     if (FAILED(iRc))
    3237     {
    3238         ProgressErrorInfo info(pProgressAsync);
    3239         Utf8Str str(info.getText());
    3240         const char *pcsz = str.c_str();
    3241         HRESULT rc2 = setError(iRc, pcsz);
    3242         throw rc2;
    3243     }
    3244 }
    3245 
    3246 void Appliance::addWarning(const char* aWarning, ...)
    3247 {
    3248     va_list args;
    3249     va_start(args, aWarning);
    3250     Utf8StrFmtVA str(aWarning, args);
    3251     va_end(args);
    3252     m->llWarnings.push_back(str);
    3253 }
    3254 
    32553703////////////////////////////////////////////////////////////////////////////////
    32563704//
     
    32603708
    32613709DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
    3262 struct shutup3 {};
    32633710
    32643711/**
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