diff options
| author | Michael Meskes <meskes@debian.org> | 2010-06-04 09:49:50 +0200 |
|---|---|---|
| committer | Michael Meskes <meskes@debian.org> | 2010-06-04 09:49:50 +0200 |
| commit | e13debb062071c46f2707d0d0e59c57675b49360 (patch) | |
| tree | 922f54068563b5cf3274bae8ba8122ce4b4ede1d /src/VBox/Main | |
| parent | abd0051802e55207e88435a185ff8d6e6b8d17d5 (diff) | |
| download | virtualbox-upstream/3.2.2-dfsg.tar.gz | |
Imported Upstream version 3.2.2-dfsgupstream/3.2.2-dfsg
Diffstat (limited to 'src/VBox/Main')
43 files changed, 2753 insertions, 1221 deletions
diff --git a/src/VBox/Main/ApplianceImpl.cpp b/src/VBox/Main/ApplianceImpl.cpp index 36e9cb96d..dbab2ad23 100644 --- a/src/VBox/Main/ApplianceImpl.cpp +++ b/src/VBox/Main/ApplianceImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: ApplianceImpl.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: ApplianceImpl.cpp 29984 2010-06-02 12:22:39Z vboxsync $ */ /** @file * * IAppliance and IVirtualSystem COM class implementations. @@ -672,6 +672,15 @@ void Appliance::disksWeight() } +/** + * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a + * progress object with the proper weights and maximum progress values. + * + * @param pProgress + * @param bstrDescription + * @param mode + * @return + */ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription, SetUpProgressMode mode) @@ -684,6 +693,8 @@ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data) disksWeight(); + m->ulWeightForManifestOperation = 0; + ULONG cOperations; ULONG ulTotalOperationsWeight; @@ -691,19 +702,28 @@ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, + m->cDisks; // plus one per disk if (m->ulTotalDisksMB) { - m->ulWeightPerOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML - ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightPerOperation; + m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML + ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation; } else { // no disks to export: - m->ulWeightPerOperation = 1; + m->ulWeightForXmlOperation = 1; ulTotalOperationsWeight = 1; } switch (mode) { - case Regular: + case ImportFileNoManifest: + break; + + case ImportFileWithManifest: + case WriteFile: + ++cOperations; // another one for creating the manifest + + // assume that checking or creating the manifest will take 10% of the time it takes to export the disks + m->ulWeightForManifestOperation = m->ulTotalDisksMB / 10; + ulTotalOperationsWeight += m->ulWeightForManifestOperation; break; case ImportS3: @@ -717,7 +737,7 @@ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import ulTotalOperationsWeight += ulImportWeight; - m->ulWeightPerOperation = ulImportWeight; /* save for using later */ + m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */ ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init ulTotalOperationsWeight += ulInitWeight; @@ -730,14 +750,14 @@ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, if (m->ulTotalDisksMB) { - m->ulWeightPerOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for OVF file upload (we didn't know the size at this point) - ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightPerOperation; + m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for OVF file upload (we didn't know the size at this point) + ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation; } else { // no disks to export: ulTotalOperationsWeight = 1; - m->ulWeightPerOperation = 1; + m->ulWeightForXmlOperation = 1; } ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */ ulTotalOperationsWeight += ulOVFCreationWeight; @@ -745,8 +765,8 @@ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, break; } - Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n", - m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation)); + Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n", + m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation)); rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this), bstrDescription, @@ -754,7 +774,7 @@ HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress, cOperations, // ULONG cOperations, ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight, bstrDescription, // CBSTR bstrFirstOperationDescription, - m->ulWeightPerOperation); // ULONG ulFirstOperationWeight, + m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight, return rc; } @@ -1036,10 +1056,10 @@ STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSys bstr = vsde.strOvf; bstr.cloneTo(&sfaOrigValues[i]); - bstr = vsde.strVbox; + bstr = vsde.strVboxCurrent; bstr.cloneTo(&sfaVboxValues[i]); - bstr = vsde.strExtraConfig; + bstr = vsde.strExtraConfigCurrent; bstr.cloneTo(&sfaExtraConfigValues[i]); } @@ -1099,10 +1119,10 @@ STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescrip bstr = vsde->strOvf; bstr.cloneTo(&sfaOrigValues[i]); - bstr = vsde->strVbox; + bstr = vsde->strVboxCurrent; bstr.cloneTo(&sfaVboxValues[i]); - bstr = vsde->strExtraConfig; + bstr = vsde->strExtraConfigCurrent; bstr.cloneTo(&sfaExtraConfigValues[i]); } @@ -1147,8 +1167,8 @@ STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionT { case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break; case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break; - case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVbox; break; - case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfig; break; + case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break; + case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break; } bstr.cloneTo(&sfaValues[i]); @@ -1200,8 +1220,8 @@ STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnab if (sfaEnabled[i]) { - vsde.strVbox = sfaVboxValues[i]; - vsde.strExtraConfig = sfaExtraConfigValues[i]; + vsde.strVboxCurrent = sfaVboxValues[i]; + vsde.strExtraConfigCurrent = sfaExtraConfigValues[i]; } else vsde.type = VirtualSystemDescriptionType_Ignore; @@ -1249,8 +1269,12 @@ void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType, vsde.type = aType; vsde.strRef = strRef; vsde.strOvf = aOvfValue; - vsde.strVbox = aVboxValue; - vsde.strExtraConfig = strExtraConfig; + vsde.strVboxSuggested // remember original value + = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues() + = aVboxValue; + vsde.strExtraConfigSuggested + = vsde.strExtraConfigCurrent + = strExtraConfig; vsde.ulSizeMB = ulSizeMB; m->llDescriptions.push_back(vsde); @@ -1299,6 +1323,7 @@ const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFro case VirtualSystemDescriptionType_HardDiskControllerIDE: case VirtualSystemDescriptionType_HardDiskControllerSATA: case VirtualSystemDescriptionType_HardDiskControllerSCSI: + case VirtualSystemDescriptionType_HardDiskControllerSAS: if (d.strRef == strRef) return &d; break; diff --git a/src/VBox/Main/ApplianceImplExport.cpp b/src/VBox/Main/ApplianceImplExport.cpp index 3d4a51af4..3e57ef38c 100644 --- a/src/VBox/Main/ApplianceImplExport.cpp +++ b/src/VBox/Main/ApplianceImplExport.cpp @@ -1,4 +1,4 @@ -/* $Id: ApplianceImplExport.cpp 29389 2010-05-11 20:10:16Z vboxsync $ */ +/* $Id: ApplianceImplExport.cpp 29984 2010-06-02 12:22:39Z vboxsync $ */ /** @file * * IAppliance and IVirtualSystem COM class implementations. @@ -264,7 +264,7 @@ STDMETHODIMP Machine::Export(IAppliance *aAppliance, IVirtualSystemDescription * // it should be a SCSI controller Utf8Str strVbox = "LsiLogicSas"; lSCSIControllerIndex = (int32_t)pNewDesc->m->llDescriptions.size(); - pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI, + pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSAS, Utf8StrFmt("%d", lSCSIControllerIndex), strVbox, strVbox); @@ -627,10 +627,9 @@ HRESULT Appliance::writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, Co HRESULT rc = S_OK; try { - Bstr progressDesc = BstrFmt(tr("Export appliance '%s'"), - aLocInfo.strPath.c_str()); - - rc = setUpProgress(aProgress, progressDesc, (aLocInfo.storageType == VFSType_File) ? Regular : WriteS3); + rc = setUpProgress(aProgress, + BstrFmt(tr("Export appliance '%s'"), aLocInfo.strPath.c_str()), + (aLocInfo.storageType == VFSType_File) ? WriteFile : WriteS3); /* Initialize our worker task */ std::auto_ptr<TaskOVF> task(new TaskOVF(this, TaskOVF::Write, aLocInfo, aProgress)); @@ -660,6 +659,7 @@ HRESULT Appliance::writeImpl(OVFFormat aFormat, const LocationInfo &aLocInfo, Co * @param stack Structure for temporary private data shared with caller. */ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSystemsTo, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes, ComObjPtr<VirtualSystemDescription> &vsdescThis, OVFFormat enFormat, XMLStack &stack) @@ -682,7 +682,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys if (llName.size() != 1) throw setError(VBOX_E_NOT_SUPPORTED, tr("Missing VM name")); - Utf8Str &strVMName = llName.front()->strVbox; + Utf8Str &strVMName = llName.front()->strVboxCurrent; pelmVirtualSystem->setAttribute("ovf:id", strVMName); // product info @@ -691,11 +691,11 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor); std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl); std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version); - bool fProduct = llProduct.size() && !llProduct.front()->strVbox.isEmpty(); - bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVbox.isEmpty(); - bool fVendor = llVendor.size() && !llVendor.front()->strVbox.isEmpty(); - bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVbox.isEmpty(); - bool fVersion = llVersion.size() && !llVersion.front()->strVbox.isEmpty(); + bool fProduct = llProduct.size() && !llProduct.front()->strVboxCurrent.isEmpty(); + bool fProductUrl = llProductUrl.size() && !llProductUrl.front()->strVboxCurrent.isEmpty(); + bool fVendor = llVendor.size() && !llVendor.front()->strVboxCurrent.isEmpty(); + bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.front()->strVboxCurrent.isEmpty(); + bool fVersion = llVersion.size() && !llVersion.front()->strVboxCurrent.isEmpty(); if (fProduct || fProductUrl || fVersion || @@ -722,21 +722,21 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys pelmAnnotationSection->createChild("Info")->addContent("Meta-information about the installed software"); if (fProduct) - pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVbox); + pelmAnnotationSection->createChild("Product")->addContent(llProduct.front()->strVboxCurrent); if (fVendor) - pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVbox); + pelmAnnotationSection->createChild("Vendor")->addContent(llVendor.front()->strVboxCurrent); if (fVersion) - pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVbox); + pelmAnnotationSection->createChild("Version")->addContent(llVersion.front()->strVboxCurrent); if (fProductUrl) - pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVbox); + pelmAnnotationSection->createChild("ProductUrl")->addContent(llProductUrl.front()->strVboxCurrent); if (fVendorUrl) - pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVbox); + pelmAnnotationSection->createChild("VendorUrl")->addContent(llVendorUrl.front()->strVboxCurrent); } // description std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description); if (llDescription.size() && - !llDescription.front()->strVbox.isEmpty()) + !llDescription.front()->strVboxCurrent.isEmpty()) { /* <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type"> <Info>A human-readable annotation</Info> @@ -753,13 +753,13 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys pelmAnnotationSection = pelmVirtualSystem->createChild("AnnotationSection"); pelmAnnotationSection->createChild("Info")->addContent("A human-readable annotation"); - pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVbox); + pelmAnnotationSection->createChild("Annotation")->addContent(llDescription.front()->strVboxCurrent); } // license std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License); if (llLicense.size() && - !llLicense.front()->strVbox.isEmpty()) + !llLicense.front()->strVboxCurrent.isEmpty()) { /* <EulaSection> <Info ovf:msgid="6">License agreement for the Virtual System.</Info> @@ -775,7 +775,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys pelmEulaSection = pelmVirtualSystem->createChild("EulaSection"); pelmEulaSection->createChild("Info")->addContent("License agreement for the virtual system"); - pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVbox); + pelmEulaSection->createChild("License")->addContent(llLicense.front()->strVboxCurrent); } // operating system @@ -874,12 +874,13 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys ( desc.type == VirtualSystemDescriptionType_HardDiskControllerIDE ? "HardDiskControllerIDE" : desc.type == VirtualSystemDescriptionType_HardDiskControllerSATA ? "HardDiskControllerSATA" : desc.type == VirtualSystemDescriptionType_HardDiskControllerSCSI ? "HardDiskControllerSCSI" + : desc.type == VirtualSystemDescriptionType_HardDiskControllerSAS ? "HardDiskControllerSAS" : desc.type == VirtualSystemDescriptionType_HardDiskImage ? "HardDiskImage" : Utf8StrFmt("%d", desc.type).c_str()), desc.strRef.c_str(), desc.strOvf.c_str(), - desc.strVbox.c_str(), - desc.strExtraConfig.c_str())); + desc.strVboxCurrent.c_str(), + desc.strExtraConfigCurrent.c_str())); ovf::ResourceType_T type = (ovf::ResourceType_T)0; // if this becomes != 0 then we do stuff Utf8Str strResourceSubType; @@ -917,7 +918,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys { strDescription = "Number of virtual CPUs"; type = ovf::ResourceType_Processor; // 3 - desc.strVbox.toInt(uTemp); + desc.strVboxCurrent.toInt(uTemp); lVirtualQuantity = (int32_t)uTemp; strCaption = Utf8StrFmt("%d virtual CPU", lVirtualQuantity); // without this ovftool won't eat the item } @@ -937,7 +938,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys { strDescription = "Memory Size"; type = ovf::ResourceType_Memory; // 4 - desc.strVbox.toInt(uTemp); + desc.strVboxCurrent.toInt(uTemp); lVirtualQuantity = (int32_t)(uTemp / _1M); strAllocationUnits = "MegaBytes"; strCaption = Utf8StrFmt("%d MB of memory", lVirtualQuantity); // without this ovftool won't eat the item @@ -957,7 +958,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys { strDescription = "IDE Controller"; type = ovf::ResourceType_IDEController; // 5 - strResourceSubType = desc.strVbox; + strResourceSubType = desc.strVboxCurrent; if (!lIDEPrimaryControllerIndex) { @@ -1003,13 +1004,13 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys lAddress = 0; lBusNumber = 0; - if ( desc.strVbox.isEmpty() // AHCI is the default in VirtualBox - || (!desc.strVbox.compare("ahci", Utf8Str::CaseInsensitive)) - ) + if ( desc.strVboxCurrent.isEmpty() // AHCI is the default in VirtualBox + || (!desc.strVboxCurrent.compare("ahci", Utf8Str::CaseInsensitive)) + ) strResourceSubType = "AHCI"; else throw setError(VBOX_E_NOT_SUPPORTED, - tr("Invalid config string \"%s\" in SATA controller"), desc.strVbox.c_str()); + tr("Invalid config string \"%s\" in SATA controller"), desc.strVboxCurrent.c_str()); // remember this ID idSATAController = ulInstanceID; @@ -1018,6 +1019,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys break; case VirtualSystemDescriptionType_HardDiskControllerSCSI: + case VirtualSystemDescriptionType_HardDiskControllerSAS: /* <Item> <rasd:Caption>scsiController0</rasd:Caption> <rasd:Description>SCSI Controller</rasd:Description> @@ -1038,17 +1040,17 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys lAddress = 0; lBusNumber = 0; - if ( desc.strVbox.isEmpty() // LsiLogic is the default in VirtualBox - || (!desc.strVbox.compare("lsilogic", Utf8Str::CaseInsensitive)) + if ( desc.strVboxCurrent.isEmpty() // LsiLogic is the default in VirtualBox + || (!desc.strVboxCurrent.compare("lsilogic", Utf8Str::CaseInsensitive)) ) strResourceSubType = "lsilogic"; - else if (!desc.strVbox.compare("buslogic", Utf8Str::CaseInsensitive)) + else if (!desc.strVboxCurrent.compare("buslogic", Utf8Str::CaseInsensitive)) strResourceSubType = "buslogic"; - else if (!desc.strVbox.compare("lsilogicsas", Utf8Str::CaseInsensitive)) + else if (!desc.strVboxCurrent.compare("lsilogicsas", Utf8Str::CaseInsensitive)) strResourceSubType = "lsilogicsas"; else throw setError(VBOX_E_NOT_SUPPORTED, - tr("Invalid config string \"%s\" in SCSI controller"), desc.strVbox.c_str()); + tr("Invalid config string \"%s\" in SCSI/SAS controller"), desc.strVboxCurrent.c_str()); // remember this ID idSCSIController = ulInstanceID; @@ -1078,12 +1080,12 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str()); // controller=<index>;channel=<c> - size_t pos1 = desc.strExtraConfig.find("controller="); - size_t pos2 = desc.strExtraConfig.find("channel="); + size_t pos1 = desc.strExtraConfigCurrent.find("controller="); + size_t pos2 = desc.strExtraConfigCurrent.find("channel="); int32_t lControllerIndex = -1; if (pos1 != Utf8Str::npos) { - RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos1 + 11, NULL, 0, &lControllerIndex); + RTStrToInt32Ex(desc.strExtraConfigCurrent.c_str() + pos1 + 11, NULL, 0, &lControllerIndex); if (lControllerIndex == lIDEPrimaryControllerIndex) ulParent = idIDEPrimaryController; else if (lControllerIndex == lIDESecondaryControllerIndex) @@ -1094,7 +1096,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys ulParent = idSATAController; } if (pos2 != Utf8Str::npos) - RTStrToInt32Ex(desc.strExtraConfig.c_str() + pos2 + 8, NULL, 0, &lAddressOnParent); + RTStrToInt32Ex(desc.strExtraConfigCurrent.c_str() + pos2 + 8, NULL, 0, &lAddressOnParent); LogFlowFunc(("HardDiskImage details: pos1=%d, pos2=%d, lControllerIndex=%d, lIDEPrimaryControllerIndex=%d, lIDESecondaryControllerIndex=%d, ulParent=%d, lAddressOnParent=%d\n", pos1, pos2, lControllerIndex, lIDEPrimaryControllerIndex, lIDESecondaryControllerIndex, ulParent, lAddressOnParent)); @@ -1103,7 +1105,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys || lAddressOnParent == -1 ) throw setError(VBOX_E_NOT_SUPPORTED, - tr("Missing or bad extra config string in hard disk image: \"%s\""), desc.strExtraConfig.c_str()); + tr("Missing or bad extra config string in hard disk image: \"%s\""), desc.strExtraConfigCurrent.c_str()); stack.mapDisks[strDiskID] = &desc; } @@ -1155,7 +1157,7 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys * To be compatible with vmware & others we set * PCNet32 for our PCNet types & E1000 for the * E1000 cards. */ - switch (desc.strVbox.toInt32()) + switch (desc.strVboxCurrent.toInt32()) { case NetworkAdapterType_Am79C970A: case NetworkAdapterType_Am79C973: strResourceSubType = "PCNet32"; break; @@ -1297,8 +1299,9 @@ void Appliance::buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSys // write the machine config to the vbox:Machine element pConfig->buildMachineXML(*pelmVBoxMachine, settings::MachineConfigFile::BuildMachineXML_WriteVboxVersionAttribute - | settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia); + | settings::MachineConfigFile::BuildMachineXML_SkipRemovableMedia, // but not BuildMachineXML_IncludeSnapshots + pllElementsWithUuidAttributes); delete pConfig; } catch (...) @@ -1424,6 +1427,10 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat else pelmToAddVirtualSystemsTo = pelmRoot; // add virtual system directly under root element + // this list receives pointers to the XML elements in the machine XML which + // might have UUIDs that need fixing after we know the UUIDs of the exported images + std::list<xml::ElementNode*> llElementsWithUuidAttributes; + list< ComObjPtr<VirtualSystemDescription> >::const_iterator it; /* Iterate throughs all virtual systems of that appliance */ for (it = m->virtualSystemDescriptions.begin(); @@ -1432,6 +1439,7 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat { ComObjPtr<VirtualSystemDescription> vsdescThis = *it; buildXMLForOneVirtualSystem(*pelmToAddVirtualSystemsTo, + &llElementsWithUuidAttributes, vsdescThis, enFormat, stack); // disks and networks stack @@ -1463,7 +1471,7 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat const VirtualSystemDescriptionEntry *pDiskEntry = itS->second; // source path: where the VBox image is - const Utf8Str &strSrcFilePath = pDiskEntry->strVbox; + const Utf8Str &strSrcFilePath = pDiskEntry->strVboxCurrent; Bstr bstrSrcFilePath(strSrcFilePath); if (!RTPathExists(strSrcFilePath.c_str())) /* This isn't allowed */ @@ -1510,9 +1518,8 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat if (FAILED(rc)) throw rc; // advance to the next operation - if (!pProgress.isNull()) - pProgress->SetNextOperation(BstrFmt(tr("Exporting to disk image '%s'"), strTargetFilePath.c_str()), - pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally); + pProgress->SetNextOperation(BstrFmt(tr("Exporting to disk image '%s'"), strTargetFilePath.c_str()), + pDiskEntry->ulSizeMB); // operation's weight, as set up with the IProgress originally); // now wait for the background disk operation to complete; this throws HRESULTs on error waitForAsyncProgress(pProgress, pProgress2); @@ -1537,6 +1544,11 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat // capacity is reported in megabytes, so... cbCapacity *= _1M; + Bstr uuidTarget; + rc = pTargetDisk->COMGETTER(Id)(uuidTarget.asOutParam()); + if (FAILED(rc)) throw rc; + Guid guidTarget(uuidTarget); + // upon success, close the disk as well rc = pTargetDisk->Close(); if (FAILED(rc)) throw rc; @@ -1561,14 +1573,34 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" // correct string as communicated to us by VMware (public bug #6612) ); - pelmDisk->setAttribute("vbox:uuid", Utf8StrFmt("%RTuuid", guidSource.raw()).c_str()); + + // add the UUID of the newly created target image to the OVF disk element, but in the + // vbox: namespace since it's not part of the standard + pelmDisk->setAttribute("vbox:uuid", Utf8StrFmt("%RTuuid", guidTarget.raw()).c_str()); + + // now, we might have other XML elements from vbox:Machine pointing to this image, + // but those would refer to the UUID of the _source_ image (which we created the + // export image from); those UUIDs need to be fixed to the export image + for (std::list<xml::ElementNode*>::iterator eit = llElementsWithUuidAttributes.begin(); + eit != llElementsWithUuidAttributes.end(); + ++eit) + { + xml::ElementNode *pelmImage = *eit; + // overwrite existing uuid attribute + pelmImage->setAttribute("uuid", guidTarget.toStringCurly()); + } } // now go write the XML xml::XmlFileWriter writer(doc); writer.write(locInfo.strPath.c_str(), false /*fSafe*/); - /* Create & write the manifest file */ + // Create & write the manifest file + Utf8Str strMfFile = manifestFileName(locInfo.strPath.c_str()); + const char *pcszManifestFileOnly = RTPathFilename(strMfFile.c_str()); + pProgress->SetNextOperation(BstrFmt(tr("Creating manifest file '%s'"), pcszManifestFileOnly), + m->ulWeightForManifestOperation); // operation's weight, as set up with the IProgress originally); + const char** ppManifestFiles = (const char**)RTMemAlloc(sizeof(char*)*diskList.size() + 1); ppManifestFiles[0] = locInfo.strPath.c_str(); list<Utf8Str>::const_iterator it1; @@ -1577,13 +1609,12 @@ HRESULT Appliance::writeFS(const LocationInfo &locInfo, const OVFFormat enFormat it1 != diskList.end(); ++it1, ++i) ppManifestFiles[i] = (*it1).c_str(); - Utf8Str strMfFile = manifestFileName(locInfo.strPath.c_str()); - int vrc = RTManifestWriteFiles(strMfFile.c_str(), ppManifestFiles, diskList.size()+1); + int vrc = RTManifestWriteFiles(strMfFile.c_str(), ppManifestFiles, diskList.size()+1, NULL, NULL); RTMemFree(ppManifestFiles); if (RT_FAILURE(vrc)) throw setError(VBOX_E_FILE_ERROR, - tr("Couldn't create manifest file '%s' (%Rrc)"), - RTPathFilename(strMfFile.c_str()), vrc); + tr("Could not create manifest file '%s' (%Rrc)"), + pcszManifestFileOnly, vrc); } catch(xml::Error &x) { @@ -1677,9 +1708,9 @@ HRESULT Appliance::writeS3(TaskOVF *pTask) throw setError(VBOX_E_FILE_ERROR, tr("Cannot find source file '%s'"), strTmpOvf.c_str()); /* Add the OVF file */ - filesList.push_back(pair<Utf8Str, ULONG>(strTmpOvf, m->ulWeightPerOperation)); /* Use 1% of the total for the OVF file upload */ + filesList.push_back(pair<Utf8Str, ULONG>(strTmpOvf, m->ulWeightForXmlOperation)); /* Use 1% of the total for the OVF file upload */ Utf8Str strMfFile = manifestFileName(strTmpOvf); - filesList.push_back(pair<Utf8Str, ULONG>(strMfFile , m->ulWeightPerOperation)); /* Use 1% of the total for the manifest file upload */ + filesList.push_back(pair<Utf8Str, ULONG>(strMfFile , m->ulWeightForXmlOperation)); /* Use 1% of the total for the manifest file upload */ /* Now add every disks of every virtual system */ list< ComObjPtr<VirtualSystemDescription> >::const_iterator it; @@ -1720,8 +1751,7 @@ HRESULT Appliance::writeS3(TaskOVF *pTask) const pair<Utf8Str, ULONG> &s = (*it1); char *pszFilename = RTPathFilename(s.first.c_str()); /* Advance to the next operation */ - if (!pTask->pProgress.isNull()) - pTask->pProgress->SetNextOperation(BstrFmt(tr("Uploading file '%s'"), pszFilename), s.second); + pTask->pProgress->SetNextOperation(BstrFmt(tr("Uploading file '%s'"), pszFilename), s.second); vrc = RTS3PutKey(hS3, bucket.c_str(), pszFilename, s.first.c_str()); if (RT_FAILURE(vrc)) { diff --git a/src/VBox/Main/ApplianceImplImport.cpp b/src/VBox/Main/ApplianceImplImport.cpp index 641ebbdd1..027ffc427 100644 --- a/src/VBox/Main/ApplianceImplImport.cpp +++ b/src/VBox/Main/ApplianceImplImport.cpp @@ -1,4 +1,4 @@ -/* $Id: ApplianceImplImport.cpp 29422 2010-05-12 14:08:52Z vboxsync $ */ +/* $Id: ApplianceImplImport.cpp 29981 2010-06-02 12:11:39Z vboxsync $ */ /** @file * * IAppliance and IVirtualSystem COM class implementations. @@ -49,7 +49,9 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// /** - * Public method implementation. + * Public method implementation. This opens the OVF with ovfreader.cpp. + * Thread implementation is in Appliance::readImpl(). + * * @param path * @return */ @@ -99,7 +101,8 @@ STDMETHODIMP Appliance::Read(IN_BSTR path, IProgress **aProgress) } /** - * Public method implementation. + * Public method implementation. This looks at the output of ovfreader.cpp and creates + * VirtualSystemDescription instances. * @return */ STDMETHODIMP Appliance::Interpret() @@ -440,15 +443,20 @@ STDMETHODIMP Appliance::Interpret() /* Check for the constrains */ if (cSCSIused < 1) { + VirtualSystemDescriptionType_T vsdet = VirtualSystemDescriptionType_HardDiskControllerSCSI; Utf8Str hdcController = "LsiLogic"; if (!hdc.strControllerType.compare("lsilogicsas", Utf8Str::CaseInsensitive)) + { + // OVF considers SAS a variant of SCSI but VirtualBox considers it a class of its own + vsdet = VirtualSystemDescriptionType_HardDiskControllerSAS; hdcController = "LsiLogicSas"; + } else if (!hdc.strControllerType.compare("BusLogic", Utf8Str::CaseInsensitive)) hdcController = "BusLogic"; - pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI, - strControllerID, - hdc.strControllerType, - hdcController); + pNewDesc->addEntry(vsdet, + strControllerID, + hdc.strControllerType, + hdcController); } else addWarning(tr("The virtual system \"%s\" requests support for an additional SCSI controller of type \"%s\" with ID %s, but VirtualBox presently supports only one SCSI controller."), @@ -538,7 +546,9 @@ STDMETHODIMP Appliance::Interpret() } /** - * Public method implementation. + * Public method implementation. This creates one or more new machines according to the + * VirtualSystemScription instances created by Appliance::Interpret(). + * Thread implementation is in Appliance::importImpl(). * @param aProgress * @return */ @@ -586,6 +596,7 @@ STDMETHODIMP Appliance::ImportMachines(IProgress **aProgress) /** * Implementation for reading an OVF. This starts a new thread which will call * Appliance::taskThreadImportOrExport() which will then call readFS() or readS3(). + * This will then open the OVF with ovfreader.cpp. * * This is in a separate private method because it is used from two locations: * @@ -634,7 +645,9 @@ HRESULT Appliance::readImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &a /** * Actual worker code for reading an OVF from disk. This is called from Appliance::taskThreadImportOrExport() - * and therefore runs on the OVF read worker thread. This runs in two contexts: + * and therefore runs on the OVF read worker thread. This opens the OVF with ovfreader.cpp. + * + * This runs in two contexts: * * 1) in a first worker thread; in that case, Appliance::Read() called Appliance::readImpl(); * @@ -662,7 +675,7 @@ HRESULT Appliance::readFS(const LocationInfo &locInfo) m->pReader = new ovf::OVFReader(locInfo.strPath); /* Create the SHA1 sum of the OVF file for later validation */ char *pszDigest; - int vrc = RTSha1Digest(locInfo.strPath.c_str(), &pszDigest); + int vrc = RTSha1Digest(locInfo.strPath.c_str(), &pszDigest, NULL, NULL); if (RT_FAILURE(vrc)) throw setError(VBOX_E_FILE_ERROR, tr("Couldn't calculate SHA1 digest for file '%s' (%Rrc)"), @@ -761,8 +774,7 @@ HRESULT Appliance::readS3(TaskOVF *pTask) RTS3Destroy(hS3); hS3 = NIL_RTS3; - if (!pTask->pProgress.isNull()) - pTask->pProgress->SetNextOperation(Bstr(tr("Reading")), 1); + pTask->pProgress->SetNextOperation(Bstr(tr("Reading")), 1); /* Prepare the temporary reading of the OVF */ ComObjPtr<Progress> progress; @@ -911,6 +923,9 @@ void Appliance::convertDiskAttachmentValues(const ovf::HardDiskController &hdc, * Implementation for importing OVF data into VirtualBox. This starts a new thread which will call * Appliance::taskThreadImportOrExport(). * + * This creates one or more new machines according to the VirtualSystemScription instances created by + * Appliance::Interpret(). + * * This is in a separate private method because it is used from two locations: * * 1) from the public Appliance::ImportMachines(). @@ -920,15 +935,30 @@ void Appliance::convertDiskAttachmentValues(const ovf::HardDiskController &hdc, * @param aProgress * @return */ -HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress) +HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, + ComObjPtr<Progress> &aProgress) { - Bstr progressDesc = BstrFmt(tr("Importing appliance '%s'"), - aLocInfo.strPath.c_str()); HRESULT rc = S_OK; + SetUpProgressMode mode; + m->strManifestFile.setNull(); + if (aLocInfo.storageType == VFSType_File) + { + Utf8Str strMfFile = manifestFileName(aLocInfo.strPath); + if (RTPathExists(strMfFile.c_str())) + { + m->strManifestFile = strMfFile; + mode = ImportFileWithManifest; + } + else + mode = ImportFileNoManifest; + } + else + mode = ImportS3; + rc = setUpProgress(aProgress, - progressDesc, - (aLocInfo.storageType == VFSType_File) ? Regular : ImportS3); + BstrFmt(tr("Importing appliance '%s'"), aLocInfo.strPath.c_str()), + mode); if (FAILED(rc)) throw rc; /* Initialize our worker task */ @@ -944,43 +974,6 @@ HRESULT Appliance::importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> } /** - * Used by Appliance::importMachineGeneric() to store - * input parameters and rollback information. - */ -struct Appliance::ImportStack -{ - // input pointers - const LocationInfo &locInfo; // ptr to location info from Appliance::importFS() - Utf8Str strSourceDir; // directory where source files reside - const ovf::DiskImagesMap &mapDisks; // ptr to disks map in OVF - ComObjPtr<Progress> &pProgress; // progress object passed into Appliance::importFS() - - // session (not initially created) - ComPtr<ISession> pSession; // session opened in Appliance::importFS() for machine manipulation - bool fSessionOpen; // true if the pSession is currently open and needs closing - - // a list of images that we created/imported; this is initially empty - // and will be cleaned up on errors - list<MyHardDiskAttachment> llHardDiskAttachments; // disks that were attached - list< ComPtr<IMedium> > llHardDisksCreated; // media that were created - list<Bstr> llMachinesRegistered; // machines that were registered; list of string UUIDs - - ImportStack(const LocationInfo &aLocInfo, - const ovf::DiskImagesMap &aMapDisks, - ComObjPtr<Progress> &aProgress) - : locInfo(aLocInfo), - mapDisks(aMapDisks), - pProgress(aProgress), - fSessionOpen(false) - { - // disk images have to be on the same place as the OVF file. So - // strip the filename out of the full file path - strSourceDir = aLocInfo.strPath; - strSourceDir.stripFilename(); - } -}; - -/** * Checks if a manifest file exists in the given location and, if so, verifies * that the relevant files (the OVF XML and the disks referenced by it, as * represented by the VirtualSystemDescription instances contained in this appliance) @@ -991,13 +984,17 @@ struct Appliance::ImportStack * @return */ HRESULT Appliance::manifestVerify(const LocationInfo &locInfo, - const ovf::OVFReader &reader) + const ovf::OVFReader &reader, + ComObjPtr<Progress> &pProgress) { HRESULT rc = S_OK; - Utf8Str strMfFile = manifestFileName(locInfo.strPath); - if (RTPathExists(strMfFile.c_str())) + if (!m->strManifestFile.isEmpty()) { + const char *pcszManifestFileOnly = RTPathFilename(m->strManifestFile.c_str()); + pProgress->SetNextOperation(BstrFmt(tr("Verifying manifest file '%s'"), pcszManifestFileOnly), + m->ulWeightForManifestOperation); // operation's weight, as set up with the IProgress originally + list<Utf8Str> filesList; Utf8Str strSrcDir(locInfo.strPath); strSrcDir.stripFilename(); @@ -1035,35 +1032,35 @@ HRESULT Appliance::manifestVerify(const LocationInfo &locInfo, ++it1, ++i) { char* pszDigest; - vrc = RTSha1Digest((*it1).c_str(), &pszDigest); + vrc = RTSha1Digest((*it1).c_str(), &pszDigest, NULL, NULL); pTestList[i].pszTestFile = (char*)(*it1).c_str(); pTestList[i].pszTestDigest = pszDigest; } // this call can take a very long time size_t cIndexOnError; - vrc = RTManifestVerify(strMfFile.c_str(), + vrc = RTManifestVerify(m->strManifestFile.c_str(), pTestList, filesList.size() + 1, &cIndexOnError); - // clean up - for (size_t j = 1; - j < filesList.size(); - ++j) - RTStrFree(pTestList[j].pszTestDigest); - RTMemFree(pTestList); - if (vrc == VERR_MANIFEST_DIGEST_MISMATCH) rc = setError(VBOX_E_FILE_ERROR, tr("The SHA1 digest of '%s' does not match the one in '%s'"), RTPathFilename(pTestList[cIndexOnError].pszTestFile), - RTPathFilename(strMfFile.c_str())); + pcszManifestFileOnly); else if (RT_FAILURE(vrc)) rc = setError(VBOX_E_FILE_ERROR, tr("Could not verify the content of '%s' against the available files (%Rrc)"), - RTPathFilename(strMfFile.c_str()), + pcszManifestFileOnly, vrc); + + // clean up + for (size_t j = 1; + j < filesList.size(); + ++j) + RTStrFree(pTestList[j].pszTestDigest); + RTMemFree(pTestList); } return rc; @@ -1071,7 +1068,10 @@ HRESULT Appliance::manifestVerify(const LocationInfo &locInfo, /** * Actual worker code for importing OVF data into VirtualBox. This is called from Appliance::taskThreadImportOrExport() - * and therefore runs on the OVF import worker thread. This runs in two contexts: + * and therefore runs on the OVF import worker thread. This creates one or more new machines according to the + * VirtualSystemScription instances created by Appliance::Interpret(). + * + * This runs in two contexts: * * 1) in a first worker thread; in that case, Appliance::ImportMachines() called Appliance::importImpl(); * @@ -1115,7 +1115,7 @@ HRESULT Appliance::importFS(const LocationInfo &locInfo, try { // if a manifest file exists, verify the content; we then need all files which are referenced by the OVF & the OVF itself - rc = manifestVerify(locInfo, reader); + rc = manifestVerify(locInfo, reader, pProgress); if (FAILED(rc)) throw rc; // create a session for the machine + disks we manipulate below @@ -1143,13 +1143,72 @@ HRESULT Appliance::importFS(const LocationInfo &locInfo, // -- or this is an OVF from an older vbox or an external source, and then we need to translate the // VirtualSystemDescriptionEntry and do import work - // @todo r=dj make this selection configurable at run-time, and from the GUI as well + // Even for the vbox:Machine case, there are a number of configuration items that will be taken from + // the OVF because otherwise the "override import parameters" mechanism in the GUI won't work. + + // VM name + std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); + if (vsdeName.size() < 1) + throw setError(VBOX_E_FILE_ERROR, + tr("Missing VM name")); + stack.strNameVBox = vsdeName.front()->strVboxCurrent; + + // guest OS type + std::list<VirtualSystemDescriptionEntry*> vsdeOS; + vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS); + if (vsdeOS.size() < 1) + throw setError(VBOX_E_FILE_ERROR, + tr("Missing guest OS type")); + stack.strOsTypeVBox = vsdeOS.front()->strVboxCurrent; + + // CPU count + std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU); + ComAssertMsgThrow(vsdeCPU.size() == 1, ("CPU count missing"), E_FAIL); + const Utf8Str &cpuVBox = vsdeCPU.front()->strVboxCurrent; + stack.cCPUs = (uint32_t)RTStrToUInt64(cpuVBox.c_str()); + // We need HWVirt & IO-APIC if more than one CPU is requested + if (stack.cCPUs > 1) + { + stack.fForceHWVirt = true; + stack.fForceIOAPIC = true; + } + + // RAM + std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory); + ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL); + const Utf8Str &memoryVBox = vsdeRAM.front()->strVboxCurrent; + stack.ulMemorySizeMB = (uint32_t)RTStrToUInt64(memoryVBox.c_str()); + // USB controller +#ifdef VBOX_WITH_USB + /* USB Controller */ + std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController); + // USB support is enabled if there's at least one such entry; to disable USB support, + // the type of the USB item would have been changed to "ignore" + stack.fUSBEnabled = vsdeUSBController.size() > 0; +#endif + // audio adapter + std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard); + /* @todo: we support one audio adapter only */ + if (vsdeAudioAdapter.size() > 0) + stack.strAudioAdapter = vsdeAudioAdapter.front()->strVboxCurrent; + + // import vbox:machine or OVF now if (vsdescThis->m->pConfig) + // vbox:Machine config importVBoxMachine(vsdescThis, pNewMachine, stack); else + // generic OVF config importMachineGeneric(vsysThis, vsdescThis, pNewMachine, stack); + // for the description of the new machine, always use the OVF entry, the user may have changed it in the import config + std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description); + if (vsdeDescription.size()) + { + const Utf8Str &strDescription = vsdeDescription.front()->strVboxCurrent; + rc = pNewMachine->COMSETTER(Description)(Bstr(strDescription)); + if (FAILED(rc)) throw rc; + } } // for (it = pAppliance->m->llVirtualSystems.begin() ... } catch (HRESULT rc2) @@ -1215,6 +1274,7 @@ HRESULT Appliance::importFS(const LocationInfo &locInfo, // restore the appliance state appLock.acquire(); m->state = Data::ApplianceIdle; + appLock.release(); LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); @@ -1258,7 +1318,6 @@ void Appliance::importOneDiskImage(const ovf::DiskImage &di, if ( strTargetPath.isEmpty() || RTPathExists(strTargetPath.c_str()) ) - /* This isn't allowed */ throw setError(VBOX_E_FILE_ERROR, tr("Destination file '%s' exists"), strTargetPath.c_str()); @@ -1293,7 +1352,7 @@ void Appliance::importOneDiskImage(const ovf::DiskImage &di, if (FAILED(rc)) throw rc; // advance to the next operation - stack.pProgress->SetNextOperation(BstrFmt(tr("Creating virtual disk image '%s'"), strTargetPath.c_str()), + stack.pProgress->SetNextOperation(BstrFmt(tr("Creating disk image '%s'"), strTargetPath.c_str()), di.ulSuggestedSizeMB); // operation's weight, as set up with the IProgress originally } else @@ -1312,12 +1371,12 @@ void Appliance::importOneDiskImage(const ovf::DiskImage &di, // First open the existing disk image rc = mVirtualBox->OpenHardDisk(Bstr(strSrcFilePath), - AccessMode_ReadOnly, - false, - NULL, - false, - NULL, - pSourceHD.asOutParam()); + AccessMode_ReadOnly, + false, + NULL, + false, + NULL, + pSourceHD.asOutParam()); if (FAILED(rc)) throw rc; fSourceHdNeedsClosing = true; @@ -1366,77 +1425,54 @@ void Appliance::importOneDiskImage(const ovf::DiskImage &di, * up any leftovers from this function. For this, the given ImportStack instance has received information * about what needs cleaning up (to support rollback). * - * @param locInfo - * @param vsysThis - * @param vsdescThis - * @param pNewMachine - * @param stack + * @param vsysThis OVF virtual system (machine) to import. + * @param vsdescThis Matching virtual system description (machine) to import. + * @param pNewMachine out: Newly created machine. + * @param stack Cleanup stack for when this throws. */ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, ComObjPtr<VirtualSystemDescription> &vsdescThis, ComPtr<IMachine> &pNewMachine, ImportStack &stack) { - /* Guest OS type */ - std::list<VirtualSystemDescriptionEntry*> vsdeOS; - vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS); - if (vsdeOS.size() < 1) - throw setError(VBOX_E_FILE_ERROR, - tr("Missing guest OS type")); - const Utf8Str &strOsTypeVBox = vsdeOS.front()->strVbox; + HRESULT rc; - /* Now that we know the base system get our internal defaults based on that. */ + // Get the instance of IGuestOSType which matches our string guest OS type so we + // can use recommended defaults for the new machine where OVF doesen't provice any ComPtr<IGuestOSType> osType; - HRESULT rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam()); + rc = mVirtualBox->GetGuestOSType(Bstr(stack.strOsTypeVBox), osType.asOutParam()); if (FAILED(rc)) throw rc; /* Create the machine */ - /* First get the name */ - std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); - if (vsdeName.size() < 1) - throw setError(VBOX_E_FILE_ERROR, - tr("Missing VM name")); - const Utf8Str &strNameVBox = vsdeName.front()->strVbox; - rc = mVirtualBox->CreateMachine(Bstr(strNameVBox), - Bstr(strOsTypeVBox), + rc = mVirtualBox->CreateMachine(Bstr(stack.strNameVBox), + Bstr(stack.strOsTypeVBox), NULL, NULL, FALSE, pNewMachine.asOutParam()); if (FAILED(rc)) throw rc; - // and the description + // set the description std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description); if (vsdeDescription.size()) { - const Utf8Str &strDescription = vsdeDescription.front()->strVbox; + const Utf8Str &strDescription = vsdeDescription.front()->strVboxCurrent; rc = pNewMachine->COMSETTER(Description)(Bstr(strDescription)); if (FAILED(rc)) throw rc; } - /* CPU count */ - std::list<VirtualSystemDescriptionEntry*> vsdeCPU = vsdescThis->findByType(VirtualSystemDescriptionType_CPU); - ComAssertMsgThrow(vsdeCPU.size() == 1, ("CPU count missing"), E_FAIL); - const Utf8Str &cpuVBox = vsdeCPU.front()->strVbox; - ULONG tmpCount = (ULONG)RTStrToUInt64(cpuVBox.c_str()); - rc = pNewMachine->COMSETTER(CPUCount)(tmpCount); + // CPU count + rc = pNewMachine->COMSETTER(CPUCount)(stack.cCPUs); if (FAILED(rc)) throw rc; - bool fEnableIOApic = false; - /* We need HWVirt & IO-APIC if more than one CPU is requested */ - if (tmpCount > 1) + + if (stack.fForceHWVirt) { rc = pNewMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, TRUE); if (FAILED(rc)) throw rc; - - fEnableIOApic = true; } - /* RAM */ - std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory); - ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL); - const Utf8Str &memoryVBox = vsdeRAM.front()->strVbox; - ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str()); - rc = pNewMachine->COMSETTER(MemorySize)(tt); + // RAM + rc = pNewMachine->COMSETTER(MemorySize)(stack.ulMemorySizeMB); if (FAILED(rc)) throw rc; /* VRAM */ @@ -1453,16 +1489,16 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, // import a Windows VM because if if Windows was installed without IOAPIC, // it will not mind finding an one later on, but if Windows was installed // _with_ an IOAPIC, it will bluescreen if it's not found - if (!fEnableIOApic) + if (!stack.fForceIOAPIC) { Bstr bstrFamilyId; rc = osType->COMGETTER(FamilyId)(bstrFamilyId.asOutParam()); if (FAILED(rc)) throw rc; if (bstrFamilyId == "Windows") - fEnableIOApic = true; + stack.fForceIOAPIC = true; } - if (fEnableIOApic) + if (stack.fForceIOAPIC) { ComPtr<IBIOSSettings> pBIOSSettings; rc = pNewMachine->COMGETTER(BIOSSettings)(pBIOSSettings.asOutParam()); @@ -1472,15 +1508,10 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (FAILED(rc)) throw rc; } - /* Audio Adapter */ - std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard); - /* @todo: we support one audio adapter only */ - if (vsdeAudioAdapter.size() > 0) - { - const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strVbox; - if (audioAdapterVBox.compare("null", Utf8Str::CaseInsensitive) != 0) + if (!stack.strAudioAdapter.isEmpty()) + if (stack.strAudioAdapter.compare("null", Utf8Str::CaseInsensitive) != 0) { - uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str()); + uint32_t audio = RTStrToUInt32(stack.strAudioAdapter.c_str()); // should be 0 for AC97 ComPtr<IAudioAdapter> audioAdapter; rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); if (FAILED(rc)) throw rc; @@ -1489,19 +1520,13 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio)); if (FAILED(rc)) throw rc; } - } #ifdef VBOX_WITH_USB /* USB Controller */ - std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController); - // USB support is enabled if there's at least one such entry; to disable USB support, - // the type of the USB item would have been changed to "ignore" - bool fUSBEnabled = vsdeUSBController.size() > 0; - ComPtr<IUSBController> usbController; rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam()); if (FAILED(rc)) throw rc; - rc = usbController->COMSETTER(Enabled)(fUSBEnabled); + rc = usbController->COMSETTER(Enabled)(stack.fUSBEnabled); if (FAILED(rc)) throw rc; #endif /* VBOX_WITH_USB */ @@ -1530,7 +1555,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, { const VirtualSystemDescriptionEntry* pvsys = *nwIt; - const Utf8Str &nwTypeVBox = pvsys->strVbox; + const Utf8Str &nwTypeVBox = pvsys->strVboxCurrent; uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str()); ComPtr<INetworkAdapter> pNetworkAdapter; rc = pNewMachine->GetNetworkAdapter((ULONG)a, pNetworkAdapter.asOutParam()); @@ -1542,7 +1567,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (FAILED(rc)) throw rc; // default is NAT; change to "bridged" if extra conf says so - if (!pvsys->strExtraConfig.compare("type=Bridged", Utf8Str::CaseInsensitive)) + if (!pvsys->strExtraConfigCurrent.compare("type=Bridged", Utf8Str::CaseInsensitive)) { /* Attach to the right interface */ rc = pNetworkAdapter->AttachToBridgedInterface(); @@ -1575,7 +1600,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, } } /* Next test for host only interfaces */ - else if (!pvsys->strExtraConfig.compare("type=HostOnly", Utf8Str::CaseInsensitive)) + else if (!pvsys->strExtraConfigCurrent.compare("type=HostOnly", Utf8Str::CaseInsensitive)) { /* Attach to the right interface */ rc = pNetworkAdapter->AttachToHostOnlyInterface(); @@ -1625,7 +1650,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, rc = pNewMachine->AddStorageController(Bstr("IDE Controller"), StorageBus_IDE, pController.asOutParam()); if (FAILED(rc)) throw rc; - const char *pcszIDEType = vsdeHDCIDE.front()->strVbox.c_str(); + const char *pcszIDEType = vsdeHDCIDE.front()->strVboxCurrent.c_str(); if (!strcmp(pcszIDEType, "PIIX3")) rc = pController->COMSETTER(ControllerType)(StorageControllerType_PIIX3); else if (!strcmp(pcszIDEType, "PIIX4")) @@ -1647,7 +1672,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (vsdeHDCSATA.size() > 0) { ComPtr<IStorageController> pController; - const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVbox; + const Utf8Str &hdcVBox = vsdeHDCSATA.front()->strVboxCurrent; if (hdcVBox == "AHCI") { rc = pNewMachine->AddStorageController(Bstr("SATA Controller"), StorageBus_SATA, pController.asOutParam()); @@ -1670,7 +1695,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, Bstr bstrName(L"SCSI Controller"); StorageBus_T busType = StorageBus_SCSI; StorageControllerType_T controllerType; - const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVbox; + const Utf8Str &hdcVBox = vsdeHDCSCSI.front()->strVboxCurrent; if (hdcVBox == "LsiLogic") controllerType = StorageControllerType_LsiLogic; else if (hdcVBox == "LsiLogicSas") @@ -1693,6 +1718,20 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, if (FAILED(rc)) throw rc; } + /* Hard disk controller SAS */ + std::list<VirtualSystemDescriptionEntry*> vsdeHDCSAS = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSAS); + if (vsdeHDCSAS.size() > 1) + throw setError(VBOX_E_FILE_ERROR, + tr("Too many SAS controllers in OVF; import facility only supports one")); + if (vsdeHDCSAS.size() > 0) + { + ComPtr<IStorageController> pController; + rc = pNewMachine->AddStorageController(Bstr(L"SAS Controller"), StorageBus_SAS, pController.asOutParam()); + if (FAILED(rc)) throw rc; + rc = pController->COMSETTER(ControllerType)(StorageControllerType_LsiLogicSas); + if (FAILED(rc)) throw rc; + } + /* Now its time to register the machine before we add any hard disks */ rc = mVirtualBox->RegisterMachine(pNewMachine); if (FAILED(rc)) throw rc; @@ -1862,7 +1901,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, ComPtr<IMedium> pTargetHD; importOneDiskImage(ovfDiskImage, - vsdeHD->strVbox, + vsdeHD->strVboxCurrent, pTargetHD, stack); @@ -1888,7 +1927,7 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, mhda.lControllerPort, mhda.lDevice); - Log(("Attaching disk %s to port %d on device %d\n", vsdeHD->strVbox.c_str(), mhda.lControllerPort, mhda.lDevice)); + Log(("Attaching disk %s to port %d on device %d\n", vsdeHD->strVboxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice)); rc = sMachine->AttachDevice(mhda.controllerType, // wstring name mhda.lControllerPort, // long controllerPort @@ -1938,7 +1977,10 @@ void Appliance::importMachineGeneric(const ovf::VirtualSystem &vsysThis, * and import the disk into VirtualBox, which creates a new UUID for it. In the machine config, * replace the old UUID with the new one. * - * 3) Create the VirtualBox machine with the modfified machine config. + * 3) Change the machine config according to the OVF virtual system descriptions, in case the + * caller has modified them using setFinalValues(). + * + * 4) Create the VirtualBox machine with the modfified machine config. * * @param config * @param pNewMachine @@ -1956,13 +1998,72 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi HRESULT rc = getDefaultHardDiskFolder(strDefaultHardDiskFolder); if (FAILED(rc)) throw rc; - // step 1): scan the machine config for attachments + /* + * + * step 1): modify machine config according to OVF config, in case the user + * has modified them using setFinalValues() + * + */ + +// std::list<VirtualSystemDescriptionEntry*> llVSDEs; + + config.hardwareMachine.cCPUs = stack.cCPUs; + config.hardwareMachine.ulMemorySizeMB = stack.ulMemorySizeMB; + if (stack.fForceIOAPIC) + config.hardwareMachine.fHardwareVirt = true; + if (stack.fForceIOAPIC) + config.hardwareMachine.biosSettings.fIOAPICEnabled = true; + +/* + <const name="HardDiskControllerIDE" value="14" /> + <const name="HardDiskControllerSATA" value="15" /> + <const name="HardDiskControllerSCSI" value="16" /> + <const name="HardDiskControllerSAS" value="17" /> + <const name="HardDiskImage" value="18" /> + <const name="Floppy" value="19" /> + <const name="CDROM" value="20" /> + <const name="NetworkAdapter" value="21" /> +*/ + +#ifdef VBOX_WITH_USB + // disable USB if user disabled USB + config.hardwareMachine.usbController.fEnabled = stack.fUSBEnabled; +#endif + + // audio adapter: only config is turning it off presently + if (stack.strAudioAdapter.isEmpty()) + config.hardwareMachine.audioAdapter.fEnabled = false; + + /* + * + * step 2: scan the machine config for media attachments + * + */ + + // for each storage controller... for (settings::StorageControllersList::iterator sit = config.storageMachine.llStorageControllers.begin(); sit != config.storageMachine.llStorageControllers.end(); ++sit) { settings::StorageController &sc = *sit; + // find the OVF virtual system description entry for this storage controller + switch (sc.storageBus) + { + case StorageBus_SATA: + break; + + case StorageBus_SCSI: + break; + + case StorageBus_IDE: + break; + + case StorageBus_SAS: + break; + } + + // for each medium attachment to this controller... for (settings::AttachedDevicesList::iterator dit = sc.llAttachedDevices.begin(); dit != sc.llAttachedDevices.end(); ++dit) @@ -1991,7 +2092,11 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi strTargetPath.append(di.strHref); searchUniqueDiskImageFilePath(strTargetPath); - // step 2): for each attachment, import the disk... + /* + * + * step 3: import disk + * + */ ComPtr<IMedium> pTargetHD; importOneDiskImage(di, strTargetPath, @@ -2019,14 +2124,11 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi } // for (settings::AttachedDevicesList::const_iterator dit = sc.llAttachedDevices.begin(); } // for (settings::StorageControllersList::const_iterator sit = config.storageMachine.llStorageControllers.begin(); - // step 3): create the machine and have it import the config - - // use the name that we computed in the OVF fields to avoid duplicates - std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name); - if (vsdeName.size() < 1) - throw setError(VBOX_E_FILE_ERROR, - tr("Missing VM name")); - const Utf8Str &strNameVBox = vsdeName.front()->strVbox; + /* + * + * step 4): create the machine and have it import the config + * + */ ComObjPtr<Machine> pNewMachine; rc = pNewMachine.createObject(); @@ -2035,8 +2137,8 @@ void Appliance::importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescThi // this magic constructor fills the new machine object with the MachineConfig // instance that we created from the vbox:Machine rc = pNewMachine->init(mVirtualBox, - strNameVBox, // name from just above (can be suffixed to avoid duplicates) - config); // the whole machine config + stack.strNameVBox, // name from OVF preparations; can be suffixed to avoid duplicates, or changed by user + config); // the whole machine config if (FAILED(rc)) throw rc; // return the new machine as an IMachine @@ -2186,8 +2288,7 @@ HRESULT Appliance::importS3(TaskOVF *pTask) RTS3Destroy(hS3); hS3 = NIL_RTS3; - if (!pTask->pProgress.isNull()) - pTask->pProgress->SetNextOperation(BstrFmt(tr("Importing appliance")), m->ulWeightPerOperation); + pTask->pProgress->SetNextOperation(BstrFmt(tr("Importing appliance")), m->ulWeightForXmlOperation); ComObjPtr<Progress> progress; /* Import the whole temporary OVF & the disk images */ diff --git a/src/VBox/Main/ConsoleImpl.cpp b/src/VBox/Main/ConsoleImpl.cpp index e1faceff1..a90d1161c 100644 --- a/src/VBox/Main/ConsoleImpl.cpp +++ b/src/VBox/Main/ConsoleImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: ConsoleImpl.cpp 29580 2010-05-17 18:23:00Z vboxsync $ */ +/* $Id: ConsoleImpl.cpp 29971 2010-06-02 08:51:13Z vboxsync $ */ /** @file * VBox Console COM Class implementation */ @@ -211,13 +211,11 @@ struct VMPowerUpTask : public VMProgressTask VMPowerUpTask(Console *aConsole, Progress *aProgress) : VMProgressTask(aConsole, aProgress, false /* aUsesVMPtr */), - mSetVMErrorCallback(NULL), mConfigConstructor(NULL), mStartPaused(false), mTeleporterEnabled(FALSE) {} - PFNVMATERROR mSetVMErrorCallback; PFNCFGMCONSTRUCTOR mConfigConstructor; Utf8Str mSavedStateFile; Console::SharedFolderDataMap mSharedFolders; @@ -1684,7 +1682,7 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress) case MachineState_Saved: return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down a saved virtual machine")); case MachineState_Stopping: - return setError(VBOX_E_INVALID_VM_STATE, tr("Virtual machine is being powered down")); + return setError(VBOX_E_INVALID_VM_STATE, tr("The virtual machine is being powered down")); default: return setError(VBOX_E_INVALID_VM_STATE, tr("Invalid machine state: %s (must be Running, Paused or Stuck)"), @@ -3416,106 +3414,108 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Don't do anything if the VM isn't running */ - if (!mpVM) - return S_OK; - - /* protect mpVM */ - AutoVMCaller autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + HRESULT rc = S_OK; - /* Get the properties we need from the adapter */ - BOOL fCableConnected, fTraceEnabled; - HRESULT rc = aNetworkAdapter->COMGETTER(CableConnected)(&fCableConnected); - AssertComRC(rc); - if (SUCCEEDED(rc)) - { - rc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fTraceEnabled); - AssertComRC(rc); - } - if (SUCCEEDED(rc)) + /* don't trigger network change if the VM isn't running */ + if (mpVM) { - ULONG ulInstance; - rc = aNetworkAdapter->COMGETTER(Slot)(&ulInstance); + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + + /* Get the properties we need from the adapter */ + BOOL fCableConnected, fTraceEnabled; + rc = aNetworkAdapter->COMGETTER(CableConnected)(&fCableConnected); AssertComRC(rc); if (SUCCEEDED(rc)) { - /* - * Find the pcnet instance, get the config interface and update - * the link state. - */ - NetworkAdapterType_T adapterType; - rc = aNetworkAdapter->COMGETTER(AdapterType)(&adapterType); + rc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fTraceEnabled); + AssertComRC(rc); + } + if (SUCCEEDED(rc)) + { + ULONG ulInstance; + rc = aNetworkAdapter->COMGETTER(Slot)(&ulInstance); AssertComRC(rc); - const char *pszAdapterName = NULL; - switch (adapterType) + if (SUCCEEDED(rc)) { - case NetworkAdapterType_Am79C970A: - case NetworkAdapterType_Am79C973: - pszAdapterName = "pcnet"; - break; + /* + * Find the pcnet instance, get the config interface and update + * the link state. + */ + NetworkAdapterType_T adapterType; + rc = aNetworkAdapter->COMGETTER(AdapterType)(&adapterType); + AssertComRC(rc); + const char *pszAdapterName = NULL; + switch (adapterType) + { + case NetworkAdapterType_Am79C970A: + case NetworkAdapterType_Am79C973: + pszAdapterName = "pcnet"; + break; #ifdef VBOX_WITH_E1000 - case NetworkAdapterType_I82540EM: - case NetworkAdapterType_I82543GC: - case NetworkAdapterType_I82545EM: - pszAdapterName = "e1000"; - break; + case NetworkAdapterType_I82540EM: + case NetworkAdapterType_I82543GC: + case NetworkAdapterType_I82545EM: + pszAdapterName = "e1000"; + break; #endif #ifdef VBOX_WITH_VIRTIO - case NetworkAdapterType_Virtio: - pszAdapterName = "virtio-net"; - break; + case NetworkAdapterType_Virtio: + pszAdapterName = "virtio-net"; + break; #endif - default: - AssertFailed(); - pszAdapterName = "unknown"; - break; - } + default: + AssertFailed(); + pszAdapterName = "unknown"; + break; + } - PPDMIBASE pBase; - int vrc = PDMR3QueryDeviceLun(mpVM, pszAdapterName, ulInstance, 0, &pBase); - ComAssertRC(vrc); - if (RT_SUCCESS(vrc)) - { - Assert(pBase); - PPDMINETWORKCONFIG pINetCfg; - pINetCfg = PDMIBASE_QUERY_INTERFACE(pBase, PDMINETWORKCONFIG); - if (pINetCfg) + PPDMIBASE pBase; + int vrc = PDMR3QueryDeviceLun(mpVM, pszAdapterName, ulInstance, 0, &pBase); + ComAssertRC(vrc); + if (RT_SUCCESS(vrc)) { - Log(("Console::onNetworkAdapterChange: setting link state to %d\n", - fCableConnected)); - vrc = pINetCfg->pfnSetLinkState(pINetCfg, - fCableConnected ? PDMNETWORKLINKSTATE_UP - : PDMNETWORKLINKSTATE_DOWN); - ComAssertRC(vrc); - } + Assert(pBase); + PPDMINETWORKCONFIG pINetCfg; + pINetCfg = PDMIBASE_QUERY_INTERFACE(pBase, PDMINETWORKCONFIG); + if (pINetCfg) + { + Log(("Console::onNetworkAdapterChange: setting link state to %d\n", + fCableConnected)); + vrc = pINetCfg->pfnSetLinkState(pINetCfg, + fCableConnected ? PDMNETWORKLINKSTATE_UP + : PDMNETWORKLINKSTATE_DOWN); + ComAssertRC(vrc); + } #ifdef VBOX_DYNAMIC_NET_ATTACH - if (RT_SUCCESS(vrc) && changeAdapter) - { - VMSTATE enmVMState = VMR3GetState(mpVM); - if ( enmVMState == VMSTATE_RUNNING /** @todo LiveMigration: Forbit or deal correctly with the _LS variants */ - || enmVMState == VMSTATE_SUSPENDED) + if (RT_SUCCESS(vrc) && changeAdapter) { - if (fTraceEnabled && fCableConnected && pINetCfg) + VMSTATE enmVMState = VMR3GetState(mpVM); + if ( enmVMState == VMSTATE_RUNNING /** @todo LiveMigration: Forbid or deal correctly with the _LS variants */ + || enmVMState == VMSTATE_SUSPENDED) { - vrc = pINetCfg->pfnSetLinkState(pINetCfg, PDMNETWORKLINKSTATE_DOWN); - ComAssertRC(vrc); - } - - rc = doNetworkAdapterChange(pszAdapterName, ulInstance, 0, aNetworkAdapter); - - if (fTraceEnabled && fCableConnected && pINetCfg) - { - vrc = pINetCfg->pfnSetLinkState(pINetCfg, PDMNETWORKLINKSTATE_UP); - ComAssertRC(vrc); + if (fTraceEnabled && fCableConnected && pINetCfg) + { + vrc = pINetCfg->pfnSetLinkState(pINetCfg, PDMNETWORKLINKSTATE_DOWN); + ComAssertRC(vrc); + } + + rc = doNetworkAdapterChange(pszAdapterName, ulInstance, 0, aNetworkAdapter); + + if (fTraceEnabled && fCableConnected && pINetCfg) + { + vrc = pINetCfg->pfnSetLinkState(pINetCfg, PDMNETWORKLINKSTATE_UP); + ComAssertRC(vrc); + } } } - } #endif /* VBOX_DYNAMIC_NET_ATTACH */ - } + } - if (RT_FAILURE(vrc)) - rc = E_FAIL; + if (RT_FAILURE(vrc)) + rc = E_FAIL; + } } } @@ -3723,17 +3723,17 @@ HRESULT Console::onSerialPortChange(ISerialPort *aSerialPort) AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Don't do anything if the VM isn't running */ - if (!mpVM) - return S_OK; - HRESULT rc = S_OK; - /* protect mpVM */ - AutoVMCaller autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* don't trigger serial port change if the VM isn't running */ + if (mpVM) + { + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); - /* nothing to do so far */ + /* nothing to do so far */ + } /* notify console callbacks on success */ if (SUCCEEDED(rc)) @@ -3757,17 +3757,17 @@ HRESULT Console::onParallelPortChange(IParallelPort *aParallelPort) AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Don't do anything if the VM isn't running */ - if (!mpVM) - return S_OK; - HRESULT rc = S_OK; - /* protect mpVM */ - AutoVMCaller autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* don't trigger parallel port change if the VM isn't running */ + if (mpVM) + { + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); - /* nothing to do so far */ + /* nothing to do so far */ + } /* notify console callbacks on success */ if (SUCCEEDED(rc)) @@ -3791,17 +3791,17 @@ HRESULT Console::onStorageControllerChange() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Don't do anything if the VM isn't running */ - if (!mpVM) - return S_OK; - HRESULT rc = S_OK; - /* protect mpVM */ - AutoVMCaller autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* don't trigger storage controller change if the VM isn't running */ + if (mpVM) + { + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); - /* nothing to do so far */ + /* nothing to do so far */ + } /* notify console callbacks on success */ if (SUCCEEDED(rc)) @@ -3825,17 +3825,17 @@ HRESULT Console::onMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForc AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Don't do anything if the VM isn't running */ - if (!mpVM) - return S_OK; - HRESULT rc = S_OK; - /* protect mpVM */ - AutoVMCaller autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* don't trigger medium change if the VM isn't running */ + if (mpVM) + { + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); - rc = doMediumChange(aMediumAttachment, !!aForce); + rc = doMediumChange(aMediumAttachment, !!aForce); + } /* notify console callbacks on success */ if (SUCCEEDED(rc)) @@ -3859,20 +3859,20 @@ HRESULT Console::onCPUChange(ULONG aCPU, BOOL aRemove) AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Don't do anything if the VM isn't running */ - if (!mpVM) - return S_OK; - HRESULT rc = S_OK; - /* protect mpVM */ - AutoVMCaller autoVMCaller(this); - if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* don't trigger CPU change if the VM isn't running */ + if (mpVM) + { + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); - if (aRemove) - rc = doCPURemove(aCPU); - else - rc = doCPUAdd(aCPU); + if (aRemove) + rc = doCPURemove(aCPU); + else + rc = doCPUAdd(aCPU); + } /* notify console callbacks on success */ if (SUCCEEDED(rc)) @@ -3974,22 +3974,24 @@ HRESULT Console::onUSBControllerChange() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Ignore if no VM is running yet. */ - if (!mpVM) - return S_OK; - HRESULT rc = S_OK; -/// @todo (dmik) -// check for the Enabled state and disable virtual USB controller?? -// Anyway, if we want to query the machine's USB Controller we need to cache -// it to mUSBController in #init() (as it is done with mDVDDrive). -// -// bird: While the VM supports hot-plugging, I doubt any guest can handle it at this time... :-) -// -// /* protect mpVM */ -// AutoVMCaller autoVMCaller(this); -// if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + /* don't trigger USB controller change if the VM isn't running */ + if (mpVM) + { + /// @todo implement one day. + // Anyway, if we want to query the machine's USB Controller we need + // to cache it to mUSBController in #init() (similar to mDVDDrive). + // + // bird: While the VM supports hot-plugging, I doubt any guest can + // handle it at this time... :-) + + /* protect mpVM */ + AutoVMCaller autoVMCaller(this); + if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc(); + + /* nothing to do so far */ + } /* notify console callbacks on success */ if (SUCCEEDED(rc)) @@ -4899,7 +4901,7 @@ HRESULT Console::addVMCaller(bool aQuiet /* = false */, { /* powerDown() is waiting for all callers to finish */ return aQuiet ? E_ACCESSDENIED : setError(E_ACCESSDENIED, - tr("Virtual machine is being powered down")); + tr("The virtual machine is being powered down")); } if (mpVM == NULL) @@ -4908,7 +4910,7 @@ HRESULT Console::addVMCaller(bool aQuiet /* = false */, /* The machine is not powered up */ return aQuiet ? E_ACCESSDENIED : setError(E_ACCESSDENIED, - tr("Virtual machine is not powered up")); + tr("The virtual machine is not powered up")); } ++ mVMCallers; @@ -5112,7 +5114,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) if (Global::IsOnlineOrTransient(mMachineState)) return setError(VBOX_E_INVALID_VM_STATE, - tr("Virtual machine is already running or busy (machine state: %s)"), + tr("The virtual machine is already running or busy (machine state: %s)"), Global::stringifyMachineState(mMachineState)); HRESULT rc = S_OK; @@ -5225,10 +5227,40 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) progressDesc = tr("Teleporting virtual machine"); else progressDesc = tr("Starting virtual machine"); - rc = powerupProgress->init(static_cast<IConsole *>(this), - progressDesc, - fTeleporterEnabled /* aCancelable */); - if (FAILED(rc)) return rc; + if (mMachineState == MachineState_Saved || !fTeleporterEnabled) + rc = powerupProgress->init(static_cast<IConsole *>(this), + progressDesc, + FALSE /* aCancelable */); + else + rc = powerupProgress->init(static_cast<IConsole *>(this), + progressDesc, + TRUE /* aCancelable */, + 3 /* cOperations */, + 10 /* ulTotalOperationsWeight */, + Bstr(tr("Teleporting virtual machine")), + 1 /* ulFirstOperationWeight */, + NULL); + if (FAILED(rc)) + return rc; + + /* Tell VBoxSVC and Machine about the progress object so they can combine + proxy it to any openRemoteSession caller. */ + rc = mControl->BeginPowerUp(powerupProgress); + if (FAILED(rc)) + { + LogFlowThisFunc(("BeginPowerUp failed\n")); + return rc; + } + + BOOL fCanceled; + rc = powerupProgress->COMGETTER(Canceled)(&fCanceled); + if (FAILED(rc)) + return rc; + if (fCanceled) + { + LogFlowThisFunc(("Canceled in BeginPowerUp\n")); + return setError(E_FAIL, tr("Powerup was canceled")); + } /* setup task object and thread to carry out the operation * asynchronously */ @@ -5236,7 +5268,6 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused) std::auto_ptr<VMPowerUpTask> task(new VMPowerUpTask(this, powerupProgress)); ComAssertComRCRetRC(task->rc()); - task->mSetVMErrorCallback = setVMErrorCallback; task->mConfigConstructor = configConstructor; task->mSharedFolders = sharedFolders; task->mStartPaused = aPaused; @@ -6836,40 +6867,30 @@ DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, voi } /** - * VM error callback function. Called by the various VM components. + * @copydoc FNVMATERROR * - * @param pVM VM handle. Can be NULL if an error occurred before - * successfully creating a VM. - * @param pvUser Pointer to the VMProgressTask structure. - * @param rc VBox status code. - * @param pszFormat Printf-like error message. - * @param args Various number of arguments for the error message. - * - * @thread EMT, VMPowerUp... - * - * @note The VMProgressTask structure modified by this callback is not thread - * safe. + * @remarks Might be some tiny serialization concerns with access to the string + * object here... */ -/* static */ DECLCALLBACK(void) -Console::setVMErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, - const char *pszFormat, va_list args) +/*static*/ DECLCALLBACK(void) +Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszErrorFmt, va_list va) { - VMProgressTask *task = static_cast<VMProgressTask *>(pvUser); - AssertReturnVoid(task); + Utf8Str *pErrorText = (Utf8Str *)pvUser; + AssertPtr(pErrorText); - /* we ignore RT_SRC_POS_DECL arguments to avoid confusion of end-users */ + /* We ignore RT_SRC_POS_DECL arguments to avoid confusion of end-users. */ va_list va2; - va_copy(va2, args); /* Have to make a copy here or GCC will break. */ + va_copy(va2, va); - /* append to the existing error message if any */ - if (task->mErrorMsg.length()) - task->mErrorMsg = Utf8StrFmt("%s.\n%N (%Rrc)", task->mErrorMsg.raw(), - pszFormat, &va2, rc, rc); + /* Append to any the existing error message. */ + if (pErrorText->length()) + *pErrorText = Utf8StrFmt("%s.\n%N (%Rrc)", pErrorText->c_str(), + pszErrorFmt, &va2, rc, rc); else - task->mErrorMsg = Utf8StrFmt("%N (%Rrc)", - pszFormat, &va2, rc, rc); + *pErrorText = Utf8StrFmt("%N (%Rrc)", pszErrorFmt, &va2, rc, rc); - va_end (va2); + va_end(va2); } /** @@ -7267,7 +7288,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) */ alock.leave(); - vrc = VMR3Create(cCpus, task->mSetVMErrorCallback, task.get(), + vrc = VMR3Create(cCpus, Console::genericVMSetErrorCallback, &task->mErrorMsg, task->mConfigConstructor, static_cast<Console *>(console), &pVM); @@ -7372,9 +7393,15 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) else if (task->mTeleporterEnabled) { /* -> ConsoleImplTeleporter.cpp */ - vrc = console->teleporterTrg(pVM, pMachine, task->mStartPaused, task->mProgress); - if (RT_FAILURE(vrc) && !task->mErrorMsg.length()) - rc = E_FAIL; /* Avoid the "Missing error message..." assertion. */ + bool fPowerOffOnFailure; + rc = console->teleporterTrg(pVM, pMachine, &task->mErrorMsg, task->mStartPaused, + task->mProgress, &fPowerOffOnFailure); + if (FAILED(rc) && fPowerOffOnFailure) + { + ErrorInfoKeeper eik; + int vrc2 = VMR3PowerOff(pVM); + AssertRC(vrc2); + } } else if (task->mStartPaused) /* done */ @@ -7410,7 +7437,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) * be sticky but our error callback isn't. */ alock.leave(); - VMR3AtErrorDeregister(pVM, task->mSetVMErrorCallback, task.get()); + VMR3AtErrorDeregister(pVM, Console::genericVMSetErrorCallback, &task->mErrorMsg); /** @todo register another VMSetError callback? */ alock.enter(); } @@ -7484,34 +7511,17 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) { /* Notify the progress object of the success */ task->mProgress->notifyComplete(S_OK); - console->mControl->SetPowerUpInfo(NULL); } else { /* The progress object will fetch the current error info */ task->mProgress->notifyComplete(rc); - ProgressErrorInfo info(task->mProgress); - ComObjPtr<VirtualBoxErrorInfo> errorInfo; - rc = errorInfo.createObject(); - if (SUCCEEDED(rc)) - { - errorInfo->init(info.getResultCode(), - info.getInterfaceID(), - info.getComponent(), - info.getText()); - console->mControl->SetPowerUpInfo(errorInfo); - } - else - { - /* If it's not possible to create an IVirtualBoxErrorInfo object - * signal success, as not signalling anything will cause a stuck - * progress object in VBoxSVC. */ - console->mControl->SetPowerUpInfo(NULL); - } - LogRel(("Power up failed (vrc=%Rrc, rc=%Rhrc (%#08X))\n", vrc, rc, rc)); } + /* Notify VBoxSVC and any waiting openRemoteSession progress object. */ + console->mControl->EndPowerUp(rc); + #if defined(RT_OS_WINDOWS) /* uninitialize COM */ CoUninitialize(); diff --git a/src/VBox/Main/ConsoleImplTeleporter.cpp b/src/VBox/Main/ConsoleImplTeleporter.cpp index 14c011dfa..208dfa5aa 100644 --- a/src/VBox/Main/ConsoleImplTeleporter.cpp +++ b/src/VBox/Main/ConsoleImplTeleporter.cpp @@ -1,4 +1,4 @@ -/* $Id: ConsoleImplTeleporter.cpp 29250 2010-05-09 17:53:58Z vboxsync $ */ +/* $Id: ConsoleImplTeleporter.cpp 29965 2010-06-01 18:41:10Z vboxsync $ */ /** @file * VBox Console COM Class implementation, The Teleporter Part. */ @@ -120,6 +120,7 @@ public: PRTTIMERLR mphTimerLR; bool mfLockedMedia; int mRc; + Utf8Str mErrorText; TeleporterStateTrg(Console *pConsole, PVM pVM, Progress *pProgress, IMachine *pMachine, IInternalMachineControl *pControl, @@ -131,6 +132,7 @@ public: , mphTimerLR(phTimerLR) , mfLockedMedia(false) , mRc(VINF_SUCCESS) + , mErrorText() { } }; @@ -218,31 +220,55 @@ static int teleporterTcpReadLine(TeleporterState *pState, char *pszBuf, size_t c */ HRESULT Console::teleporterSrcReadACK(TeleporterStateSrc *pState, const char *pszWhich, - const char *pszNAckMsg /*= NULL*/) + const char *pszNAckMsg /*= NULL*/) { - char szMsg[128]; + char szMsg[256]; int vrc = teleporterTcpReadLine(pState, szMsg, sizeof(szMsg)); if (RT_FAILURE(vrc)) return setError(E_FAIL, tr("Failed reading ACK(%s): %Rrc"), pszWhich, vrc); - if (strcmp(szMsg, "ACK")) + + if (!strcmp(szMsg, "ACK")) + return S_OK; + + if (!strncmp(szMsg, "NACK=", sizeof("NACK=") - 1)) { - if (!strncmp(szMsg, "NACK=", sizeof("NACK=") - 1)) + char *pszMsgText = strchr(szMsg, ';'); + if (pszMsgText) + *pszMsgText++ = '\0'; + + int32_t vrc2; + vrc = RTStrToInt32Full(&szMsg[sizeof("NACK=") - 1], 10, &vrc2); + if (vrc == VINF_SUCCESS) { - int32_t vrc2; - vrc = RTStrToInt32Full(&szMsg[sizeof("NACK=") - 1], 10, &vrc2); - if (vrc == VINF_SUCCESS) + /* + * Well formed NACK, transform it into an error. + */ + if (pszNAckMsg) { - if (pszNAckMsg) - { - LogRel(("Teleporter: %s: NACK=%Rrc (%d)\n", pszWhich, vrc2, vrc2)); - return setError(E_FAIL, pszNAckMsg); - } - return setError(E_FAIL, "NACK(%s) - %Rrc (%d)", pszWhich, vrc2, vrc2); + LogRel(("Teleporter: %s: NACK=%Rrc (%d)\n", pszWhich, vrc2, vrc2)); + return setError(E_FAIL, pszNAckMsg); } + + if (pszMsgText) + { + pszMsgText = RTStrStrip(pszMsgText); + for (size_t off = 0; pszMsgText[off]; off++) + if (pszMsgText[off] == '\r') + pszMsgText[off] = '\n'; + + LogRel(("Teleporter: %s: NACK=%Rrc (%d) - '%s'\n", pszWhich, vrc2, vrc2, pszMsgText)); + if (strlen(pszMsgText) > 4) + return setError(E_FAIL, "%s", pszMsgText); + return setError(E_FAIL, "NACK(%s) - %Rrc (%d) '%s'", pszWhich, vrc2, vrc2, pszMsgText); + } + + return setError(E_FAIL, "NACK(%s) - %Rrc (%d)", pszWhich, vrc2, vrc2); } - return setError(E_FAIL, tr("%s: Expected ACK or NACK, got '%s'"), pszWhich, szMsg); + + if (pszMsgText) + pszMsgText[-1] = ';'; } - return S_OK; + return setError(E_FAIL, tr("%s: Expected ACK or NACK, got '%s'"), pszWhich, szMsg); } @@ -663,13 +689,24 @@ Console::teleporterSrc(TeleporterStateSrc *pState) if (FAILED(hrc)) return hrc; + RTSocketRetain(pState->mhSocket); void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(pState)); vrc = VMR3Teleport(pState->mpVM, pState->mcMsMaxDowntime, &g_teleporterTcpOps, pvUser, teleporterProgressCallback, pvUser, &pState->mfSuspendedByUs); + RTSocketRelease(pState->mhSocket); if (RT_FAILURE(vrc)) + { + if ( vrc == VERR_SSM_CANCELLED + && RT_SUCCESS(RTTcpSelectOne(pState->mhSocket, 1))) + { + hrc = teleporterSrcReadACK(pState, "load-complete"); + if (FAILED(hrc)) + return hrc; + } return setError(E_FAIL, tr("VMR3Teleport -> %Rrc"), vrc); + } hrc = teleporterSrcReadACK(pState, "load-complete"); if (FAILED(hrc)) @@ -978,36 +1015,44 @@ Console::Teleport(IN_BSTR aHostname, ULONG aPort, IN_BSTR aPassword, ULONG aMaxD * @returns VBox status code. * @param pVM The VM handle * @param pMachine The IMachine for the virtual machine. + * @param pErrorMsg Pointer to the error string for VMSetError. * @param fStartPaused Whether to start it in the Paused (true) or * Running (false) state, * @param pProgress Pointer to the progress object. + * @param pfPowerOffOnFailure Whether the caller should power off + * the VM on failure. * * @remarks The caller expects error information to be set on failure. * @todo Check that all the possible failure paths sets error info... */ -int -Console::teleporterTrg(PVM pVM, IMachine *pMachine, bool fStartPaused, Progress *pProgress) +HRESULT +Console::teleporterTrg(PVM pVM, IMachine *pMachine, Utf8Str *pErrorMsg, bool fStartPaused, + Progress *pProgress, bool *pfPowerOffOnFailure) { + LogThisFunc(("pVM=%p pMachine=%p fStartPaused=%RTbool pProgress=%p\n", pVM, pMachine, fStartPaused, pProgress)); + + *pfPowerOffOnFailure = true; + /* * Get the config. */ ULONG uPort; HRESULT hrc = pMachine->COMGETTER(TeleporterPort)(&uPort); if (FAILED(hrc)) - return VERR_GENERAL_FAILURE; + return hrc; ULONG const uPortOrg = uPort; Bstr bstrAddress; hrc = pMachine->COMGETTER(TeleporterAddress)(bstrAddress.asOutParam()); if (FAILED(hrc)) - return VERR_GENERAL_FAILURE; + return hrc; Utf8Str strAddress(bstrAddress); const char *pszAddress = strAddress.isEmpty() ? NULL : strAddress.c_str(); Bstr bstrPassword; hrc = pMachine->COMGETTER(TeleporterPassword)(bstrPassword.asOutParam()); if (FAILED(hrc)) - return VERR_GENERAL_FAILURE; + return hrc; Utf8Str strPassword(bstrPassword); strPassword.append('\n'); /* To simplify password checking. */ @@ -1033,12 +1078,12 @@ Console::teleporterTrg(PVM pVM, IMachine *pMachine, bool fStartPaused, Progress if (FAILED(hrc)) { RTTcpServerDestroy(hServer); - return VERR_GENERAL_FAILURE; + return hrc; } } } if (RT_FAILURE(vrc)) - return vrc; + return setError(E_FAIL, tr("RTTcpServerCreateEx failed with status %Rrc"), vrc); /* * Create a one-shot timer for timing out after 5 mins. @@ -1061,59 +1106,66 @@ Console::teleporterTrg(PVM pVM, IMachine *pMachine, bool fStartPaused, Progress if (pProgress->setCancelCallback(teleporterProgressCancelCallback, pvUser)) { LogRel(("Teleporter: Waiting for incoming VM...\n")); - vrc = RTTcpServerListen(hServer, Console::teleporterTrgServeConnection, &theState); - pProgress->setCancelCallback(NULL, NULL); - - bool fPowerOff = false; - if (vrc == VERR_TCP_SERVER_STOP) + hrc = pProgress->SetNextOperation(Bstr(tr("Waiting for incoming VM")), 1); + if (SUCCEEDED(hrc)) { - vrc = theState.mRc; - /* Power off the VM on failure unless the state callback - already did that. */ - if (RT_FAILURE(vrc)) + vrc = RTTcpServerListen(hServer, Console::teleporterTrgServeConnection, &theState); + pProgress->setCancelCallback(NULL, NULL); + + if (vrc == VERR_TCP_SERVER_STOP) { - VMSTATE enmVMState = VMR3GetState(pVM); - if ( enmVMState != VMSTATE_OFF - && enmVMState != VMSTATE_POWERING_OFF) - fPowerOff = true; + vrc = theState.mRc; + /* Power off the VM on failure unless the state callback + already did that. */ + *pfPowerOffOnFailure = false; + if (RT_SUCCESS(vrc)) + hrc = S_OK; + else + { + VMSTATE enmVMState = VMR3GetState(pVM); + if ( enmVMState != VMSTATE_OFF + && enmVMState != VMSTATE_POWERING_OFF) + *pfPowerOffOnFailure = true; + + /* Set error. */ + if (pErrorMsg->length()) + hrc = setError(E_FAIL, "%s", pErrorMsg->c_str()); + else + hrc = setError(E_FAIL, tr("Teleporation failed (%Rrc)"), vrc); + } } - } - else if (vrc == VERR_TCP_SERVER_SHUTDOWN) - { - BOOL fCancelled = TRUE; - hrc = pProgress->COMGETTER(Canceled)(&fCancelled); - if (FAILED(hrc) || fCancelled) + else if (vrc == VERR_TCP_SERVER_SHUTDOWN) { - setError(E_FAIL, tr("Teleporting canceled")); - vrc = VERR_SSM_CANCELLED; + BOOL fCancelled = TRUE; + hrc = pProgress->COMGETTER(Canceled)(&fCancelled); + if (FAILED(hrc) || fCancelled) + hrc = setError(E_FAIL, tr("Teleporting canceled")); + else + hrc = setError(E_FAIL, tr("Teleporter timed out waiting for incoming connection")); + LogRel(("Teleporter: RTTcpServerListen aborted - %Rrc\n", vrc)); } else { - setError(E_FAIL, tr("Teleporter timed out waiting for incoming connection")); - vrc = VERR_TIMEOUT; + hrc = setError(E_FAIL, tr("Unexpected RTTcpServerListen status code %Rrc"), vrc); + LogRel(("Teleporter: Unexpected RTTcpServerListen rc: %Rrc\n", vrc)); } - LogRel(("Teleporter: RTTcpServerListen aborted - %Rrc\n", vrc)); - fPowerOff = true; } else - { - LogRel(("Teleporter: Unexpected RTTcpServerListen rc: %Rrc\n", vrc)); - vrc = VERR_IPE_UNEXPECTED_STATUS; - fPowerOff = true; - } - - if (fPowerOff) - { - int vrc2 = VMR3PowerOff(pVM); - AssertRC(vrc2); - } + LogThisFunc(("SetNextOperation failed, %Rhrc\n", hrc)); } else - vrc = VERR_SSM_CANCELLED; + { + LogThisFunc(("Canceled - check point #1\n")); + hrc = setError(E_FAIL, tr("Teleporting canceled")); + } } + else + hrc = setError(E_FAIL, "RTTimerLRStart -> %Rrc", vrc); RTTimerLRDestroy(hTimerLR); } + else + hrc = setError(E_FAIL, "RTTimerLRCreate -> %Rrc", vrc); RTTcpServerDestroy(hServer); /* @@ -1121,9 +1173,12 @@ Console::teleporterTrg(PVM pVM, IMachine *pMachine, bool fStartPaused, Progress * value before returning. */ if (uPortOrg != uPort) + { + ErrorInfoKeeper Eik; pMachine->COMSETTER(TeleporterPort)(uPortOrg); + } - return vrc; + return hrc; } @@ -1158,7 +1213,7 @@ static int teleporterTcpWriteACK(TeleporterStateTrg *pState, bool fAutomaticUnlo } -static int teleporterTcpWriteNACK(TeleporterStateTrg *pState, int32_t rc2) +static int teleporterTcpWriteNACK(TeleporterStateTrg *pState, int32_t rc2, const char *pszMsgText = NULL) { /* * Unlock media sending the NACK. That way the other doesn't have to spin @@ -1166,8 +1221,17 @@ static int teleporterTcpWriteNACK(TeleporterStateTrg *pState, int32_t rc2) */ teleporterTrgUnlockMedia(pState); - char szMsg[64]; - size_t cch = RTStrPrintf(szMsg, sizeof(szMsg), "NACK=%d\n", rc2); + char szMsg[256]; + size_t cch; + if (pszMsgText && *pszMsgText) + { + cch = RTStrPrintf(szMsg, sizeof(szMsg), "NACK=%d;%s\n", rc2, pszMsgText); + for (size_t off = 6; off + 1 < cch; off++) + if (szMsg[off] == '\n') + szMsg[off] = '\r'; + } + else + cch = RTStrPrintf(szMsg, sizeof(szMsg), "NACK=%d\n", rc2); int rc = RTTcpWrite(pState->mhSocket, szMsg, cch); if (RT_FAILURE(rc)) LogRel(("Teleporter: RTTcpWrite(,%s,%zu) -> %Rrc\n", szMsg, cch, rc)); @@ -1221,7 +1285,24 @@ Console::teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser) vrc = teleporterTcpWriteACK(pState); if (RT_FAILURE(vrc)) return VINF_SUCCESS; - LogRel(("Teleporter: Incoming VM!\n")); + + /* + * Update the progress bar, with peer name if available. + */ + HRESULT hrc; + RTNETADDR Addr; + vrc = RTTcpGetPeerAddress(Sock, &Addr); + if (RT_SUCCESS(vrc)) + { + LogRel(("Teleporter: Incoming VM from %RTnaddr!\n", &Addr)); + hrc = pState->mptrProgress->SetNextOperation(Bstr(Utf8StrFmt(tr("Teleporting VM from %RTnaddr"), &Addr)), 8); + } + else + { + LogRel(("Teleporter: Incoming VM!\n")); + hrc = pState->mptrProgress->SetNextOperation(Bstr(tr("Teleporting VM")), 8); + } + AssertMsg(SUCCEEDED(hrc) || hrc == E_FAIL, ("%Rhrc\n", hrc)); /* * Stop the server and cancel the timeout timer. @@ -1250,16 +1331,21 @@ Console::teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser) if (RT_FAILURE(vrc)) break; + int vrc2 = VMR3AtErrorRegister(pState->mpVM, Console::genericVMSetErrorCallback, &pState->mErrorText); AssertRC(vrc2); RTSocketRetain(pState->mhSocket); /* For concurrent access by I/O thread and EMT. */ pState->moffStream = 0; + void *pvUser2 = static_cast<void *>(static_cast<TeleporterState *>(pState)); vrc = VMR3LoadFromStream(pState->mpVM, &g_teleporterTcpOps, pvUser2, teleporterProgressCallback, pvUser2); + RTSocketRelease(pState->mhSocket); + vrc2 = VMR3AtErrorDeregister(pState->mpVM, Console::genericVMSetErrorCallback, &pState->mErrorText); AssertRC(vrc2); + if (RT_FAILURE(vrc)) { LogRel(("Teleporter: VMR3LoadFromStream -> %Rrc\n", vrc)); - teleporterTcpWriteNACK(pState, vrc); + teleporterTcpWriteNACK(pState, vrc, pState->mErrorText.c_str()); break; } @@ -1284,7 +1370,7 @@ Console::teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser) } else if (!strcmp(szCmd, "lock-media")) { - HRESULT hrc = pState->mpControl->LockMedia(); + hrc = pState->mpControl->LockMedia(); if (SUCCEEDED(hrc)) { pState->mfLockedMedia = true; diff --git a/src/VBox/Main/Global.cpp b/src/VBox/Main/Global.cpp index 325f32106..a704c209b 100644 --- a/src/VBox/Main/Global.cpp +++ b/src/VBox/Main/Global.cpp @@ -1,4 +1,4 @@ -/* $Id: Global.cpp 29595 2010-05-18 08:05:46Z vboxsync $ */ +/* $Id: Global.cpp 29815 2010-05-26 13:41:36Z vboxsync $ */ /** @file * @@ -165,19 +165,19 @@ const Global::OSType Global::sOSTypes[SchemaDefs::OSTypeId_COUNT] = StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_Mandriva, "Mandriva", VBOXOSTYPE_Mandriva, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 384, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_Mandriva_64, "Mandriva (64 bit)", VBOXOSTYPE_Mandriva_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, - 384, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_RedHat, "Red Hat", - VBOXOSTYPE_RedHat, VBOXOSHINT_RTCUTC, - 384, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + VBOXOSTYPE_RedHat, VBOXOSHINT_RTCUTC | VBOXOSHINT_PAE, + 512, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_RedHat_64, "Red Hat (64 bit)", - VBOXOSTYPE_RedHat_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, - 384, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + VBOXOSTYPE_RedHat_x64, VBOXOSHINT_64BIT | VBOXOSHINT_PAE | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, + 512, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_Turbolinux, "Turbolinux", VBOXOSTYPE_Turbolinux, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, @@ -205,11 +205,11 @@ const Global::OSType Global::sOSTypes[SchemaDefs::OSTypeId_COUNT] = StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_Oracle, "Oracle", VBOXOSTYPE_Oracle, VBOXOSHINT_RTCUTC, - 384, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_Oracle_64, "Oracle (64 bit)", VBOXOSTYPE_Oracle_x64, VBOXOSHINT_64BIT | VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_RTCUTC, - 384, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, + 512, 12, 8 * _1K, NetworkAdapterType_I82540EM, 0, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_IntelAhci, StorageBus_SATA }, { "Linux", "Linux", SchemaDefs_OSTypeId_Linux, "Other Linux", VBOXOSTYPE_Linux, VBOXOSHINT_RTCUTC | VBOXOSHINT_USBTABLET, @@ -275,11 +275,11 @@ const Global::OSType Global::sOSTypes[SchemaDefs::OSTypeId_COUNT] = VBOXOSTYPE_OS2, VBOXOSHINT_HWVIRTEX, 96, 4, 2 * _1K, NetworkAdapterType_Am79C973, 1, StorageControllerType_PIIX4, StorageBus_IDE, StorageControllerType_PIIX4, StorageBus_IDE }, - { "MacOS", "Mac OS X", SchemaDefs_OSTypeId_MacOS, "Mac OS X", + { "MacOS", "Mac OS X", SchemaDefs_OSTypeId_MacOS, "Mac OS X Server", VBOXOSTYPE_MacOS, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_USBTABLET, 1024, 4, 20 * _1K, NetworkAdapterType_I82543GC, 0, StorageControllerType_ICH6, StorageBus_IDE, StorageControllerType_ICH6, StorageBus_IDE }, - { "MacOS", "Mac OS X", SchemaDefs_OSTypeId_MacOS_64, "Mac OS X (64 bit)", + { "MacOS", "Mac OS X", SchemaDefs_OSTypeId_MacOS_64, "Mac OS X Server (64 bit)", VBOXOSTYPE_MacOS_x64, VBOXOSHINT_HWVIRTEX | VBOXOSHINT_IOAPIC | VBOXOSHINT_EFI | VBOXOSHINT_PAE | VBOXOSHINT_64BIT | VBOXOSHINT_USBHID | VBOXOSHINT_HPET | VBOXOSHINT_USBTABLET, 1024, 4, 20 * _1K, NetworkAdapterType_I82543GC, 0, StorageControllerType_ICH6, StorageBus_IDE, StorageControllerType_ICH6, StorageBus_IDE }, diff --git a/src/VBox/Main/GuestImpl.cpp b/src/VBox/Main/GuestImpl.cpp index 13e7395a7..029c1774c 100644 --- a/src/VBox/Main/GuestImpl.cpp +++ b/src/VBox/Main/GuestImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: GuestImpl.cpp 29645 2010-05-18 15:41:46Z vboxsync $ */ +/* $Id: GuestImpl.cpp 29997 2010-06-02 13:39:06Z vboxsync $ */ /** @file * @@ -268,9 +268,13 @@ STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize) { mMemoryBalloonSize = aMemoryBalloonSize; /* forward the information to the VMM device */ - VMMDev *vmmDev = mParent->getVMMDev(); - if (vmmDev) - vmmDev->getVMMDevPort()->pfnSetMemoryBalloon(vmmDev->getVMMDevPort(), aMemoryBalloonSize); + VMMDev *pVMMDev = mParent->getVMMDev(); + if (pVMMDev) + { + PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); + ComAssertRet(pVMMDevPort, E_FAIL); + pVMMDevPort->pfnSetMemoryBalloon(pVMMDevPort, aMemoryBalloonSize); + } } return ret; @@ -298,9 +302,13 @@ STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval) mStatUpdateInterval = aUpdateInterval; /* forward the information to the VMM device */ - VMMDev *vmmDev = mParent->getVMMDev(); - if (vmmDev) - vmmDev->getVMMDevPort()->pfnSetStatisticsInterval(vmmDev->getVMMDevPort(), aUpdateInterval); + VMMDev *pVMMDev = mParent->getVMMDev(); + if (pVMMDev) + { + PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); + ComAssertRet(pVMMDevPort, E_FAIL); + pVMMDevPort->pfnSetStatisticsInterval(pVMMDevPort, aUpdateInterval); + } return S_OK; } @@ -392,14 +400,17 @@ STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword, if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* forward the information to the VMM device */ - VMMDev *vmmDev = mParent->getVMMDev(); - if (vmmDev) + VMMDev *pVMMDev = mParent->getVMMDev(); + if (pVMMDev) { + PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); + ComAssertRet(pVMMDevPort, E_FAIL); + uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON; if (!aAllowInteractiveLogon) u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON; - vmmDev->getVMMDevPort()->pfnSetCredentials(vmmDev->getVMMDevPort(), + pVMMDevPort->pfnSetCredentials(pVMMDevPort, Utf8Str(aUserName).raw(), Utf8Str(aPassword).raw(), Utf8Str(aDomain).raw(), u32Flags); return S_OK; @@ -483,25 +494,36 @@ DECLCALLBACK(int) Guest::doGuestCtrlNotification(void *pvExtension, ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension); int rc = VINF_SUCCESS; - if (u32Function == GUEST_EXEC_SEND_STATUS) + if (u32Function == GUEST_DISCONNECTED) + { + LogFlowFunc(("GUEST_DISCONNECTED\n")); + + PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms); + AssertPtr(pCBData); + AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER); + AssertReturn(CALLBACKDATAMAGICCLIENTDISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); + + rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData); + } + else if (u32Function == GUEST_EXEC_SEND_STATUS) { LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n")); - PHOSTEXECCALLBACKDATA pCBData = reinterpret_cast<PHOSTEXECCALLBACKDATA>(pvParms); + PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms); AssertPtr(pCBData); - AssertReturn(sizeof(HOSTEXECCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER); - AssertReturn(HOSTEXECCALLBACKDATAMAGIC == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); + AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER); + AssertReturn(CALLBACKDATAMAGICEXECSTATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); - rc = pGuest->notifyCtrlExec(u32Function, pCBData); + rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData); } else if (u32Function == GUEST_EXEC_SEND_OUTPUT) { LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n")); - PHOSTEXECOUTCALLBACKDATA pCBData = reinterpret_cast<PHOSTEXECOUTCALLBACKDATA>(pvParms); + PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms); AssertPtr(pCBData); - AssertReturn(sizeof(HOSTEXECOUTCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER); - AssertReturn(HOSTEXECOUTCALLBACKDATAMAGIC == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); + AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER); + AssertReturn(CALLBACKDATAMAGICEXECOUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); rc = pGuest->notifyCtrlExecOut(u32Function, pCBData); } @@ -511,8 +533,8 @@ DECLCALLBACK(int) Guest::doGuestCtrlNotification(void *pvExtension, } /* Function for handling the execution start/termination notification. */ -int Guest::notifyCtrlExec(uint32_t u32Function, - PHOSTEXECCALLBACKDATA pData) +int Guest::notifyCtrlExecStatus(uint32_t u32Function, + PCALLBACKDATAEXECSTATUS pData) { LogFlowFuncEnter(); int rc = VINF_SUCCESS; @@ -525,7 +547,7 @@ int Guest::notifyCtrlExec(uint32_t u32Function, /* Callback can be called several times. */ if (it != mCallbackList.end()) { - PHOSTEXECCALLBACKDATA pCBData = (HOSTEXECCALLBACKDATA*)it->pvData; + PCALLBACKDATAEXECSTATUS pCBData = (PCALLBACKDATAEXECSTATUS)it->pvData; AssertPtr(pCBData); pCBData->u32PID = pData->u32PID; @@ -587,11 +609,11 @@ int Guest::notifyCtrlExec(uint32_t u32Function, { /* Not found, add to list. */ GuestProcess p; - p.mPID = pCBData->u32PID; + p.mPID = pCBData->u32PID; p.mStatus = pCBData->u32Status; p.mExitCode = pCBData->u32Flags; /* Contains exit code. */ p.mFlags = 0; - + mGuestProcessList.push_back(p); } else /* Update list. */ @@ -616,7 +638,7 @@ int Guest::notifyCtrlExec(uint32_t u32Function, LogFlowFunc(("Callback (context ID=%u, status=%u) progress already marked as completed\n", pData->hdr.u32ContextID, pData->u32Status)); } - ASMAtomicWriteBool(&it->bCalled, true); + ASMAtomicWriteBool(&it->fCalled, true); } else LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID)); @@ -625,8 +647,8 @@ int Guest::notifyCtrlExec(uint32_t u32Function, } /* Function for handling the execution output notification. */ -int Guest::notifyCtrlExecOut(uint32_t u32Function, - PHOSTEXECOUTCALLBACKDATA pData) +int Guest::notifyCtrlExecOut(uint32_t u32Function, + PCALLBACKDATAEXECOUT pData) { LogFlowFuncEnter(); int rc = VINF_SUCCESS; @@ -637,8 +659,8 @@ int Guest::notifyCtrlExecOut(uint32_t u32Function, CallbackListIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID); if (it != mCallbackList.end()) { - Assert(!it->bCalled); - PHOSTEXECOUTCALLBACKDATA pCBData = (HOSTEXECOUTCALLBACKDATA*)it->pvData; + Assert(!it->fCalled); + PCALLBACKDATAEXECOUT pCBData = (CALLBACKDATAEXECOUT*)it->pvData; AssertPtr(pCBData); pCBData->u32PID = pData->u32PID; @@ -661,7 +683,7 @@ int Guest::notifyCtrlExecOut(uint32_t u32Function, pCBData->pvData = NULL; pCBData->cbData = 0; } - ASMAtomicWriteBool(&it->bCalled, true); + ASMAtomicWriteBool(&it->fCalled, true); } else LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID)); @@ -669,6 +691,26 @@ int Guest::notifyCtrlExecOut(uint32_t u32Function, return rc; } +int Guest::notifyCtrlClientDisconnected(uint32_t u32Function, + PCALLBACKDATACLIENTDISCONNECTED pData) +{ + LogFlowFuncEnter(); + int rc = VINF_SUCCESS; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + /** @todo Maybe use a map instead of list for fast context lookup. */ + CallbackListIter it; + for (it = mCallbackList.begin(); it != mCallbackList.end(); it++) + { + if (it->mContextID == pData->hdr.u32ContextID) + destroyCtrlCallbackContext(it); + } + + LogFlowFuncLeave(); + return rc; +} + Guest::CallbackListIter Guest::getCtrlCallbackContextByID(uint32_t u32ContextID) { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -715,9 +757,9 @@ void Guest::destroyCtrlCallbackContext(Guest::CallbackListIter it) BOOL fCancelled; if (SUCCEEDED(it->pProgress->COMGETTER(Canceled)(&fCancelled)) && !fCancelled) it->pProgress->Cancel(); - /* - * Do *not NULL pProgress here, because waiting function like executeProcess() - * will still rely on this object for checking whether they have to give up! + /* + * Do *not NULL pProgress here, because waiting function like executeProcess() + * will still rely on this object for checking whether they have to give up! */ } LogFlowFuncLeave(); @@ -737,7 +779,7 @@ uint32_t Guest::addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void CallbackContext context; context.mContextID = uNewContext; context.mType = enmType; - context.bCalled = false; + context.fCalled = false; context.pvData = pvData; context.cbData = cbData; context.pProgress = pProgress; @@ -745,9 +787,10 @@ uint32_t Guest::addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void uint32_t nCallbacks; { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + /// @todo r=bird: check if already in the list and find another one. mCallbackList.push_back(context); nCallbacks = mCallbackList.size(); - } + } #if 0 if (nCallbacks > 256) /* Don't let the container size get too big! */ @@ -771,6 +814,8 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword, ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress) { +/** @todo r=bird: Eventually we should clean up all the timeout parameters + * in the API and have the same way of specifying infinite waits! */ #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else /* VBOX_WITH_GUEST_CONTROL */ @@ -828,6 +873,7 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, AssertReturn(papszArgv, E_OUTOFMEMORY); for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++) { + /// @todo r=bird: RTUtf16ToUtf8(). int cbLen = RTStrAPrintf(&papszArgv[i], "%s", Utf8Str(args[i]).raw()); if (cbLen < 0) vrc = VERR_NO_MEMORY; @@ -867,10 +913,10 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, if (RT_SUCCESS(vrc)) { - PHOSTEXECCALLBACKDATA pData = (HOSTEXECCALLBACKDATA*)RTMemAlloc(sizeof(HOSTEXECCALLBACKDATA)); + PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS)); AssertReturn(pData, VBOX_E_IPRT_ERROR); - uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, - pData, sizeof(HOSTEXECCALLBACKDATA), progress); + uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, + pData, sizeof(CALLBACKDATAEXECSTATUS), progress); Assert(uContextID > 0); VBOXHGCMSVCPARM paParms[15]; @@ -889,11 +935,11 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, VMMDev *vmmDev; { - /* Make sure mParent is valid, so set the read lock while using. + /* Make sure mParent is valid, so set the read lock while using. * Do not keep this lock while doing the actual call, because in the meanwhile * another thread could request a write lock which would be a bad idea ... */ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - + /* Forward the information to the VMM device. */ AssertPtr(mParent); vmmDev = mParent->getVMMDev(); @@ -925,7 +971,7 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, if (it != mCallbackList.end()) { uint64_t u64Started = RTTimeMilliTS(); - while (!it->bCalled) + while (!it->fCalled) { /* Check for timeout. */ unsigned cMsWait; @@ -941,12 +987,15 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, /* Check for manual stop. */ if (!it->pProgress.isNull()) - { + { rc = it->pProgress->COMGETTER(Canceled)(&fCanceled); if (FAILED(rc)) throw rc; if (fCanceled) - break; /* Client wants to abort. */ + break; /* HGCM/guest wants to abort because of status change. */ + } + /// @todo r=bird: two operation progress object and wait first operation. + /// IProgress::WaitForOperationCompletion. RTThreadSleep(cMsWait); } } @@ -954,13 +1003,13 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, /* Was the whole thing canceled? */ if (!fCanceled) { - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - PHOSTEXECCALLBACKDATA pData = (HOSTEXECCALLBACKDATA*)it->pvData; - Assert(it->cbData == sizeof(HOSTEXECCALLBACKDATA)); + PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)it->pvData; + Assert(it->cbData == sizeof(CALLBACKDATAEXECSTATUS)); AssertPtr(pData); - if (it->bCalled) + if (it->fCalled) { /* Did we get some status? */ switch (pData->u32Status) @@ -969,7 +1018,7 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, /* Process is (still) running; get PID. */ *aPID = pData->u32PID; break; - + /* In any other case the process either already * terminated or something else went wrong, so no PID ... */ case PROC_STS_TEN: /* Terminated normally. */ @@ -978,17 +1027,17 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, case PROC_STS_TOK: case PROC_STS_TOA: case PROC_STS_DWN: - /* + /* * Process (already) ended, but we want to get the - * PID anyway to retrieve the output in a later call. + * PID anyway to retrieve the output in a later call. */ *aPID = pData->u32PID; break; - + case PROC_STS_ERROR: vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */ break; - + default: vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */ break; @@ -1008,6 +1057,11 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, rc = setError(VBOX_E_IPRT_ERROR, tr("The file '%s' was not found on guest"), Utf8Command.raw()); } + else if (vrc == VERR_PATH_NOT_FOUND) + { + rc = setError(VBOX_E_IPRT_ERROR, + tr("The path to file '%s' was not found on guest"), Utf8Command.raw()); + } else if (vrc == VERR_BAD_EXE_FORMAT) { rc = setError(VBOX_E_IPRT_ERROR, @@ -1023,11 +1077,6 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, rc = setError(VBOX_E_IPRT_ERROR, tr("The guest did not respond within time (%ums)"), aTimeoutMS); } - else if (vrc == VERR_INVALID_PARAMETER) - { - rc = setError(VBOX_E_IPRT_ERROR, - tr("The guest reported an unknown process status (%u)"), pData->u32Status); - } else if (vrc == VERR_PERMISSION_DENIED) { rc = setError(VBOX_E_IPRT_ERROR, @@ -1035,9 +1084,13 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, } else { - rc = setError(E_UNEXPECTED, - tr("The service call failed with error %Rrc"), vrc); - } + if (pData->u32Status == PROC_STS_ERROR) + rc = setError(VBOX_E_IPRT_ERROR, + tr("Process could not be started: %Rrc"), pData->u32Flags); + else + rc = setError(E_UNEXPECTED, + tr("The service call failed with error %Rrc"), vrc); + } } else /* Execution went fine. */ { @@ -1085,6 +1138,8 @@ STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags, STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ULONG64 aSize, ComSafeArrayOut(BYTE, aData)) { +/** @todo r=bird: Eventually we should clean up all the timeout parameters + * in the API and have the same way of specifying infinite waits! */ #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else /* VBOX_WITH_GUEST_CONTROL */ @@ -1096,7 +1151,7 @@ STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, return E_INVALIDARG; AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); HRESULT rc = S_OK; @@ -1122,31 +1177,31 @@ STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, aTimeoutMS = UINT32_MAX; /* Search for existing PID. */ - PHOSTEXECOUTCALLBACKDATA pData = (HOSTEXECOUTCALLBACKDATA*)RTMemAlloc(sizeof(HOSTEXECOUTCALLBACKDATA)); + PCALLBACKDATAEXECOUT pData = (CALLBACKDATAEXECOUT*)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT)); AssertReturn(pData, VBOX_E_IPRT_ERROR); uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT, - pData, sizeof(HOSTEXECOUTCALLBACKDATA), progress); + pData, sizeof(CALLBACKDATAEXECOUT), progress); Assert(uContextID > 0); - + size_t cbData = (size_t)RT_MIN(aSize, _64K); com::SafeArray<BYTE> outputData(cbData); - + VBOXHGCMSVCPARM paParms[5]; int i = 0; paParms[i++].setUInt32(uContextID); paParms[i++].setUInt32(aPID); paParms[i++].setUInt32(aFlags); /** @todo Should represent stdout and/or stderr. */ - + int vrc = VINF_SUCCESS; - + { VMMDev *vmmDev; { - /* Make sure mParent is valid, so set the read lock while using. + /* Make sure mParent is valid, so set the read lock while using. * Do not keep this lock while doing the actual call, because in the meanwhile * another thread could request a write lock which would be a bad idea ... */ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - + /* Forward the information to the VMM device. */ AssertPtr(mParent); vmmDev = mParent->getVMMDev(); @@ -1159,11 +1214,11 @@ STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, i, paParms); } } - + if (RT_SUCCESS(vrc)) { LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS)); - + /* * Wait for the HGCM low level callback until the process * has been started (or something went wrong). This is necessary to @@ -1174,7 +1229,7 @@ STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, if (it != mCallbackList.end()) { uint64_t u64Started = RTTimeMilliTS(); - while (!it->bCalled) + while (!it->fCalled) { /* Check for timeout. */ unsigned cMsWait; @@ -1197,26 +1252,26 @@ STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, break; /* Client wants to abort. */ } RTThreadSleep(cMsWait); - } - + } + /* Was the whole thing canceled? */ if (!fCanceled) { - if (it->bCalled) + if (it->fCalled) { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - + /* Did we get some output? */ - pData = (HOSTEXECOUTCALLBACKDATA*)it->pvData; - Assert(it->cbData == sizeof(HOSTEXECOUTCALLBACKDATA)); + pData = (PCALLBACKDATAEXECOUT)it->pvData; + Assert(it->cbData == sizeof(CALLBACKDATAEXECOUT)); AssertPtr(pData); - + if (pData->cbData) { /* Do we need to resize the array? */ if (pData->cbData > cbData) outputData.resize(pData->cbData); - + /* Fill output in supplied out buffer. */ memcpy(outputData.raw(), pData->pvData, pData->cbData); outputData.resize(pData->cbData); /* Shrink to fit actual buffer size. */ @@ -1260,12 +1315,12 @@ STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, } else /* PID lookup failed. */ rc = setError(VBOX_E_IPRT_ERROR, - tr("Process (PID %u) not found!"), aPID); + tr("Process (PID %u) not found!"), aPID); } else /* HGCM operation failed. */ rc = setError(E_UNEXPECTED, tr("The HGCM call failed with error %Rrc"), vrc); - + /* Cleanup. */ progress->uninit(); progress.setNull(); @@ -1292,21 +1347,21 @@ STDMETHODIMP Guest::GetProcessStatus(ULONG aPID, ULONG *aExitCode, ULONG *aFlags using namespace guestControl; AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); HRESULT rc = S_OK; try { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - + GuestProcessIterConst it; for (it = mGuestProcessList.begin(); it != mGuestProcessList.end(); it++) { if (it->mPID == aPID) break; } - + if (it != mGuestProcessList.end()) { *aExitCode = it->mExitCode; diff --git a/src/VBox/Main/HostImpl.cpp b/src/VBox/Main/HostImpl.cpp index a1edc2dd3..a1894e4a5 100644 --- a/src/VBox/Main/HostImpl.cpp +++ b/src/VBox/Main/HostImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: HostImpl.cpp 29620 2010-05-18 12:15:55Z vboxsync $ */ +/* $Id: HostImpl.cpp 29945 2010-06-01 12:49:25Z vboxsync $ */ /** @file * VirtualBox COM class implementation: Host */ @@ -500,12 +500,6 @@ STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInte AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* The code is so hideously complicated that I can't tell whether the - * host object lock is really needed. It was taken here, and as the - * VirtualBox (mParent) is taken as well below nested deep down that - * would be a lock order violation. */ - AutoMultiWriteLock2 alock(m->pParent, this COMMA_LOCKVAL_SRC_POS); - std::list <ComObjPtr<HostNetworkInterface> > list; # ifdef VBOX_WITH_HOSTNETIF_API diff --git a/src/VBox/Main/MachineImpl.cpp b/src/VBox/Main/MachineImpl.cpp index e13be6044..aa6fc5d70 100644 --- a/src/VBox/Main/MachineImpl.cpp +++ b/src/VBox/Main/MachineImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: MachineImpl.cpp 29620 2010-05-18 12:15:55Z vboxsync $ */ +/* $Id: MachineImpl.cpp 29971 2010-06-02 08:51:13Z vboxsync $ */ /** @file * Implementation of IMachine in VBoxSVC. */ @@ -35,6 +35,7 @@ #include "VirtualBoxImpl.h" #include "MachineImpl.h" #include "ProgressImpl.h" +#include "ProgressProxyImpl.h" #include "MediumAttachmentImpl.h" #include "MediumImpl.h" #include "MediumLock.h" @@ -4965,8 +4966,9 @@ STDMETHODIMP Machine::QueryLogFilename(ULONG aIdx, BSTR *aName) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); Utf8Str log = queryLogFilename(aIdx); - if (RTFileExists(log.c_str())) - log.cloneTo(aName); + if (!RTFileExists(log.c_str())) + log.setNull(); + log.cloneTo(aName); return S_OK; } @@ -5173,7 +5175,8 @@ HRESULT Machine::openSession(IInternalSessionControl *aControl) AssertReturn(aControl, E_FAIL); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -5325,6 +5328,8 @@ HRESULT Machine::openSession(IInternalSessionControl *aControl) if (mData->mSession.mState == SessionState_Spawning) { /* Note that the progress object is finalized later */ + /** @todo Consider checking mData->mSession.mProgress for cancellation + * around here. */ /* We don't reset mSession.mPid here because it is necessary for * SessionMachine::uninit() to reap the child process later. */ @@ -5376,7 +5381,7 @@ HRESULT Machine::openSession(IInternalSessionControl *aControl) if (FAILED(rc)) sessionMachine->uninit(); - LogFlowThisFunc(("rc=%08X\n", rc)); + LogFlowThisFunc(("rc=%Rhrc\n", rc)); LogFlowThisFuncLeave(); return rc; } @@ -5388,7 +5393,7 @@ HRESULT Machine::openSession(IInternalSessionControl *aControl) HRESULT Machine::openRemoteSession(IInternalSessionControl *aControl, IN_BSTR aType, IN_BSTR aEnvironment, - Progress *aProgress) + ProgressProxy *aProgress) { LogFlowThisFuncEnter(); @@ -5612,6 +5617,7 @@ HRESULT Machine::openRemoteSession(IInternalSessionControl *aControl, return S_OK; } + /** * @note Locks this object for writing, calls the client process * (outside the lock). @@ -5837,7 +5843,7 @@ bool Machine::checkForSpawnFailure() /* the process was already unexpectedly terminated, we just need to set an * error and finalize session spawning */ rc = setError(E_FAIL, - tr("Virtual machine '%ls' has terminated unexpectedly during startup"), + tr("The virtual machine '%ls' has terminated unexpectedly during startup"), getName().raw()); #else @@ -5853,19 +5859,19 @@ bool Machine::checkForSpawnFailure() { if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_NORMAL) rc = setError(E_FAIL, - tr("Virtual machine '%ls' has terminated unexpectedly during startup with exit code %d"), + tr("The virtual machine '%ls' has terminated unexpectedly during startup with exit code %d"), getName().raw(), status.iStatus); else if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_SIGNAL) rc = setError(E_FAIL, - tr("Virtual machine '%ls' has terminated unexpectedly during startup because of signal %d"), + tr("The virtual machine '%ls' has terminated unexpectedly during startup because of signal %d"), getName().raw(), status.iStatus); else if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_ABEND) rc = setError(E_FAIL, - tr("Virtual machine '%ls' has terminated abnormally"), + tr("The virtual machine '%ls' has terminated abnormally"), getName().raw(), status.iStatus); else rc = setError(E_FAIL, - tr("Virtual machine '%ls' has terminated unexpectedly during startup (%Rrc)"), + tr("The virtual machine '%ls' has terminated unexpectedly during startup (%Rrc)"), getName().raw(), rc); } @@ -9823,45 +9829,43 @@ STDMETHODIMP SessionMachine::GetIPCId(BSTR *aId) /** * @note Locks this object for writing. */ -STDMETHODIMP SessionMachine::SetPowerUpInfo(IVirtualBoxErrorInfo *aError) +STDMETHODIMP SessionMachine::BeginPowerUp(IProgress *aProgress) { AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - if ( mData->mSession.mState == SessionState_Open - && mData->mSession.mProgress) + if (mData->mSession.mState != SessionState_Open) + return VBOX_E_INVALID_OBJECT_STATE; + + if (!mData->mSession.mProgress.isNull()) + mData->mSession.mProgress->setOtherProgressObject(aProgress); + + return S_OK; +} + + +/** + * @note Locks this object for writing. + */ +STDMETHODIMP SessionMachine::EndPowerUp(LONG iResult) +{ + AutoCaller autoCaller(this); + AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (mData->mSession.mState != SessionState_Open) + return VBOX_E_INVALID_OBJECT_STATE; + + /* Finalize the openRemoteSession progress object. */ + if (mData->mSession.mProgress) { - /* Finalize the progress, since the remote session has completed - * power on (successful or not). */ - if (aError) - { - /* Transfer error information immediately, as the - * IVirtualBoxErrorInfo object is most likely transient. */ - HRESULT rc; - LONG rRc = S_OK; - rc = aError->COMGETTER(ResultCode)(&rRc); - AssertComRCReturnRC(rc); - Bstr rIID; - rc = aError->COMGETTER(InterfaceID)(rIID.asOutParam()); - AssertComRCReturnRC(rc); - Bstr rComponent; - rc = aError->COMGETTER(Component)(rComponent.asOutParam()); - AssertComRCReturnRC(rc); - Bstr rText; - rc = aError->COMGETTER(Text)(rText.asOutParam()); - AssertComRCReturnRC(rc); - mData->mSession.mProgress->notifyComplete(rRc, Guid(rIID), rComponent, Utf8Str(rText).raw()); - } - else - mData->mSession.mProgress->notifyComplete(S_OK); + mData->mSession.mProgress->notifyComplete((HRESULT)iResult); mData->mSession.mProgress.setNull(); - - return S_OK; } - else - return VBOX_E_INVALID_OBJECT_STATE; + return S_OK; } /** @@ -10055,13 +10059,16 @@ STDMETHODIMP SessionMachine::OnSessionEnd(ISession *aSession, /* Create the progress object the client will use to wait until * #checkForDeath() is called to uninitialize this session object after - * it releases the IPC semaphore. */ + * it releases the IPC semaphore. + * Note! Because we're "reusing" mProgress here, this must be a proxy + * object just like for openRemoteSession. */ Assert(mData->mSession.mProgress.isNull()); - ComObjPtr<Progress> progress; + ComObjPtr<ProgressProxy> progress; progress.createObject(); ComPtr<IUnknown> pPeer(mPeer); progress->init(mParent, pPeer, - Bstr(tr("Closing session")), FALSE /* aCancelable */); + Bstr(tr("Closing session")), + FALSE /* aCancelable */); progress.queryInterfaceTo(aProgress); mData->mSession.mProgress = progress; } diff --git a/src/VBox/Main/Makefile.kmk b/src/VBox/Main/Makefile.kmk index ca129c365..39c5f33ce 100644 --- a/src/VBox/Main/Makefile.kmk +++ b/src/VBox/Main/Makefile.kmk @@ -1,4 +1,4 @@ -# $Id: Makefile.kmk 29162 2010-05-06 15:15:40Z vboxsync $ +# $Id: Makefile.kmk 29859 2010-05-28 13:17:24Z vboxsync $ ## @file # Makefile for the VBox Main module. # @@ -76,18 +76,18 @@ VBOX_IDL_HEADER.XPCOM = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCO # The MS COM specific stuff. if defined(VBOX_ONLY_SDK) || "$(KBUILD_TARGET)" == "win" OTHERS += \ - $(VBOX_IDL_FILE.MSCOM) \ - $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h \ - $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox.tlb \ - $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c + $(VBOX_IDL_FILE.MSCOM) \ + $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox.tlb \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c OTHER_CLEAN += \ - $(VBOX_IDL_FILE.MSCOM) \ - $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h \ - $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox.tlb \ - $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c \ - $(PATH_VBoxCOM)/VirtualBox.h \ - $(PATH_VBoxCOM)/VirtualBox_i.c \ - $(PATH_VBoxCOM)/VirtualBox.tlb + $(VBOX_IDL_FILE.MSCOM) \ + $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox.tlb \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c \ + $(PATH_VBoxCOM)/VirtualBox.h \ + $(PATH_VBoxCOM)/VirtualBox_i.c \ + $(PATH_VBoxCOM)/VirtualBox.tlb VBOX_MAIN_PREREQS += $(PATH_VBoxCOM)/VirtualBox_i.c BLDDIRS += $(VBOX_PATH_SDK)/bindings/mscom/idl @@ -224,10 +224,10 @@ VBoxSVC_DEFS = \ $(if $(VBOX_WITH_VUSB),VBOX_WITH_VUSB,) ifdef VBOX_WITH_USB VBoxSVC_DEFS += \ - VBOX_WITH_USB \ - $(if $(VBOX_WITH_EHCI),VBOX_WITH_EHCI,) \ - $(if $(VBOX_WITH_NEW_USB_CODE_ON_DARWIN),VBOX_WITH_NEW_USB_CODE_ON_DARWIN,) \ - $(if $(VBOX_WITH_NEW_USB_CODE_ON_SOLARIS),VBOX_WITH_NEW_USB_CODE_ON_SOLARIS,) +VBOX_WITH_USB \ + $(if $(VBOX_WITH_EHCI),VBOX_WITH_EHCI,) \ + $(if $(VBOX_WITH_NEW_USB_CODE_ON_DARWIN),VBOX_WITH_NEW_USB_CODE_ON_DARWIN,) \ + $(if $(VBOX_WITH_NEW_USB_CODE_ON_SOLARIS),VBOX_WITH_NEW_USB_CODE_ON_SOLARIS,) endif VBoxSVC_DEFS.win += VBOX_COM_OUTOFPROC_MODULE VBoxSVC_DEFS.win.x86 += _WIN32_WINNT=0x0500 @@ -301,6 +301,7 @@ VBoxSVC_SOURCES = \ MediumAttachmentImpl.cpp \ MediumFormatImpl.cpp \ ProgressImpl.cpp \ + ProgressProxyImpl.cpp \ HostImpl.cpp \ HostNetworkInterfaceImpl.cpp \ DHCPServerImpl.cpp \ @@ -353,9 +354,9 @@ ifdef VBOX_WITH_USB linux/USBProxyServiceLinux.cpp_DEFS += VBOX_WITH_SYSFS_BY_DEFAULT endif VBoxSVC_SOURCES += \ - USBDeviceFilterImpl.cpp \ - USBProxyService.cpp \ - HostUSBDeviceImpl.cpp + USBDeviceFilterImpl.cpp \ + USBProxyService.cpp \ + HostUSBDeviceImpl.cpp VBoxSVC_SOURCES.darwin += darwin/USBProxyServiceDarwin.cpp VBoxSVC_SOURCES.linux += linux/USBProxyServiceLinux.cpp VBoxSVC_SOURCES.os2 += os2/USBProxyServiceOs2.cpp @@ -391,8 +392,8 @@ endif ifdef VBOX_WITH_RESOURCE_USAGE_API VBoxSVC_SOURCES += \ - PerformanceImpl.cpp \ - Performance.cpp + PerformanceImpl.cpp \ + Performance.cpp VBoxSVC_SOURCES.darwin += darwin/PerformanceDarwin.cpp VBoxSVC_SOURCES.freebsd += freebsd/PerformanceFreeBSD.cpp VBoxSVC_SOURCES.linux += linux/PerformanceLinux.cpp @@ -479,8 +480,8 @@ if ( defined(VBOX_WITH_QTGUI) \ VBoxTestOGL_SOURCES = generic/OpenGLTestApp.cpp VBoxTestOGL_LIBS = \ $(if $(VBOX_WITH_CROGL), \ - $(PATH_LIB)/VBoxOGLhostspuload$(VBOX_SUFF_LIB) \ - $(VBOX_LIB_OGL_HOSTCRUTIL),) \ + $(PATH_LIB)/VBoxOGLhostspuload$(VBOX_SUFF_LIB) \ + $(VBOX_LIB_OGL_HOSTCRUTIL),) \ $(if $(VBOX_WITH_VIDEOHWACCEL), $(PATH_LIB)/VBoxOGL2D$(VBOX_SUFF_LIB),) \ $(LIB_RUNTIME) VBoxTestOGL_DEFS += \ @@ -609,7 +610,7 @@ VBoxC_LIBS += \ ifdef VBOX_WITH_NETFLT VBoxC_LIBS.win += $(PATH_LIB)/WinNetConfig.lib \ - $(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/comsupp.lib \ + $(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/comsupp.lib \ $(PATH_SDK_WINPSDK_LIB)/WbemUuid.Lib endif @@ -734,11 +735,11 @@ if defined(VBOX_WITH_HARDENING) && "$(KBUILD_TARGET)" == "linux" INSTALLS.linux += VBoxMain-hardening-inst VBoxMain-hardening-inst_INST = $(INST_BIN)components/ VBoxMain-hardening-inst_SYMLINKS = \ - VBoxDDU.so=>../VBoxDDU.so \ - VBoxREM.so=>../VBoxREM.so \ - VBoxRT.so=>../VBoxRT.so \ - VBoxVMM.so=>../VBoxVMM.so \ - VBoxXPCOM.so=>../VBoxXPCOM.so + VBoxDDU.so=>../VBoxDDU.so \ + VBoxREM.so=>../VBoxREM.so \ + VBoxRT.so=>../VBoxRT.so \ + VBoxVMM.so=>../VBoxVMM.so \ + VBoxXPCOM.so=>../VBoxXPCOM.so endif @@ -829,6 +830,61 @@ VBoxC_VBOX_HEADERS = \ VBoxC_VBOX_TRANSLATIONS = \ nls/VBoxC_de.ts +ifdef VBOX_WITH_JMSCOM +INSTALLS += VBoxJMscom-inst-jar + +# +# Java glue JAR files +# +VBOX_JMSCOM_JAR = $(VBoxJMscom-inst-jar_0_OUTDIR)/vboxjmscom.jar +VBOX_JMSCOM_TARGET := $(PATH_TARGET)/vboxjmscom-gen +VBOX_JMSCOM_GEN = $(VBOX_JMSCOM_TARGET)/jmscomgen +VBOX_JMSCOM_JDEST := $(VBOX_JMSCOM_TARGET)/jdest +VBOX_GLUE_XSLT_DIR := $(PATH_ROOT)/src/VBox/Main/glue +VBOX_JACOB_DIR := $(PATH_ROOT)/src/libs/jacob-1.15-M3 + +VBoxJMscom-inst-jar_INST = $(INST_SDK)bindings/mscom/java/ +VBoxJMscom-inst-jar_SOURCES = \ + $(VBOX_JMSCOM_JAR) +VBoxJMscom-inst-jar_CLEAN = \ + $(VBOX_JMSCOM_JAR) \ + $(VBOX_JMSCOM_GEN)/jmscomglue.list \ + $(wildcard \ + $(VBOX_JMSCOM_GEN)/java/*.java \ + $(VBOX_JMSCOM_JDEST)/*.class \ + $(VBOX_JMSCOM_JDEST)/*/*.class \ + $(VBOX_JMSCOM_JDEST)/*/*/*.class \ + $(VBOX_JMSCOM_JDEST)/*/*/*/*.class \ + ) +VBoxJMscom-inst-jar_BLDDIRS += $(VBOX_JMSCOM_GEN)/java + +$(VBOX_JMSCOM_GEN)/jmscomglue.list: \ + $(VBOX_XIDL_FILE) \ + $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl \ + $(VBOX_FILESPLIT) \ + | $(VBOX_JMSCOM_GEN)/java/ + $(call MSG_L1,Generating Java glue files from XIDL) + $(QUIET)$(RM) -f $(wildcard $(VBOX_JMSCOM_GEN)/java/*.java) + $(QUIET)$(VBOX_XSLTPROC) \ + --stringparam G_vboxApiSuffix $(VBOX_API_SUFFIX) \ + --stringparam G_vboxGlueStyle mscom \ + -o $(VBOX_JMSCOM_GEN)/java/merged.file $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $< + $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JMSCOM_GEN)/java/merged.file $(VBOX_JMSCOM_GEN)/java + $(QUIET)echo $(VBOX_JMSCOM_GEN)/java/*.java > $@ + +$$(VBOX_JMSCOM_JAR): $(VBOX_JMSCOM_GEN)/jmscomglue.list | $$(dir $$@) + $(call MSG_TOOL,javac,$(notdir $@),jmscomgen.list,) + $(QUIET)$(RM) -Rf $(VBOX_JMSCOM_JDEST) + $(QUIET)$(MKDIR) -p $(VBOX_JMSCOM_JDEST) + $(call MSG_TOOL,javac,$(notdir $@),...,) + $(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) \ + @$(VBOX_JMSCOM_GEN)/jmscomglue.list \ + -d $(VBOX_JMSCOM_JDEST) -classpath $(VBOX_JMSCOM_JDEST)$(VBOX_SEP)$(VBOX_JACOB_DIR)/jacob.jar + $(call MSG_LINK,$(notdir $@),$@) + $(VBOX_JAR) cf $@ -C $(VBOX_JMSCOM_JDEST) . + +endif # VBOX_WITH_JMSCOM + updatenls:: $(VBOX_LUPDATE) $(VBoxSVC_SOURCES) $(VBoxSVC_VBOX_HEADERS) -ts $(VBoxSVC_VBOX_TRANSLATIONS) $(VBOX_LUPDATE) $(VBoxC_SOURCES) $(VBoxC_VBOX_HEADERS) -ts $(VBoxC_VBOX_TRANSLATIONS) diff --git a/src/VBox/Main/MediumImpl.cpp b/src/VBox/Main/MediumImpl.cpp index edfff34c9..61d04da96 100644 --- a/src/VBox/Main/MediumImpl.cpp +++ b/src/VBox/Main/MediumImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: MediumImpl.cpp 29618 2010-05-18 12:07:30Z vboxsync $ */ +/* $Id: MediumImpl.cpp 29940 2010-06-01 11:09:44Z vboxsync $ */ /** @file * VirtualBox COM class implementation */ @@ -1440,12 +1440,12 @@ STDMETHODIMP Medium::COMSETTER(Type)(MediumType_T aType) m->type = aType; + mlock.release(); + // saveSettings needs vbox lock - ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox); - mlock.leave(); AutoWriteLock alock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS); - HRESULT rc = pVirtualBox->saveSettings(); + HRESULT rc = m->pVirtualBox->saveSettings(); return rc; } @@ -1558,8 +1558,7 @@ STDMETHODIMP Medium::COMSETTER(AutoReset)(BOOL aAutoReset) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* VirtualBox::saveSettings() needs a write lock */ - AutoMultiWriteLock2 alock(m->pVirtualBox, this COMMA_LOCKVAL_SRC_POS); + AutoWriteLock mlock(this COMMA_LOCKVAL_SRC_POS); if (m->pParent.isNull()) return setError(VBOX_E_NOT_SUPPORTED, @@ -1570,6 +1569,11 @@ STDMETHODIMP Medium::COMSETTER(AutoReset)(BOOL aAutoReset) { m->autoReset = !!aAutoReset; + mlock.release(); + + // saveSettings needs vbox lock + AutoWriteLock alock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS); + return m->pVirtualBox->saveSettings(); } @@ -1979,8 +1983,7 @@ STDMETHODIMP Medium::SetProperty(IN_BSTR aName, IN_BSTR aValue) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* VirtualBox::saveSettings() needs a write lock */ - AutoMultiWriteLock2 alock(m->pVirtualBox, this COMMA_LOCKVAL_SRC_POS); + AutoWriteLock mlock(this COMMA_LOCKVAL_SRC_POS); switch (m->state) { @@ -2002,6 +2005,10 @@ STDMETHODIMP Medium::SetProperty(IN_BSTR aName, IN_BSTR aValue) else it->second = aValue; + mlock.release(); + + // saveSettings needs vbox lock + AutoWriteLock alock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS); HRESULT rc = m->pVirtualBox->saveSettings(); return rc; @@ -2050,8 +2057,7 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames), AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* VirtualBox::saveSettings() needs a write lock */ - AutoMultiWriteLock2 alock(m->pVirtualBox, this COMMA_LOCKVAL_SRC_POS); + AutoWriteLock mlock(this COMMA_LOCKVAL_SRC_POS); com::SafeArray<IN_BSTR> names(ComSafeArrayInArg(aNames)); com::SafeArray<IN_BSTR> values(ComSafeArrayInArg(aValues)); @@ -2080,6 +2086,10 @@ STDMETHODIMP Medium::SetProperties(ComSafeArrayIn(IN_BSTR, aNames), it->second = values[i]; } + mlock.release(); + + // saveSettings needs vbox lock + AutoWriteLock alock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS); HRESULT rc = m->pVirtualBox->saveSettings(); return rc; @@ -3448,9 +3458,7 @@ HRESULT Medium::queryInfo() || m->state == MediumState_LockedWrite); alock.leave(); - vrc = RTSemEventMultiWait(m->queryInfoSem, RT_INDEFINITE_WAIT); - alock.enter(); AssertRC(vrc); @@ -5160,7 +5168,7 @@ HRESULT Medium::taskCreateBaseHandler(Medium::CreateBaseTask &task) ComAssertRCThrow(vrc, E_FAIL); /* unlock before the potentially lengthy operation */ - thisLock.leave(); + thisLock.release(); try { @@ -5294,7 +5302,7 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task) /* the two media are now protected by their non-default states; * unlock the media before the potentially lengthy operation */ - mediaLock.leave(); + mediaLock.release(); try { @@ -5411,7 +5419,7 @@ HRESULT Medium::taskCreateDiffHandler(Medium::CreateDiffTask &task) { if (fNeedsSaveSettings) { - mediaLock.leave(); + mediaLock.release(); AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS); m->pVirtualBox->saveSettings(); } @@ -5816,7 +5824,7 @@ HRESULT Medium::taskCloneHandler(Medium::CloneTask &task) Assert(pParent.isNull() || pParent->m->state == MediumState_LockedRead); /* unlock before the potentially lengthy operation */ - thisLock.leave(); + thisLock.release(); /* ensure the target directory exists */ rc = VirtualBox::ensureFilePathExists(targetLocation); @@ -6237,7 +6245,7 @@ HRESULT Medium::taskCompactHandler(Medium::CompactTask &task) Utf8Str location(m->strLocationFull); /* unlock before the potentially lengthy operation */ - thisLock.leave(); + thisLock.release(); vrc = VDCompact(hdd, VD_LAST_IMAGE, task.mVDOperationIfaces); if (RT_FAILURE(vrc)) diff --git a/src/VBox/Main/ProgressImpl.cpp b/src/VBox/Main/ProgressImpl.cpp index 90b9589c3..39ec05c29 100644 --- a/src/VBox/Main/ProgressImpl.cpp +++ b/src/VBox/Main/ProgressImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: ProgressImpl.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: ProgressImpl.cpp 29989 2010-06-02 12:46:49Z vboxsync $ */ /** @file * * VirtualBox Progress COM class implementation @@ -330,7 +330,7 @@ STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) { uint64_t ullTimeNow = RTTimeMilliTS(); uint64_t ullTimeElapsed = ullTimeNow - m_ullTimestamp; - uint64_t ullTimeTotal = (uint64_t)(ullTimeElapsed / dPercentDone * 100); + uint64_t ullTimeTotal = (uint64_t)(ullTimeElapsed * 100 / dPercentDone); uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed; // Log(("ProgressBase::GetTimeRemaining: dPercentDone %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n", @@ -834,20 +834,17 @@ STDMETHODIMP Progress::WaitForCompletion (LONG aTimeout) /* if we're already completed, take a shortcut */ if (!mCompleted) { - RTTIMESPEC time; - RTTimeNow(&time); /** @todo r=bird: Use monotonic time (RTTimeMilliTS()) here because of daylight saving and things like that. */ - int vrc = VINF_SUCCESS; bool fForever = aTimeout < 0; int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeSpecGetMilli(&time); + int64_t lastTime = RTTimeMilliTS(); while (!mCompleted && (fForever || timeLeft > 0)) { mWaitersCount++; alock.leave(); vrc = RTSemEventMultiWait(mCompletedSem, - fForever ? RT_INDEFINITE_WAIT : (unsigned)timeLeft); + fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft); alock.enter(); mWaitersCount--; @@ -860,9 +857,9 @@ STDMETHODIMP Progress::WaitForCompletion (LONG aTimeout) if (!fForever) { - RTTimeNow (&time); - timeLeft -= RTTimeSpecGetMilli(&time) - lastTime; - lastTime = RTTimeSpecGetMilli(&time); + int64_t now = RTTimeMilliTS(); + timeLeft -= now - lastTime; + lastTime = now; } } @@ -900,13 +897,10 @@ STDMETHODIMP Progress::WaitForOperationCompletion(ULONG aOperation, LONG aTimeou if ( !mCompleted && aOperation >= m_ulCurrentOperation) { - RTTIMESPEC time; - RTTimeNow (&time); - int vrc = VINF_SUCCESS; bool fForever = aTimeout < 0; int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeSpecGetMilli (&time); + int64_t lastTime = RTTimeMilliTS(); while ( !mCompleted && aOperation >= m_ulCurrentOperation && (fForever || timeLeft > 0)) @@ -927,9 +921,9 @@ STDMETHODIMP Progress::WaitForOperationCompletion(ULONG aOperation, LONG aTimeou if (!fForever) { - RTTimeNow(&time); - timeLeft -= RTTimeSpecGetMilli(&time) - lastTime; - lastTime = RTTimeSpecGetMilli(&time); + int64_t now = RTTimeMilliTS(); + timeLeft -= now - lastTime; + lastTime = now; } } @@ -957,11 +951,15 @@ STDMETHODIMP Progress::Cancel() if (!mCanceled) { + LogThisFunc(("Canceling\n")); mCanceled = TRUE; if (m_pfnCancelCallback) m_pfnCancelCallback(m_pvCancelUserArg); } + else + LogThisFunc(("Already canceled\n")); + return S_OK; } @@ -1010,7 +1008,9 @@ STDMETHODIMP Progress::SetNextOperation(IN_BSTR bstrNextOperationDescription, UL AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - AssertReturn(!mCompleted && !mCanceled, E_FAIL); + if (mCanceled) + return E_FAIL; + AssertReturn(!mCompleted, E_FAIL); AssertReturn(m_ulCurrentOperation + 1 < m_cOperations, E_FAIL); ++m_ulCurrentOperation; @@ -1148,6 +1148,22 @@ HRESULT Progress::notifyComplete(HRESULT aResultCode) } /** + * Wrapper around Progress:notifyCompleteV. + */ +HRESULT Progress::notifyComplete(HRESULT aResultCode, + const GUID &aIID, + const Bstr &aComponent, + const char *aText, + ...) +{ + va_list va; + va_start(va, aText); + HRESULT hrc = notifyCompleteV(aResultCode, aIID, aComponent, aText, va); + va_end(va); + return hrc; +} + +/** * Marks the operation as complete and attaches full error info. * * See com::SupportErrorInfoImpl::setError(HRESULT, const GUID &, const wchar_t @@ -1158,18 +1174,15 @@ HRESULT Progress::notifyComplete(HRESULT aResultCode) * @param aComponent Name of the component that generates the error. * @param aText Error message (must not be null), an RTStrPrintf-like * format string in UTF-8 encoding. - * @param ... List of arguments for the format string. + * @param va List of arguments for the format string. */ -HRESULT Progress::notifyComplete(HRESULT aResultCode, - const GUID &aIID, - const Bstr &aComponent, - const char *aText, - ...) +HRESULT Progress::notifyCompleteV(HRESULT aResultCode, + const GUID &aIID, + const Bstr &aComponent, + const char *aText, + va_list va) { - va_list args; - va_start(args, aText); - Utf8Str text = Utf8StrFmtVA(aText, args); - va_end (args); + Utf8Str text = Utf8StrFmtVA(aText, va); AutoCaller autoCaller(this); AssertComRCReturnRC(autoCaller.rc()); @@ -1230,9 +1243,13 @@ bool Progress::notifyPointOfNoReturn(void) AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (mCanceled) + { + LogThisFunc(("returns false\n")); return false; + } mCancelable = FALSE; + LogThisFunc(("returns true\n")); return true; } @@ -1570,13 +1587,10 @@ STDMETHODIMP CombinedProgress::WaitForCompletion (LONG aTimeout) /* if we're already completed, take a shortcut */ if (!mCompleted) { - RTTIMESPEC time; - RTTimeNow(&time); - HRESULT rc = S_OK; bool forever = aTimeout < 0; int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeSpecGetMilli(&time); + int64_t lastTime = RTTimeMilliTS(); while (!mCompleted && (forever || timeLeft > 0)) { @@ -1591,9 +1605,9 @@ STDMETHODIMP CombinedProgress::WaitForCompletion (LONG aTimeout) if (!forever) { - RTTimeNow(&time); - timeLeft -= RTTimeSpecGetMilli(&time) - lastTime; - lastTime = RTTimeSpecGetMilli(&time); + int64_t now = RTTimeMilliTS(); + timeLeft -= now - lastTime; + lastTime = now; } } @@ -1657,12 +1671,9 @@ STDMETHODIMP CombinedProgress::WaitForOperationCompletion (ULONG aOperation, LON LogFlowThisFunc(("will wait for mProgresses [%d] (%d)\n", progress, operation)); - RTTIMESPEC time; - RTTimeNow (&time); - bool forever = aTimeout < 0; int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeSpecGetMilli (&time); + int64_t lastTime = RTTimeMilliTS(); while (!mCompleted && aOperation >= m_ulCurrentOperation && (forever || timeLeft > 0)) @@ -1680,9 +1691,9 @@ STDMETHODIMP CombinedProgress::WaitForOperationCompletion (ULONG aOperation, LON if (!forever) { - RTTimeNow(&time); - timeLeft -= RTTimeSpecGetMilli(&time) - lastTime; - lastTime = RTTimeSpecGetMilli(&time); + int64_t now = RTTimeMilliTS(); + timeLeft -= now - lastTime; + lastTime = now; } } @@ -1706,6 +1717,7 @@ STDMETHODIMP CombinedProgress::Cancel() if (!mCanceled) { + LogThisFunc(("Canceling\n")); mCanceled = TRUE; /** @todo Teleportation: Shouldn't this be propagated to mProgresses? If * powerUp creates passes a combined progress object to the client, I @@ -1715,6 +1727,9 @@ STDMETHODIMP CombinedProgress::Cancel() m_pfnCancelCallback(m_pvCancelUserArg); } + else + LogThisFunc(("Already canceled\n")); + return S_OK; } diff --git a/src/VBox/Main/ProgressProxyImpl.cpp b/src/VBox/Main/ProgressProxyImpl.cpp new file mode 100644 index 000000000..042414620 --- /dev/null +++ b/src/VBox/Main/ProgressProxyImpl.cpp @@ -0,0 +1,693 @@ +/* $Id: ProgressProxyImpl.cpp 29948 2010-06-01 12:55:23Z vboxsync $ */ +/** @file + * IProgress implementation for Machine::openRemoteSession in VBoxSVC. + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include <iprt/types.h> + +#if defined (VBOX_WITH_XPCOM) +#include <nsIServiceManager.h> +#include <nsIExceptionService.h> +#include <nsCOMPtr.h> +#endif /* defined (VBOX_WITH_XPCOM) */ + +#include "ProgressProxyImpl.h" + +#include "VirtualBoxImpl.h" +#include "VirtualBoxErrorInfoImpl.h" + +#include "Logging.h" + +#include <iprt/time.h> +#include <iprt/semaphore.h> + +#include <VBox/err.h> + +//////////////////////////////////////////////////////////////////////////////// +// ProgressProxy class +//////////////////////////////////////////////////////////////////////////////// + +// constructor / destructor / uninitializer +//////////////////////////////////////////////////////////////////////////////// + + +HRESULT ProgressProxy::FinalConstruct() +{ + mfMultiOperation = false; + muOtherProgressStartWeight = 0; + muOtherProgressWeight = 0; + muOtherProgressStartOperation = 0; + + HRESULT rc = Progress::FinalConstruct(); + return rc; +} + +/** + * Initalize it as a one operation Progress object. + * + * This is used by SessionMachine::OnSessionEnd. + */ +HRESULT ProgressProxy::init( +#if !defined (VBOX_COM_INPROC) + VirtualBox *pParent, +#endif + IUnknown *pInitiator, + CBSTR bstrDescription, + BOOL fCancelable) +{ + mfMultiOperation = false; + muOtherProgressStartWeight = 1; + muOtherProgressWeight = 1; + muOtherProgressStartOperation = 1; + + return Progress::init( +#if !defined (VBOX_COM_INPROC) + pParent, +#endif + pInitiator, + bstrDescription, + fCancelable, + 1 /* cOperations */, + 1 /* ulTotalOperationsWeight */, + bstrDescription /* bstrFirstOperationDescription */, + 1 /* ulFirstOperationWeight */, + NULL /* pId */); +} + +/** + * Initialize for proxying one other progress object. + * + * This is tailored explicitly for the openRemoteSession code, so we start out + * with one operation where we don't have any remote object (powerUp). Then a + * remote object is added and stays with us till the end. + * + * The user must do normal completion notification or risk leave the threads + * waiting forever! + */ +HRESULT ProgressProxy::init( +#if !defined (VBOX_COM_INPROC) + VirtualBox *pParent, +#endif + IUnknown *pInitiator, + CBSTR bstrDescription, + BOOL fCancelable, + ULONG uTotalOperationsWeight, + CBSTR bstrFirstOperationDescription, + ULONG uFirstOperationWeight, + ULONG cOtherProgressObjectOperations) +{ + mfMultiOperation = false; + muOtherProgressStartWeight = uFirstOperationWeight; + muOtherProgressWeight = uTotalOperationsWeight - uFirstOperationWeight; + muOtherProgressStartOperation = 1; + + return Progress::init( +#if !defined (VBOX_COM_INPROC) + pParent, +#endif + pInitiator, + bstrDescription, + fCancelable, + 1 + cOtherProgressObjectOperations /* cOperations */, + uTotalOperationsWeight, + bstrFirstOperationDescription, + uFirstOperationWeight, + NULL); +} + +void ProgressProxy::FinalRelease() +{ + uninit(); + mfMultiOperation = false; + muOtherProgressStartWeight = 0; + muOtherProgressWeight = 0; + muOtherProgressStartOperation = 0; +} + +void ProgressProxy::uninit() +{ + LogFlowThisFunc(("\n")); + + mptrOtherProgress.setNull(); + Progress::uninit(); +} + +// Public methods +//////////////////////////////////////////////////////////////////////////////// + +/** Just a wrapper so we can automatically do the handover before setting + * the result locally. */ +HRESULT ProgressProxy::notifyComplete(HRESULT aResultCode) +{ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + clearOtherProgressObjectInternal(true /* fEarly */); + HRESULT hrc = S_OK; + if (!mCompleted) + hrc = Progress::notifyComplete(aResultCode); + return hrc; +} + +/** Just a wrapper so we can automatically do the handover before setting + * the result locally. */ +HRESULT ProgressProxy::notifyComplete(HRESULT aResultCode, + const GUID &aIID, + const Bstr &aComponent, + const char *aText, + ...) +{ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + clearOtherProgressObjectInternal(true /* fEarly */); + + HRESULT hrc = S_OK; + if (!mCompleted) + { + va_list va; + va_start(va, aText); + hrc = Progress::notifyCompleteV(aResultCode, aIID, aComponent, aText, va); + va_end(va); + } + return hrc; +} + +/** + * Sets the other progress object unless the operation has been completed / + * canceled already. + * + * @returns false if failed/canceled, true if not. + * @param pOtherProgress The other progress object. Must not be NULL. + */ +bool ProgressProxy::setOtherProgressObject(IProgress *pOtherProgress) +{ + LogFlowThisFunc(("setOtherProgressObject: %p\n", pOtherProgress)); + ComPtr<IProgress> ptrOtherProgress = pOtherProgress; + + /* + * Query information from the other progress object before we grab the + * lock. + */ + ULONG cOperations; + HRESULT hrc = pOtherProgress->COMGETTER(OperationCount)(&cOperations); + if (FAILED(hrc)) + cOperations = 1; + + Bstr bstrOperationDescription; + hrc = pOtherProgress->COMGETTER(Description)(bstrOperationDescription.asOutParam()); + if (FAILED(hrc)) + bstrOperationDescription = "oops"; + + + /* + * Take the lock and check for cancelation, cancel the other object if + * we've been canceled already. + */ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + BOOL fCompletedOrCanceled = mCompleted || mCanceled; + if (!fCompletedOrCanceled) + { + /* + * Advance to the next object and operation. If the other object has + * more operations than anticipated, adjust our internal count. + */ + mptrOtherProgress = ptrOtherProgress; + mfMultiOperation = cOperations > 1; + + muOtherProgressStartWeight = m_ulOperationsCompletedWeight + m_ulCurrentOperationWeight; + muOtherProgressWeight = m_ulTotalOperationsWeight - muOtherProgressStartWeight; + Progress::SetNextOperation(bstrOperationDescription, muOtherProgressWeight); + + muOtherProgressStartOperation = m_ulCurrentOperation; + m_cOperations = cOperations + m_ulCurrentOperation; + + /* + * Check for cancelation and completion. + */ + BOOL f; + hrc = ptrOtherProgress->COMGETTER(Completed)(&f); + fCompletedOrCanceled = FAILED(hrc) || f; + + if (!fCompletedOrCanceled) + { + hrc = ptrOtherProgress->COMGETTER(Canceled)(&f); + fCompletedOrCanceled = SUCCEEDED(hrc) && f; + } + + if (fCompletedOrCanceled) + { + LogFlowThisFunc(("Other object completed or canceled, clearing...\n")); + clearOtherProgressObjectInternal(false /*fEarly*/); + } + else + { + /* + * Finally, mirror the cancelable property. + * Note! Note necessary if we do passthru! + */ + if (mCancelable) + { + hrc = ptrOtherProgress->COMGETTER(Cancelable)(&f); + if (SUCCEEDED(hrc) && !f) + { + LogFlowThisFunc(("The other progress object is not cancelable\n")); + mCancelable = FALSE; + } + } + } + } + else + { + LogFlowThisFunc(("mCompleted=%RTbool mCanceled=%RTbool - Canceling the other progress object!\n", + mCompleted, mCanceled)); + hrc = ptrOtherProgress->Cancel(); + LogFlowThisFunc(("Cancel -> %Rhrc", hrc)); + } + + LogFlowThisFunc(("Returns %RTbool\n", !fCompletedOrCanceled)); + return !fCompletedOrCanceled; +} + +// Internal methods. +//////////////////////////////////////////////////////////////////////////////// + + +/** + * Clear the other progress object reference, first copying over its state. + * + * This is used internally when completion is signalled one way or another. + * + * @param fEarly Early clearing or not. + */ +void ProgressProxy::clearOtherProgressObjectInternal(bool fEarly) +{ + if (mptrOtherProgress.isNotNull()) + { + ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress; + mptrOtherProgress.setNull(); + copyProgressInfo(ptrOtherProgress, fEarly); + } +} + +/** + * Called to copy over the progress information from @a pOtherProgress. + * + * @param pOtherProgress The source of the information. + * @param fEarly Early copy. + * + * @note The caller owns the write lock and as cleared mptrOtherProgress + * already (or we might recurse forever)! + */ +void ProgressProxy::copyProgressInfo(IProgress *pOtherProgress, bool fEarly) +{ + HRESULT hrc; + LogFlowThisFunc(("\n")); + + /* + * No point in doing this if the progress object was canceled already. + */ + if (!mCanceled) + { + /* Detect if the other progress object was canceled. */ + BOOL fCanceled; + hrc = pOtherProgress->COMGETTER(Canceled)(&fCanceled); + if (FAILED(hrc)) + fCanceled = FALSE; + if (fCanceled) + { + LogFlowThisFunc(("Canceled\n")); + mCanceled = TRUE; + if (m_pfnCancelCallback) + m_pfnCancelCallback(m_pvCancelUserArg); + } + else + { + /* Has it completed? */ + BOOL fCompleted; + hrc = pOtherProgress->COMGETTER(Completed)(&fCompleted); + if (FAILED(hrc)) + fCompleted = TRUE; + Assert(fCompleted || fEarly); + if (fCompleted) + { + /* Check the result. */ + LONG hrcResult; + hrc = pOtherProgress->COMGETTER(ResultCode)(&hrcResult); + if (FAILED(hrc)) + hrcResult = hrc; + if (SUCCEEDED((HRESULT)hrcResult)) + LogFlowThisFunc(("Succeeded\n")); + else + { + /* Get the error information. */ + ComPtr<IVirtualBoxErrorInfo> ptrErrorInfo; + hrc = pOtherProgress->COMGETTER(ErrorInfo)(ptrErrorInfo.asOutParam()); + if (SUCCEEDED(hrc)) + { + Bstr bstrIID; + hrc = ptrErrorInfo->COMGETTER(InterfaceID)(bstrIID.asOutParam()); AssertComRC(hrc); + if (FAILED(hrc)) + bstrIID.setNull(); + + Bstr bstrComponent; + hrc = ptrErrorInfo->COMGETTER(Component)(bstrComponent.asOutParam()); AssertComRC(hrc); + if (FAILED(hrc)) + bstrComponent = "failed"; + + Bstr bstrText; + hrc = ptrErrorInfo->COMGETTER(Text)(bstrText.asOutParam()); AssertComRC(hrc); + if (FAILED(hrc)) + bstrText = "<failed>"; + + Utf8Str strText(bstrText); + LogFlowThisFunc(("Got ErrorInfo(%s); hrcResult=%Rhrc\n", strText.c_str(), hrcResult)); + Progress::notifyComplete((HRESULT)hrcResult, Guid(bstrIID), bstrComponent, "%s", strText.c_str()); + } + else + { + LogFlowThisFunc(("ErrorInfo failed with hrc=%Rhrc; hrcResult=%Rhrc\n", hrc, hrcResult)); + Progress::notifyComplete((HRESULT)hrcResult, COM_IIDOF(IProgress), Bstr("ProgressProxy"), + tr("No error info")); + } + } + } + else + LogFlowThisFunc(("Not completed\n")); + } + } + else + LogFlowThisFunc(("Already canceled\n")); + + /* + * Did cancelable state change (point of no return)? + */ + if (mCancelable && !mCompleted && !mCanceled) + { + BOOL fCancelable; + hrc = pOtherProgress->COMGETTER(Cancelable)(&fCancelable); AssertComRC(hrc); + if (SUCCEEDED(hrc) && !fCancelable) + { + LogFlowThisFunc(("point-of-no-return reached\n")); + mCancelable = FALSE; + } + } +} + + +// IProgress properties +//////////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP ProgressProxy::COMGETTER(Cancelable)(BOOL *aCancelable) +{ + CheckComArgOutPointerValid(aCancelable); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* ASSUME: The cancelable property can only change to FALSE. */ + if (!mCancelable || mptrOtherProgress.isNull()) + *aCancelable = mCancelable; + else + { + hrc = mptrOtherProgress->COMGETTER(Cancelable)(aCancelable); + if (SUCCEEDED(hrc) && !*aCancelable) + { + LogFlowThisFunc(("point-of-no-return reached\n")); + mCancelable = FALSE; + } + } + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMGETTER(Percent)(ULONG *aPercent) +{ + CheckComArgOutPointerValid(aPercent); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (mptrOtherProgress.isNull()) + hrc = Progress::COMGETTER(Percent)(aPercent); + else + { + /* + * Get the overall percent of the other object and adjust it with + * the weighting given to the period before proxying started. + */ + ULONG uPct; + hrc = mptrOtherProgress->COMGETTER(Percent)(&uPct); + if (SUCCEEDED(hrc)) + { + double rdPercent = ((double)uPct / 100 * muOtherProgressWeight + muOtherProgressStartWeight) + / m_ulTotalOperationsWeight * 100; + *aPercent = RT_MIN((ULONG)rdPercent, 99); /* mptrOtherProgress is cleared when its completed, so we can never return 100%. */ + } + } + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) +{ + CheckComArgOutPointerValid(aTimeRemaining); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if (mptrOtherProgress.isNull()) + hrc = Progress::COMGETTER(TimeRemaining)(aTimeRemaining); + else + hrc = mptrOtherProgress->COMGETTER(TimeRemaining)(aTimeRemaining); + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMGETTER(Completed)(BOOL *aCompleted) +{ + /* Not proxied since we EXPECT a normal completion notification call. */ + return Progress::COMGETTER(Completed)(aCompleted); +} + +STDMETHODIMP ProgressProxy::COMGETTER(Canceled)(BOOL *aCanceled) +{ + CheckComArgOutPointerValid(aCanceled); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + /* Check the local data first, then the other object. */ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + hrc = Progress::COMGETTER(Canceled)(aCanceled); + if ( SUCCEEDED(hrc) + && !*aCanceled + && mptrOtherProgress.isNotNull() + && mCancelable) + { + hrc = mptrOtherProgress->COMGETTER(Canceled)(aCanceled); + if (SUCCEEDED(hrc) && *aCanceled) + /* This will not complete the object, only mark it as canceled. */ + clearOtherProgressObjectInternal(false /*fEarly*/); + } + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMGETTER(ResultCode)(LONG *aResultCode) +{ + /* Not proxied since we EXPECT a normal completion notification call. */ + return Progress::COMGETTER(ResultCode)(aResultCode); +} + +STDMETHODIMP ProgressProxy::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) +{ + /* Not proxied since we EXPECT a normal completion notification call. */ + return Progress::COMGETTER(ErrorInfo)(aErrorInfo); +} + +STDMETHODIMP ProgressProxy::COMGETTER(Operation)(ULONG *aOperation) +{ + CheckComArgOutPointerValid(aOperation); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (mptrOtherProgress.isNull()) + hrc = Progress::COMGETTER(Operation)(aOperation); + else + { + ULONG uCurOtherOperation; + hrc = mptrOtherProgress->COMGETTER(Operation)(&uCurOtherOperation); + if (SUCCEEDED(hrc)) + *aOperation = uCurOtherOperation + muOtherProgressStartOperation; + } + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMGETTER(OperationDescription)(BSTR *aOperationDescription) +{ + CheckComArgOutPointerValid(aOperationDescription); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (mptrOtherProgress.isNull() || !mfMultiOperation) + hrc = Progress::COMGETTER(OperationDescription)(aOperationDescription); + else + hrc = mptrOtherProgress->COMGETTER(OperationDescription)(aOperationDescription); + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMGETTER(OperationPercent)(ULONG *aOperationPercent) +{ + CheckComArgOutPointerValid(aOperationPercent); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (mptrOtherProgress.isNull() || !mfMultiOperation) + hrc = Progress::COMGETTER(OperationPercent)(aOperationPercent); + else + hrc = mptrOtherProgress->COMGETTER(OperationPercent)(aOperationPercent); + } + return hrc; +} + +STDMETHODIMP ProgressProxy::COMSETTER(Timeout)(ULONG aTimeout) +{ + /* Not currently supported. */ + NOREF(aTimeout); + AssertFailed(); + return E_NOTIMPL; +} + +STDMETHODIMP ProgressProxy::COMGETTER(Timeout)(ULONG *aTimeout) +{ + /* Not currently supported. */ + CheckComArgOutPointerValid(aTimeout); + + AssertFailed(); + return E_NOTIMPL; +} + +// IProgress methods +///////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP ProgressProxy::WaitForCompletion(LONG aTimeout) +{ + HRESULT hrc; + LogFlowThisFuncEnter(); + LogFlowThisFunc(("aTimeout=%d\n", aTimeout)); + + /* No need to wait on the proxied object for these since we'll get the + normal completion notifications. */ + hrc = Progress::WaitForCompletion(aTimeout); + + LogFlowThisFuncLeave(); + return hrc; +} + +STDMETHODIMP ProgressProxy::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout) +{ + LogFlowThisFuncEnter(); + LogFlowThisFunc(("aOperation=%d aTimeout=%d\n", aOperation, aTimeout)); + + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + CheckComArgExpr(aOperation, aOperation < m_cOperations); + + /* + * Check if we can wait locally. + */ + if ( aOperation + 1 == m_cOperations /* final operation */ + || mptrOtherProgress.isNull()) + { + /* ASSUMES that Progress::WaitForOperationCompletion is using + AutoWriteLock::leave() as it saves us from duplicating the code! */ + hrc = Progress::WaitForOperationCompletion(aOperation, aTimeout); + } + else + { + LogFlowThisFunc(("calling the other object...\n")); + ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress; + alock.release(); + + hrc = ptrOtherProgress->WaitForOperationCompletion(aOperation, aTimeout); + } + } + + LogFlowThisFuncLeave(); + return hrc; +} + +STDMETHODIMP ProgressProxy::Cancel() +{ + LogFlowThisFunc(("\n")); + AutoCaller autoCaller(this); + HRESULT hrc = autoCaller.rc(); + if (SUCCEEDED(hrc)) + { + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (mptrOtherProgress.isNull() || !mCancelable) + hrc = Progress::Cancel(); + else + { + hrc = mptrOtherProgress->Cancel(); + if (SUCCEEDED(hrc)) + clearOtherProgressObjectInternal(false /*fEarly*/); + } + } + + LogFlowThisFunc(("returns %Rhrc\n", hrc)); + return hrc; +} + +STDMETHODIMP ProgressProxy::SetCurrentOperationProgress(ULONG aPercent) +{ + /* Not supported - why do we actually expose this? */ + NOREF(aPercent); + return E_NOTIMPL; +} + +STDMETHODIMP ProgressProxy::SetNextOperation(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight) +{ + /* Not supported - why do we actually expose this? */ + NOREF(bstrNextOperationDescription); + NOREF(ulNextOperationsWeight); + return E_NOTIMPL; +} + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ + diff --git a/src/VBox/Main/SessionImpl.cpp b/src/VBox/Main/SessionImpl.cpp index fc4f5feaf..47d74fce9 100644 --- a/src/VBox/Main/SessionImpl.cpp +++ b/src/VBox/Main/SessionImpl.cpp @@ -1,6 +1,6 @@ +/* $Id: SessionImpl.cpp 29953 2010-06-01 15:03:06Z vboxsync $ */ /** @file - * - * VBox Client Session COM Class implementation + * VBox Client Session COM Class implementation in VBoxC. */ /* @@ -180,13 +180,21 @@ STDMETHODIMP Session::COMGETTER(Machine)(IMachine **aMachine) CHECK_OPEN(); - HRESULT rc = E_FAIL; - + HRESULT rc; if (mConsole) rc = mConsole->machine().queryInterfaceTo(aMachine); else rc = mRemoteMachine.queryInterfaceTo(aMachine); - ComAssertComRC(rc); + if (FAILED(rc)) + { + /** @todo VBox 3.3: replace E_FAIL with rc here. */ + if (mConsole) + setError(E_FAIL, tr("Failed to query the session machine (%Rhrc)"), rc); + else if (FAILED_DEAD_INTERFACE(rc)) + setError(E_FAIL, tr("Peer process crashed")); + else + setError(E_FAIL, tr("Failed to query the remote session machine (%Rhrc)"), rc); + } return rc; } @@ -202,13 +210,21 @@ STDMETHODIMP Session::COMGETTER(Console)(IConsole **aConsole) CHECK_OPEN(); - HRESULT rc = E_FAIL; - + HRESULT rc; if (mConsole) rc = mConsole.queryInterfaceTo(aConsole); else rc = mRemoteConsole.queryInterfaceTo(aConsole); - ComAssertComRC(rc); + if (FAILED(rc)) + { + /** @todo VBox 3.3: replace E_FAIL with rc here. */ + if (mConsole) + setError(E_FAIL, tr("Failed to query the console (%Rhrc)"), rc); + else if (FAILED_DEAD_INTERFACE(rc)) + setError(E_FAIL, tr("Peer process crashed")); + else + setError(E_FAIL, tr("Failed to query the remote console (%Rhrc)"), rc); + } return rc; } @@ -365,7 +381,7 @@ STDMETHODIMP Session::AssignRemoteMachine(IMachine *aMachine, IConsole *aConsole /* query IInternalMachineControl interface */ mControl = aMachine; - AssertReturn(!!mControl, E_FAIL); // This test appears to be redundant --JS + AssertReturn(!!mControl, E_FAIL); /// @todo (dmik) // currently, the remote session returns the same machine and diff --git a/src/VBox/Main/StorageControllerImpl.cpp b/src/VBox/Main/StorageControllerImpl.cpp index d30326672..a8146be8c 100644 --- a/src/VBox/Main/StorageControllerImpl.cpp +++ b/src/VBox/Main/StorageControllerImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: StorageControllerImpl.cpp 29480 2010-05-14 15:24:19Z vboxsync $ */ +/* $Id: StorageControllerImpl.cpp 29686 2010-05-20 11:46:09Z vboxsync $ */ /** @file * @@ -143,7 +143,8 @@ HRESULT StorageController::init(Machine *aParent, m->bd->strName = aName; m->bd->mInstance = aInstance; m->bd->mStorageBus = aStorageBus; - if (aStorageBus != StorageBus_IDE) + if ( aStorageBus != StorageBus_IDE + && aStorageBus != StorageBus_Floppy) m->bd->fUseHostIOCache = false; else m->bd->fUseHostIOCache = true; diff --git a/src/VBox/Main/VirtualBoxImpl.cpp b/src/VBox/Main/VirtualBoxImpl.cpp index 0f660a5a7..dbb68c7e0 100644 --- a/src/VBox/Main/VirtualBoxImpl.cpp +++ b/src/VBox/Main/VirtualBoxImpl.cpp @@ -1,4 +1,4 @@ -/* $Id: VirtualBoxImpl.cpp 28955 2010-05-02 18:03:45Z vboxsync $ */ +/* $Id: VirtualBoxImpl.cpp 29937 2010-06-01 08:41:32Z vboxsync $ */ /** @file * Implementation of IVirtualBox in VBoxSVC. @@ -56,6 +56,7 @@ #include "MediumImpl.h" #include "SharedFolderImpl.h" #include "ProgressImpl.h" +#include "ProgressProxyImpl.h" #include "HostImpl.h" #include "USBControllerImpl.h" #include "SystemPropertiesImpl.h" @@ -1993,24 +1994,36 @@ STDMETHODIMP VirtualBox::OpenRemoteSession(ISession *aSession, ComAssertMsgRet(!!control, ("No IInternalSessionControl interface"), E_INVALIDARG); + /* get the teleporter enable state for the progress object init. */ + BOOL fTeleporterEnabled; + rc = machine->COMGETTER(TeleporterEnabled)(&fTeleporterEnabled); + if (FAILED(rc)) + return rc; + /* create a progress object */ - ComObjPtr<Progress> progress; + ComObjPtr<ProgressProxy> progress; progress.createObject(); - progress->init(this, static_cast <IMachine *>(machine), - Bstr(tr("Spawning session")), - FALSE /* aCancelable */); - - rc = machine->openRemoteSession(control, aType, aEnvironment, progress); - + rc = progress->init(this, + static_cast<IMachine *>(machine), + Bstr(tr("Spawning session")), + TRUE /* aCancelable */, + fTeleporterEnabled ? 20 : 10 /* uTotalOperationsWeight */, + Bstr(tr("Spawning session")), + 2 /* uFirstOperationWeight */, + fTeleporterEnabled ? 3 : 1 /* cOtherProgressObjectOperations */); if (SUCCEEDED(rc)) { - progress.queryInterfaceTo(aProgress); + rc = machine->openRemoteSession(control, aType, aEnvironment, progress); + if (SUCCEEDED(rc)) + { + progress.queryInterfaceTo(aProgress); - /* signal the client watcher thread */ - updateClientWatcher(); + /* signal the client watcher thread */ + updateClientWatcher(); - /* fire an event */ - onSessionStateChange(id, SessionState_Spawning); + /* fire an event */ + onSessionStateChange(id, SessionState_Spawning); + } } return rc; @@ -4454,6 +4467,7 @@ DECLCALLBACK(int) VirtualBox::AsyncEventHandler(RTTHREAD thread, void *pvUser) return 0; } + //////////////////////////////////////////////////////////////////////////////// /** @@ -4486,6 +4500,70 @@ void *VirtualBox::CallbackEvent::handler() callbacks = mVirtualBox->m->llCallbacks; } +#ifdef RT_OS_WINDOWS +#if 0 + // WIP + + LPTYPEINFO ptinfo; + HRESULT hr; + LPTYPELIB ptlib; + DISPID dispid; + + /* Real solution must cache all needed dispids once, ofc */ + hr = ::LoadRegTypeLib(LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion, LOCALE_SYSTEM_DEFAULT, &ptlib); + hr = ptlib->GetTypeInfoOfGuid(IID_IVirtualBoxCallback, &ptinfo); + ptlib->Release(); + + OLECHAR FAR* szMember = L"OnMachineStateChange"; + + hr = ::DispGetIDsOfNames(ptinfo, &szMember, 1, &dispid); + ptinfo->Release(); + + int nConnections = mVirtualBox->m_vec.GetSize(); + for (int i=0; i<nConnections; i++) + { + ComPtr<IUnknown> sp = mVirtualBox->m_vec.GetAt(i); + ComPtr<IVirtualBoxCallback> cbI; + ComPtr<IDispatch> cbD; + + cbI = sp; + cbD = sp; + + /** + * Would be like this in ideal world, unfortunately our consumers want to be invoked via IDispatch, + * thus going the hard way. + */ +#if 0 + if (cbI != NULL) + { + HRESULT hrc = handleCallback(cbI); + if (hrc == VBOX_E_DONT_CALL_AGAIN) + { + // need to handle that somehow, maybe just set element to 0 + } + } +#endif + if (cbI != NULL && cbD != NULL) + { + CComVariant varResult, arg1, arg2; + + ::VariantClear(&varResult); + ::VariantClear(&arg1); + ::VariantClear(&arg2); + + VARIANTARG args[] = {arg1, arg2}; + DISPPARAMS disp = { args, NULL, sizeof(args)/sizeof(args[0]), 0}; + + cbD->Invoke(dispid, IID_NULL, + LOCALE_USER_DEFAULT, + DISPATCH_METHOD, + &disp, &varResult, + NULL, NULL); + } + } +#endif +#endif + for (CallbackList::const_iterator it = callbacks.begin(); it != callbacks.end(); ++it) diff --git a/src/VBox/Main/glue/tests/Makefile.kmk b/src/VBox/Main/glue/tests/Makefile.kmk new file mode 100644 index 000000000..e5473468f --- /dev/null +++ b/src/VBox/Main/glue/tests/Makefile.kmk @@ -0,0 +1,48 @@ +# +# Copyright (C) 2010 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +ifeq ($(KBUILD_HOST),darwin) + VBOX_BIN=/Applications/VirtualBox.app/Contents/MacOS + VBOX_SDK=$(VBOX_BIN)/sdk +# JAVA_ARGS += -d32 +endif + +ifeq ($(KBUILD_HOST),linux) + VBOX_SDK=/home/nike/work/ws/out/linux.amd64/debug/bin/sdk + VBOX_BIN=/home/nike/work/ws/out/linux.amd64/debug/bin +endif + +ifeq ($(KBUILD_HOST),win) + VBOX_SDK=e:/ws/out/win.amd64/debug/bin/sdk + VBOX_BIN=e:/ws/out/win.amd64/debug/bin + JACOB_DIR=e:/ws/src/libs/jacob-1.15-M3/ + JACOB_JAR=$(JACOB_DIR)/jacob.jar + CLASSPATH += $(JACOB_JAR)$(SEP) + JAVA_ARGS += -Djava.library.path=$(JACOB_DIR) +endif + +ifeq ($(KBUILD_HOST),win) + VBOX_JAR=$(VBOX_SDK)/bindings/mscom/java/vboxjmscom.jar + SEP=\; +else + VBOX_JAR=$(VBOX_SDK)/bindings/xpcom/java/vboxjxpcom.jar + SEP=: +endif + +JAVA_ARGS += -Dvbox.home=$(VBOX_BIN) +CLASSPATH := $(CLASSPATH)$(VBOX_JAR)$(SEP). + +all: testvb + +testvb: + javac -cp $(VBOX_JAR) TestVBox.java + java $(JAVA_ARGS) -cp $(CLASSPATH) TestVBox + diff --git a/src/VBox/Main/glue/tests/TestVBox.java b/src/VBox/Main/glue/tests/TestVBox.java new file mode 100644 index 000000000..d480f88f7 --- /dev/null +++ b/src/VBox/Main/glue/tests/TestVBox.java @@ -0,0 +1,107 @@ +/* $Id:$ */ +/* + * Copyright (C) 2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +import org.virtualbox_3_2.*; +import java.util.List; + +class VBoxCallbacks extends VBoxObjectBase implements IVirtualBoxCallback +{ + public void onGuestPropertyChange(String machineId, String name, String value, String flags) + { + System.out.println("onGuestPropertyChange -- VM: " + machineId + ", " + name + "->" + value); + } + public void onSnapshotChange(String machineId, String snapshotId) + { + } + public void onSnapshotDeleted(String machineId, String snapshotId) + { + } + public void onSnapshotTaken(String machineId, String snapshotId) {} + public void onSessionStateChange(String machineId, SessionState state) + { + System.out.println("onSessionStateChange -- VM: " + machineId + ", state: " + state); + } + public void onMachineRegistered(String machineId, Boolean registered) {} + public void onMediumRegistered(String mediumId, DeviceType mediumType, Boolean registered) {} + public void onExtraDataChange(String machineId, String key, String value) + { + System.out.println("onExtraDataChange -- VM: " + machineId + ": " + key+"->"+value); + } + public Boolean onExtraDataCanChange(String machineId, String key, String value, Holder<String> error) { return true; } + public void onMachineDataChange(String machineId) + {} + public void onMachineStateChange(String machineId, MachineState state) + { + System.out.println("onMachineStateChange -- VM: " + machineId + ", state: " + state); + } +} + +public class TestVBox +{ + static void testCallbacks(VirtualBoxManager mgr, IVirtualBox vbox) + { + IVirtualBoxCallback cbs = mgr.createIVirtualBoxCallback(new VBoxCallbacks()); + vbox.registerCallback(cbs); + for (int i=0; i<100; i++) + { + mgr.waitForEvents(500); + } + vbox.unregisterCallback(cbs); + } + + static void testEnumeration(VirtualBoxManager mgr, IVirtualBox vbox) + { + List<IMachine> machs = vbox.getMachines(); + for (IMachine m : machs) + { + System.out.println("VM name: " + m.getName());// + ", RAM size: " + m.getMemorySize() + "MB"); + System.out.println(" HWVirt: " + m.getHWVirtExProperty(HWVirtExPropertyType.Enabled) + + ", Nested Paging: " + m.getHWVirtExProperty(HWVirtExPropertyType.NestedPaging) + + ", PAE: " + m.getCPUProperty(CPUPropertyType.PAE) ); + } + } + + static void testStart(VirtualBoxManager mgr, IVirtualBox vbox) + { + String m = vbox.getMachines().get(0).getName(); + System.out.println("\nAttempting to start VM '" + m + "'"); + mgr.startVm(m, null, 7000); + } + + public static void main(String[] args) + { + VirtualBoxManager mgr = VirtualBoxManager.getInstance(null); + + System.out.println("\n--> initialized\n"); + + try + { + IVirtualBox vbox = mgr.getVBox(); + System.out.println("VirtualBox version: " + vbox.getVersion() + "\n"); + testEnumeration(mgr, vbox); + testStart(mgr, vbox); + //testCallbacks(mgr, vbox); + + System.out.println("done, press Enter..."); + int ch = System.in.read(); + } + catch (Throwable e) + { + e.printStackTrace(); + } + + mgr.cleanup(); + + System.out.println("\n--< done\n"); + } + +} diff --git a/src/VBox/Main/hgcm/HGCMThread.cpp b/src/VBox/Main/hgcm/HGCMThread.cpp index f60ae03a0..edeadcffb 100644 --- a/src/VBox/Main/hgcm/HGCMThread.cpp +++ b/src/VBox/Main/hgcm/HGCMThread.cpp @@ -89,6 +89,7 @@ class HGCMThread: public HGCMObject /* A caller thread waits for completion of a SENT message on this event. */ RTSEMEVENTMULTI m_eventSend; + int32_t volatile m_i32MessagesProcessed; /* Critical section for accessing the thread data, mostly for message queues. */ RTCRITSECT m_critsect; @@ -212,6 +213,7 @@ HGCMThread::HGCMThread () m_thread (NIL_RTTHREAD), m_eventThread (0), m_eventSend (0), + m_i32MessagesProcessed (0), m_fu32ThreadFlags (0), m_pMsgInputQueueHead (NULL), m_pMsgInputQueueTail (NULL), @@ -432,12 +434,30 @@ int HGCMThread::MsgPost (HGCMMsgCore *pMsg, PHGCMMSGCALLBACK pfnCallback, bool f if (fWait) { + /* Immediately check if the message has been processed. */ while ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0) { - RTSemEventMultiWait (m_eventSend, RT_INDEFINITE_WAIT); - RTSemEventMultiReset (m_eventSend); + /* Poll infrequently to make sure no completed message has been missed. */ + RTSemEventMultiWait (m_eventSend, 1000); LogFlow(("HGCMThread::MsgPost: wait completed flags = %08X\n", pMsg->m_fu32Flags)); + + if ((pMsg->m_fu32Flags & HGCM_MSG_F_PROCESSED) == 0) + { + RTThreadYield(); + } + } + + /* 'Our' message has been processed, so should reset the semaphore. + * There is still possible that another message has been processed + * and the semaphore has been signalled again. + * Reset only if there are no other messages completed. + */ + int32_t c = ASMAtomicDecS32(&m_i32MessagesProcessed); + Assert(c >= 0); + if (c == 0) + { + RTSemEventMultiReset (m_eventSend); } rc = pMsg->m_rcSend; @@ -580,6 +600,14 @@ void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result) bool fWaited = ((pMsg->m_fu32Flags & HGCM_MSG_F_WAIT) != 0); + if (fWaited) + { + ASMAtomicIncS32(&m_i32MessagesProcessed); + + /* This should be done before setting the HGCM_MSG_F_PROCESSED flag. */ + pMsg->m_rcSend = result; + } + /* The message is now completed. */ pMsg->m_fu32Flags &= ~HGCM_MSG_F_IN_PROCESS; pMsg->m_fu32Flags &= ~HGCM_MSG_F_WAIT; @@ -591,11 +619,6 @@ void HGCMThread::MsgComplete (HGCMMsgCore *pMsg, int32_t result) if (fWaited) { - /* If message is being waited, then it is referenced by the waiter and the pointer - * if valid even after hgcmObjDeleteHandle. - */ - pMsg->m_rcSend = result; - /* Wake up all waiters. so they can decide if their message has been processed. */ RTSemEventMultiSignal (m_eventSend); } diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl index b28f960d1..526b2cfdc 100644 --- a/src/VBox/Main/idl/VirtualBox.xidl +++ b/src/VBox/Main/idl/VirtualBox.xidl @@ -2729,6 +2729,16 @@ If the environment string is @c null or empty, the server environment is inherited by the started process as is. + The progress object will have at least 2 operation. The first operation + covers the period up to the new VM process calls powerUp. The + subsequent operations mirrors the <link to="IConsole::powerUp"/> + progress object. Because <link to="IConsole::powerUp"/> may require + some extra operation, the <link to="IProgress::operationCount"/> may + change at the completion of operation1. + + For details on the teleportation progress operation, see + <link to="IConsole::powerUp"/>. + <see>openExistingSession</see> <result name="E_UNEXPECTED"> @@ -3238,13 +3248,13 @@ VirtualBox front-end such as the GUI, and the suggestions can be displayed to the user. In particular, the <link to="#virtualSystemDescriptions" /> array contains instances of <link to="IVirtualSystemDescription" /> which represent the virtual - systems in the OVF, which in turn describe the virtual hardware prescribed by the - OVF (network and hardware adapters, virtual disk images, memory size and so on). + systems (machines) in the OVF, which in turn describe the virtual hardware prescribed + by the OVF (network and hardware adapters, virtual disk images, memory size and so on). The GUI can then give the user the option to confirm and/or change these suggestions. </li> <li>If desired, call <link to="IVirtualSystemDescription::setFinalValues" /> for each - virtual system to override the suggestions made by the interpret() routine. + virtual system (machine) to override the suggestions made by the interpret() routine. </li> <li>Finally, call <link to="#importMachines" /> to create virtual machines in @@ -3261,12 +3271,12 @@ </li> <li>For each machine you would like to export, call <link to="IMachine::export" /> - with the IAppliance object you just created. This creates an instance of + with the IAppliance object you just created. Each such call creates one instance of <link to="IVirtualSystemDescription" /> inside the appliance. </li> <li>If desired, call <link to="IVirtualSystemDescription::setFinalValues" /> for each - virtual system to override the suggestions made by the export() routine. + virtual system (machine) to override the suggestions made by the export() routine. </li> <li>Finally, call <link to="#write" /> with a path specification to have the OVF @@ -3324,7 +3334,7 @@ <attribute name="virtualSystemDescriptions" type="IVirtualSystemDescription" readonly="yes" safearray="yes"> <desc> Array of virtual system descriptions. One such description is created - for each virtual system found in the OVF. + for each virtual system (machine) found in the OVF. This array is empty until either <link to="#interpret" /> (for import) or <link to="IMachine::export" /> (for export) has been called. </desc> @@ -3489,11 +3499,12 @@ wsmap="managed" > - <desc>This interface is used in the <link to="IAppliance::virtualSystemDescriptions" /> array. - After <link to="IAppliance::interpret" /> has been called, that array contains - information about how the virtual systems described in the OVF should best be imported into VirtualBox - virtual machines. See <link to="IAppliance" /> for the steps required to import an OVF - into VirtualBox. + <desc>Represents one virtual system (machine) in an appliance. This interface is used in + the <link to="IAppliance::virtualSystemDescriptions" /> array. After + <link to="IAppliance::interpret" /> has been called, that array contains information + about how the virtual systems described in the OVF should best be imported into + VirtualBox virtual machines. See <link to="IAppliance" /> for the steps required to + import an OVF into VirtualBox. </desc> <attribute name="count" type="unsigned long" readonly="yes"> @@ -3749,7 +3760,7 @@ <interface name="IInternalMachineControl" extends="$unknown" - uuid="57e9a280-8d57-4331-aa31-f009f5194f52" + uuid="26604a54-8628-491b-a0ea-e1392a16d13b" internal="yes" wsmap="suppress" > @@ -3777,15 +3788,28 @@ <param name="id" type="wstring" dir="return"/> </method> - <method name="setPowerUpInfo"> + <method name="beginPowerUp"> <desc> - Transfers success (@c null) or error information for this session. - This method updates the progress object to signal completion of the - <link to="IVirtualBox::openRemoteSession"/> method if appropriate, - which means that the progress object returned by - <link to="IConsole::powerUp"/>. + Tells VBoxSVC that <link to="IConsole::powerUp"/> is under ways and + gives it the progress object that should be part of any pending + <link to="IVirtualBox::openRemoteSession"/> operations. The progress + object may be called back to reflect an early cancelation, so some care + have to be taken with respect to any cancelation callbacks. The console + object will call <link to="IInternalMachineControl::endPowerUp"/> + to signal the completion of the progress object. </desc> - <param name="error" type="IVirtualBoxErrorInfo" dir="in"/> + <param name="progress" type="IProgress" dir="in"/> + </method> + + <method name="endPowerUp"> + <desc> + Tells VBoxSVC that <link to="IConsole::powerUp"/> has completed. + This method may query status information from the progress object it + received in <link to="IInternalMachineControl::beginPowerUp"/> and copy + it over to any in progress <link to="IVirtualBox::openRemoteSession"/> + call in order to complete that progress object. + </desc> + <param name="result" type="long" dir="in"/> </method> <method name="runUSBDeviceFilters"> @@ -6836,6 +6860,16 @@ it will continue its execution the point where the state has been saved. + If the machine <link to="IMachine::teleporterEnabled"/> property is + enabled on the machine being powered up, the machine will wait for an + incoming teleportation in the <link to="MachineState_TeleportingIn"/> + state. The returned progress object will have at least three + operations where the last three are defined as: (1) powering up and + starting TCP server, (2) waiting for incoming teleportations, and + (3) perform teleportation. These operations will be reflected as the + last three operations of the progress objected returned by + <link to="IVirtualBox::openRemoteSession"/> as well. + <note> Unless you are trying to write a new VirtualBox front-end that performs direct machine execution (like the VirtualBox or VBoxSDL @@ -14515,6 +14549,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) <class name="VirtualBox" uuid="B1A7A4F2-47B9-4A1E-82B2-07CCD5323C3F" namespace="virtualbox.org"> <interface name="IVirtualBox" default="yes"/> + <eventsink name="IVirtualBoxCallback" default="yes"/> </class> </module> @@ -14522,6 +14557,8 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi) <class name="Session" uuid="3C02F46D-C9D2-4F11-A384-53F0CF917214" namespace="virtualbox.org"> <interface name="ISession" default="yes"/> + <eventsink name="IConsoleCallback" default="yes"/> + </class> <class name="CallbackWrapper" uuid="49EE8561-5563-4715-B18C-A4B1A490DAFE" namespace="virtualbox.org"> diff --git a/src/VBox/Main/idl/midl.xsl b/src/VBox/Main/idl/midl.xsl index dca1adb03..b8bca3833 100644 --- a/src/VBox/Main/idl/midl.xsl +++ b/src/VBox/Main/idl/midl.xsl @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<!-- $Id: midl.xsl 29200 2010-05-07 12:14:18Z vboxsync $ --> +<!-- $Id: midl.xsl 29874 2010-05-28 18:14:44Z vboxsync $ --> <!-- * A template to generate a MS IDL compatible interface definition file @@ -632,6 +632,16 @@ <xsl:value-of select="@name"/> <xsl:text>;
</xsl:text> </xsl:for-each> + <xsl:for-each select="eventsink"> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test="@default='yes'"><xsl:text>[default,source]</xsl:text></xsl:when> + <xsl:otherwise><xsl:text>[source]</xsl:text></xsl:otherwise> + </xsl:choose> + <xsl:text> interface </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>;
</xsl:text> + </xsl:for-each> <xsl:text>
}; /* coclass </xsl:text> <xsl:value-of select="@name"/> <xsl:text> */

</xsl:text> diff --git a/src/VBox/Main/include/ApplianceImpl.h b/src/VBox/Main/include/ApplianceImpl.h index 14a8f0247..eac4fb26f 100644 --- a/src/VBox/Main/include/ApplianceImpl.h +++ b/src/VBox/Main/include/ApplianceImpl.h @@ -1,4 +1,4 @@ -/* $Id: ApplianceImpl.h 29422 2010-05-12 14:08:52Z vboxsync $ */ +/* $Id: ApplianceImpl.h 29925 2010-05-31 18:33:15Z vboxsync $ */ /** @file * @@ -119,7 +119,7 @@ private: void addWarning(const char* aWarning, ...); void disksWeight(); - enum SetUpProgressMode { Regular, ImportS3, WriteS3 }; + enum SetUpProgressMode { ImportFileWithManifest, ImportFileNoManifest, ImportS3, WriteFile, WriteS3 }; HRESULT setUpProgress(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription, SetUpProgressMode mode); @@ -144,7 +144,7 @@ private: int32_t &lDevice); HRESULT importImpl(const LocationInfo &aLocInfo, ComObjPtr<Progress> &aProgress); - HRESULT manifestVerify(const LocationInfo &locInfo, const ovf::OVFReader &reader); + HRESULT manifestVerify(const LocationInfo &locInfo, const ovf::OVFReader &reader, ComObjPtr<Progress> &pProgress); HRESULT importFS(const LocationInfo &locInfo, ComObjPtr<Progress> &aProgress); @@ -167,6 +167,7 @@ private: struct XMLStack; void buildXMLForOneVirtualSystem(xml::ElementNode &elmToAddVirtualSystemsTo, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes, ComObjPtr<VirtualSystemDescription> &vsdescThis, OVFFormat enFormat, XMLStack &stack); @@ -183,8 +184,10 @@ struct VirtualSystemDescriptionEntry VirtualSystemDescriptionType_T type; // type of this entry Utf8Str strRef; // reference number (hard disk controllers only) Utf8Str strOvf; // original OVF value (type-dependent) - Utf8Str strVbox; // configuration value (type-dependent) - Utf8Str strExtraConfig; // extra configuration key=value strings (type-dependent) + Utf8Str strVboxSuggested; // configuration value (type-dependent); original value suggested by interpret() + Utf8Str strVboxCurrent; // configuration value (type-dependent); current value, either from interpret() or setFinalValue() + Utf8Str strExtraConfigSuggested; // extra configuration key=value strings (type-dependent); original value suggested by interpret() + Utf8Str strExtraConfigCurrent; // extra configuration key=value strings (type-dependent); current value, either from interpret() or setFinalValue() uint32_t ulSizeMB; // hard disk images only: a copy of ovf::DiskImage::ulSuggestedSizeMB }; diff --git a/src/VBox/Main/include/ApplianceImplPrivate.h b/src/VBox/Main/include/ApplianceImplPrivate.h index f88043fb4..b09eea658 100644 --- a/src/VBox/Main/include/ApplianceImplPrivate.h +++ b/src/VBox/Main/include/ApplianceImplPrivate.h @@ -61,23 +61,24 @@ struct Appliance::Data } } - ApplianceState state; + ApplianceState state; - LocationInfo locInfo; // location info for the currently processed OVF + LocationInfo locInfo; // location info for the currently processed OVF - ovf::OVFReader *pReader; - - bool fBusyWriting; // state protection; while this is true nobody else can call methods + ovf::OVFReader *pReader; std::list< ComObjPtr<VirtualSystemDescription> > - virtualSystemDescriptions; + virtualSystemDescriptions; + + std::list<Utf8Str> llWarnings; - std::list<Utf8Str> llWarnings; + Utf8Str strManifestFile; // on import, contains path of manifest file if it exists - ULONG ulWeightPerOperation; - ULONG ulTotalDisksMB; - ULONG cDisks; - Utf8Str strOVFSHA1Digest; + ULONG ulWeightForXmlOperation; + ULONG ulWeightForManifestOperation; + ULONG ulTotalDisksMB; + ULONG cDisks; + Utf8Str strOVFSHA1Digest; }; struct Appliance::XMLStack @@ -130,6 +131,60 @@ struct MyHardDiskAttachment int32_t lDevice; // IDE: 0 or 1, otherwise 0 always }; +/** + * Used by Appliance::importMachineGeneric() to store + * input parameters and rollback information. + */ +struct Appliance::ImportStack +{ + // input pointers + const LocationInfo &locInfo; // ptr to location info from Appliance::importFS() + Utf8Str strSourceDir; // directory where source files reside + const ovf::DiskImagesMap &mapDisks; // ptr to disks map in OVF + ComObjPtr<Progress> &pProgress; // progress object passed into Appliance::importFS() + + // input parameters from VirtualSystemDescriptions + Utf8Str strNameVBox; // VM name + Utf8Str strOsTypeVBox; // VirtualBox guest OS type as string + uint32_t cCPUs; // CPU count + bool fForceHWVirt; // if true, we force enabling hardware virtualization + bool fForceIOAPIC; // if true, we force enabling the IOAPIC + uint32_t ulMemorySizeMB; // virtual machien RAM in megabytes +#ifdef VBOX_WITH_USB + bool fUSBEnabled; +#endif + Utf8Str strAudioAdapter; // if not empty, then the guest has audio enabled, and this is the decimal + // representation of the audio adapter (should always be "0" for AC97 presently) + + // session (not initially created) + ComPtr<ISession> pSession; // session opened in Appliance::importFS() for machine manipulation + bool fSessionOpen; // true if the pSession is currently open and needs closing + + // a list of images that we created/imported; this is initially empty + // and will be cleaned up on errors + std::list<MyHardDiskAttachment> llHardDiskAttachments; // disks that were attached + std::list< ComPtr<IMedium> > llHardDisksCreated; // media that were created + std::list<Bstr> llMachinesRegistered; // machines that were registered; list of string UUIDs + + ImportStack(const LocationInfo &aLocInfo, + const ovf::DiskImagesMap &aMapDisks, + ComObjPtr<Progress> &aProgress) + : locInfo(aLocInfo), + mapDisks(aMapDisks), + pProgress(aProgress), + cCPUs(1), + fForceHWVirt(false), + fForceIOAPIC(false), + ulMemorySizeMB(0), + fSessionOpen(false) + { + // disk images have to be on the same place as the OVF file. So + // strip the filename out of the full file path + strSourceDir = aLocInfo.strPath; + strSourceDir.stripFilename(); + } +}; + //////////////////////////////////////////////////////////////////////////////// // // VirtualSystemDescription data definition diff --git a/src/VBox/Main/include/ConsoleImpl.h b/src/VBox/Main/include/ConsoleImpl.h index aad6de296..9198f1b1b 100644 --- a/src/VBox/Main/include/ConsoleImpl.h +++ b/src/VBox/Main/include/ConsoleImpl.h @@ -1,4 +1,4 @@ -/* $Id: ConsoleImpl.h 29580 2010-05-17 18:23:00Z vboxsync $ */ +/* $Id: ConsoleImpl.h 29965 2010-06-01 18:41:10Z vboxsync $ */ /** @file * VBox Console COM Class definition */ @@ -518,8 +518,8 @@ private: static DECLCALLBACK(int) stateProgressCallback(PVM pVM, unsigned uPercent, void *pvUser); - static DECLCALLBACK(void) setVMErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, - const char *pszFormat, va_list args); + static DECLCALLBACK(void) genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszErrorFmt, va_list va); static DECLCALLBACK(void) setVMRuntimeErrorCallbackF(PVM pVM, void *pvUser, uint32_t fFatal, const char *pszErrorId, @@ -572,7 +572,8 @@ private: HRESULT teleporterSrc(TeleporterStateSrc *pState); HRESULT teleporterSrcReadACK(TeleporterStateSrc *pState, const char *pszWhich, const char *pszNAckMsg = NULL); HRESULT teleporterSrcSubmitCommand(TeleporterStateSrc *pState, const char *pszCommand, bool fWaitForAck = true); - int teleporterTrg(PVM pVM, IMachine *pMachine, bool fStartPaused, Progress *pProgress); + HRESULT teleporterTrg(PVM pVM, IMachine *pMachine, Utf8Str *pErrorMsg, bool fStartPaused, + Progress *pProgress, bool *pfPowerOffOnFailure); static DECLCALLBACK(int) teleporterTrgServeConnection(RTSOCKET Sock, void *pvUser); /** @} */ diff --git a/src/VBox/Main/include/GuestImpl.h b/src/VBox/Main/include/GuestImpl.h index cb9039f22..032a1ed97 100644 --- a/src/VBox/Main/include/GuestImpl.h +++ b/src/VBox/Main/include/GuestImpl.h @@ -126,7 +126,7 @@ private: void *pvData; uint32_t cbData; /** Atomic flag whether callback was called. */ - volatile bool bCalled; + volatile bool fCalled; /** Pointer to user-supplied IProgress. */ ComObjPtr<Progress> pProgress; }; @@ -136,10 +136,10 @@ private: struct GuestProcess { - uint32_t mPID; - uint32_t mStatus; - uint32_t mFlags; - uint32_t mExitCode; + uint32_t mPID; + uint32_t mStatus; + uint32_t mFlags; + uint32_t mExitCode; }; typedef std::list< GuestProcess > GuestProcessList; typedef std::list< GuestProcess >::iterator GuestProcessIter; @@ -147,8 +147,9 @@ private: int prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv); /** Handler for guest execution control notifications. */ - int notifyCtrlExec(uint32_t u32Function, PHOSTEXECCALLBACKDATA pData); - int notifyCtrlExecOut(uint32_t u32Function, PHOSTEXECOUTCALLBACKDATA pData); + int notifyCtrlClientDisconnected(uint32_t u32Function, PCALLBACKDATACLIENTDISCONNECTED pData); + int notifyCtrlExecStatus(uint32_t u32Function, PCALLBACKDATAEXECSTATUS pData); + int notifyCtrlExecOut(uint32_t u32Function, PCALLBACKDATAEXECOUT pData); CallbackListIter getCtrlCallbackContextByID(uint32_t u32ContextID); GuestProcessIter getProcessByPID(uint32_t u32PID); void destroyCtrlCallbackContext(CallbackListIter it); diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h index e66b135f6..548ce1781 100644 --- a/src/VBox/Main/include/MachineImpl.h +++ b/src/VBox/Main/include/MachineImpl.h @@ -1,4 +1,4 @@ -/* $Id: MachineImpl.h 29462 2010-05-14 11:27:59Z vboxsync $ */ +/* $Id: MachineImpl.h 29864 2010-05-28 13:34:53Z vboxsync $ */ /** @file * VirtualBox COM class implementation */ @@ -53,6 +53,7 @@ //////////////////////////////////////////////////////////////////////////////// class Progress; +class ProgressProxy; class Keyboard; class Mouse; class Display; @@ -124,7 +125,7 @@ public: RemoteControlList mRemoteControls; /** openRemoteSession() and OnSessionEnd() progress indicator */ - ComObjPtr<Progress> mProgress; + ComObjPtr<ProgressProxy> mProgress; /** * PID of the session object that must be passed to openSession() to @@ -621,7 +622,7 @@ public: HRESULT openSession(IInternalSessionControl *aControl); HRESULT openRemoteSession(IInternalSessionControl *aControl, IN_BSTR aType, IN_BSTR aEnvironment, - Progress *aProgress); + ProgressProxy *aProgress); HRESULT openExistingSession(IInternalSessionControl *aControl); HRESULT getDirectControl(ComPtr<IInternalSessionControl> *directControl) @@ -886,7 +887,8 @@ public: STDMETHOD(SetRemoveSavedState)(BOOL aRemove); STDMETHOD(UpdateState)(MachineState_T machineState); STDMETHOD(GetIPCId)(BSTR *id); - STDMETHOD(SetPowerUpInfo)(IVirtualBoxErrorInfo *aError); + STDMETHOD(BeginPowerUp)(IProgress *aProgress); + STDMETHOD(EndPowerUp)(LONG iResult); STDMETHOD(RunUSBDeviceFilters)(IUSBDevice *aUSBDevice, BOOL *aMatched, ULONG *aMaskedIfs); STDMETHOD(CaptureUSBDevice)(IN_BSTR aId); STDMETHOD(DetachUSBDevice)(IN_BSTR aId, BOOL aDone); diff --git a/src/VBox/Main/include/ProgressCombinedImpl.h b/src/VBox/Main/include/ProgressCombinedImpl.h index 57bd23ab6..b74372307 100644 --- a/src/VBox/Main/include/ProgressCombinedImpl.h +++ b/src/VBox/Main/include/ProgressCombinedImpl.h @@ -1,4 +1,4 @@ -/* $Id: ProgressCombinedImpl.h 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: ProgressCombinedImpl.h 29923 2010-05-31 17:55:44Z vboxsync $ */ /** @file * * VirtualBox COM class implementation @@ -31,6 +31,11 @@ * that follow each other in the same order as progress objects are passed to * the #init() method. * + * @note CombinedProgress is legacy code and deprecated. It does not support + * weighted operations, all suboperations are assumed to take the same + * amount of time. For new code, please use IProgress directly which + * has supported multiple weighted suboperations since VirtualBox 3.0. + * * Individual progress objects are sequentially combined so that this progress * object: * diff --git a/src/VBox/Main/include/ProgressImpl.h b/src/VBox/Main/include/ProgressImpl.h index 41cf845df..de174fe07 100644 --- a/src/VBox/Main/include/ProgressImpl.h +++ b/src/VBox/Main/include/ProgressImpl.h @@ -1,4 +1,4 @@ -/* $Id: ProgressImpl.h 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: ProgressImpl.h 29916 2010-05-31 15:26:56Z vboxsync $ */ /** @file * * VirtualBox COM class implementation @@ -70,7 +70,7 @@ public: STDMETHOD(COMGETTER(ResultCode)) (LONG *aResultCode); STDMETHOD(COMGETTER(ErrorInfo)) (IVirtualBoxErrorInfo **aErrorInfo); STDMETHOD(COMGETTER(OperationCount)) (ULONG *aOperationCount); - STDMETHOD(COMGETTER(Operation)) (ULONG *aCount); + STDMETHOD(COMGETTER(Operation)) (ULONG *aOperation); STDMETHOD(COMGETTER(OperationDescription)) (BSTR *aOperationDescription); STDMETHOD(COMGETTER(OperationPercent)) (ULONG *aOperationPercent); STDMETHOD(COMSETTER(Timeout)) (ULONG aTimeout); @@ -260,7 +260,13 @@ public: HRESULT notifyComplete(HRESULT aResultCode, const GUID &aIID, const Bstr &aComponent, - const char *aText, ...); + const char *aText, + ...); + HRESULT notifyCompleteV(HRESULT aResultCode, + const GUID &aIID, + const Bstr &aComponent, + const char *aText, + va_list va); bool notifyPointOfNoReturn(void); /** For com::SupportErrorInfoImpl. */ diff --git a/src/VBox/Main/include/ProgressProxyImpl.h b/src/VBox/Main/include/ProgressProxyImpl.h new file mode 100644 index 000000000..164637888 --- /dev/null +++ b/src/VBox/Main/include/ProgressProxyImpl.h @@ -0,0 +1,120 @@ +/* $Id: ProgressProxyImpl.h 29937 2010-06-01 08:41:32Z vboxsync $ */ +/** @file + * IProgress implementation for Machine::openRemoteSession in VBoxSVC. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ____H_PROGRESSPROXYIMPL +#define ____H_PROGRESSPROXYIMPL + +#include "ProgressImpl.h" +#include "AutoCaller.h" + + +/** + * The ProgressProxy class allows proxying the important Progress calls and + * attributes to a different IProgress object for a period of time. + */ +class ATL_NO_VTABLE ProgressProxy : + //public com::SupportErrorInfoDerived<Progress, ProgressProxy, IProgress>, + public Progress, + public VirtualBoxSupportTranslation<ProgressProxy> +{ +public: + VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(ProgressProxy) + DECLARE_NOT_AGGREGATABLE(ProgressProxy) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(ProgressProxy) + COM_INTERFACE_ENTRY (ISupportErrorInfo) + COM_INTERFACE_ENTRY (IProgress) + COM_INTERFACE_ENTRY2(IDispatch, IProgress) + END_COM_MAP() + + HRESULT FinalConstruct(); + void FinalRelease(); + HRESULT init( +#if !defined (VBOX_COM_INPROC) + VirtualBox *pParent, +#endif + IUnknown *pInitiator, + CBSTR bstrDescription, + BOOL fCancelable); + HRESULT init( +#if !defined (VBOX_COM_INPROC) + VirtualBox *pParent, +#endif + IUnknown *pInitiator, + CBSTR bstrDescription, + BOOL fCancelable, + ULONG uTotalOperationsWeight, + CBSTR bstrFirstOperationDescription, + ULONG uFirstOperationWeight, + ULONG cOtherProgressObjectOperations); + void uninit(); + + // IProgress properties + STDMETHOD(COMGETTER(Cancelable))(BOOL *aCancelable); + STDMETHOD(COMGETTER(Percent))(ULONG *aPercent); + STDMETHOD(COMGETTER(TimeRemaining))(LONG *aTimeRemaining); + STDMETHOD(COMGETTER(Completed))(BOOL *aCompleted); + STDMETHOD(COMGETTER(Canceled))(BOOL *aCanceled); + STDMETHOD(COMGETTER(ResultCode))(LONG *aResultCode); + STDMETHOD(COMGETTER(ErrorInfo))(IVirtualBoxErrorInfo **aErrorInfo); + //STDMETHOD(COMGETTER(OperationCount))(ULONG *aOperationCount); - not necessary + STDMETHOD(COMGETTER(Operation))(ULONG *aOperation); + STDMETHOD(COMGETTER(OperationDescription))(BSTR *aOperationDescription); + STDMETHOD(COMGETTER(OperationPercent))(ULONG *aOperationPercent); + STDMETHOD(COMSETTER(Timeout))(ULONG aTimeout); + STDMETHOD(COMGETTER(Timeout))(ULONG *aTimeout); + + // IProgress methods + STDMETHOD(WaitForCompletion)(LONG aTimeout); + STDMETHOD(WaitForOperationCompletion)(ULONG aOperation, LONG aTimeout); + STDMETHOD(Cancel)(); + STDMETHOD(SetCurrentOperationProgress)(ULONG aPercent); + STDMETHOD(SetNextOperation)(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight); + + // public methods only for internal purposes + + HRESULT notifyComplete(HRESULT aResultCode); + HRESULT notifyComplete(HRESULT aResultCode, + const GUID &aIID, + const Bstr &aComponent, + const char *aText, ...); + bool setOtherProgressObject(IProgress *pOtherProgress); + + /** For com::SupportErrorInfoImpl. */ + static const char *ComponentName() { return "ProgressProxy"; } + +protected: + void clearOtherProgressObjectInternal(bool fEarly); + void copyProgressInfo(IProgress *pOtherProgress, bool fEarly); + +private: + /** The other progress object. This can be NULL. */ + ComPtr<IProgress> mptrOtherProgress; + /** Set if the other progress object has multiple operations. */ + bool mfMultiOperation; + /** The weight the other progress object started at. */ + ULONG muOtherProgressStartWeight; + /** The weight of other progress object. */ + ULONG muOtherProgressWeight; + /** The operation number the other progress object started at. */ + ULONG muOtherProgressStartOperation; + +}; + +#endif /* !____H_PROGRESSPROXYIMPL */ + diff --git a/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h b/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h index b439124b2..186bfed48 100644 --- a/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h +++ b/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h @@ -1,10 +1,9 @@ /** @file - * - * VirtualBoxErrorInfo COM classe definition + * VirtualBoxErrorInfo COM class definition. */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,8 +22,11 @@ using namespace com; class ATL_NO_VTABLE VirtualBoxErrorInfo - : public CComObjectRootEx <CComMultiThreadModel> - , public IVirtualBoxErrorInfo + : public CComObjectRootEx<CComMultiThreadModel> + , VBOX_SCRIPTABLE_IMPL(IVirtualBoxErrorInfo) +#ifndef VBOX_WITH_XPCOM /* IErrorInfo doesn't inherit from IDispatch, ugly 3am hack: */ + , public IDispatch +#endif { public: @@ -35,44 +37,69 @@ public: BEGIN_COM_MAP(VirtualBoxErrorInfo) COM_INTERFACE_ENTRY(IErrorInfo) COM_INTERFACE_ENTRY(IVirtualBoxErrorInfo) + COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() -#if defined (RT_OS_WINDOWS) +#ifndef VBOX_WITH_XPCOM + + HRESULT init(IErrorInfo *aInfo); + + STDMETHOD(GetGUID)(GUID *guid); + STDMETHOD(GetSource)(BSTR *source); + STDMETHOD(GetDescription)(BSTR *description); + STDMETHOD(GetHelpFile)(BSTR *pBstrHelpFile); + STDMETHOD(GetHelpContext)(DWORD *pdwHelpContext); + + // IDispatch forwarding - 3am hack. + typedef IDispatchImpl<IVirtualBoxErrorInfo, &IID_IVirtualBoxErrorInfo, &LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion> idi; + + STDMETHOD(GetTypeInfoCount)(UINT *pcInfo) + { + return idi::GetTypeInfoCount(pcInfo); + } + + STDMETHOD(GetTypeInfo)(UINT iInfo, LCID Lcid, ITypeInfo **ppTypeInfo) + { + return idi::GetTypeInfo(iInfo, Lcid, ppTypeInfo); + } - HRESULT init (IErrorInfo *aInfo); + STDMETHOD(GetIDsOfNames)(REFIID rIID, LPOLESTR *papwszNames, UINT cNames, LCID Lcid, DISPID *paDispIDs) + { + return idi::GetIDsOfNames(rIID, papwszNames, cNames, Lcid, paDispIDs); + } - STDMETHOD(GetGUID) (GUID *guid); - STDMETHOD(GetSource) (BSTR *source); - STDMETHOD(GetDescription) (BSTR *description); - STDMETHOD(GetHelpFile) (BSTR *pBstrHelpFile); - STDMETHOD(GetHelpContext) (DWORD *pdwHelpContext); + STDMETHOD(Invoke)(DISPID idDispMember, REFIID rIID, LCID Lcid, WORD fw, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *piErrArg) + { + return idi::Invoke(idDispMember, rIID, Lcid, fw, pDispParams, pVarResult, pExcepInfo, piErrArg); + } -#else // !defined (RT_OS_WINDOWS) +#else // defined(VBOX_WITH_XPCOM) - HRESULT init (nsIException *aInfo); + HRESULT init(nsIException *aInfo); NS_DECL_NSIEXCEPTION #endif - VirtualBoxErrorInfo() : mResultCode (S_OK) {} + VirtualBoxErrorInfo() : mResultCode(S_OK) {} // public initializer/uninitializer for internal purposes only - HRESULT init (HRESULT aResultCode, const GUID &aIID, - CBSTR aComponent, CBSTR aText, - IVirtualBoxErrorInfo *aNext = NULL); + HRESULT init(HRESULT aResultCode, const GUID &aIID, + CBSTR aComponent, CBSTR aText, + IVirtualBoxErrorInfo *aNext = NULL); // IVirtualBoxErrorInfo properties - STDMETHOD(COMGETTER(ResultCode)) (LONG *aResultCode); - STDMETHOD(COMGETTER(InterfaceID)) (BSTR *aIID); - STDMETHOD(COMGETTER(Component)) (BSTR *aComponent); - STDMETHOD(COMGETTER(Text)) (BSTR *aText); - STDMETHOD(COMGETTER(Next)) (IVirtualBoxErrorInfo **aNext); + STDMETHOD(COMGETTER(ResultCode))(LONG *aResultCode); + STDMETHOD(COMGETTER(InterfaceID))(BSTR *aIID); + STDMETHOD(COMGETTER(Component))(BSTR *aComponent); + STDMETHOD(COMGETTER(Text))(BSTR *aText); + STDMETHOD(COMGETTER(Next))(IVirtualBoxErrorInfo **aNext); private: // FIXME: declare these here until VBoxSupportsTranslation base // is available in this class. - static const char *tr (const char *a) { return a; } + static const char *tr(const char *a) { return a; } static HRESULT setError(HRESULT rc, const char * /* a */, const char * /* b */, @@ -85,6 +112,6 @@ private: ComPtr<IVirtualBoxErrorInfo> mNext; }; -#endif // ____H_VIRTUALBOXERRORINFOIMPL +#endif // !____H_VIRTUALBOXERRORINFOIMPL /* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/VBox/Main/include/VirtualBoxImpl.h b/src/VBox/Main/include/VirtualBoxImpl.h index 1c30d4d28..64cf7ddf5 100644 --- a/src/VBox/Main/include/VirtualBoxImpl.h +++ b/src/VBox/Main/include/VirtualBoxImpl.h @@ -1,4 +1,4 @@ -/* $Id: VirtualBoxImpl.h 28944 2010-04-30 17:49:02Z vboxsync $ */ +/* $Id: VirtualBoxImpl.h 29925 2010-05-31 18:33:15Z vboxsync $ */ /** @file * @@ -62,6 +62,8 @@ class ATL_NO_VTABLE VirtualBox : VBOX_SCRIPTABLE_IMPL(IVirtualBox) #ifdef RT_OS_WINDOWS , public CComCoClass<VirtualBox, &CLSID_VirtualBox> + , public IConnectionPointContainerImpl<VirtualBox> + , public IConnectionPointImpl<VirtualBox, &IID_IVirtualBoxCallback, CComDynamicUnkArray> #endif { @@ -83,11 +85,18 @@ public: DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(VirtualBox) - COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY2(IDispatch, IVirtualBox) COM_INTERFACE_ENTRY(ISupportErrorInfo) COM_INTERFACE_ENTRY(IVirtualBox) + COM_INTERFACE_ENTRY(IConnectionPointContainer) END_COM_MAP() +#ifdef RT_OS_WINDOWS + BEGIN_CONNECTION_POINT_MAP(VirtualBox) + CONNECTION_POINT_ENTRY(IID_IVirtualBoxCallback) + END_CONNECTION_POINT_MAP() +#endif + // to postpone generation of the default ctor/dtor VirtualBox(); ~VirtualBox(); diff --git a/src/VBox/Main/include/ovfreader.h b/src/VBox/Main/include/ovfreader.h index 3b4fa7dbc..698019045 100644 --- a/src/VBox/Main/include/ovfreader.h +++ b/src/VBox/Main/include/ovfreader.h @@ -1,4 +1,4 @@ -/* $Id: ovfreader.h 29422 2010-05-12 14:08:52Z vboxsync $ */ +/* $Id: ovfreader.h 29925 2010-05-31 18:33:15Z vboxsync $ */ /** @file * OVF reader declarations. * @@ -310,7 +310,7 @@ struct VirtualSystem { iprt::MiniString strName; // copy of VirtualSystem/@id - iprt::MiniString strDescription; // copy of VirtualSystem/Info content + iprt::MiniString strDescription; // copy of VirtualSystem/AnnotationSection content, if any CIMOSType_T cimos; iprt::MiniString strCimosDesc; // readable description of the cimos type in the case of cimos = 0/1/102 diff --git a/src/VBox/Main/linux/PerformanceLinux.cpp b/src/VBox/Main/linux/PerformanceLinux.cpp index 1f763e5ba..87e3faa33 100644 --- a/src/VBox/Main/linux/PerformanceLinux.cpp +++ b/src/VBox/Main/linux/PerformanceLinux.cpp @@ -1,4 +1,4 @@ -/* $Id: PerformanceLinux.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */ +/* $Id: PerformanceLinux.cpp 29969 2010-06-02 07:31:27Z vboxsync $ */ /** @file * @@ -182,6 +182,7 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin long long unsigned int u64Tmp; unsigned uTmp; unsigned long ulTmp; + signed long ilTmp; ULONG u32user, u32kernel; char buf[80]; /* @todo: this should be tied to max allowed proc name. */ @@ -196,7 +197,7 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin "%ld %ld %ld %ld %ld %ld %llu %lu %u", &pid2, buf, &c, &iTmp, &iTmp, &iTmp, &iTmp, &iTmp, &uTmp, &ulTmp, &ulTmp, &ulTmp, &ulTmp, &u32user, &u32kernel, - &ulTmp, &ulTmp, &ulTmp, &ulTmp, &ulTmp, &ulTmp, &u64Tmp, + &ilTmp, &ilTmp, &ilTmp, &ilTmp, &ilTmp, &ilTmp, &u64Tmp, &ulTmp, memPagesUsed) == 24) { Assert((pid_t)process == pid2); diff --git a/src/VBox/Main/webservice/Makefile.kmk b/src/VBox/Main/webservice/Makefile.kmk index a3a7bfc67..9824126af 100644 --- a/src/VBox/Main/webservice/Makefile.kmk +++ b/src/VBox/Main/webservice/Makefile.kmk @@ -1,4 +1,4 @@ -# $Id: Makefile.kmk 28800 2010-04-27 08:22:32Z vboxsync $ +# $Id: Makefile.kmk 29843 2010-05-27 11:18:30Z vboxsync $ ## @file # Sub-Makefile for the VBox web service. # @@ -208,33 +208,33 @@ ifdef VBOX_GSOAP_INSTALLED split-soapC_SOURCES = split-soapC.cpp vboxsoap_SOURCES = \ - $(VBOXWEB_OUT_DIR)/soapC-1.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-2.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-3.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-4.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-5.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-6.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-7.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-8.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-9.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-10.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-11.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-12.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-13.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-14.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-15.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-16.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-17.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-18.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-19.cpp \ - $(VBOXWEB_OUT_DIR)/soapC-20.cpp + $(VBOXWEB_OUT_DIR)/soapC-1.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-2.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-3.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-4.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-5.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-6.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-7.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-8.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-9.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-10.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-11.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-12.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-13.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-14.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-15.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-16.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-17.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-18.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-19.cpp \ + $(VBOXWEB_OUT_DIR)/soapC-20.cpp endif vboxsoap_CLEAN := $(vboxsoap_SOURCES) # lazy bird vboxsoap_SOURCES += \ - $(VBOX_GSOAP_CXX_SOURCES) + $(VBOX_GSOAP_CXX_SOURCES) vboxsoap_ORDERDEPS = \ - $(VBOXWEB_IDL_SRC) \ - $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts + $(VBOXWEB_IDL_SRC) \ + $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts ifn1of ($(KBUILD_TARGET), win) $(VBOX_GSOAP_CXX_SOURCES)_CXXFLAGS = -Wno-format endif @@ -262,9 +262,9 @@ endif vboxwebsrv_TEMPLATE = VBOXMAINCLIENTEXE vboxwebsrv_DEFS += SOCKET_CLOSE_ON_EXEC vboxwebsrv_INCS = \ - $(VBOX_GSOAP_INCS) \ - $(VBOXWEB_OUT_DIR) \ - . + $(VBOX_GSOAP_INCS) \ + $(VBOXWEB_OUT_DIR) \ + . ifdef VBOX_USE_VCC80 vboxwebsrv_CXXFLAGS.win += -bigobj endif @@ -272,16 +272,16 @@ endif vboxwebsrv_CXXFLAGS += -Wno-shadow endif vboxwebsrv_LIBS += \ - $(PATH_LIB)/vboxsoap$(VBOX_SUFF_LIB) \ - $(VBOX_GSOAP_CXX_LIBS) + $(PATH_LIB)/vboxsoap$(VBOX_SUFF_LIB) \ + $(VBOX_GSOAP_CXX_LIBS) vboxwebsrv_LIBS.solaris += socket nsl vboxwebsrv_SOURCES = \ - vboxweb.cpp \ - $(VBOXWEB_OUT_DIR)/methodmaps.cpp \ - $(VBOXWEB_OUT_DIR)/soapServer.cpp + vboxweb.cpp \ + $(VBOXWEB_OUT_DIR)/methodmaps.cpp \ + $(VBOXWEB_OUT_DIR)/soapServer.cpp vboxwebsrv_CLEAN = \ - $(VBOXWEB_OUT_DIR)/methodmaps.cpp \ - $(VBOXWEB_OUT_DIR)/soapServer.cpp + $(VBOXWEB_OUT_DIR)/methodmaps.cpp \ + $(VBOXWEB_OUT_DIR)/soapServer.cpp vboxwebsrv_ORDERDEPS = $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts endif # !VBOX_ONLY_SDK @@ -300,18 +300,18 @@ endif webtest_CXXFLAGS += -Wno-shadow endif webtest_INCS := \ - $(VBOX_GSOAP_INCS) \ - $(VBOXWEB_OUT_DIR) \ - . + $(VBOX_GSOAP_INCS) \ + $(VBOXWEB_OUT_DIR) \ + . webtest_LIBS += \ - $(PATH_LIB)/vboxsoap$(VBOX_SUFF_LIB) \ - $(VBOX_GSOAP_CXX_LIBS) + $(PATH_LIB)/vboxsoap$(VBOX_SUFF_LIB) \ + $(VBOX_GSOAP_CXX_LIBS) webtest_LIBS.solaris += nsl webtest_SOURCES = \ - webtest.cpp \ - $(VBOXWEB_OUT_DIR)/soapClient.cpp + webtest.cpp \ + $(VBOXWEB_OUT_DIR)/soapClient.cpp webtest_CLEAN = \ - $(VBOXWEB_OUT_DIR)/soapClient.cpp + $(VBOXWEB_OUT_DIR)/soapClient.cpp webtest_ORDERDEPS = $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts endif # !VBOX_ONLY_SDK @@ -322,21 +322,21 @@ endif # ## @todo figure out whether the SDK really needs this or not... OTHER_CLEAN += \ - $(wildcard $(VBOXWEB_OUT_DIR)/soap*.h) \ - $(wildcard $(VBOXWEB_OUT_DIR)/soap*.cpp) \ - $(wildcard $(VBOXWEB_OUT_DIR)/*.nsmap) \ - $(VBOXWEB_GSOAPH_FROM_XSLT) \ - $(VBOXWEB_GSOAPH_FROM_GSOAP) \ - $(VBOXWEB_SOAP_CLIENT_H) \ - $(VBOXWEB_SOAP_SERVER_H) \ - $(VBOXWEB_OUT_DIR)/gsoap_generate_all_ts \ - $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts \ - $(wildcard $(PATH_TARGET_SOAPDEMOXML)/*) \ - $(PATH_TARGET_SOAPDEMOXML)/dummy_file \ - $(wildcard $(PATH_TARGET_SOAPDEMOHEADERS)/*) \ - $(PATH_TARGET_SOAPDEMOHEADERS)/dummy_file \ - $(wildcard $(PATH_TARGET_SOAPDEMONSMAPS)/*) \ - $(PATH_TARGET_SOAPDEMONSMAPS)/dummy_file + $(wildcard $(VBOXWEB_OUT_DIR)/soap*.h) \ + $(wildcard $(VBOXWEB_OUT_DIR)/soap*.cpp) \ + $(wildcard $(VBOXWEB_OUT_DIR)/*.nsmap) \ + $(VBOXWEB_GSOAPH_FROM_XSLT) \ + $(VBOXWEB_GSOAPH_FROM_GSOAP) \ + $(VBOXWEB_SOAP_CLIENT_H) \ + $(VBOXWEB_SOAP_SERVER_H) \ + $(VBOXWEB_OUT_DIR)/gsoap_generate_all_ts \ + $(VBOXWEB_OUT_DIR)/gsoap_copy_all_ts \ + $(wildcard $(PATH_TARGET_SOAPDEMOXML)/*) \ + $(PATH_TARGET_SOAPDEMOXML)/dummy_file \ + $(wildcard $(PATH_TARGET_SOAPDEMOHEADERS)/*) \ + $(PATH_TARGET_SOAPDEMOHEADERS)/dummy_file \ + $(wildcard $(PATH_TARGET_SOAPDEMONSMAPS)/*) \ + $(PATH_TARGET_SOAPDEMONSMAPS)/dummy_file endif # VBOX_GSOAP_INSTALLED @@ -364,13 +364,13 @@ define find_java_files $(shell find $(1) -name \*.java) endef - VBOX_JAXWS_LIBDIR = $(VBOX_PATH_WEBSERVICE)/jaxlibs # well, not really good VBOX_JAVA15 = $(firstword $(wildcard \ /usr/lib/jvm/java-1.5.0-sun/bin/java \ - /usr/jdk/jdk1.5*/bin/java \ - /opt/sun-jdk-1.5*/bin/java)) + /usr/jdk/jdk1.5*/bin/java \ + /opt/sun-jdk-1.5*/bin/java \ + /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java)) ifndef VBOX_JAVA15 $(error Failed to autodetect VBOX_JAVA15, please set it manually) endif @@ -386,26 +386,18 @@ endef $(error Failed to autodetect VBOX_WSIMPORT16, please set it manually) endif VBOX_JAR = jar - # Keep in sync with G_virtualBoxPackage in glue-jaxws.xsl - # Changed with every new version, so beware! - if $(VBOX_VERSION_BUILD) < 51 - VBOX_API_SUFFIX = _$(VBOX_VERSION_MAJOR)_$(VBOX_VERSION_MINOR) - else - VBOX_API_SUFFIX = _$(VBOX_VERSION_MAJOR)_$(expr $(VBOX_VERSION_MINOR) + 1) - endif - VBOX_JAVA_PACKAGE = org.virtualbox$(VBOX_API_SUFFIX) VBOXWEB_OTHERS += \ - $(VBOXWEB_GLUE_JAVA_TMP) \ - $(VBOXWEB_GLUE_PYTHON) \ - $(VBOXWEB_WS_PYTHON) \ - $(VBOXWEB_WS_PERL) \ - $(VBOXWEB_WS_PHP) \ - $(VBOXWEB_PYTHONWSSAMPLE)\ - $(VBOXWEB_JAXWSSAMPLE) \ - $(VBOXWEB_METRICSAMPLE) \ - $(VBOXWEB_JAVA15_JAR) \ - $(VBOXWEB_JAVA16_JAR) + $(VBOXWEB_GLUE_JAVA_TMP) \ + $(VBOXWEB_GLUE_PYTHON) \ + $(VBOXWEB_WS_PYTHON) \ + $(VBOXWEB_WS_PERL) \ + $(VBOXWEB_WS_PHP) \ + $(VBOXWEB_PYTHONWSSAMPLE)\ + $(VBOXWEB_JAXWSSAMPLE) \ + $(VBOXWEB_METRICSAMPLE) \ + $(VBOXWEB_JAVA15_JAR) \ + $(VBOXWEB_JAVA16_JAR) # # Install sample code. @@ -414,20 +406,13 @@ endef vboxwebinst_INST = $(INST_SDK)bindings/webservice/ vboxwebinst_MODE = a+rx,u+w vboxwebinst_SOURCES = \ - samples/java/axis/clienttest.java=>java/axis/samples/clienttest.java \ - samples/java/jax-ws/Makefile.glue=>java/jax-ws/src/Makefile \ - samples/java/jax-ws/Makefile=>java/jax-ws/samples/Makefile \ - samples/perl/clienttest.pl=>perl/samples/clienttest.pl \ - samples/php/clienttest.php=>php/samples/clienttest.php \ - samples/python/Makefile=>python/samples/Makefile \ - samples/python/Makefile.glue=>python/lib/Makefile - - # - # filesplitter - build helper, splits up the java classes. - # - BLDPROGS += filesplitter - filesplitter_TEMPLATE = VBOXBLDPROG - filesplitter_SOURCES = filesplitter.cpp + samples/java/axis/clienttest.java=>java/axis/samples/clienttest.java \ + samples/java/jax-ws/Makefile.glue=>java/jax-ws/src/Makefile \ + samples/java/jax-ws/Makefile=>java/jax-ws/samples/Makefile \ + samples/perl/clienttest.pl=>perl/samples/clienttest.pl \ + samples/php/clienttest.php=>php/samples/clienttest.php \ + samples/python/Makefile=>python/samples/Makefile \ + samples/python/Makefile.glue=>python/lib/Makefile endif # VBOX_ONLY_SDK @@ -619,7 +604,7 @@ $(VBOXWEB_METRICSAMPLE): $(VBOX_PATH_WEBSERVICE)/samples/java/jax-ws/metrictest. $(QUIET)$(SED) -e 's/{VBOX_API_SUFFIX}/$(VBOX_API_SUFFIX)/' < $< > $@ # generate jax-ws wrapper for java client code -$(VBOXWEB_GLUE_JAVA_TMP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/glue-jaxws.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $$(TARGET_filesplitter) $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) +$(VBOXWEB_GLUE_JAVA_TMP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/glue-jaxws.xsl $(VBOX_PATH_WEBSERVICE)/websrv-shared.inc.xsl $(RECOMPILE_ON_MAKEFILE_CURRENT) | $$(dir $$@) $(QUIET)$(MKDIR) -p $(@D) $(call MSG_GENERATE,,$@,$(VBOXWEB_IDL_SRC) using glue-jaxws.xsl) $(QUIET)$(VBOX_XSLTPROC) $(VBOXWEB_XSLTPROC_VERBOSE) \ @@ -628,7 +613,7 @@ $(VBOXWEB_GLUE_JAVA_TMP): $(VBOXWEB_IDL_SRC) $(VBOX_PATH_WEBSERVICE)/glue-jaxws. $(call MSG_GENERATE,,java client glue files in $(VBOXWEB_PATH_SDK_GLUE_JAVA)) $(RM) -R -f $(VBOXWEB_PATH_SDK_GLUE_JAVA) $(QUIET)$(MKDIR) -p $(VBOXWEB_PATH_SDK_GLUE_JAVA) - $(QUIET)$(TARGET_filesplitter) $@ $(VBOXWEB_PATH_SDK_GLUE_JAVA) + $(QUIET)$(VBOX_FILESPLIT) $@ $(VBOXWEB_PATH_SDK_GLUE_JAVA) $(QUIET)$(CP) -f $(VBOX_PATH_WEBSERVICE)/../../../../COPYING.LIB $(VBOXWEB_PATH_SDK_GLUE_JAVA) $(VBOXWEB_GLUE_JAVA_TMP).done: $(VBOXWEB_GLUE_JAVA_TMP) @@ -664,4 +649,3 @@ $(VBOXWEB_JAVA16_JAR): $(VBOXWEB_GLUE_JAVA_TMP).done $(VBOXWEB_WSDL) $(VBOXWEBSE endif # VBOX_ONLY_SDK include $(KBUILD_PATH)/subfooter.kmk - diff --git a/src/VBox/Main/webservice/filesplitter.cpp b/src/VBox/Main/webservice/filesplitter.cpp deleted file mode 100644 index 9fb716d25..000000000 --- a/src/VBox/Main/webservice/filesplitter.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** @file - * File splitter: splits a text file according to ###### markers in it. - */ - -/* - * Copyright (C) 2006-2009 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -static unsigned long lineNumber(const char *pStr, const char *pPos) -{ - unsigned long cLine = 0; - while (*pStr && pStr < pPos) - { - pStr = strchr(pStr, '\n'); - if (!pStr) - break; - ++cLine; - ++pStr; - } - - return cLine; -} - -int main(int argc, char *argv[]) -{ - int rc = 0; - const char *pcszBeginMarker = "\n// ##### BEGINFILE \""; - const char *pcszEndMarker = "\n// ##### ENDFILE"; - const size_t cbBeginMarker = strlen(pcszBeginMarker); - FILE *pFileIn = NULL; - char *pBuffer = NULL; - - do { - if (argc != 3) - { - fprintf(stderr, "filesplitter: Must be started with exactly two arguments,\n" - "1) the input file and 2) the directory where to put the output files\n"); - rc = 2; - break; - } - - struct stat lStat; - if ( stat(argv[2], &lStat) != 0 - || (lStat.st_mode & S_IFMT) != S_IFDIR) - { - fprintf(stderr, "filesplitter: Given argument \"%s\" is not a valid directory.\n", argv[2]); - rc = 2; - break; - } - - if ( stat(argv[1], &lStat) - || !(pFileIn = fopen(argv[1], "r"))) - { - fprintf(stderr, "filesplitter: Cannot open file \"%s\" for reading.\n", argv[1]); - rc = 2; - break; - } - - if (!(pBuffer = (char*)malloc(lStat.st_size + 1))) - { - fprintf(stderr, "filesplitter: Failed to allocate %ld bytes.\n", (long)lStat.st_size); - rc = 2; - break; - } - - if (fread(pBuffer, 1, lStat.st_size, pFileIn) != lStat.st_size) - { - fprintf(stderr, "filesplitter: Failed to read %ld bytes from input file.\n", (long)lStat.st_size); - rc = 2; - break; - } - pBuffer[lStat.st_size] = '\0'; - - const char *pSearch = pBuffer; - unsigned long cFiles = 0; - size_t cbDirName = strlen(argv[2]); - - do - { - /* find begin marker */ - const char *pBegin = strstr(pSearch, pcszBeginMarker); - if (!pBegin) - break; - - /* find line after begin marker */ - const char *pLineAfterBegin = strchr(pBegin + cbBeginMarker, '\n'); - if (!pLineAfterBegin) - { - fprintf(stderr, "filesplitter: No newline after begin-file marker found.\n"); - rc = 2; - break; - } - ++pLineAfterBegin; - - /* find second quote in begin marker line */ - const char *pSecondQuote = strchr(pBegin + cbBeginMarker, '\"'); - if ( !pSecondQuote - || pSecondQuote >= pLineAfterBegin) - { - fprintf(stderr, "filesplitter: Can't parse filename after begin-file marker (line %lu).\n", lineNumber(pBuffer, pcszBeginMarker)); - rc = 2; - break; - } - - /* find end marker */ - const char *pEnd = strstr(pLineAfterBegin, pcszEndMarker); - if (!pEnd) - { - fprintf(stderr, "filesplitter: No matching end-line marker for begin-file marker found (line %lu).\n", lineNumber(pBuffer, pcszBeginMarker)); - rc = 2; - break; - } - - /* construct output filename */ - char *pszFilename; - size_t cbFilename; - cbFilename = pSecondQuote - (pBegin + cbBeginMarker); - if (!(pszFilename = (char*)malloc(cbDirName + 1 + cbFilename + 1))) - { - fprintf(stderr, "filesplitter: Can't allocate memory for filename.\n"); - rc = 2; - break; - } - memcpy(pszFilename, argv[2], cbDirName); - pszFilename[cbDirName] = '/'; - memcpy(pszFilename + cbDirName + 1, pBegin + cbBeginMarker, cbFilename); - pszFilename[cbFilename + 1 + cbDirName] = '\0'; - - /* create output file and write file contents */ - FILE *pFileOut; - if (!(pFileOut = fopen(pszFilename, "w"))) - { - fprintf(stderr, "filesplitter: Failed to open file \"%s\" for writing\n", pszFilename); - rc = 2; - } - else - { - size_t cbFile = pEnd - pLineAfterBegin; - if (fwrite(pLineAfterBegin, 1, cbFile, pFileOut) != cbFile) - { - fprintf(stderr, "filesplitter: Failed to write %ld bytes to file \"%s\"\n", (long)cbFile, pszFilename); - rc = 2; - } - - fclose(pFileOut); - - if (!rc) - { - ++cFiles; - pSearch = strchr(pEnd, '\n'); - } - } - - free(pszFilename); - - if (rc) - break; - - } while (pSearch); - - printf("filesplitter: Created %lu files.\n", cFiles); - } while (0); - - if (pBuffer) - free(pBuffer); - if (pFileIn) - fclose(pFileIn); - - return rc; -} diff --git a/src/VBox/Main/webservice/glue-jaxws.xsl b/src/VBox/Main/webservice/glue-jaxws.xsl index 61cb412a1..ae871b60f 100644 --- a/src/VBox/Main/webservice/glue-jaxws.xsl +++ b/src/VBox/Main/webservice/glue-jaxws.xsl @@ -50,7 +50,7 @@ <xsl:template name="fileheader"> <xsl:param name="name" /> <xsl:text>/** - * Copyright (C) 2008-2009 Sun Microsystems, Inc. + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of a free software library; you can redistribute * it and/or modify it under the terms of the GNU Lesser General @@ -59,19 +59,15 @@ * The library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY of any kind. * - * Sun LGPL Disclaimer: For the avoidance of doubt, except that if + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if * any license choice other than GPL or LGPL is available it will - * apply instead, Sun elects to use only the Lesser General Public + * apply instead, Oracle elects to use only the Lesser General Public * License version 2.1 (LGPLv2) at this time for any software where * a choice of LGPL license versions is made available with the * language indicating that LGPLv2 or any later version may be used, * or where a choice of which version of the LGPL is applied is * otherwise unspecified. * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa - * Clara, CA 95054 USA or visit http://www.sun.com if you need - * additional information or have any questions. - * </xsl:text> <xsl:value-of select="concat(' * ',$name)"/> <xsl:text> @@ -957,7 +953,7 @@ public class IWebsessionManager { <xsl:call-template name="fatalError"> <xsl:with-param name="msg" select="concat('Interface generation: interface "', $ifname, '" has invalid "extends" value ', $extends, '.')" /> </xsl:call-template> - </xsl:otherwise>> + </xsl:otherwise> </xsl:choose> <!-- interface (class) constructor --> diff --git a/src/VBox/Main/webservice/vboxweb.cpp b/src/VBox/Main/webservice/vboxweb.cpp index fab1a440b..57fc3c042 100644 --- a/src/VBox/Main/webservice/vboxweb.cpp +++ b/src/VBox/Main/webservice/vboxweb.cpp @@ -1471,6 +1471,8 @@ int __vbox__IManagedObjectRef_USCOREgetInterfaceName( WEBDEBUG(("\n-- entering %s\n", __FUNCTION__)); do { + util::AutoReadLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS); + ManagedObjectRef *pRef; if (!ManagedObjectRef::findRefFromId(req->_USCOREthis, &pRef, false)) resp->returnval = pRef->getInterfaceName(); @@ -1502,6 +1504,8 @@ int __vbox__IManagedObjectRef_USCORErelease( WEBDEBUG(("\n-- entering %s\n", __FUNCTION__)); do { + util::AutoReadLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS); + ManagedObjectRef *pRef; if ((rc = ManagedObjectRef::findRefFromId(req->_USCOREthis, &pRef, false))) { @@ -1555,10 +1559,6 @@ int __vbox__IManagedObjectRef_USCORErelease( * a much better solution, both for performance and cleanliness, for the webservice * client to clean up itself. * - * Preconditions: Caller must have locked g_mutexSessions. - * Since this gets called from main() like other SOAP method - * implementations, this is ensured. - * * @param * @param vbox__IWebsessionManager_USCORElogon * @param vbox__IWebsessionManager_USCORElogonResponse @@ -1584,8 +1584,8 @@ int __vbox__IWebsessionManager_USCORElogon( if (!(pSession->authenticate(req->username.c_str(), req->password.c_str()))) { - // in the new session, create a managed object reference (moref) for the - // global VirtualBox object; this encodes the session ID in the moref so + // in the new session, create a managed object reference (MOR) for the + // global VirtualBox object; this encodes the session ID in the MOR so // that it will be implicitly be included in all future requests of this // webservice client ManagedObjectRef *pRef = new ManagedObjectRef(*pSession, g_pcszIVirtualBox, g_pVirtualBox); @@ -1603,10 +1603,6 @@ int __vbox__IWebsessionManager_USCORElogon( /** * Returns the ISession object that was created for the webservice client * on logon. - * - * Preconditions: Caller must have locked g_mutexSessions. - * Since this gets called from main() like other SOAP method - * implementations, this is ensured. */ int __vbox__IWebsessionManager_USCOREgetSessionObject( struct soap*, @@ -1617,6 +1613,9 @@ int __vbox__IWebsessionManager_USCOREgetSessionObject( WEBDEBUG(("\n-- entering %s\n", __FUNCTION__)); do { + // findSessionFromRef needs read lock + util::AutoReadLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS); + WebServiceSession* pSession; if ((pSession = WebServiceSession::findSessionFromRef(req->refIVirtualBox))) { @@ -1633,10 +1632,6 @@ int __vbox__IWebsessionManager_USCOREgetSessionObject( /** * hard-coded implementation for IWebsessionManager::logoff. * - * Preconditions: Caller must have locked g_mutexSessions. - * Since this gets called from main() like other SOAP method - * implementations, this is ensured. - * * @param * @param vbox__IWebsessionManager_USCORElogon * @param vbox__IWebsessionManager_USCORElogonResponse diff --git a/src/VBox/Main/webservice/websrv-php.xsl b/src/VBox/Main/webservice/websrv-php.xsl index 1dd6595d2..147ae0b7d 100644 --- a/src/VBox/Main/webservice/websrv-php.xsl +++ b/src/VBox/Main/webservice/websrv-php.xsl @@ -348,22 +348,26 @@ class <xsl:value-of select="$ifname"/>Collection extends VBox_EnumCollection { <xsl:text><?php /* -* Copyright (C) 2009 Sun Microsystems, Inc. -* -* This file is part of VirtualBox Open Source Edition (OSE), as -* available from http://www.virtualbox.org. This file is free software; -* you can redistribute it and/or modify it under the terms of the GNU -* General Public License (GPL) as published by the Free Software -* Foundation, in version 2 as it comes in the "COPYING" file of the -* VirtualBox OSE distribution. VirtualBox OSE is distributed in the -* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -* -* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa -* Clara, CA 95054 USA or visit http://www.sun.com if you need -* additional information or have any questions. -* -* This file is autogenerated from VirtualBox.xidl, DO NOT EDIT! -*/ + * Copyright (C) 2008-2010 Oracle Corporation + * + * This file is part of a free software library; you can redistribute + * it and/or modify it under the terms of the GNU Lesser General + * Public License version 2.1 as published by the Free Software + * Foundation and shipped in the "COPYING.LIB" file with this library. + * The library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY of any kind. + * + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if + * any license choice other than GPL or LGPL is available it will + * apply instead, Oracle elects to use only the Lesser General Public + * License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the + * language indicating that LGPLv2 or any later version may be used, + * or where a choice of which version of the LGPL is applied is + * otherwise unspecified. + * + * This file is autogenerated from VirtualBox.xidl, DO NOT EDIT! + */ class VBox_ManagedObject { diff --git a/src/VBox/Main/webservice/websrv-python.xsl b/src/VBox/Main/webservice/websrv-python.xsl index aaaa30302..9accb148f 100644 --- a/src/VBox/Main/webservice/websrv-python.xsl +++ b/src/VBox/Main/webservice/websrv-python.xsl @@ -442,19 +442,23 @@ class <xsl:value-of select="@name"/>: </xsl:template> <xsl:template match="/"> -<xsl:text># Copyright (C) 2008-2009 Sun Microsystems, Inc. +<xsl:text># Copyright (C) 2008-2010 Oracle Corporation # -# This file is part of VirtualBox Open Source Edition (OSE), as -# available from http://www.virtualbox.org. This file is free software; -# you can redistribute it and/or modify it under the terms of the GNU -# General Public License (GPL) as published by the Free Software -# Foundation, in version 2 as it comes in the "COPYING" file of the -# VirtualBox OSE distribution. VirtualBox OSE is distributed in the -# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# This file is part of a free software library; you can redistribute +# it and/or modify it under the terms of the GNU Lesser General +# Public License version 2.1 as published by the Free Software +# Foundation and shipped in the "COPYING.LIB" file with this library. +# The library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY of any kind. # -# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa -# Clara, CA 95054 USA or visit http://www.sun.com if you need -# additional information or have any questions. +# Oracle LGPL Disclaimer: For the avoidance of doubt, except that if +# any license choice other than GPL or LGPL is available it will +# apply instead, Oracle elects to use only the Lesser General Public +# License version 2.1 (LGPLv2) at this time for any software where +# a choice of LGPL license versions is made available with the +# language indicating that LGPLv2 or any later version may be used, +# or where a choice of which version of the LGPL is applied is +# otherwise unspecified. # # This file is autogenerated from VirtualBox.xidl, DO NOT EDIT! # diff --git a/src/VBox/Main/webservice/webtest.cpp b/src/VBox/Main/webservice/webtest.cpp index 65c1a4822..e28d95063 100644 --- a/src/VBox/Main/webservice/webtest.cpp +++ b/src/VBox/Main/webservice/webtest.cpp @@ -48,6 +48,7 @@ int main(int argc, char* argv[]) " - IVirtualBox:\n" " - webtest version <vboxref>: IVirtualBox::getVersion().\n" " - webtest gethost <vboxref>: IVirtualBox::getHost().\n" + " - webtest getpc <vboxref>: IVirtualBox::getPerformanceCollector().\n" " - webtest getmachines <vboxref>: IVirtualBox::getMachines().\n" " - webtest createmachine <vboxref> <baseFolder> <name>: IVirtualBox::createMachine().\n" " - webtest registermachine <vboxref> <machineref>: IVirtualBox::registerMachine().\n" @@ -60,6 +61,9 @@ int main(int argc, char* argv[]) " - webtest getid <machineref>: IMachine::getId().\n" " - webtest getostype <machineref>: IMachine::getGuestOSType().\n" " - webtest savesettings <machineref>: IMachine::saveSettings().\n" + " - IPerformanceCollector:\n" + " - webtest setupmetrics <pcref>: IPerformanceCollector::setupMetrics()\n" + " - webtest querymetricsdata <pcref>: IPerformanceCollector::QueryMetricsData()\n" " - All managed object references:\n" " - webtest getif <ref>: report interface of object.\n" " - webtest release <ref>: IUnknown::Release().\n"; @@ -166,6 +170,26 @@ int main(int argc, char* argv[]) } } } + else if (!strcmp(pcszMode, "getpc")) + { + if (argc < 3) + std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n"; + else + { + _vbox__IVirtualBox_USCOREgetPerformanceCollector req; + req._USCOREthis = argv[2]; + _vbox__IVirtualBox_USCOREgetPerformanceCollectorResponse resp; + + if (!(soaprc = soap_call___vbox__IVirtualBox_USCOREgetPerformanceCollector(&soap, + pcszArgEndpoint, + NULL, + &req, + &resp))) + { + std::cout << "Performance collector objref " << resp.returnval << "\n"; + } + } + } else if (!strcmp(pcszMode, "getmachines")) { if (argc < 3) @@ -324,6 +348,62 @@ int main(int argc, char* argv[]) std::cout << "Settings saved\n"; } } + else if (!strcmp(pcszMode, "setupmetrics")) + { + if (argc < 3) + std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n"; + else + { + _vbox__IPerformanceCollector_USCOREsetupMetrics req; + req._USCOREthis = argv[2]; +// req.metricNames[0] = "*"; +// req.objects + req.period = 1; // seconds + req.count = 100; + _vbox__IPerformanceCollector_USCOREsetupMetricsResponse resp; + if (!(soaprc = soap_call___vbox__IPerformanceCollector_USCOREsetupMetrics(&soap, + pcszArgEndpoint, + NULL, + &req, + &resp))) + { + size_t c = resp.returnval.size(); + for (size_t i = 0; + i < c; + ++i) + { + std::cout << "Metric " << i << ": objref " << resp.returnval[i] << "\n"; + } + } + } + } + else if (!strcmp(pcszMode, "querymetricsdata")) + { + if (argc < 3) + std::cout << "Not enough arguments for \"" << pcszMode << "\" mode.\n"; + else + { + _vbox__IPerformanceCollector_USCOREqueryMetricsData req; + req._USCOREthis = argv[2]; +// req.metricNames[0] = "*"; +// req.objects + _vbox__IPerformanceCollector_USCOREqueryMetricsDataResponse resp; + if (!(soaprc = soap_call___vbox__IPerformanceCollector_USCOREqueryMetricsData(&soap, + pcszArgEndpoint, + NULL, + &req, + &resp))) + { + size_t c = resp.returnval.size(); + for (size_t i = 0; + i < c; + ++i) + { + std::cout << "long " << i << ": " << resp.returnval[i] << "\n"; + } + } + } + } else if (!strcmp(pcszMode, "release")) { if (argc < 3) diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp index 7ff36f93d..9027e5dac 100644 --- a/src/VBox/Main/xml/Settings.cpp +++ b/src/VBox/Main/xml/Settings.cpp @@ -1,4 +1,4 @@ -/* $Id: Settings.cpp 29593 2010-05-18 07:23:46Z vboxsync $ */ +/* $Id: Settings.cpp 29873 2010-05-28 17:14:53Z vboxsync $ */ /** @file * Settings File Manipulation API. * @@ -429,19 +429,6 @@ com::Utf8Str ConfigFileBase::makeString(const RTTIMESPEC &stamp) } /** - * Helper to create a string for a GUID. - * @param guid - * @return - */ -com::Utf8Str ConfigFileBase::makeString(const Guid &guid) -{ - Utf8Str str("{"); - str.append(guid.toString()); - str.append("}"); - return str; -} - -/** * Helper method to read in an ExtraData subtree and stores its contents * in the given map of extradata items. Used for both main and machine * extradata (MainConfigFile and MachineConfigFile). @@ -1161,7 +1148,7 @@ void MainConfigFile::writeHardDisk(xml::ElementNode &elmMedium, uint32_t level) // 0 for "root" call, incremented with each recursion { xml::ElementNode *pelmHardDisk = elmMedium.createChild("HardDisk"); - pelmHardDisk->setAttribute("uuid", makeString(mdm.uuid)); + pelmHardDisk->setAttribute("uuid", mdm.uuid.toStringCurly()); pelmHardDisk->setAttribute("location", mdm.strLocation); pelmHardDisk->setAttribute("format", mdm.strFormat); if (mdm.fAutoReset) @@ -1221,7 +1208,7 @@ void MainConfigFile::write(const com::Utf8Str strFilename) // <MachineEntry uuid="{5f102a55-a51b-48e3-b45a-b28d33469488}" src="/mnt/innotek-unix/vbox-machines/Windows 5.1 XP 1 (Office 2003)/Windows 5.1 XP 1 (Office 2003).xml"/> const MachineRegistryEntry &mre = *it; xml::ElementNode *pelmMachineEntry = pelmMachineRegistry->createChild("MachineEntry"); - pelmMachineEntry->setAttribute("uuid", makeString(mre.uuid)); + pelmMachineEntry->setAttribute("uuid", mre.uuid.toStringCurly()); pelmMachineEntry->setAttribute("src", mre.strSettingsFile); } @@ -1242,7 +1229,7 @@ void MainConfigFile::write(const com::Utf8Str strFilename) { const Medium &mdm = *it; xml::ElementNode *pelmMedium = pelmDVDImages->createChild("Image"); - pelmMedium->setAttribute("uuid", makeString(mdm.uuid)); + pelmMedium->setAttribute("uuid", mdm.uuid.toStringCurly()); pelmMedium->setAttribute("location", mdm.strLocation); if (mdm.strDescription.length()) pelmMedium->setAttribute("Description", mdm.strDescription); @@ -1255,7 +1242,7 @@ void MainConfigFile::write(const com::Utf8Str strFilename) { const Medium &mdm = *it; xml::ElementNode *pelmMedium = pelmFloppyImages->createChild("Image"); - pelmMedium->setAttribute("uuid", makeString(mdm.uuid)); + pelmMedium->setAttribute("uuid", mdm.uuid.toStringCurly()); pelmMedium->setAttribute("location", mdm.strLocation); if (mdm.strDescription.length()) pelmMedium->setAttribute("Description", mdm.strDescription); @@ -3062,7 +3049,7 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, if ( (m->sv >= SettingsVersion_v1_9) && (!hw.uuid.isEmpty()) ) - pelmHardware->setAttribute("uuid", makeString(hw.uuid)); + pelmHardware->setAttribute("uuid", hw.uuid.toStringCurly()); xml::ElementNode *pelmCPU = pelmHardware->createChild("CPU"); @@ -3296,7 +3283,7 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, pelmDVD->setAttribute("passthrough", att.fPassThrough); if (!att.uuid.isEmpty()) - pelmDVD->createChild("Image")->setAttribute("uuid", makeString(att.uuid)); + pelmDVD->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly()); else if (att.strHostDriveSrc.length()) pelmDVD->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc); } @@ -3312,7 +3299,7 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, const AttachedDevice &att = sctl.llAttachedDevices.front(); pelmFloppy->setAttribute("enabled", true); if (!att.uuid.isEmpty()) - pelmFloppy->createChild("Image")->setAttribute("uuid", makeString(att.uuid)); + pelmFloppy->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly()); else if (att.strHostDriveSrc.length()) pelmFloppy->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc); } @@ -3652,10 +3639,15 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode, * an empty drive is always written instead. This is for the OVF export case. * This parameter is ignored unless the settings version is at least v1.9, which * is always the case when this gets called for OVF export. + * @param pllElementsWithUuidAttributes If not NULL, must point to a list of element node + * pointers to which we will append all allements that we created here that contain + * UUID attributes. This allows the OVF export code to quickly replace the internal + * media UUIDs with the UUIDs of the media that were exported. */ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, const Storage &st, - bool fSkipRemovableMedia) + bool fSkipRemovableMedia, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes) { xml::ElementNode *pelmStorageControllers = elmParent.createChild("StorageControllers"); @@ -3758,12 +3750,20 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, pelmDevice->setAttribute("port", att.lPort); pelmDevice->setAttribute("device", att.lDevice); + // attached image, if any if ( !att.uuid.isEmpty() && ( att.deviceType == DeviceType_HardDisk || !fSkipRemovableMedia ) ) - pelmDevice->createChild("Image")->setAttribute("uuid", makeString(att.uuid)); + { + xml::ElementNode *pelmImage = pelmDevice->createChild("Image"); + pelmImage->setAttribute("uuid", att.uuid.toStringCurly()); + + // if caller wants a list of UUID elements, give it to them + if (pllElementsWithUuidAttributes) + pllElementsWithUuidAttributes->push_back(pelmImage); + } else if ( (m->sv >= SettingsVersion_v1_9) && (att.strHostDriveSrc.length()) ) @@ -3784,7 +3784,7 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, { xml::ElementNode *pelmSnapshot = elmParent.createChild("Snapshot"); - pelmSnapshot->setAttribute("uuid", makeString(snap.uuid)); + pelmSnapshot->setAttribute("uuid", snap.uuid.toStringCurly()); pelmSnapshot->setAttribute("name", snap.strName); pelmSnapshot->setAttribute("timeStamp", makeString(snap.timestamp)); @@ -3797,7 +3797,8 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, buildHardwareXML(*pelmSnapshot, snap.hardware, snap.storage); buildStorageControllersXML(*pelmSnapshot, snap.storage, - false /* fSkipRemovableMedia */); + false /* fSkipRemovableMedia */, + NULL); /* pllElementsWithUuidAttributes */ // we only skip removable media for OVF, but we never get here for OVF // since snapshots never get written then @@ -3845,15 +3846,18 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, * * @param elmMachine XML <Machine> element to add attributes and elements to. * @param fl Flags. + * @param pllElementsWithUuidAttributes pointer to list that should receive UUID elements or NULL; + * see buildStorageControllersXML() for details. */ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, - uint32_t fl) + uint32_t fl, + std::list<xml::ElementNode*> *pllElementsWithUuidAttributes) { if (fl & BuildMachineXML_WriteVboxVersionAttribute) // add settings version attribute to machine element setVersionAttribute(elmMachine); - elmMachine.setAttribute("uuid", makeString(uuid)); + elmMachine.setAttribute("uuid", uuid.toStringCurly()); elmMachine.setAttribute("name", strName); if (!fNameSync) elmMachine.setAttribute("nameSync", fNameSync); @@ -3864,7 +3868,7 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, elmMachine.setAttribute("stateFile", strStateFile); if ( (fl & BuildMachineXML_IncludeSnapshots) && !uuidCurrentSnapshot.isEmpty()) - elmMachine.setAttribute("currentSnapshot", makeString(uuidCurrentSnapshot)); + elmMachine.setAttribute("currentSnapshot", uuidCurrentSnapshot.toStringCurly()); if (strSnapshotFolder.length()) elmMachine.setAttribute("snapshotFolder", strSnapshotFolder); if (!fCurrentStateModified) @@ -3896,7 +3900,8 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, buildHardwareXML(elmMachine, hardwareMachine, storageMachine); buildStorageControllersXML(elmMachine, storageMachine, - !!(fl & BuildMachineXML_SkipRemovableMedia)); + !!(fl & BuildMachineXML_SkipRemovableMedia), + pllElementsWithUuidAttributes); } /** @@ -4084,8 +4089,9 @@ void MachineConfigFile::write(const com::Utf8Str &strFilename) xml::ElementNode *pelmMachine = m->pelmRoot->createChild("Machine"); buildMachineXML(*pelmMachine, - MachineConfigFile::BuildMachineXML_IncludeSnapshots); + MachineConfigFile::BuildMachineXML_IncludeSnapshots, // but not BuildMachineXML_WriteVboxVersionAttribute + NULL); /* pllElementsWithUuidAttributes */ // now go write the XML xml::XmlFileWriter writer(*m->pDoc); diff --git a/src/VBox/Main/xml/ovfreader.cpp b/src/VBox/Main/xml/ovfreader.cpp index 4be482683..18e3dba82 100644 --- a/src/VBox/Main/xml/ovfreader.cpp +++ b/src/VBox/Main/xml/ovfreader.cpp @@ -1,4 +1,4 @@ -/* $Id: ovfreader.cpp 29422 2010-05-12 14:08:52Z vboxsync $ */ +/* $Id: ovfreader.cpp 29893 2010-05-31 10:37:17Z vboxsync $ */ /** @file * * OVF reader declarations. Depends only on IPRT, including the iprt::MiniString @@ -85,7 +85,9 @@ void OVFReader::LoopThruSections(const xml::ElementNode *pReferencesElem, const char *pcszElemName = pElem->getName(); const char *pcszTypeAttr = ""; const xml::AttributeNode *pTypeAttr; - if ((pTypeAttr = pElem->findAttribute("type"))) + if ( ((pTypeAttr = pElem->findAttribute("xsi:type"))) + || ((pTypeAttr = pElem->findAttribute("type"))) + ) pcszTypeAttr = pTypeAttr->getValue(); if ( (!strcmp(pcszElemName, "DiskSection")) @@ -96,7 +98,7 @@ void OVFReader::LoopThruSections(const xml::ElementNode *pReferencesElem, { HandleDiskSection(pReferencesElem, pElem); } - else if ( (!strcmp(pcszElemName, "NetworkSection")) + else if ( (!strcmp(pcszElemName, "NetworkSection")) || ( (!strcmp(pcszElemName, "Section")) && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type")) ) @@ -294,8 +296,19 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy while ((pelmThis = loop.forAllNodes())) { const char *pcszElemName = pelmThis->getName(); - const xml::AttributeNode *pTypeAttr = pelmThis->findAttribute("type"); - const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : ""; + const char *pcszTypeAttr = ""; + if (!strcmp(pcszElemName, "Section")) // OVF 0.9 used "Section" element always with a varying "type" attribute + { + const xml::AttributeNode *pTypeAttr; + if ( ((pTypeAttr = pelmThis->findAttribute("type"))) + || ((pTypeAttr = pelmThis->findAttribute("xsi:type"))) + ) + pcszTypeAttr = pTypeAttr->getValue(); + else + throw OVFLogicError(N_("Error reading \"%s\": element \"Section\" has no \"type\" attribute, line %d"), + m_strPath.c_str(), + pelmThis->getLineNumber()); + } if ( (!strcmp(pcszElemName, "EulaSection")) || (!strcmp(pcszTypeAttr, "ovf:EulaSection_Type")) diff --git a/src/VBox/Main/xpcom/server.cpp b/src/VBox/Main/xpcom/server.cpp index 2372e3a80..5c5e3c194 100644 --- a/src/VBox/Main/xpcom/server.cpp +++ b/src/VBox/Main/xpcom/server.cpp @@ -1,4 +1,4 @@ -/* $Id: server.cpp 29385 2010-05-11 18:05:44Z vboxsync $ */ +/* $Id: server.cpp 29864 2010-05-28 13:34:53Z vboxsync $ */ /** @file * XPCOM server process (VBoxSVC) start point. */ @@ -66,6 +66,7 @@ #include <MediumImpl.h> #include <MediumFormatImpl.h> #include <ProgressCombinedImpl.h> +#include <ProgressProxyImpl.h> #include <VRDPServerImpl.h> #include <SharedFolderImpl.h> #include <HostImpl.h> @@ -127,6 +128,9 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress) NS_DECL_CLASSINFO(CombinedProgress) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress) +NS_DECL_CLASSINFO(ProgressProxy) +NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress) + NS_DECL_CLASSINFO(SharedFolder) NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder) |
