- Timestamp:
- May 26, 2009 3:38:55 PM (16 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ApplianceImpl.cpp
r19681 r20044 21 21 */ 22 22 23 #include <VBox/param.h>24 23 #include <iprt/stream.h> 25 24 #include <iprt/path.h> 26 25 #include <iprt/dir.h> 27 26 #include <iprt/file.h> 27 #include <iprt/s3.h> 28 29 #include <VBox/param.h> 30 #include <VBox/version.h> 28 31 29 32 #include "ApplianceImpl.h" 33 #include "VFSExplorerImpl.h" 30 34 #include "VirtualBoxImpl.h" 31 35 #include "GuestOSTypeImpl.h" … … 460 464 * @return 461 465 */ 462 463 466 HRESULT Appliance::init(VirtualBox *aVirtualBox) 464 467 { … … 2501 2504 struct Appliance::TaskWriteOVF 2502 2505 { 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), 2507 2522 rc(S_OK) 2508 2523 {} 2509 2524 ~TaskWriteOVF() {} 2510 2525 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; 2513 2536 Appliance *pAppliance; 2514 enum { unspecified, OVF_0_9, OVF_1_0 }2515 enFormat;2516 2517 2537 ComObjPtr<Progress> progress; 2518 2538 HRESULT rc; 2519 2539 }; 2520 2540 2521 HRESULTAppliance::TaskWriteOVF::startThread()2541 int Appliance::TaskWriteOVF::startThread() 2522 2542 { 2523 2543 int vrc = RTThreadCreate(NULL, Appliance::taskThreadWriteOVF, this, 2524 2544 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0, 2525 2545 "Appliance::Task"); 2546 2526 2547 ComAssertMsgRCRet(vrc, 2527 ("Could not create taskThread ExportOVF (%Rrc)\n", vrc), E_FAIL);2528 2529 return S_OK;2548 ("Could not create taskThreadWriteOVF (%Rrc)\n", vrc), E_FAIL); 2549 2550 return vrc; 2530 2551 } 2531 2552 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) 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 2532 2618 STDMETHODIMP Appliance::Write(IN_BSTR format, IN_BSTR path, IProgress **aProgress) 2533 2619 { … … 2537 2623 2538 2624 AutoCaller autoCaller(this); 2539 if (FAILED(rc = autoCaller.rc())) return rc;2625 CheckComRCReturnRC(autoCaller.rc()); 2540 2626 2541 2627 AutoWriteLock(this); 2542 2628 2543 2629 // 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)) 2546 2632 return setError(VBOX_E_FILE_ERROR, 2547 2633 tr("Appliance file must have .ovf extension")); 2548 2634 2549 2635 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); 2579 2647 2580 2648 if (SUCCEEDED(rc)) … … 2583 2651 2584 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 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 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; 2585 2764 } 2586 2765 … … 2591 2770 */ 2592 2771 /* 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 2772 int Appliance::writeFS(TaskWriteOVF *pTask) 2773 { 2600 2774 LogFlowFuncEnter(); 2601 LogFlowFunc(("Appliance %p\n", pAppliance));2602 2603 AutoCaller autoCaller( pAppliance);2775 LogFlowFunc(("Appliance %p\n", this)); 2776 2777 AutoCaller autoCaller(this); 2604 2778 CheckComRCReturnRC(autoCaller.rc()); 2605 2779 2606 AutoWriteLock appLock( pAppliance);2780 AutoWriteLock appLock(this); 2607 2781 2608 2782 HRESULT rc = S_OK; 2609 2610 ComPtr<IVirtualBox> pVirtualBox(pAppliance->mVirtualBox);2611 2783 2612 2784 try … … 2615 2787 xml::ElementNode *pelmRoot = doc.createRootElement("Envelope"); 2616 2788 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"); 2618 2790 pelmRoot->setAttribute("xml:lang", "en-US"); 2619 2791 … … 2624 2796 pelmRoot->setAttribute("xmlns:ovf", strNamespace); 2625 2797 2626 //pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1");2798 pelmRoot->setAttribute("xmlns:ovfstr", "http://schema.dmtf.org/ovf/strings/1"); 2627 2799 pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"); 2628 2800 pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"); 2629 2801 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"); 2631 2803 2632 2804 // <Envelope>/<References> … … 2639 2811 </DiskSection> */ 2640 2812 xml::ElementNode *pelmDiskSection; 2641 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2813 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2642 2814 { 2643 2815 // <Section xsi:type="ovf:DiskSection_Type"> … … 2662 2834 </NetworkSection> */ 2663 2835 xml::ElementNode *pelmNetworkSection; 2664 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2836 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2665 2837 { 2666 2838 // <Section xsi:type="ovf:NetworkSection_Type"> … … 2684 2856 // one machine, it seems 2685 2857 xml::ElementNode *pelmToAddVirtualSystemsTo; 2686 if ( pAppliance->m->virtualSystemDescriptions.size() > 1)2858 if (m->virtualSystemDescriptions.size() > 1) 2687 2859 { 2688 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2860 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2689 2861 throw setError(VBOX_E_FILE_ERROR, 2690 2862 tr("Cannot export more than one virtual system with OVF 0.9, use OVF 1.0")); … … 2698 2870 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it; 2699 2871 /* 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(); 2702 2874 ++it) 2703 2875 { … … 2705 2877 2706 2878 xml::ElementNode *pelmVirtualSystem; 2707 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2879 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2708 2880 { 2709 2881 // <Section xsi:type="ovf:NetworkSection_Type"> … … 2749 2921 </Section> */ 2750 2922 xml::ElementNode *pelmAnnotationSection; 2751 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2923 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2752 2924 { 2753 2925 // <Section ovf:required="false" xsi:type="ovf:ProductSection_Type"> … … 2781 2953 </Section> */ 2782 2954 xml::ElementNode *pelmAnnotationSection; 2783 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2955 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2784 2956 { 2785 2957 // <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type"> … … 2804 2976 </EulaSection> */ 2805 2977 xml::ElementNode *pelmEulaSection; 2806 if ( task->enFormat == TaskWriteOVF::OVF_0_9)2978 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2807 2979 { 2808 2980 pelmEulaSection = pelmVirtualSystem->createChild("Section"); … … 2826 2998 </OperatingSystemSection> */ 2827 2999 xml::ElementNode *pelmOperatingSystemSection; 2828 if ( task->enFormat == TaskWriteOVF::OVF_0_9)3000 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2829 3001 { 2830 3002 pelmOperatingSystemSection = pelmVirtualSystem->createChild("Section"); … … 2842 3014 // <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso"> 2843 3015 xml::ElementNode *pelmVirtualHardwareSection; 2844 if ( task->enFormat == TaskWriteOVF::OVF_0_9)3016 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2845 3017 { 2846 3018 // <Section xsi:type="ovf:VirtualHardwareSection_Type"> … … 2868 3040 // <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType> 2869 3041 const char *pcszHardware = "virtualbox-2.2"; 2870 if ( task->enFormat == TaskWriteOVF::OVF_0_9)3042 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 2871 3043 // pretend to be vmware compatible then 2872 3044 pcszHardware = "vmx-6"; … … 3226 3398 // <rasd:InstanceID>1</rasd:InstanceID> 3227 3399 xml::ElementNode *pelmInstanceID; 3228 if ( task->enFormat == TaskWriteOVF::OVF_0_9)3400 if (pTask->enFormat == TaskWriteOVF::OVF_0_9) 3229 3401 pelmInstanceID = pItem->createChild("rasd:InstanceId"); 3230 3402 else … … 3302 3474 const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf; 3303 3475 // 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); 3305 3477 strTargetFilePath.append("/"); 3306 3478 strTargetFilePath.append(strTargetFileNameOnly); … … 3312 3484 3313 3485 Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw())); 3314 rc = pVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam());3486 rc = mVirtualBox->FindHardDisk(bstrSrcFilePath, pSourceDisk.asOutParam()); 3315 3487 if (FAILED(rc)) throw rc; 3316 3488 … … 3320 3492 // create a new hard disk interface for the destination disk image 3321 3493 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()); 3323 3495 if (FAILED(rc)) throw rc; 3324 3496 … … 3332 3504 3333 3505 // 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()), 3336 3508 pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally); 3337 3509 3338 3510 // 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); 3340 3512 } 3341 3513 catch (HRESULT rc3) … … 3344 3516 // it'll stick in the registry forever 3345 3517 pTargetDisk->Close(); 3346 throw rc3;3518 throw; 3347 3519 } 3348 3520 … … 3381 3553 // now go write the XML 3382 3554 xml::XmlFileWriter writer(doc); 3383 writer.write( pAppliance->m->strPath.c_str());3555 writer.write(m->strPath.c_str()); 3384 3556 } 3385 3557 catch(xml::Error &x) … … 3393 3565 } 3394 3566 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 */ 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); 3399 3748 3400 3749 LogFlowFunc(("rc=%Rhrc\n", rc)); … … 3542 3891 bstrDescription, // CBSTR bstrFirstOperationDescription, 3543 3892 m->ulWeightPerOperation); // ULONG ulFirstOperationWeight, 3893 return rc; 3894 } 3895 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 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, 3544 3952 return rc; 3545 3953 } -
trunk/src/VBox/Main/Makefile.kmk
r20042 r20044 285 285 VirtualBoxImplExtra.cpp \ 286 286 ApplianceImpl.cpp \ 287 VFSExplorerImpl.cpp \ 287 288 MachineImpl.cpp \ 288 289 SnapshotImpl.cpp \ -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r20042 r20044 2890 2890 </method> 2891 2891 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 2892 2989 </interface> 2893 2990 … … 3043 3140 <interface 3044 3141 name="IAppliance" extends="$unknown" 3045 uuid=" 30bfa6b8-9eda-4b0a-b218-a86813248ccd"3142 uuid="07495095-d16c-4911-8964-5914341ced5d" 3046 3143 wsmap="managed" 3047 3144 > … … 3226 3323 <param name="aProgress" type="IProgress" dir="return"> 3227 3324 <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 /> 3228 3337 </param> 3229 3338 </method> -
trunk/src/VBox/Main/include/ApplianceImpl.h
r19239 r20044 75 75 76 76 /* IAppliance methods */ 77 /* Import methods */ 77 78 STDMETHOD(Read)(IN_BSTR path); 78 79 STDMETHOD(Interpret)(void); 79 80 STDMETHOD(ImportMachines)(IProgress **aProgress); 81 /* Export methods */ 82 STDMETHOD(CreateVFSExplorer)(IN_BSTR aURI, IVFSExplorer **aExplorer); 80 83 STDMETHOD(Write)(IN_BSTR format, IN_BSTR path, IProgress **aProgress); 84 81 85 STDMETHOD(GetWarnings)(ComSafeArrayOut(BSTR, aWarnings)); 82 86 … … 99 103 HRESULT searchUniqueDiskImageFilePath(Utf8Str& aName) const; 100 104 HRESULT setUpProgress(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription); 105 HRESULT setUpProgressUpload(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription); 101 106 void waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis, ComPtr<IProgress> &pProgressAsync); 102 107 void addWarning(const char* aWarning, ...); 103 108 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 104 112 struct TaskImportMachines; /* Worker thread for import */ 105 113 static DECLCALLBACK(int) taskThreadImportMachines(RTTHREAD thread, void *pvUser); 106 114 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); 109 120 110 121 friend class Machine; -
trunk/src/VBox/Main/xpcom/server.cpp
r19296 r20044 74 74 #include <VirtualBoxImpl.h> 75 75 #include <MachineImpl.h> 76 #include <VFSExplorerImpl.h> 76 77 #include <ApplianceImpl.h> 77 78 #include <SnapshotImpl.h> … … 110 111 NS_DECL_CLASSINFO(Machine) 111 112 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine) 113 114 NS_DECL_CLASSINFO(VFSExplorer) 115 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VFSExplorer, IVFSExplorer) 112 116 113 117 NS_DECL_CLASSINFO(Appliance)
Note:
See TracChangeset
for help on using the changeset viewer.