Changeset 20045 in vbox for trunk/src/VBox/Main
- Timestamp:
- May 26, 2009 3:44:07 PM (16 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 deleted
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ApplianceImpl.cpp
r20044 r20045 21 21 */ 22 22 23 #include <VBox/param.h> 23 24 #include <iprt/stream.h> 24 25 #include <iprt/path.h> 25 26 #include <iprt/dir.h> 26 27 #include <iprt/file.h> 27 #include <iprt/s3.h>28 29 #include <VBox/param.h>30 #include <VBox/version.h>31 28 32 29 #include "ApplianceImpl.h" 33 #include "VFSExplorerImpl.h"34 30 #include "VirtualBoxImpl.h" 35 31 #include "GuestOSTypeImpl.h" … … 464 460 * @return 465 461 */ 462 466 463 HRESULT Appliance::init(VirtualBox *aVirtualBox) 467 464 { … … 2504 2501 struct Appliance::TaskWriteOVF 2505 2502 { 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), 2503 TaskWriteOVF(Appliance *aThat, Progress *aProgress) 2504 : pAppliance(aThat), 2505 enFormat(unspecified), 2506 progress(aProgress), 2522 2507 rc(S_OK) 2523 2508 {} 2524 2509 ~TaskWriteOVF() {} 2525 2510 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; 2511 HRESULT startThread(); 2512 2536 2513 Appliance *pAppliance; 2514 enum { unspecified, OVF_0_9, OVF_1_0 } 2515 enFormat; 2516 2537 2517 ComObjPtr<Progress> progress; 2538 2518 HRESULT rc; 2539 2519 }; 2540 2520 2541 intAppliance::TaskWriteOVF::startThread()2521 HRESULT Appliance::TaskWriteOVF::startThread() 2542 2522 { 2543 2523 int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this, 2544 2524 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0, 2545 2525 "Appliance::Task"); 2546 2547 2526 ComAssertMsgRCRet(vrc, 2548 ("Could not create taskThread WriteOVF (%Rrc)\n", vrc), E_FAIL);2549 2550 return vrc;2527 ("Could not create taskThreadExportOVF (%Rrc)\n", vrc), E_FAIL); 2528 2529 return S_OK; 2551 2530 } 2552 2531 2553 /* static */ 2554 int 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 2571 STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer) 2532 STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress) 2572 2533 { 2573 2534 HRESULT rc = S_OK; 2574 2535 2575 CheckComArgOutPointerValid(a Explorer);2536 CheckComArgOutPointerValid(aProgress); 2576 2537 2577 2538 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 2618 STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress) 2619 { 2620 HRESULT rc = S_OK; 2621 2622 CheckComArgOutPointerValid(aProgress); 2623 2624 AutoCaller autoCaller(this); 2625 CheckComRCReturnRC(autoCaller.rc()); 2539 if (FAILED(rc = autoCaller.rc())) return rc; 2626 2540 2627 2541 AutoWriteLock(this); 2628 2542 2629 2543 // see if we can handle this file; for now we insist it has an ".ovf" extension 2630 Utf8StrstrPath = path;2631 if (! strPath.endsWith(".ovf", Utf8Str::CaseInsensitive))2544 m->strPath = path; 2545 if (!m->strPath.endsWith(".ovf", Utf8Str::CaseInsensitive)) 2632 2546 return setError(VBOX_E_FILE_ERROR, 2633 2547 tr("Appliance file must have .ovf extension")); 2634 2548 2635 2549 ComObjPtr<Progress> progress; 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 else2643 return setError(VBOX_E_FILE_ERROR,2644 tr("Invalid format \"%s\" specified"), strFormat.c_str());2645 2646 rc = writeImpl(ovfF, strPath, progress);2647 2648 if (SUCCEEDED(rc))2649 /* Return progress to the caller */2650 progress.queryInterfaceTo(aProgress);2651 2652 return rc;2653 }2654 2655 void 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 2682 HRESULT Appliance::writeImpl(int aFormat, Utf8Str aPath, ComObjPtr<Progress> &aProgress)2683 {2684 HRESULT rc = S_OK;2685 2550 try 2686 2551 { 2687 m->strPath = aPath; 2552 Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"), 2553 m->strPath.raw()); 2554 rc = setUpProgress(progress, progressDesc); 2555 if (FAILED(rc)) throw rc; 2688 2556 2689 2557 /* 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); 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; 2715 2566 else 2716 rc = setUpProgress(aProgress, progressDesc); 2717 if (FAILED(rc)) throw rc; 2718 2719 task->progress = aProgress; 2567 return setError(VBOX_E_FILE_ERROR, 2568 tr("Invalid format \"%s\" specified"), strFormat.c_str()); 2720 2569 2721 2570 rc = task->startThread(); … … 2729 2578 } 2730 2579 2580 if (SUCCEEDED(rc)) 2581 /* Return progress to the caller */ 2582 progress.queryInterfaceTo(aProgress); 2583 2731 2584 return rc; 2732 }2733 2734 DECLCALLBACK(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;2764 2585 } 2765 2586 … … 2770 2591 */ 2771 2592 /* static */ 2772 int Appliance::writeFS(TaskWriteOVF *pTask) 2773 { 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 2774 2600 LogFlowFuncEnter(); 2775 LogFlowFunc(("Appliance %p\n", this));2776 2777 AutoCaller autoCaller( this);2601 LogFlowFunc(("Appliance %p\n", pAppliance)); 2602 2603 AutoCaller autoCaller(pAppliance); 2778 2604 CheckComRCReturnRC(autoCaller.rc()); 2779 2605 2780 AutoWriteLock appLock( this);2606 AutoWriteLock appLock(pAppliance); 2781 2607 2782 2608 HRESULT rc = S_OK; 2609 2610 ComPtr<IVirtualBox> pVirtualBox(pAppliance->mVirtualBox); 2783 2611 2784 2612 try … … 2787 2615 xml::ElementNode *pelmRoot = doc.createRootElement("Envelope"); 2788 2616 2789 pelmRoot->setAttribute("ovf:version", ( pTask->enFormat == TaskWriteOVF::OVF_1_0) ? "1.0" : "0.9");2617 pelmRoot->setAttribute("ovf:version", (task->enFormat == TaskWriteOVF::OVF_1_0) ? "1.0" : "0.9"); 2790 2618 pelmRoot->setAttribute("xml:lang", "en-US"); 2791 2619 … … 2796 2624 pelmRoot->setAttribute("xmlns:ovf", strNamespace); 2797 2625 2798 pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");2626 // pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1"); 2799 2627 pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"); 2800 2628 pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"); 2801 2629 pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 2802 pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");2630 // pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd"); 2803 2631 2804 2632 // <Envelope>/<References> … … 2811 2639 </DiskSection> */ 2812 2640 xml::ElementNode *pelmDiskSection; 2813 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2641 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2814 2642 { 2815 2643 // <Section xsi:type="ovf:DiskSection_Type"> … … 2834 2662 </NetworkSection> */ 2835 2663 xml::ElementNode *pelmNetworkSection; 2836 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2664 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2837 2665 { 2838 2666 // <Section xsi:type="ovf:NetworkSection_Type"> … … 2856 2684 // one machine, it seems 2857 2685 xml::ElementNode *pelmToAddVirtualSystemsTo; 2858 if ( m->virtualSystemDescriptions.size() > 1)2686 if (pAppliance->m->virtualSystemDescriptions.size() > 1) 2859 2687 { 2860 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2688 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2861 2689 throw setError(VBOX_E_FILE_ERROR, 2862 2690 tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0")); … … 2870 2698 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it; 2871 2699 /* Iterate through all virtual systems of that appliance */ 2872 for (it = m->virtualSystemDescriptions.begin();2873 it != m->virtualSystemDescriptions.end();2700 for (it = pAppliance->m->virtualSystemDescriptions.begin(); 2701 it != pAppliance->m->virtualSystemDescriptions.end(); 2874 2702 ++it) 2875 2703 { … … 2877 2705 2878 2706 xml::ElementNode *pelmVirtualSystem; 2879 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2707 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2880 2708 { 2881 2709 // <Section xsi:type="ovf:NetworkSection_Type"> … … 2921 2749 </Section> */ 2922 2750 xml::ElementNode *pelmAnnotationSection; 2923 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2751 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2924 2752 { 2925 2753 // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type"> … … 2953 2781 </Section> */ 2954 2782 xml::ElementNode *pelmAnnotationSection; 2955 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2783 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2956 2784 { 2957 2785 // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type"> … … 2976 2804 </EulaSection> */ 2977 2805 xml::ElementNode *pelmEulaSection; 2978 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2806 if (task->enFormat == TaskWriteOVF::OVF_0_9) 2979 2807 { 2980 2808 pelmEulaSection = pelmVirtualSystem->createChild("Section"); … … 2998 2826 </OperatingSystemSection> */ 2999 2827 xml::ElementNode *pelmOperatingSystemSection; 3000 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2828 if (task->enFormat == TaskWriteOVF::OVF_0_9) 3001 2829 { 3002 2830 pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section"); … … 3014 2842 // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso"> 3015 2843 xml::ElementNode *pelmVirtualHardwareSection; 3016 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2844 if (task->enFormat == TaskWriteOVF::OVF_0_9) 3017 2845 { 3018 2846 // <Section xsi:type="ovf:VirtualHardwareSection_Type"> … … 3040 2868 // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType> 3041 2869 const char *pcszHardware = "virtualbox-2.2"; 3042 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)2870 if (task->enFormat == TaskWriteOVF::OVF_0_9) 3043 2871 // pretend to be vmware compatible then 3044 2872 pcszHardware = "vmx-6"; … … 3398 3226 // <rasd:InstanceID>1</rasd:InstanceID> 3399 3227 xml::ElementNode *pelmInstanceID; 3400 if ( pTask->enFormat == TaskWriteOVF::OVF_0_9)3228 if (task->enFormat == TaskWriteOVF::OVF_0_9) 3401 3229 pelmInstanceID = pItem->createChild("rasd:InstanceId"); 3402 3230 else … … 3474 3302 const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf; 3475 3303 // target path needs to be composed from where the output OVF is 3476 Utf8Str strTargetFilePath = stripFilename( m->strPath);3304 Utf8Str strTargetFilePath = stripFilename(pAppliance->m->strPath); 3477 3305 strTargetFilePath.append("/"); 3478 3306 strTargetFilePath.append(strTargetFileNameOnly); … … 3484 3312 3485 3313 Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw())); 3486 rc = mVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());3314 rc = pVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam()); 3487 3315 if (FAILED(rc)) throw rc; 3488 3316 … … 3492 3320 // create a new hard disk interface for the destination disk image 3493 3321 Log(("Creating target disk \"%s\"\n", strTargetFilePath.raw())); 3494 rc = mVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam());3322 rc = pVirtualBox->CreateHardDisk(bstrSrcFormat, Bstr(strTargetFilePath), pTargetDisk.asOutParam()); 3495 3323 if (FAILED(rc)) throw rc; 3496 3324 … … 3504 3332 3505 3333 // advance to the next operation 3506 if (! pTask->progress.isNull())3507 pTask->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),3334 if (!task->progress.isNull()) 3335 task->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()), 3508 3336 pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally); 3509 3337 3510 3338 // now wait for the background disk operation to complete; this throws HRESULTs on error 3511 waitForAsyncProgress(pTask->progress, pProgress2);3339 pAppliance->waitForAsyncProgress(task->progress, pProgress2); 3512 3340 } 3513 3341 catch (HRESULT rc3) … … 3516 3344 // it'll stick in the registry forever 3517 3345 pTargetDisk->Close(); 3518 throw ;3346 throw rc3; 3519 3347 } 3520 3348 … … 3553 3381 // now go write the XML 3554 3382 xml::XmlFileWriter writer(doc); 3555 writer.write( m->strPath.c_str());3383 writer.write(pAppliance->m->strPath.c_str()); 3556 3384 } 3557 3385 catch(xml::Error &x) … … 3565 3393 } 3566 3394 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 */ 3584 int 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); 3395 task->rc = rc; 3396 3397 if (!task->progress.isNull()) 3398 task->progress->notifyComplete(rc); 3748 3399 3749 3400 LogFlowFunc(("rc=%Rhrc\n", rc)); … … 3894 3545 } 3895 3546 3896 HRESULT 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 sizes3904 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 else3934 {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,3952 return rc;3953 }3954 3955 3547 /** 3956 3548 * Called from the import and export background threads to synchronize the second -
trunk/src/VBox/Main/Makefile.kmk
r20044 r20045 285 285 VirtualBoxImplExtra.cpp \ 286 286 ApplianceImpl.cpp \ 287 VFSExplorerImpl.cpp \288 287 MachineImpl.cpp \ 289 288 SnapshotImpl.cpp \ -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r20044 r20045 2890 2890 </method> 2891 2891 2892 </interface>2893 2894 <!--2895 // IVFSExplorer2896 /////////////////////////////////////////////////////////////////////////2897 -->2898 2899 <enum2900 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 <enum2913 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 <interface2931 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 2989 2892 </interface> 2990 2893 … … 3140 3043 <interface 3141 3044 name="IAppliance" extends="$unknown" 3142 uuid=" 07495095-d16c-4911-8964-5914341ced5d"3045 uuid="30bfa6b8-9eda-4b0a-b218-a86813248ccd" 3143 3046 wsmap="managed" 3144 3047 > … … 3323 3226 <param name="aProgress" type="IProgress" dir="return"> 3324 3227 <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 />3337 3228 </param> 3338 3229 </method> -
trunk/src/VBox/Main/include/ApplianceImpl.h
r20044 r20045 75 75 76 76 /* IAppliance methods */ 77 /* Import methods */78 77 STDMETHOD(Read)(IN_BSTR path); 79 78 STDMETHOD(Interpret)(void); 80 79 STDMETHOD(ImportMachines)(IProgress **aProgress); 81 /* Export methods */82 STDMETHOD(CreateVFSExplorer)(IN_BSTR aURI, IVFSExplorer **aExplorer);83 80 STDMETHOD(Write)(IN_BSTR format, IN_BSTR path, IProgress **aProgress); 84 85 81 STDMETHOD(GetWarnings)(ComSafeArrayOut(BSTR, aWarnings)); 86 82 … … 103 99 HRESULT searchUniqueDiskImageFilePath(Utf8Str& aName) const; 104 100 HRESULT setUpProgress(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription); 105 HRESULT setUpProgressUpload(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription);106 101 void waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis, ComPtr<IProgress> &pProgressAsync); 107 102 void addWarning(const char* aWarning, ...); 108 103 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 112 104 struct TaskImportMachines; /* Worker thread for import */ 113 105 static DECLCALLBACK(int) taskThreadImportMachines(RTTHREAD thread, void *pvUser); 114 106 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); 107 struct TaskWriteOVF; /* Worker thread for export */ 108 static DECLCALLBACK(int) taskThreadWriteOVF(RTTHREAD thread, void *pvUser); 120 109 121 110 friend class Machine; -
trunk/src/VBox/Main/xpcom/server.cpp
r20044 r20045 74 74 #include <VirtualBoxImpl.h> 75 75 #include <MachineImpl.h> 76 #include <VFSExplorerImpl.h>77 76 #include <ApplianceImpl.h> 78 77 #include <SnapshotImpl.h> … … 111 110 NS_DECL_CLASSINFO(Machine) 112 111 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine) 113 114 NS_DECL_CLASSINFO(VFSExplorer)115 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VFSExplorer, IVFSExplorer)116 112 117 113 NS_DECL_CLASSINFO(Appliance)
Note:
See TracChangeset
for help on using the changeset viewer.