VirtualBox

Changeset 20044 in vbox for trunk


Ignore:
Timestamp:
May 26, 2009 3:38:55 PM (16 years ago)
Author:
vboxsync
Message:

Main-S3: initial code for the export of OVF's to an S3 server

Location:
trunk/src/VBox/Main
Files:
2 added
5 edited

Legend:

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

    r19681 r20044  
    2121 */
    2222
    23 #include <VBox/param.h>
    2423#include <iprt/stream.h>
    2524#include <iprt/path.h>
    2625#include <iprt/dir.h>
    2726#include <iprt/file.h>
     27#include <iprt/s3.h>
     28
     29#include <VBox/param.h>
     30#include <VBox/version.h>
    2831
    2932#include "ApplianceImpl.h"
     33#include "VFSExplorerImpl.h"
    3034#include "VirtualBoxImpl.h"
    3135#include "GuestOSTypeImpl.h"
     
    460464 * @return
    461465 */
    462 
    463466HRESULT Appliance::init(VirtualBox *aVirtualBox)
    464467{
     
    25012504struct Appliance::TaskWriteOVF
    25022505{
    2503     TaskWriteOVF(Appliance *aThat, Progress *aProgress)
    2504         : pAppliance(aThat),
    2505           enFormat(unspecified),
    2506           progress(aProgress),
     2506    enum OVFFormat
     2507    {
     2508        unspecified,
     2509        OVF_0_9,
     2510        OVF_1_0
     2511    };
     2512    enum TaskType
     2513    {
     2514        Write
     2515    };
     2516
     2517    TaskWriteOVF(OVFFormat aFormat, Appliance *aThat)
     2518        : taskType(Write),
     2519          storageType(VFSType_File),
     2520          enFormat(aFormat),
     2521          pAppliance(aThat),
    25072522          rc(S_OK)
    25082523    {}
    25092524    ~TaskWriteOVF() {}
    25102525
    2511     HRESULT startThread();
    2512 
     2526    int startThread();
     2527    static int uploadProgress(unsigned uPercent, void *pvUser);
     2528
     2529    TaskType taskType;
     2530    VFSType_T storageType;
     2531    Utf8Str filepath;
     2532    Utf8Str hostname;
     2533    Utf8Str username;
     2534    Utf8Str password;
     2535    OVFFormat enFormat;
    25132536    Appliance *pAppliance;
    2514     enum { unspecified, OVF_0_9, OVF_1_0 }
    2515         enFormat;
    2516 
    25172537    ComObjPtr<Progress> progress;
    25182538    HRESULT rc;
    25192539};
    25202540
    2521 HRESULT Appliance::TaskWriteOVF::startThread()
     2541int Appliance::TaskWriteOVF::startThread()
    25222542{
    25232543    int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this,
    25242544                             0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    25252545                             "Appliance::Task");
     2546
    25262547    ComAssertMsgRCRet(vrc,
    2527                       ("Could not create taskThreadExportOVF (%Rrc)\n", vrc), E_FAIL);
    2528 
    2529     return S_OK;
     2548                      ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL);
     2549
     2550    return vrc;
    25302551}
    25312552
     2553/* static */
     2554int Appliance::TaskWriteOVF::uploadProgress(unsigned uPercent, void *pvUser)
     2555{
     2556    Appliance::TaskWriteOVF* pTask = *(Appliance::TaskWriteOVF**)pvUser;
     2557
     2558    if (pTask &&
     2559        !pTask->progress.isNull())
     2560    {
     2561        BOOL fCanceled;
     2562        pTask->progress->COMGETTER(Canceled)(&fCanceled);
     2563        if (fCanceled)
     2564            return -1;
     2565        pTask->progress->setCurrentOperationProgress(uPercent);
     2566    }
     2567    RTPrintf ("%u%%\n", uPercent);
     2568    return VINF_SUCCESS;
     2569}
     2570
     2571STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
     2572{
     2573    HRESULT rc = S_OK;
     2574
     2575    CheckComArgOutPointerValid(aExplorer);
     2576
     2577    AutoCaller autoCaller(this);
     2578    CheckComRCReturnRC(autoCaller.rc());
     2579
     2580    AutoReadLock(this);
     2581
     2582    Utf8Str uri(aURI);
     2583    /* Check which kind of export the user has requested */
     2584    VFSType_T type = VFSType_File;
     2585    Utf8Str strProtocol = "";
     2586    /* Check the URI for the target format */
     2587    if (uri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
     2588    {
     2589        type = VFSType_S3;
     2590        strProtocol = "SunCloud://";
     2591    }
     2592    else if (uri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
     2593    {
     2594        type = VFSType_S3;
     2595        strProtocol = "S3://";
     2596    }
     2597    else if (uri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
     2598        throw E_NOTIMPL;
     2599
     2600    Utf8Str strFilepath;
     2601    Utf8Str strHostname;
     2602    Utf8Str strUsername;
     2603    Utf8Str strPassword;
     2604    parseURI(uri, strProtocol, strFilepath, strHostname, strUsername, strPassword);
     2605
     2606    ComObjPtr<VFSExplorer> explorer;
     2607    explorer.createObject();
     2608
     2609    rc = explorer->init(type, strFilepath, strHostname, strUsername, strPassword, mVirtualBox);
     2610
     2611    if (SUCCEEDED(rc))
     2612        /* Return explorer to the caller */
     2613        explorer.queryInterfaceTo(aExplorer);
     2614
     2615    return rc;
     2616}
     2617
    25322618STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress)
    25332619{
     
    25372623
    25382624    AutoCaller autoCaller(this);
    2539     if (FAILED(rc = autoCaller.rc())) return rc;
     2625    CheckComRCReturnRC(autoCaller.rc());
    25402626
    25412627    AutoWriteLock(this);
    25422628
    25432629    // see if we can handle this file; for now we insist it has an ".ovf" extension
    2544     m->strPath = path;
    2545     if (!m->strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
     2630    Utf8Str strPath = path;
     2631    if (!strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))
    25462632        return setError(VBOX_E_FILE_ERROR,
    25472633                        tr("Appliance file must have .ovf extension"));
    25482634
    25492635    ComObjPtr<Progress> progress;
    2550     try
    2551     {
    2552         Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"),
    2553                                     m->strPath.raw());
    2554         rc = setUpProgress(progress, progressDesc);
    2555         if (FAILED(rc)) throw rc;
    2556 
    2557         /* Initialize our worker task */
    2558         std::auto_ptr<TaskWriteOVF> task(new TaskWriteOVF(this, progress));
    2559         //AssertComRCThrowRC (task->autoCaller.rc());
    2560 
    2561         Utf8Str strFormat(format);
    2562         if (strFormat == "ovf-0.9")
    2563             task->enFormat = TaskWriteOVF::OVF_0_9;
    2564         else if (strFormat == "ovf-1.0")
    2565             task->enFormat = TaskWriteOVF::OVF_1_0;
    2566         else
    2567             return setError(VBOX_E_FILE_ERROR,
    2568                             tr("Invalid format \"%s\" specified"), strFormat.c_str());
    2569 
    2570         rc = task->startThread();
    2571         CheckComRCThrowRC(rc);
    2572 
    2573         task.release();
    2574     }
    2575     catch (HRESULT aRC)
    2576     {
    2577         rc = aRC;
    2578     }
     2636    Utf8Str strFormat(format);
     2637    TaskWriteOVF::OVFFormat ovfF;
     2638    if (strFormat == "ovf-0.9")
     2639        ovfF = TaskWriteOVF::OVF_0_9;
     2640    else if (strFormat == "ovf-1.0")
     2641        ovfF = TaskWriteOVF::OVF_1_0;
     2642    else
     2643        return setError(VBOX_E_FILE_ERROR,
     2644                        tr("Invalid format \"%s\" specified"), strFormat.c_str());
     2645
     2646    rc = writeImpl(ovfF, strPath, progress);
    25792647
    25802648    if (SUCCEEDED(rc))
     
    25832651
    25842652    return rc;
     2653}
     2654
     2655void Appliance::parseURI(Utf8Str strUri, const Utf8Str &strProtocol, Utf8Str &strFilepath, Utf8Str &strHostname, Utf8Str &strUsername, Utf8Str &strPassword)
     2656{
     2657    /* Remove the protocol */
     2658    if (strUri.startsWith(strProtocol, Utf8Str::CaseInsensitive))
     2659        strUri = strUri.substr(strProtocol.length());
     2660    size_t uppos = strUri.find("@");
     2661    if (uppos != Utf8Str::npos)
     2662    {
     2663        strUsername = strUri.substr(0, uppos);
     2664        strUri = strUri.substr(uppos + 1);
     2665        size_t upos = strUsername.find(":");
     2666        if (upos != Utf8Str::npos)
     2667        {
     2668            strPassword = strUsername.substr(upos + 1);
     2669            strUsername = strUsername.substr(0, upos);
     2670        }
     2671    }
     2672    size_t hpos = strUri.find("/");
     2673    if (hpos != Utf8Str::npos)
     2674    {
     2675        strHostname = strUri.substr(0, hpos);
     2676        strUri = strUri.substr(hpos);
     2677    }
     2678    strFilepath = strUri;
     2679    RTPrintf("%s - %s - %s - %s\n", strUsername.c_str(), strPassword.c_str(), strHostname.c_str(), strFilepath.c_str());
     2680}
     2681
     2682HRESULT Appliance::writeImpl(int aFormat, Utf8Str aPath, ComObjPtr<Progress> &aProgress)
     2683{
     2684    HRESULT rc = S_OK;
     2685    try
     2686    {
     2687        m->strPath = aPath;
     2688
     2689        /* Initialize our worker task */
     2690        std::auto_ptr<TaskWriteOVF> task(new TaskWriteOVF((TaskWriteOVF::OVFFormat)aFormat, this));
     2691
     2692        /* Check which kind of export the user has requested */
     2693        Utf8Str strProtocol = "";
     2694        /* Check the URI for the target format */
     2695        if (m->strPath.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
     2696        {
     2697            task->storageType = VFSType_S3;
     2698            strProtocol = "SunCloud://";
     2699        }
     2700        else if (m->strPath.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
     2701        {
     2702            task->storageType = VFSType_S3;
     2703            strProtocol = "S3://";
     2704        }
     2705        else if (m->strPath.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
     2706            throw E_NOTIMPL;
     2707
     2708        parseURI(m->strPath, strProtocol, task->filepath, task->hostname, task->username, task->password);
     2709        Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"),
     2710                                    task->filepath.c_str());
     2711
     2712        /* todo: This progress init stuff should be done a little bit more generic */
     2713        if (task->storageType == VFSType_S3)
     2714            rc = setUpProgressUpload(aProgress, progressDesc);
     2715        else
     2716            rc = setUpProgress(aProgress, progressDesc);
     2717        if (FAILED(rc)) throw rc;
     2718
     2719        task->progress = aProgress;
     2720
     2721        rc = task->startThread();
     2722        CheckComRCThrowRC(rc);
     2723
     2724        task.release();
     2725    }
     2726    catch (HRESULT aRC)
     2727    {
     2728        rc = aRC;
     2729    }
     2730
     2731    return rc;
     2732}
     2733
     2734DECLCALLBACK(int) Appliance::taskThreadWriteOVF(RTTHREAD /* aThread */, void *pvUser)
     2735{
     2736    std::auto_ptr<TaskWriteOVF> task(static_cast<TaskWriteOVF*>(pvUser));
     2737    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
     2738
     2739    Appliance *pAppliance = task->pAppliance;
     2740
     2741    LogFlowFuncEnter();
     2742    LogFlowFunc(("Appliance %p\n", pAppliance));
     2743
     2744    HRESULT rc = S_OK;
     2745
     2746    switch(task->taskType)
     2747    {
     2748        case TaskWriteOVF::Write:
     2749        {
     2750            if (task->storageType == VFSType_File)
     2751                rc = pAppliance->writeFS(task.get());
     2752            else if (task->storageType == VFSType_S3)
     2753                rc = pAppliance->writeS3(task.get());
     2754            break;
     2755        }
     2756    }
     2757
     2758    task->rc = rc;
     2759
     2760    LogFlowFunc(("rc=%Rhrc\n", rc));
     2761    LogFlowFuncLeave();
     2762
     2763    return VINF_SUCCESS;
    25852764}
    25862765
     
    25912770 */
    25922771/* static */
    2593 DECLCALLBACK(int) Appliance::taskThreadWriteOVF(RTTHREAD /* aThread */, void *pvUser)
    2594 {
    2595     std::auto_ptr<TaskWriteOVF> task(static_cast<TaskWriteOVF*>(pvUser));
    2596     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    2597 
    2598     Appliance *pAppliance = task->pAppliance;
    2599 
     2772int Appliance::writeFS(TaskWriteOVF *pTask)
     2773{
    26002774    LogFlowFuncEnter();
    2601     LogFlowFunc(("Appliance %p\n", pAppliance));
    2602 
    2603     AutoCaller autoCaller(pAppliance);
     2775    LogFlowFunc(("Appliance %p\n", this));
     2776
     2777    AutoCaller autoCaller(this);
    26042778    CheckComRCReturnRC(autoCaller.rc());
    26052779
    2606     AutoWriteLock appLock(pAppliance);
     2780    AutoWriteLock appLock(this);
    26072781
    26082782    HRESULT rc = S_OK;
    2609 
    2610     ComPtr<IVirtualBox> pVirtualBox(pAppliance->mVirtualBox);
    26112783
    26122784    try
     
    26152787        xml::ElementNode *pelmRoot = doc.createRootElement("Envelope");
    26162788
    2617         pelmRoot->setAttribute("ovf:version", (task->enFormat == TaskWriteOVF::OVF_1_0) ? "1.0" : "0.9");
     2789        pelmRoot->setAttribute("ovf:version", (pTask->enFormat == TaskWriteOVF::OVF_1_0) ? "1.0" : "0.9");
    26182790        pelmRoot->setAttribute("xml:lang", "en-US");
    26192791
     
    26242796        pelmRoot->setAttribute("xmlns:ovf", strNamespace);
    26252797
    2626 //         pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");
     2798         pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");
    26272799        pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData");
    26282800        pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData");
    26292801        pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    2630 //         pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
     2802         pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
    26312803
    26322804        // <Envelope>/<References>
     
    26392811            </DiskSection> */
    26402812        xml::ElementNode *pelmDiskSection;
    2641         if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2813        if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    26422814        {
    26432815            // <Section xsi:type="ovf:DiskSection_Type">
     
    26622834            </NetworkSection> */
    26632835        xml::ElementNode *pelmNetworkSection;
    2664         if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2836        if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    26652837        {
    26662838            // <Section xsi:type="ovf:NetworkSection_Type">
     
    26842856        // one machine, it seems
    26852857        xml::ElementNode *pelmToAddVirtualSystemsTo;
    2686         if (pAppliance->m->virtualSystemDescriptions.size() > 1)
     2858        if (m->virtualSystemDescriptions.size() > 1)
    26872859        {
    2688             if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2860            if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    26892861                throw setError(VBOX_E_FILE_ERROR,
    26902862                               tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0"));
     
    26982870        list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    26992871        /* Iterate through all virtual systems of that appliance */
    2700         for (it = pAppliance->m->virtualSystemDescriptions.begin();
    2701              it != pAppliance->m->virtualSystemDescriptions.end();
     2872        for (it = m->virtualSystemDescriptions.begin();
     2873             it != m->virtualSystemDescriptions.end();
    27022874             ++it)
    27032875        {
     
    27052877
    27062878            xml::ElementNode *pelmVirtualSystem;
    2707             if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2879            if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    27082880            {
    27092881                // <Section xsi:type="ovf:NetworkSection_Type">
     
    27492921                </Section> */
    27502922                xml::ElementNode *pelmAnnotationSection;
    2751                 if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2923                if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    27522924                {
    27532925                    // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
     
    27812953                    </Section> */
    27822954                xml::ElementNode *pelmAnnotationSection;
    2783                 if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2955                if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    27842956                {
    27852957                    // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
     
    28042976                   </EulaSection> */
    28052977                xml::ElementNode *pelmEulaSection;
    2806                 if (task->enFormat == TaskWriteOVF::OVF_0_9)
     2978                if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    28072979                {
    28082980                    pelmEulaSection = pelmVirtualSystem->createChild("Section");
     
    28262998                </OperatingSystemSection> */
    28272999            xml::ElementNode *pelmOperatingSystemSection;
    2828             if (task->enFormat == TaskWriteOVF::OVF_0_9)
     3000            if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    28293001            {
    28303002                pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section");
     
    28423014            // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso">
    28433015            xml::ElementNode *pelmVirtualHardwareSection;
    2844             if (task->enFormat == TaskWriteOVF::OVF_0_9)
     3016            if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    28453017            {
    28463018                // <Section xsi:type="ovf:VirtualHardwareSection_Type">
     
    28683040            // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
    28693041            const char *pcszHardware = "virtualbox-2.2";
    2870             if (task->enFormat == TaskWriteOVF::OVF_0_9)
     3042            if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    28713043                // pretend to be vmware compatible then
    28723044                pcszHardware = "vmx-6";
     
    32263398                        // <rasd:InstanceID>1</rasd:InstanceID>
    32273399                        xml::ElementNode *pelmInstanceID;
    3228                         if (task->enFormat == TaskWriteOVF::OVF_0_9)
     3400                        if (pTask->enFormat == TaskWriteOVF::OVF_0_9)
    32293401                            pelmInstanceID = pItem->createChild("rasd:InstanceId");
    32303402                        else
     
    33023474            const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
    33033475            // target path needs to be composed from where the output OVF is
    3304             Utf8Str strTargetFilePath = stripFilename(pAppliance->m->strPath);
     3476            Utf8Str strTargetFilePath = stripFilename(m->strPath);
    33053477            strTargetFilePath.append("/");
    33063478            strTargetFilePath.append(strTargetFileNameOnly);
     
    33123484
    33133485            Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
    3314             rc = pVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());
     3486            rc = mVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());
    33153487            if (FAILED(rc)) throw rc;
    33163488
     
    33203492            // create a new hard disk interface for the destination disk image
    33213493            Log(("Creating target disk \"%s\"\n", strTargetFilePath.raw()));
    3322             rc = pVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam());
     3494            rc = mVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam());
    33233495            if (FAILED(rc)) throw rc;
    33243496
     
    33323504
    33333505                // advance to the next operation
    3334                 if (!task->progress.isNull())
    3335                     task->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),
     3506                if (!pTask->progress.isNull())
     3507                    pTask->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),
    33363508                                                     pDiskEntry->ulSizeMB);     // operation's weight, as set up with the IProgress originally);
    33373509
    33383510                // now wait for the background disk operation to complete; this throws HRESULTs on error
    3339                 pAppliance->waitForAsyncProgress(task->progress, pProgress2);
     3511                waitForAsyncProgress(pTask->progress, pProgress2);
    33403512            }
    33413513            catch (HRESULT rc3)
     
    33443516                // it'll stick in the registry forever
    33453517                pTargetDisk->Close();
    3346                 throw rc3;
     3518                throw;
    33473519            }
    33483520
     
    33813553        // now go write the XML
    33823554        xml::XmlFileWriter writer(doc);
    3383         writer.write(pAppliance->m->strPath.c_str());
     3555        writer.write(m->strPath.c_str());
    33843556    }
    33853557    catch(xml::Error &x)
     
    33933565    }
    33943566
    3395     task->rc = rc;
    3396 
    3397     if (!task->progress.isNull())
    3398         task->progress->notifyComplete(rc);
     3567    pTask->rc = rc;
     3568
     3569    if (!pTask->progress.isNull())
     3570        pTask->progress->notifyComplete(rc);
     3571
     3572    LogFlowFunc(("rc=%Rhrc\n", rc));
     3573    LogFlowFuncLeave();
     3574
     3575    return VINF_SUCCESS;
     3576}
     3577
     3578/**
     3579 * Worker thread implementation for Upload() (ovf uploader).
     3580 * @param aThread
     3581 * @param pvUser
     3582 */
     3583/* static */
     3584int Appliance::writeS3(TaskWriteOVF *pTask)
     3585{
     3586    LogFlowFuncEnter();
     3587    LogFlowFunc(("Appliance %p\n", this));
     3588
     3589    AutoCaller autoCaller(this);
     3590    CheckComRCReturnRC(autoCaller.rc());
     3591
     3592    HRESULT rc = S_OK;
     3593
     3594    AutoWriteLock appLock(this);
     3595
     3596    /* Buckets are S3 specific. So parse the bucket out of the file path */
     3597    Utf8Str tmpPath = pTask->filepath;
     3598    if (!tmpPath.startsWith("/"))
     3599        return setError(E_INVALIDARG,
     3600                        tr("The path '%s' must start with /"), tmpPath.c_str());
     3601    Utf8Str bucket;
     3602    size_t bpos = tmpPath.find("/", 1);
     3603    if (bpos != Utf8Str::npos)
     3604    {
     3605        bucket = tmpPath.substr(1, bpos - 1); /* The bucket without any slashes */
     3606        tmpPath = tmpPath.substr(bpos); /* The rest of the file path */
     3607    }
     3608    /* If there is no bucket name provided reject the upload */
     3609    if (bucket.isEmpty())
     3610        return setError(E_INVALIDARG,
     3611                        tr("You doesn't provide a bucket name in the URI"), tmpPath.c_str());
     3612
     3613    int vrc = VINF_SUCCESS;
     3614    RTS3 hS3 = NULL;
     3615    char szOSTmpDir[RTPATH_MAX];
     3616    RTPathTemp(szOSTmpDir, sizeof(szOSTmpDir));
     3617    /* The template for the temporary directory created below */
     3618    char *pszTmpDir;
     3619    RTStrAPrintf(&pszTmpDir, "%s/vbox-ovf-XXXXXX", szOSTmpDir);
     3620    list< pair<Utf8Str, ULONG> > filesList;
     3621
     3622    // todo:
     3623    // - getting the tmp directory (especially on win)
     3624    // - usable error codes
     3625    // - seems snapshot filenames are problematic {uuid}.vdi
     3626    try
     3627    {
     3628        /* We need a temporary directory which we can put the OVF file & all
     3629         * disk images in */
     3630        if (!mkdtemp(pszTmpDir))
     3631            throw setError(VBOX_E_FILE_ERROR,
     3632                           tr("Cannot create temporary directory '%s'"), pszTmpDir);
     3633
     3634        /* The temporary name of the target OVF file */
     3635        Utf8StrFmt strTmpOvf("%s/%s", pszTmpDir, RTPathFilename(tmpPath));
     3636
     3637        /* Prepare the temporary writing of the OVF */
     3638        ComObjPtr<Progress> progress;
     3639        rc = writeImpl(pTask->enFormat, strTmpOvf.c_str(), progress);
     3640        if (FAILED(rc)) throw rc;
     3641
     3642        /* Unlock the appliance for the writing thread */
     3643        appLock.unlock();
     3644        /* Wait until the writing is done, but report the progress back to the
     3645           caller */
     3646        ComPtr<IProgress> progressInt(progress);
     3647        waitForAsyncProgress(pTask->progress, progressInt); /* Any errors will be thrown */
     3648
     3649        /* Again lock the appliance for the next steps */
     3650        appLock.lock();
     3651
     3652        vrc = RTPathExists(strTmpOvf.c_str()); /* Paranoid check */
     3653        if(RT_FAILURE(vrc))
     3654            throw setError(VBOX_E_FILE_ERROR,
     3655                           tr("Cannot find source file '%s'"), strTmpOvf.c_str());
     3656        /* Add the OVF file */
     3657        filesList.push_back(pair<Utf8Str, ULONG>(strTmpOvf, m->ulWeightPerOperation)); /* Use 1% of the total for the OVF file upload */
     3658
     3659        /* Now add every disks of every virtual system */
     3660        list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
     3661        for (it = m->virtualSystemDescriptions.begin();
     3662             it != m->virtualSystemDescriptions.end();
     3663             ++it)
     3664        {
     3665            ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
     3666            std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
     3667            std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
     3668            for (itH = avsdeHDs.begin();
     3669                 itH != avsdeHDs.end();
     3670                 ++itH)
     3671            {
     3672                const Utf8Str &strTargetFileNameOnly = (*itH)->strOvf;
     3673                /* Target path needs to be composed from where the output OVF is */
     3674                Utf8Str strTargetFilePath = stripFilename(m->strPath);
     3675                strTargetFilePath.append("/");
     3676                strTargetFilePath.append(strTargetFileNameOnly);
     3677                vrc = RTPathExists(strTargetFilePath.c_str()); /* Paranoid check */
     3678                if(RT_FAILURE(vrc))
     3679                    throw setError(VBOX_E_FILE_ERROR,
     3680                                   tr("Cannot find source file '%s'"), strTargetFilePath.c_str());
     3681                filesList.push_back(pair<Utf8Str, ULONG>(strTargetFilePath, (*itH)->ulSizeMB));
     3682            }
     3683        }
     3684        /* Next we have to upload the OVF & all disk images */
     3685        vrc = RTS3Create(&hS3, pTask->username.c_str(), pTask->password.c_str(), pTask->hostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
     3686        if(RT_FAILURE(vrc))
     3687            throw setError(VBOX_E_IPRT_ERROR,
     3688                           tr("Cannot create S3 service handler"));
     3689        RTS3SetProgressCallback(hS3, pTask->uploadProgress, &pTask);
     3690
     3691        /* Upload all files */
     3692        for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
     3693        {
     3694            const pair<Utf8Str, ULONG> &s = (*it1);
     3695            char *pszFilename = RTPathFilename(s.first.c_str());
     3696            /* Advance to the next operation */
     3697            if (!pTask->progress.isNull())
     3698                pTask->progress->setNextOperation(BstrFmt(tr("Uploading file '%s'"), pszFilename), s.second);
     3699            vrc = RTS3PutKey(hS3, bucket.c_str(), pszFilename, s.first.c_str());
     3700            if (RT_FAILURE(vrc))
     3701            {
     3702                if(vrc == VERR_S3_CANCELED)
     3703                    break;
     3704                else if(vrc == VERR_S3_ACCESS_DENIED)
     3705                    throw setError(E_ACCESSDENIED,
     3706                                   tr("Cannot upload file '%s' to S3 storage server (Access denied)"), pszFilename);
     3707                else if(vrc == VERR_S3_NOT_FOUND)
     3708                    throw setError(VBOX_E_FILE_ERROR,
     3709                                   tr("Cannot upload file '%s' to S3 storage server (File not found)"), pszFilename);
     3710                else
     3711                    throw setError(VBOX_E_IPRT_ERROR,
     3712                                   tr("Cannot upload file '%s' to S3 storage server (%Rrc)"), pszFilename, vrc);
     3713            }
     3714        }
     3715
     3716    }
     3717    catch(HRESULT aRC)
     3718    {
     3719        rc = aRC;
     3720    }
     3721    /* Cleanup */
     3722    if (hS3)
     3723        RTS3Destroy(hS3);
     3724    /* Delete all files which where temporary created */
     3725    for (list< pair<Utf8Str, ULONG> >::const_iterator it1 = filesList.begin(); it1 != filesList.end(); ++it1)
     3726    {
     3727        const pair<Utf8Str, ULONG> &s = (*it1);
     3728        vrc = RTFileDelete(s.first.c_str());
     3729        if(RT_FAILURE(vrc))
     3730            rc = setError(VBOX_E_FILE_ERROR,
     3731                          tr("Cannot delete file '%s'"), s.first.c_str());
     3732    }
     3733    /* Delete the temporary directory */
     3734    if (RTPathExists(pszTmpDir))
     3735    {
     3736        vrc = RTDirRemove(pszTmpDir);
     3737        if(RT_FAILURE(vrc))
     3738            rc = setError(VBOX_E_FILE_ERROR,
     3739                          tr("Cannot delete temporary directory '%s'"), pszTmpDir);
     3740    }
     3741    if (pszTmpDir)
     3742        RTStrFree(pszTmpDir);
     3743
     3744    pTask->rc = rc;
     3745
     3746    if (!pTask->progress.isNull())
     3747        pTask->progress->notifyComplete(rc);
    33993748
    34003749    LogFlowFunc(("rc=%Rhrc\n", rc));
     
    35423891                         bstrDescription, // CBSTR bstrFirstOperationDescription,
    35433892                         m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
     3893    return rc;
     3894}
     3895
     3896HRESULT Appliance::setUpProgressUpload(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
     3897{
     3898    HRESULT rc;
     3899
     3900    /* Create the progress object */
     3901    pProgress.createObject();
     3902
     3903    // weigh the disk images according to their sizes
     3904    uint32_t ulTotalMB = 0;
     3905    uint32_t cDisks = 0;
     3906    list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
     3907    for (it = m->virtualSystemDescriptions.begin();
     3908         it != m->virtualSystemDescriptions.end();
     3909         ++it)
     3910    {
     3911        ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
     3912        /* One for every hard disk of the Virtual System */
     3913        std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
     3914        std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
     3915        for (itH = avsdeHDs.begin();
     3916             itH != avsdeHDs.end();
     3917             ++itH)
     3918        {
     3919            const VirtualSystemDescriptionEntry *pHD = *itH;
     3920            ulTotalMB += pHD->ulSizeMB;
     3921            ++cDisks;
     3922        }
     3923    }
     3924
     3925    ULONG cOperations = 1 + 1 + cDisks;     // one op per disk plus 1 for the OVF & 1 plus to the temporary creation */
     3926
     3927    ULONG ulTotalOperationsWeight;
     3928    if (ulTotalMB)
     3929    {
     3930        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)
     3931        ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
     3932    }
     3933    else
     3934    {
     3935        // no disks to export:
     3936        ulTotalOperationsWeight = 1;
     3937        m->ulWeightPerOperation = 1;
     3938    }
     3939    ULONG ulOVFCreationWeight = ((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
     3940    ulTotalOperationsWeight += ulOVFCreationWeight;
     3941
     3942    Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
     3943         ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
     3944
     3945    rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
     3946                         bstrDescription,
     3947                         TRUE /* aCancelable */,
     3948                         cOperations, // ULONG cOperations,
     3949                         ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
     3950                         bstrDescription, // CBSTR bstrFirstOperationDescription,
     3951                         ulOVFCreationWeight); // ULONG ulFirstOperationWeight,
    35443952    return rc;
    35453953}
  • trunk/src/VBox/Main/Makefile.kmk

    r20042 r20044  
    285285        VirtualBoxImplExtra.cpp \
    286286        ApplianceImpl.cpp \
     287        VFSExplorerImpl.cpp \
    287288        MachineImpl.cpp \
    288289        SnapshotImpl.cpp \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r20042 r20044  
    28902890    </method>
    28912891
     2892  </interface>
     2893
     2894  <!--
     2895  // IVFSExplorer
     2896  /////////////////////////////////////////////////////////////////////////
     2897  -->
     2898
     2899  <enum
     2900    name="VFSType"
     2901    uuid="813999ba-b949-48a8-9230-aadc6285e2f2"
     2902  >
     2903    <desc>
     2904    </desc>
     2905
     2906    <const name="File" value="1" />
     2907    <const name="Cloud" value="2" />
     2908    <const name="S3" value="3" />
     2909    <const name="WebDav" value="4" />
     2910  </enum>
     2911
     2912  <enum
     2913    name="FileType"
     2914    uuid="714333cd-44e2-415f-a245-d378fa9b1242"
     2915  >
     2916    <desc>
     2917    </desc>
     2918
     2919    <const name="Unknown" value="1" />
     2920    <const name="Fifo" value="2" />
     2921    <const name="DevChar" value="3" />
     2922    <const name="Directory" value="4" />
     2923    <const name="DevBlock" value="5" />
     2924    <const name="File" value="6" />
     2925    <const name="SymLink" value="7" />
     2926    <const name="Socket" value="8" />
     2927    <const name="WhiteOut" value="9" />
     2928  </enum>
     2929
     2930  <interface
     2931     name="IVFSExplorer" extends="$unknown"
     2932     uuid="fd7da337-80ef-4a5c-9122-918435e33003"
     2933     wsmap="managed"
     2934     >
     2935    <desc />
     2936
     2937    <attribute name="path" type="wstring" readonly="yes">
     2938      <desc />
     2939    </attribute>
     2940
     2941    <attribute name="type" type="VFSType" readonly="yes">
     2942      <desc />
     2943    </attribute>
     2944
     2945    <method name="update">
     2946      <desc />
     2947
     2948      <param name="aProgress" type="IProgress" dir="return">
     2949        <desc />
     2950      </param>
     2951    </method>
     2952
     2953    <method name="entryList">
     2954      <desc />
     2955
     2956      <param name="aNames" type="wstring" safearray="yes" dir="out">
     2957        <desc />
     2958      </param>
     2959
     2960      <param name="aTypes" type="unsigned long" safearray="yes" dir="out">
     2961        <desc />
     2962      </param>
     2963    </method>
     2964
     2965    <method name="exists">
     2966      <desc />
     2967
     2968      <param name="aNames" type="wstring" safearray="yes" dir="in">
     2969        <desc />
     2970      </param>
     2971
     2972      <param name="aExists" type="wstring" safearray="yes" dir="return">
     2973        <desc />
     2974      </param>
     2975    </method>
     2976
     2977    <method name="remove">
     2978      <desc />
     2979
     2980      <param name="aNames" type="wstring" safearray="yes" dir="in">
     2981        <desc />
     2982      </param>
     2983
     2984      <param name="aProgress" type="IProgress" dir="return">
     2985        <desc />
     2986      </param>
     2987    </method>
     2988   
    28922989  </interface>
    28932990
     
    30433140  <interface
    30443141     name="IAppliance" extends="$unknown"
    3045      uuid="30bfa6b8-9eda-4b0a-b218-a86813248ccd"
     3142     uuid="07495095-d16c-4911-8964-5914341ced5d"
    30463143     wsmap="managed"
    30473144     >
     
    32263323      <param name="aProgress" type="IProgress" dir="return">
    32273324        <desc></desc>
     3325      </param>
     3326    </method>
     3327
     3328    <method name="createVFSExplorer">
     3329      <desc />
     3330
     3331      <param name="aUri" type="wstring" dir="in">
     3332        <desc />
     3333      </param>
     3334
     3335      <param name="aExplorer" type="IVFSExplorer" dir="return">
     3336        <desc />
    32283337      </param>
    32293338    </method>
  • trunk/src/VBox/Main/include/ApplianceImpl.h

    r19239 r20044  
    7575
    7676    /* IAppliance methods */
     77    /* Import methods */
    7778    STDMETHOD(Read)(IN_BSTR path);
    7879    STDMETHOD(Interpret)(void);
    7980    STDMETHOD(ImportMachines)(IProgress **aProgress);
     81    /* Export methods */
     82    STDMETHOD(CreateVFSExplorer)(IN_BSTR aURI, IVFSExplorer **aExplorer);
    8083    STDMETHOD(Write)(IN_BSTR format, IN_BSTR path, IProgress **aProgress);
     84
    8185    STDMETHOD(GetWarnings)(ComSafeArrayOut(BSTR, aWarnings));
    8286
     
    99103    HRESULT searchUniqueDiskImageFilePath(Utf8Str& aName) const;
    100104    HRESULT setUpProgress(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription);
     105    HRESULT setUpProgressUpload(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription);
    101106    void waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis, ComPtr<IProgress> &pProgressAsync);
    102107    void addWarning(const char* aWarning, ...);
    103108
     109    void parseURI(Utf8Str strUri, const Utf8Str &strProtocol, Utf8Str &strFilepath, Utf8Str &strHostname, Utf8Str &strUsername, Utf8Str &strPassword);
     110    HRESULT writeImpl(int aFormat, Utf8Str aPath, ComObjPtr<Progress> &aProgress);
     111
    104112    struct TaskImportMachines;  /* Worker thread for import */
    105113    static DECLCALLBACK(int) taskThreadImportMachines(RTTHREAD thread, void *pvUser);
    106114
    107     struct TaskWriteOVF;       /* Worker thread for export */
    108     static DECLCALLBACK(int) taskThreadWriteOVF(RTTHREAD thread, void *pvUser);
     115    struct TaskWriteOVF;        /* Worker threads for export */
     116    static DECLCALLBACK(int) taskThreadWriteOVF(RTTHREAD aThread, void *pvUser);
     117
     118    int writeFS(TaskWriteOVF *pTask);
     119    int writeS3(TaskWriteOVF *pTask);
    109120
    110121    friend class Machine;
  • trunk/src/VBox/Main/xpcom/server.cpp

    r19296 r20044  
    7474#include <VirtualBoxImpl.h>
    7575#include <MachineImpl.h>
     76#include <VFSExplorerImpl.h>
    7677#include <ApplianceImpl.h>
    7778#include <SnapshotImpl.h>
     
    110111NS_DECL_CLASSINFO(Machine)
    111112NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine)
     113
     114NS_DECL_CLASSINFO(VFSExplorer)
     115NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VFSExplorer, IVFSExplorer)
    112116
    113117NS_DECL_CLASSINFO(Appliance)
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