VirtualBox

source: vbox/trunk/src/VBox/Main/ApplianceImpl.cpp@ 16560

Last change on this file since 16560 was 16560, checked in by vboxsync, 15 years ago

Main: do not include include/VBox/settings.h from other header files but only from implementations that need it (save compile time)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 90.3 KB
RevLine 
[16205]1/* $Id: ApplianceImpl.cpp 16560 2009-02-06 18:06:04Z vboxsync $ */
2/** @file
3 *
4 * IAppliance and IVirtualSystem COM class implementations
5 */
6
7/*
8 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include <iprt/stream.h>
24#include <iprt/path.h>
[16298]25#include <iprt/dir.h>
26#include <iprt/file.h>
[16205]27
28#include "ApplianceImpl.h"
29#include "VirtualBoxImpl.h"
30#include "GuestOSTypeImpl.h"
[16503]31#include "ProgressImpl.h"
[16205]32
33#include "Logging.h"
34
35#include "VBox/xml.h"
36
37#include <iostream>
38#include <sstream>
39
40using namespace std;
41
42// defines
43////////////////////////////////////////////////////////////////////////////////
44
45struct DiskImage
46{
[16325]47 Utf8Str strDiskId; // value from DiskSection/Disk/@diskId
[16205]48 int64_t iCapacity; // value from DiskSection/Disk/@capacity;
49 // (maximum size for dynamic images, I guess; we always translate this to bytes)
50 int64_t iPopulatedSize; // value from DiskSection/Disk/@populatedSize
51 // (actual used size of disk, always in bytes; can be an estimate of used disk
52 // space, but cannot be larger than iCapacity)
[16325]53 Utf8Str strFormat; // value from DiskSection/Disk/@format
[16205]54 // typically http://www.vmware.com/specifications/vmdk.html#sparse
55
56 // fields from /References/File; the spec says the file reference from disk can be empty,
57 // so in that case, strFilename will be empty, then a new disk should be created
[16325]58 Utf8Str strHref; // value from /References/File/@href (filename); if empty, then the remaining fields are ignored
[16205]59 int64_t iSize; // value from /References/File/@size (optional according to spec; then we set -1 here)
60 int64_t iChunkSize; // value from /References/File/@chunkSize (optional, unsupported)
[16325]61 Utf8Str strCompression; // value from /References/File/@compression (optional, can be "gzip" according to spec)
[16205]62};
63
64struct Network
65{
[16325]66 Utf8Str strNetworkName; // value from NetworkSection/Network/@name
[16205]67 // unfortunately the OVF spec is unspecific about how networks should be specified further
68};
69
70struct VirtualHardwareItem
71{
[16325]72 Utf8Str strDescription;
73 Utf8Str strCaption;
74 Utf8Str strElementName;
[16205]75
76 uint32_t ulInstanceID;
77 uint32_t ulParent;
78
79 OVFResourceType_T resourceType;
[16325]80 Utf8Str strOtherResourceType;
81 Utf8Str strResourceSubType;
[16248]82
[16325]83 Utf8Str strHostResource; // "Abstractly specifies how a device shall connect to a resource on the deployment platform.
[16248]84 // Not all devices need a backing." Used with disk items, for which this references a virtual
85 // disk from the Disks section.
[16205]86 bool fAutomaticAllocation;
87 bool fAutomaticDeallocation;
[16325]88 Utf8Str strConnection; // "All Ethernet adapters that specify the same abstract network connection name within an OVF
[16248]89 // package shall be deployed on the same network. The abstract network connection name shall be
90 // listed in the NetworkSection at the outermost envelope level."
[16325]91 Utf8Str strAddress; // "Device-specific. For an Ethernet adapter, this specifies the MAC address."
92 Utf8Str strAddressOnParent; // "For a device, this specifies its location on the controller."
93 Utf8Str strAllocationUnits; // "Specifies the units of allocation used. For example, “byte * 2^20”."
[16248]94 uint64_t ullVirtualQuantity; // "Specifies the quantity of resources presented. For example, “256”."
95 uint64_t ullReservation; // "Specifies the minimum quantity of resources guaranteed to be available."
96 uint64_t ullLimit; // "Specifies the maximum quantity of resources that will be granted."
97 uint64_t ullWeight; // "Specifies a relative priority for this allocation in relation to other allocations."
98
[16325]99 Utf8Str strConsumerVisibility;
100 Utf8Str strMappingBehavior;
101 Utf8Str strPoolID;
[16248]102 uint32_t ulBusNumber; // seen with IDE controllers, but not listed in OVF spec
[16205]103
[16248]104 uint32_t ulLineNumber; // line number of <Item> element in XML source; cached for error messages
[16205]105
106 VirtualHardwareItem()
[16248]107 : ulInstanceID(0), fAutomaticAllocation(false), fAutomaticDeallocation(false), ullVirtualQuantity(0), ullReservation(0), ullLimit(0), ullWeight(0), ulBusNumber(0), ulLineNumber(0)
[16205]108 {};
109};
110
[16515]111typedef map<Utf8Str, DiskImage> DiskImagesMap;
[16325]112typedef map<Utf8Str, Network> NetworksMap;
[16205]113
114struct VirtualSystem;
115
116// opaque private instance data of Appliance class
117struct Appliance::Data
118{
119 Bstr bstrPath;
120
121 DiskImagesMap mapDisks; // map of DiskImage structs, sorted by DiskImage.strDiskId
122
123 NetworksMap mapNetworks; // map of Network structs, sorted by Network.strNetworkName
124
125 list<VirtualSystem> llVirtualSystems;
126
127 list< ComObjPtr<VirtualSystemDescription> > virtualSystemDescriptions;
128};
129
130typedef map<uint32_t, VirtualHardwareItem> HardwareItemsMap;
131
132struct HardDiskController
133{
134 uint32_t idController; // instance ID (Item/InstanceId); this gets referenced from HardDisk
[16495]135 enum ControllerSystemType { IDE, SATA, SCSI };
136 ControllerSystemType system; // one of IDE, SATA, SCSI
[16515]137 Utf8Str strControllerType; // controller subtype (Item/ResourceSubType); e.g. "LsiLogic"; can be empty (esp. for IDE)
[16325]138 Utf8Str strAddress; // for IDE
[16228]139 uint32_t ulBusNumber; // for IDE
140
141 HardDiskController()
142 : idController(0),
143 ulBusNumber(0)
144 {
145 }
[16205]146};
147
148typedef map<uint32_t, HardDiskController> ControllersMap;
149
150struct VirtualDisk
151{
152 uint32_t idController; // SCSI (or IDE) controller this disk is connected to;
153 // points into VirtualSystem.mapControllers
[16325]154 Utf8Str strDiskId; // if the hard disk has an ovf:/disk/<id> reference,
[16205]155 // this receives the <id> component; points to one of the
156 // references in Appliance::Data.mapDisks
157};
158
[16325]159typedef map<Utf8Str, VirtualDisk> VirtualDisksMap;
[16298]160
[16205]161struct VirtualSystem
162{
[16325]163 Utf8Str strName; // copy of VirtualSystem/@id
[16210]164
[16205]165 CIMOSType_T cimos;
[16325]166 Utf8Str strVirtualSystemType; // generic hardware description; OVF says this can be something like "vmx-4" or "xen";
[16302]167 // VMware Workstation 6.5 is "vmx-07"
[16205]168
169 HardwareItemsMap mapHardwareItems; // map of virtual hardware items, sorted by unique instance ID
170
171 uint64_t ullMemorySize; // always in bytes, copied from llHardwareItems; default = 0 (unspecified)
172 uint16_t cCPUs; // no. of CPUs, copied from llHardwareItems; default = 1
173
[16325]174 list<Utf8Str> llNetworkNames;
[16205]175 // list of strings referring to network names
176 // (one for each VirtualSystem/Item[@ResourceType=10]/Connection element)
177
178 ControllersMap mapControllers;
179 // list of hard disk controllers
180 // (one for each VirtualSystem/Item[@ResourceType=6] element with accumulated data from children)
181
[16298]182 VirtualDisksMap mapVirtualDisks;
[16205]183 // (one for each VirtualSystem/Item[@ResourceType=17] element with accumulated data from children)
184
[16306]185 bool fHasFloppyDrive; // true if there's a floppy item in mapHardwareItems
186 bool fHasCdromDrive; // true if there's a CD-ROM item in mapHardwareItems; ISO images are not yet supported by OVFtool
187 bool fHasUsbController; // true if there's a USB controller item in mapHardwareItems
[16208]188
[16325]189 Utf8Str strSoundCardType; // if not empty, then the system wants a soundcard; this then specifies the hardware;
[16306]190 // VMware Workstation 6.5 uses "ensoniq1371" for example
191
[16325]192 Utf8Str strLicenceInfo; // license info if any; receives contents of VirtualSystem/EulaSection/Info
193 Utf8Str strLicenceText; // license info if any; receives contents of VirtualSystem/EulaSection/License
[16306]194
[16205]195 VirtualSystem()
[16306]196 : ullMemorySize(0), cCPUs(1), fHasFloppyDrive(false), fHasCdromDrive(false), fHasUsbController(false)
[16205]197 {
198 }
199};
200
[16503]201struct Appliance::Task
202{
203 Task(Appliance *aThat, Progress *aProgress)
204 : that(aThat)
205 , progress(aProgress)
[16512]206 , rc(S_OK)
[16503]207 {}
208 ~Task() {}
209
210 HRESULT startThread();
211
212 Appliance *that;
213 ComObjPtr<Progress> progress;
214 HRESULT rc;
215};
216
[16205]217// globals
218////////////////////////////////////////////////////////////////////////////////
219
[16325]220template <class T>
221inline
222com::Utf8Str toString(const T& val)
[16205]223{
[16325]224 // @todo optimize
[16205]225 std::ostringstream ss;
226 ss << val;
[16325]227 return Utf8Str(ss.str().c_str());
[16205]228}
229
[16517]230static Utf8Str stripFilename(const Utf8Str &strFile)
231{
232 Utf8Str str2(strFile);
233 RTPathStripFilename(str2.mutableRaw());
234 return str2;
235}
236
[16205]237// IVirtualBox public methods
238////////////////////////////////////////////////////////////////////////////////
239
240/**
[16218]241 * Implementation for IVirtualBox::openAppliance. Loads the given appliance (see API reference).
[16205]242 *
243 * @param bstrPath Appliance to open (either .ovf or .ova file, see API reference)
244 * @param anAppliance IAppliance object created if S_OK is returned.
245 * @return S_OK or error.
246 */
[16503]247STDMETHODIMP VirtualBox::OpenAppliance(IN_BSTR bstrPath, IAppliance** anAppliance)
[16205]248{
249 HRESULT rc;
250
251 ComObjPtr<Appliance> appliance;
252 appliance.createObject();
[16234]253 rc = appliance->init(this, bstrPath);
[16205]254// ComAssertComRCThrowRC(rc);
255
256 if (SUCCEEDED(rc))
257 appliance.queryInterfaceTo(anAppliance);
258
259 return rc;
260}
261
[16503]262// Appliance::task methods
263////////////////////////////////////////////////////////////////////////////////
264
265HRESULT Appliance::Task::startThread()
266{
267 int vrc = RTThreadCreate(NULL, Appliance::taskThread, this,
268 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
[16512]269 "Appliance::Task");
[16503]270 ComAssertMsgRCRet(vrc,
271 ("Could not create Appliance::Task thread (%Rrc)\n", vrc), E_FAIL);
272
273 return S_OK;
274}
275
[16205]276// IAppliance constructor / destructor
277////////////////////////////////////////////////////////////////////////////////
278
279DEFINE_EMPTY_CTOR_DTOR(Appliance)
280struct shutup {};
281
282// IAppliance private methods
283////////////////////////////////////////////////////////////////////////////////
284
285/**
286 * Private helper method that goes thru the elements of the given "current" element in the OVF XML
287 * and handles the contained child elements (which can be "Section" or "Content" elements).
288 *
289 * @param pcszPath Path spec of the XML file, for error messages.
290 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
291 * @param pCurElem Element whose children are to be analyzed here.
292 * @return
293 */
294HRESULT Appliance::LoopThruSections(const char *pcszPath,
295 const xml::Node *pReferencesElem,
296 const xml::Node *pCurElem)
297{
298 HRESULT rc;
299
300 xml::NodesLoop loopChildren(*pCurElem);
301 const xml::Node *pElem;
302 while ((pElem = loopChildren.forAllNodes()))
303 {
304 const char *pcszElemName = pElem->getName();
305 const char *pcszTypeAttr = "";
306 const xml::Node *pTypeAttr;
307 if ((pTypeAttr = pElem->findAttribute("type")))
308 pcszTypeAttr = pTypeAttr->getValue();
309
310 if ( (!strcmp(pcszElemName, "DiskSection"))
311 || ( (!strcmp(pcszElemName, "Section"))
312 && (!strcmp(pcszTypeAttr, "ovf:DiskSection_Type"))
313 )
314 )
315 {
316 if (!(SUCCEEDED((rc = HandleDiskSection(pcszPath, pReferencesElem, pElem)))))
317 return rc;
318 }
319 else if ( (!strcmp(pcszElemName, "NetworkSection"))
320 || ( (!strcmp(pcszElemName, "Section"))
321 && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type"))
322 )
323 )
324 {
325 if (!(SUCCEEDED((rc = HandleNetworkSection(pcszPath, pElem)))))
326 return rc;
327 }
328 else if ( (!strcmp(pcszElemName, "DeploymentOptionSection>")))
329 {
330 // TODO
331 }
332 else if ( (!strcmp(pcszElemName, "Info")))
333 {
334 // child of VirtualSystemCollection -- TODO
335 }
336 else if ( (!strcmp(pcszElemName, "ResourceAllocationSection")))
337 {
338 // child of VirtualSystemCollection -- TODO
339 }
340 else if ( (!strcmp(pcszElemName, "StartupSection")))
341 {
342 // child of VirtualSystemCollection -- TODO
343 }
344 else if ( (!strcmp(pcszElemName, "VirtualSystem"))
345 || ( (!strcmp(pcszElemName, "Content"))
346 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type"))
347 )
348 )
349 {
350 if (!(SUCCEEDED((rc = HandleVirtualSystemContent(pcszPath, pElem)))))
351 return rc;
352 }
353 else if ( (!strcmp(pcszElemName, "VirtualSystemCollection"))
354 || ( (!strcmp(pcszElemName, "Content"))
355 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type"))
356 )
357 )
358 {
359 // TODO ResourceAllocationSection
360
361 // recurse for this, since it has VirtualSystem elements as children
362 if (!(SUCCEEDED((rc = LoopThruSections(pcszPath, pReferencesElem, pElem)))))
363 return rc;
364 }
365 }
366
367 return S_OK;
368}
369
370/**
371 * Private helper method that handles disk sections in the OVF XML.
372 * @param pcszPath Path spec of the XML file, for error messages.
373 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
374 * @param pSectionElem Section element for which this helper is getting called.
375 * @return
376 */
377HRESULT Appliance::HandleDiskSection(const char *pcszPath,
378 const xml::Node *pReferencesElem,
379 const xml::Node *pSectionElem)
380{
381 // contains "Disk" child elements
382 xml::NodesLoop loopDisks(*pSectionElem, "Disk");
383 const xml::Node *pelmDisk;
384 while ((pelmDisk = loopDisks.forAllNodes()))
385 {
386 DiskImage d;
387 const char *pcszBad = NULL;
388 if (!(pelmDisk->getAttributeValue("diskId", d.strDiskId)))
389 pcszBad = "diskId";
390 else if (!(pelmDisk->getAttributeValue("format", d.strFormat)))
391 pcszBad = "format";
392 else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity)))
393 pcszBad = "capacity";
394 else
395 {
396 if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)))
397 // optional
398 d.iPopulatedSize = -1;
399
[16325]400 Utf8Str strFileRef;
[16205]401 if (pelmDisk->getAttributeValue("fileRef", strFileRef)) // optional
402 {
403 // look up corresponding /References/File nodes (list built above)
404 const xml::Node *pFileElem;
405 if ( pReferencesElem
[16208]406 && ((pFileElem = pReferencesElem->findChildElementFromId(strFileRef.c_str())))
407 )
[16205]408 {
409 // copy remaining values from file node then
410 const char *pcszBadInFile = NULL;
411 if (!(pFileElem->getAttributeValue("href", d.strHref)))
412 pcszBadInFile = "href";
413 else if (!(pFileElem->getAttributeValue("size", d.iSize)))
414 d.iSize = -1; // optional
415 // if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
416 d.iChunkSize = -1; // optional
417 pFileElem->getAttributeValue("compression", d.strCompression);
418
419 if (pcszBadInFile)
420 return setError(VBOX_E_FILE_ERROR,
421 tr("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
422 pcszPath,
423 pcszBadInFile,
424 pFileElem->getLineNumber());
425 }
426 else
427 return setError(VBOX_E_FILE_ERROR,
428 tr("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
429 pcszPath,
430 strFileRef.c_str(),
431 pelmDisk->getLineNumber());
432 }
433 }
434
435 if (pcszBad)
436 return setError(VBOX_E_FILE_ERROR,
437 tr("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
438 pcszPath,
439 pcszBad,
440 pelmDisk->getLineNumber());
441
442 m->mapDisks[d.strDiskId] = d;
443 }
444
445 return S_OK;
446}
447
448/**
449 * Private helper method that handles network sections in the OVF XML.
450 * @param pcszPath Path spec of the XML file, for error messages.
451 * @param pSectionElem Section element for which this helper is getting called.
452 * @return
453 */
454HRESULT Appliance::HandleNetworkSection(const char *pcszPath,
455 const xml::Node *pSectionElem)
456{
457 // contains "Disk" child elements
458 xml::NodesLoop loopNetworks(*pSectionElem, "Network");
459 const xml::Node *pelmNetwork;
460 while ((pelmNetwork = loopNetworks.forAllNodes()))
461 {
462 Network n;
463 if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
464 return setError(VBOX_E_FILE_ERROR,
465 tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
466 pcszPath,
467 pelmNetwork->getLineNumber());
468
469 m->mapNetworks[n.strNetworkName] = n;
470 }
471
472 return S_OK;
473}
474
475/**
476 * Private helper method that handles a "VirtualSystem" element in the OVF XML.
477 *
478 * @param pcszPath
479 * @param pContentElem
480 * @return
481 */
482HRESULT Appliance::HandleVirtualSystemContent(const char *pcszPath,
483 const xml::Node *pelmVirtualSystem)
484{
[16495]485 VirtualSystem vsys;
[16205]486
[16234]487 const xml::Node *pIdAttr = pelmVirtualSystem->findAttribute("id");
[16210]488 if (pIdAttr)
[16495]489 vsys.strName = pIdAttr->getValue();
[16210]490
[16205]491 xml::NodesLoop loop(*pelmVirtualSystem); // all child elements
492 const xml::Node *pelmThis;
493 while ((pelmThis = loop.forAllNodes()))
494 {
495 const char *pcszElemName = pelmThis->getName();
496 const xml::Node *pTypeAttr = pelmThis->findAttribute("type");
497 const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : "";
498
499 if (!strcmp(pcszElemName, "EulaSection"))
500 {
[16208]501 /* <EulaSection>
502 <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
503 <License ovf:msgid="1">License terms can go in here.</License>
504 </EulaSection> */
505
506 const xml::Node *pelmInfo, *pelmLicense;
507 if ( ((pelmInfo = pelmThis->findChildElement("Info")))
508 && ((pelmLicense = pelmThis->findChildElement("License")))
509 )
510 {
[16495]511 vsys.strLicenceInfo = pelmInfo->getValue();
512 vsys.strLicenceText = pelmLicense->getValue();
[16208]513 }
[16205]514 }
515 else if ( (!strcmp(pcszElemName, "VirtualHardwareSection"))
516 || (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type"))
517 )
518 {
519 const xml::Node *pelmSystem, *pelmVirtualSystemType;
520 if ((pelmSystem = pelmThis->findChildElement("System")))
521 {
522 /* <System>
523 <vssd:Description>Description of the virtual hardware section.</vssd:Description>
524 <vssd:ElementName>vmware</vssd:ElementName>
525 <vssd:InstanceID>1</vssd:InstanceID>
526 <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
527 <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
528 </System>*/
529 if ((pelmVirtualSystemType = pelmSystem->findChildElement("VirtualSystemType")))
[16495]530 vsys.strVirtualSystemType = pelmVirtualSystemType->getValue();
[16205]531 }
532
533 xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements
534 const xml::Node *pelmItem;
535 while ((pelmItem = loopVirtualHardwareItems.forAllNodes()))
536 {
537 VirtualHardwareItem i;
538
539 i.ulLineNumber = pelmItem->getLineNumber();
540
541 xml::NodesLoop loopItemChildren(*pelmItem); // all child elements
542 const xml::Node *pelmItemChild;
543 while ((pelmItemChild = loopItemChildren.forAllNodes()))
544 {
545 const char *pcszItemChildName = pelmItemChild->getName();
546 if (!strcmp(pcszItemChildName, "Description"))
547 i.strDescription = pelmItemChild->getValue();
548 else if (!strcmp(pcszItemChildName, "Caption"))
549 i.strCaption = pelmItemChild->getValue();
550 else if (!strcmp(pcszItemChildName, "ElementName"))
551 i.strElementName = pelmItemChild->getValue();
[16224]552 else if ( (!strcmp(pcszItemChildName, "InstanceID"))
553 || (!strcmp(pcszItemChildName, "InstanceId"))
554 )
[16205]555 pelmItemChild->copyValue(i.ulInstanceID);
556 else if (!strcmp(pcszItemChildName, "HostResource"))
557 i.strHostResource = pelmItemChild->getValue();
558 else if (!strcmp(pcszItemChildName, "ResourceType"))
559 {
560 int32_t iType; /** @todo how to fix correctly? (enum fun.) */
561 pelmItemChild->copyValue(iType);
562 i.resourceType = (OVFResourceType_T)iType;
563 }
564 else if (!strcmp(pcszItemChildName, "OtherResourceType"))
565 i.strOtherResourceType = pelmItemChild->getValue();
566 else if (!strcmp(pcszItemChildName, "ResourceSubType"))
567 i.strResourceSubType = pelmItemChild->getValue();
568 else if (!strcmp(pcszItemChildName, "AutomaticAllocation"))
569 i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
570 else if (!strcmp(pcszItemChildName, "AutomaticDeallocation"))
571 i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
572 else if (!strcmp(pcszItemChildName, "Parent"))
573 pelmItemChild->copyValue(i.ulParent);
574 else if (!strcmp(pcszItemChildName, "Connection"))
575 i.strConnection = pelmItemChild->getValue();
576 else if (!strcmp(pcszItemChildName, "Address"))
577 i.strAddress = pelmItemChild->getValue();
578 else if (!strcmp(pcszItemChildName, "AddressOnParent"))
579 i.strAddressOnParent = pelmItemChild->getValue();
580 else if (!strcmp(pcszItemChildName, "AllocationUnits"))
581 i.strAllocationUnits = pelmItemChild->getValue();
582 else if (!strcmp(pcszItemChildName, "VirtualQuantity"))
583 pelmItemChild->copyValue(i.ullVirtualQuantity);
584 else if (!strcmp(pcszItemChildName, "Reservation"))
585 pelmItemChild->copyValue(i.ullReservation);
586 else if (!strcmp(pcszItemChildName, "Limit"))
587 pelmItemChild->copyValue(i.ullLimit);
588 else if (!strcmp(pcszItemChildName, "Weight"))
589 pelmItemChild->copyValue(i.ullWeight);
590 else if (!strcmp(pcszItemChildName, "ConsumerVisibility"))
591 i.strConsumerVisibility = pelmItemChild->getValue();
592 else if (!strcmp(pcszItemChildName, "MappingBehavior"))
593 i.strMappingBehavior = pelmItemChild->getValue();
594 else if (!strcmp(pcszItemChildName, "PoolID"))
595 i.strPoolID = pelmItemChild->getValue();
[16224]596 else if (!strcmp(pcszItemChildName, "BusNumber"))
597 pelmItemChild->copyValue(i.ulBusNumber);
[16205]598 else
599 return setError(VBOX_E_FILE_ERROR,
600 tr("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
601 pcszPath,
602 pcszItemChildName,
603 i.ulLineNumber);
604 }
605
606 // store!
[16495]607 vsys.mapHardwareItems[i.ulInstanceID] = i;
[16205]608 }
609
610 HardwareItemsMap::const_iterator itH;
611
[16495]612 for (itH = vsys.mapHardwareItems.begin();
613 itH != vsys.mapHardwareItems.end();
[16205]614 ++itH)
615 {
616 const VirtualHardwareItem &i = itH->second;
617
618 // do some analysis
619 switch (i.resourceType)
620 {
621 case OVFResourceType_Processor: // 3
622 /* <rasd:Caption>1 virtual CPU</rasd:Caption>
623 <rasd:Description>Number of virtual CPUs</rasd:Description>
624 <rasd:ElementName>virtual CPU</rasd:ElementName>
625 <rasd:InstanceID>1</rasd:InstanceID>
626 <rasd:ResourceType>3</rasd:ResourceType>
627 <rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
628 if (i.ullVirtualQuantity < UINT16_MAX)
[16495]629 vsys.cCPUs = (uint16_t)i.ullVirtualQuantity;
[16205]630 else
631 return setError(VBOX_E_FILE_ERROR,
632 tr("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
633 pcszPath,
634 i.ullVirtualQuantity,
635 UINT16_MAX,
636 i.ulLineNumber);
637 break;
638
639 case OVFResourceType_Memory: // 4
640 if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit
641 || (i.strAllocationUnits == "MB") // found in MS docs
642 || (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21
643 )
[16495]644 vsys.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024;
[16205]645 else
646 return setError(VBOX_E_FILE_ERROR,
647 tr("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
648 pcszPath,
649 i.strAllocationUnits.c_str(),
650 i.ulLineNumber);
651 break;
652
[16228]653 case OVFResourceType_IdeController: // 5 IdeController
654 {
655 /* <Item>
656 <rasd:Caption>ideController0</rasd:Caption>
657 <rasd:Description>IDE Controller</rasd:Description>
658 <rasd:InstanceId>5</rasd:InstanceId>
659 <rasd:ResourceType>5</rasd:ResourceType>
660 <rasd:Address>0</rasd:Address>
661 <rasd:BusNumber>0</rasd:BusNumber>
662 </Item> */
663 HardDiskController hdc;
[16495]664 hdc.system = HardDiskController::IDE;
[16228]665 hdc.idController = i.ulInstanceID;
666 hdc.strAddress = i.strAddress;
667 hdc.ulBusNumber = i.ulBusNumber;
668
[16495]669 vsys.mapControllers[i.ulInstanceID] = hdc;
[16228]670 }
[16495]671 break;
[16228]672
[16205]673 case OVFResourceType_ParallelScsiHba: // 6 SCSI controller
674 {
675 /* <Item>
676 <rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
677 <rasd:Description>SCI Controller</rasd:Description>
678 <rasd:ElementName>SCSI controller</rasd:ElementName>
679 <rasd:InstanceID>4</rasd:InstanceID>
680 <rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
681 <rasd:ResourceType>6</rasd:ResourceType>
682 </Item> */
683 HardDiskController hdc;
[16495]684 hdc.system = HardDiskController::SCSI;
[16205]685 hdc.idController = i.ulInstanceID;
686 hdc.strControllerType = i.strResourceSubType;
687
[16495]688 vsys.mapControllers[i.ulInstanceID] = hdc;
[16205]689 }
690 break;
691
692 case OVFResourceType_EthernetAdapter: // 10
693 {
694 /* <Item>
695 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
696 <rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
697 <rasd:Connection>VM Network</rasd:Connection>
698 <rasd:Description>VM Network?</rasd:Description>
699 <rasd:ElementName>Ethernet adapter</rasd:ElementName>
700 <rasd:InstanceID>3</rasd:InstanceID>
701 <rasd:ResourceType>10</rasd:ResourceType>
702 </Item>
703
704 OVF spec DSP 0243 page 21:
705 "For an Ethernet adapter, this specifies the abstract network connection name
706 for the virtual machine. All Ethernet adapters that specify the same abstract
707 network connection name within an OVF package shall be deployed on the same
708 network. The abstract network connection name shall be listed in the NetworkSection
709 at the outermost envelope level." */
710
711 // make sure we have a matching NetworkSection/Network
712 NetworksMap::iterator it = m->mapNetworks.find(i.strConnection);
713 if (it == m->mapNetworks.end())
714 return setError(VBOX_E_FILE_ERROR,
715 tr("Error reading \"%s\": Invalid connection \"%s\"; cannot find matching NetworkSection/Network element, line %d"),
716 pcszPath,
717 i.strConnection.c_str(),
718 i.ulLineNumber);
719
[16495]720 vsys.llNetworkNames.push_back(i.strConnection);
[16205]721 }
722 break;
723
[16306]724 case OVFResourceType_FloppyDrive: // 14
[16495]725 vsys.fHasFloppyDrive = true; // we have no additional information
[16306]726 break;
727
728 case OVFResourceType_CdDrive: // 15
729 /* <Item ovf:required="false">
730 <rasd:Caption>cdrom1</rasd:Caption>
731 <rasd:InstanceId>7</rasd:InstanceId>
732 <rasd:ResourceType>15</rasd:ResourceType>
733 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
734 <rasd:Parent>5</rasd:Parent>
735 <rasd:AddressOnParent>0</rasd:AddressOnParent>
736 </Item> */
737 // I tried to see what happens if I set an ISO for the CD-ROM in VMware Workstation,
738 // but then the ovftool dies with "Device backing not supported". So I guess if
739 // VMware can't export ISOs, then we don't need to be able to import them right now.
[16495]740 vsys.fHasCdromDrive = true; // we have no additional information
[16306]741 break;
742
[16205]743 case OVFResourceType_HardDisk: // 17
744 {
745 /* <Item>
746 <rasd:Caption>Harddisk 1</rasd:Caption>
747 <rasd:Description>HD</rasd:Description>
748 <rasd:ElementName>Hard Disk</rasd:ElementName>
749 <rasd:HostResource>ovf://disk/lamp</rasd:HostResource>
750 <rasd:InstanceID>5</rasd:InstanceID>
751 <rasd:Parent>4</rasd:Parent>
752 <rasd:ResourceType>17</rasd:ResourceType>
753 </Item> */
754
755 // look up the hard disk controller element whose InstanceID equals our Parent;
756 // this is how the connection is specified in OVF
[16495]757 ControllersMap::const_iterator it = vsys.mapControllers.find(i.ulParent);
758 if (it == vsys.mapControllers.end())
[16205]759 return setError(VBOX_E_FILE_ERROR,
760 tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
761 pcszPath,
762 i.ulInstanceID,
763 i.ulParent,
764 i.ulLineNumber);
765 const HardDiskController &hdc = it->second;
766
767 VirtualDisk vd;
768 vd.idController = i.ulParent;
769 bool fFound = false;
770 // ovf://disk/lamp
771 // 12345678901234
772 if (i.strHostResource.substr(0, 11) == "ovf://disk/")
773 vd.strDiskId = i.strHostResource.substr(11);
[16233]774 else if (i.strHostResource.substr(0, 6) == "/disk/")
775 vd.strDiskId = i.strHostResource.substr(6);
[16205]776
[16233]777 if ( !(vd.strDiskId.length())
778 || (m->mapDisks.find(vd.strDiskId) == m->mapDisks.end())
779 )
[16205]780 return setError(VBOX_E_FILE_ERROR,
781 tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
782 pcszPath,
783 i.ulInstanceID,
784 i.strHostResource.c_str(),
785 i.ulLineNumber);
786
[16495]787 vsys.mapVirtualDisks[vd.strDiskId] = vd;
[16205]788 }
789 break;
[16306]790
791 case OVFResourceType_UsbController: // 23
792 /* <Item ovf:required="false">
793 <rasd:Caption>usb</rasd:Caption>
794 <rasd:Description>USB Controller</rasd:Description>
795 <rasd:InstanceId>3</rasd:InstanceId>
796 <rasd:ResourceType>23</rasd:ResourceType>
797 <rasd:Address>0</rasd:Address>
798 <rasd:BusNumber>0</rasd:BusNumber>
799 </Item> */
[16495]800 vsys.fHasUsbController = true; // we have no additional information
[16306]801 break;
802
803 case OVFResourceType_SoundCard: // 35
804 /* <Item ovf:required="false">
805 <rasd:Caption>sound</rasd:Caption>
806 <rasd:Description>Sound Card</rasd:Description>
807 <rasd:InstanceId>10</rasd:InstanceId>
808 <rasd:ResourceType>35</rasd:ResourceType>
809 <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
810 <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
811 <rasd:AddressOnParent>3</rasd:AddressOnParent>
812 </Item> */
[16495]813 vsys.strSoundCardType = i.strResourceSubType;
[16306]814 break;
815
816 default:
817 return setError(VBOX_E_FILE_ERROR,
818 tr("Error reading \"%s\": Unknown resource type %d in hardware item, line %d"),
819 pcszPath,
820 i.resourceType,
821 i.ulLineNumber);
[16205]822 }
823 }
824 }
825 else if ( (!strcmp(pcszElemName, "OperatingSystemSection"))
826 || (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type"))
827 )
828 {
829 uint64_t cimos64;
830 if (!(pelmThis->getAttributeValue("id", cimos64)))
831 return setError(VBOX_E_FILE_ERROR,
832 tr("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
833 pcszPath,
834 pelmThis->getLineNumber());
835
[16495]836 vsys.cimos = (CIMOSType_T)cimos64;
[16205]837 }
838 }
839
840 // now create the virtual system
[16495]841 m->llVirtualSystems.push_back(vsys);
[16205]842
843 return S_OK;
844}
845
846// IAppliance public methods
847////////////////////////////////////////////////////////////////////////////////
848
849/**
850 * Appliance initializer.
851 *
852 * This loads the given appliance.
853 * @param
854 * @return
855 */
856
[16234]857HRESULT Appliance::init(VirtualBox *aVirtualBox, IN_BSTR &path)
[16205]858{
859 HRESULT rc;
860
861 /* Enclose the state transition NotReady->InInit->Ready */
862 AutoInitSpan autoInitSpan(this);
[16234]863 AssertReturn(autoInitSpan.isOk(), E_FAIL);
[16205]864
[16218]865 /* Weakly reference to a VirtualBox object */
[16234]866 unconst(mVirtualBox) = aVirtualBox;
[16218]867
[16205]868 // initialize data
869 m = new Data;
870 m->bstrPath = path;
871
872 // see if we can handle this file; for now we insist it has an ".ovf" extension
873 Utf8Str utf8Path(path);
874 const char *pcszLastDot = strrchr(utf8Path, '.');
875 if ( (!pcszLastDot)
876 || ( strcmp(pcszLastDot, ".ovf")
877 && strcmp(pcszLastDot, ".OVF")
878 )
879 )
880 return setError(VBOX_E_FILE_ERROR,
881 tr("Appliance file must have .ovf extension"));
882
883 try
884 {
885 xml::XmlFileParser parser;
886 xml::Document doc;
887 parser.read(utf8Path.raw(),
888 doc);
889
890 const xml::Node *pRootElem = doc.getRootElement();
891 if (strcmp(pRootElem->getName(), "Envelope"))
892 return setError(VBOX_E_FILE_ERROR,
893 tr("Root element in OVF file must be \"Envelope\"."));
894
895 // OVF has the following rough layout:
896 /*
897 -- <References> .... files referenced from other parts of the file, such as VMDK images
898 -- Metadata, comprised of several section commands
899 -- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
900 -- optionally <Strings> for localization
901 */
902
903 // get all "File" child elements of "References" section so we can look up files easily;
904 // first find the "References" sections so we can look up files
905 xml::NodesList listFileElements; // receives all /Envelope/References/File nodes
906 const xml::Node *pReferencesElem;
907 if ((pReferencesElem = pRootElem->findChildElement("References")))
908 pReferencesElem->getChildElements(listFileElements, "File");
909
910 // now go though the sections
911 if (!(SUCCEEDED(rc = LoopThruSections(utf8Path.raw(), pReferencesElem, pRootElem))))
912 return rc;
913 }
914 catch(xml::Error &x)
915 {
916 return setError(VBOX_E_FILE_ERROR,
917 x.what());
918 }
919
920 /* Confirm a successful initialization */
921 autoInitSpan.setSucceeded();
922
923 return S_OK;
924}
925
926void Appliance::uninit()
927{
928 delete m;
929 m = NULL;
930}
931
932STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
933{
934 if (!aPath)
935 return E_POINTER;
936
937 AutoCaller autoCaller(this);
938 CheckComRCReturnRC(autoCaller.rc());
939
940 AutoReadLock alock(this);
941
942 m->bstrPath.cloneTo(aPath);
943
944 return S_OK;
945}
946
[16248]947STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
[16205]948{
949 CheckComArgOutSafeArrayPointerValid(aDisks);
950
951 AutoCaller autoCaller(this);
952 CheckComRCReturnRC(autoCaller.rc());
953
954 AutoReadLock alock(this);
955
956 size_t c = m->mapDisks.size();
957 com::SafeArray<BSTR> sfaDisks(c);
958
959 DiskImagesMap::const_iterator it;
960 size_t i = 0;
961 for (it = m->mapDisks.begin();
962 it != m->mapDisks.end();
963 ++it, ++i)
964 {
965 // create a string representing this disk
966 const DiskImage &d = it->second;
967 char *psz = NULL;
968 RTStrAPrintf(&psz,
969 "%s\t"
970 "%RI64\t"
971 "%RI64\t"
972 "%s\t"
973 "%s\t"
974 "%RI64\t"
975 "%RI64\t"
976 "%s",
977 d.strDiskId.c_str(),
978 d.iCapacity,
979 d.iPopulatedSize,
980 d.strFormat.c_str(),
981 d.strHref.c_str(),
982 d.iSize,
983 d.iChunkSize,
984 d.strCompression.c_str());
985 Utf8Str utf(psz);
986 Bstr bstr(utf);
987 // push to safearray
988 bstr.cloneTo(&sfaDisks[i]);
989 RTStrFree(psz);
990 }
991
992 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
993
994 return S_OK;
995}
996
[16209]997STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
[16205]998{
[16234]999 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
[16205]1000
[16234]1001 AutoCaller autoCaller(this);
1002 CheckComRCReturnRC(autoCaller.rc());
[16205]1003
[16234]1004 AutoReadLock alock(this);
[16205]1005
[16234]1006 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
1007 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
[16205]1008
1009 return S_OK;
1010}
1011
[16495]1012void convertCIMOSType2VBoxOSType(Utf8Str &osTypeVBox, CIMOSType_T c)
[16205]1013{
[16495]1014 switch (c)
1015 {
1016 case CIMOSType_CIMOS_Unknown: // 0 - Unknown
1017 osTypeVBox = SchemaDefs_OSTypeId_Other;
1018 break;
[16205]1019
[16495]1020 case CIMOSType_CIMOS_OS2: // 12 - OS/2
1021 osTypeVBox = SchemaDefs_OSTypeId_OS2;
1022 break;
[16218]1023
[16495]1024 case CIMOSType_CIMOS_MSDOS: // 14 - MSDOS
1025 osTypeVBox = SchemaDefs_OSTypeId_DOS;
1026 break;
[16205]1027
[16495]1028 case CIMOSType_CIMOS_WIN3x: // 15 - WIN3x
1029 osTypeVBox = SchemaDefs_OSTypeId_Windows31;
1030 break;
[16205]1031
[16495]1032 case CIMOSType_CIMOS_WIN95: // 16 - WIN95
1033 osTypeVBox = SchemaDefs_OSTypeId_Windows95;
1034 break;
[16205]1035
[16495]1036 case CIMOSType_CIMOS_WIN98: // 17 - WIN98
1037 osTypeVBox = SchemaDefs_OSTypeId_Windows98;
1038 break;
[16205]1039
[16495]1040 case CIMOSType_CIMOS_WINNT: // 18 - WINNT
1041 osTypeVBox = SchemaDefs_OSTypeId_WindowsNT4;
1042 break;
[16205]1043
[16495]1044 case CIMOSType_CIMOS_NetWare: // 21 - NetWare
1045 case CIMOSType_CIMOS_NovellOES: // 86 - Novell OES
1046 osTypeVBox = SchemaDefs_OSTypeId_Netware;
1047 break;
[16205]1048
[16495]1049 case CIMOSType_CIMOS_Solaris: // 29 - Solaris
1050 case CIMOSType_CIMOS_SunOS: // 30 - SunOS
1051 osTypeVBox = SchemaDefs_OSTypeId_Solaris;
1052 break;
[16205]1053
[16495]1054 case CIMOSType_CIMOS_FreeBSD: // 42 - FreeBSD
1055 osTypeVBox = SchemaDefs_OSTypeId_FreeBSD;
1056 break;
[16205]1057
[16495]1058 case CIMOSType_CIMOS_NetBSD: // 43 - NetBSD
1059 osTypeVBox = SchemaDefs_OSTypeId_NetBSD;
1060 break;
[16205]1061
[16495]1062 case CIMOSType_CIMOS_QNX: // 48 - QNX
1063 osTypeVBox = SchemaDefs_OSTypeId_QNX;
1064 break;
[16205]1065
[16495]1066 case CIMOSType_CIMOS_Windows2000: // 58 - Windows 2000
1067 osTypeVBox = SchemaDefs_OSTypeId_Windows2000;
1068 break;
[16205]1069
[16495]1070 case CIMOSType_CIMOS_WindowsMe: // 63 - Windows (R) Me
1071 osTypeVBox = SchemaDefs_OSTypeId_WindowsMe;
1072 break;
[16205]1073
[16495]1074 case CIMOSType_CIMOS_OpenBSD: // 65 - OpenBSD
1075 osTypeVBox = SchemaDefs_OSTypeId_OpenBSD;
1076 break;
[16205]1077
[16495]1078 case CIMOSType_CIMOS_WindowsXP: // 67 - Windows XP
1079 case CIMOSType_CIMOS_WindowsXPEmbedded: // 72 - Windows XP Embedded
1080 case CIMOSType_CIMOS_WindowsEmbeddedforPointofService: // 75 - Windows Embedded for Point of Service
1081 osTypeVBox = SchemaDefs_OSTypeId_WindowsXP;
1082 break;
[16205]1083
[16495]1084 case CIMOSType_CIMOS_MicrosoftWindowsServer2003: // 69 - Microsoft Windows Server 2003
1085 osTypeVBox = SchemaDefs_OSTypeId_Windows2003;
1086 break;
[16205]1087
[16495]1088 case CIMOSType_CIMOS_MicrosoftWindowsServer2003_64: // 70 - Microsoft Windows Server 2003 64-Bit
1089 osTypeVBox = SchemaDefs_OSTypeId_Windows2003_64;
1090 break;
[16205]1091
[16495]1092 case CIMOSType_CIMOS_WindowsXP_64: // 71 - Windows XP 64-Bit
1093 osTypeVBox = SchemaDefs_OSTypeId_WindowsXP_64;
1094 break;
[16205]1095
[16495]1096 case CIMOSType_CIMOS_WindowsVista: // 73 - Windows Vista
1097 osTypeVBox = SchemaDefs_OSTypeId_WindowsVista;
1098 break;
[16205]1099
[16495]1100 case CIMOSType_CIMOS_WindowsVista_64: // 74 - Windows Vista 64-Bit
1101 osTypeVBox = SchemaDefs_OSTypeId_WindowsVista_64;
1102 break;
[16205]1103
[16495]1104 case CIMOSType_CIMOS_MicrosoftWindowsServer2008: // 76 - Microsoft Windows Server 2008
1105 osTypeVBox = SchemaDefs_OSTypeId_Windows2008;
1106 break;
[16205]1107
[16495]1108 case CIMOSType_CIMOS_MicrosoftWindowsServer2008_64: // 77 - Microsoft Windows Server 2008 64-Bit
1109 osTypeVBox = SchemaDefs_OSTypeId_Windows2008_64;
1110 break;
[16205]1111
[16495]1112 case CIMOSType_CIMOS_FreeBSD_64: // 78 - FreeBSD 64-Bit
1113 osTypeVBox = SchemaDefs_OSTypeId_FreeBSD_64;
1114 break;
[16205]1115
[16495]1116 case CIMOSType_CIMOS_RedHatEnterpriseLinux: // 79 - RedHat Enterprise Linux
1117 osTypeVBox = SchemaDefs_OSTypeId_RedHat;
1118 break;
[16205]1119
[16495]1120 case CIMOSType_CIMOS_RedHatEnterpriseLinux_64: // 80 - RedHat Enterprise Linux 64-Bit
1121 osTypeVBox = SchemaDefs_OSTypeId_RedHat_64;
1122 break;
[16205]1123
[16495]1124 case CIMOSType_CIMOS_Solaris_64: // 81 - Solaris 64-Bit
1125 osTypeVBox = SchemaDefs_OSTypeId_Solaris_64;
1126 break;
[16205]1127
[16495]1128 case CIMOSType_CIMOS_SUSE: // 82 - SUSE
1129 case CIMOSType_CIMOS_SLES: // 84 - SLES
1130 case CIMOSType_CIMOS_NovellLinuxDesktop: // 87 - Novell Linux Desktop
1131 osTypeVBox = SchemaDefs_OSTypeId_OpenSUSE;
1132 break;
[16205]1133
[16495]1134 case CIMOSType_CIMOS_SUSE_64: // 83 - SUSE 64-Bit
1135 case CIMOSType_CIMOS_SLES_64: // 85 - SLES 64-Bit
1136 osTypeVBox = SchemaDefs_OSTypeId_OpenSUSE_64;
1137 break;
[16205]1138
[16495]1139 case CIMOSType_CIMOS_LINUX: // 36 - LINUX
1140 case CIMOSType_CIMOS_SunJavaDesktopSystem: // 88 - Sun Java Desktop System
1141 case CIMOSType_CIMOS_TurboLinux: // 91 - TurboLinux
1142 osTypeVBox = SchemaDefs_OSTypeId_Linux;
1143 break;
[16205]1144
[16495]1145 // case CIMOSType_CIMOS_TurboLinux_64: // 92 - TurboLinux 64-Bit
1146 // case CIMOSType_CIMOS_Linux_64: // 101 - Linux 64-Bit
1147 // osTypeVBox = VBOXOSTYPE_Linux_x64;
1148 // break;
[16205]1149
[16495]1150 case CIMOSType_CIMOS_Mandriva: // 89 - Mandriva
1151 osTypeVBox = SchemaDefs_OSTypeId_Mandriva;
1152 break;
[16205]1153
[16495]1154 case CIMOSType_CIMOS_Mandriva_64: // 90 - Mandriva 64-Bit
1155 osTypeVBox = SchemaDefs_OSTypeId_Mandriva_64;
1156 break;
[16205]1157
[16495]1158 case CIMOSType_CIMOS_Ubuntu: // 93 - Ubuntu
1159 osTypeVBox = SchemaDefs_OSTypeId_Ubuntu;
1160 break;
[16205]1161
[16495]1162 case CIMOSType_CIMOS_Ubuntu_64: // 94 - Ubuntu 64-Bit
1163 osTypeVBox = SchemaDefs_OSTypeId_Ubuntu_64;
1164 break;
[16205]1165
[16495]1166 case CIMOSType_CIMOS_Debian: // 95 - Debian
1167 osTypeVBox = SchemaDefs_OSTypeId_Debian;
1168 break;
[16205]1169
[16495]1170 case CIMOSType_CIMOS_Debian_64: // 96 - Debian 64-Bit
1171 osTypeVBox = SchemaDefs_OSTypeId_Debian_64;
1172 break;
[16205]1173
[16495]1174 case CIMOSType_CIMOS_Linux_2_4_x: // 97 - Linux 2.4.x
1175 osTypeVBox = SchemaDefs_OSTypeId_Linux24;
1176 break;
[16205]1177
[16495]1178 case CIMOSType_CIMOS_Linux_2_4_x_64: // 98 - Linux 2.4.x 64-Bit
1179 osTypeVBox = SchemaDefs_OSTypeId_Linux24_64;
1180 break;
[16205]1181
[16495]1182 case CIMOSType_CIMOS_Linux_2_6_x: // 99 - Linux 2.6.x
1183 osTypeVBox = SchemaDefs_OSTypeId_Linux26;
1184 break;
[16205]1185
[16495]1186 case CIMOSType_CIMOS_Linux_2_6_x_64: // 100 - Linux 2.6.x 64-Bit
1187 osTypeVBox = SchemaDefs_OSTypeId_Linux26_64;
1188 break;
1189 default:
1190 {
[16503]1191 /* If we are here we have no clue what OS this should be. Set
1192 to other type as default. */
[16495]1193 osTypeVBox = SchemaDefs_OSTypeId_Other;
1194 }
1195 }
1196}
[16205]1197
[16495]1198STDMETHODIMP Appliance::Interpret()
1199{
1200 // @todo:
1201 // - Locking
1202 // - COM error handling
1203 // - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk2))
1204 // - Appropriate handle errors like not supported file formats
1205 AutoCaller autoCaller(this);
1206 CheckComRCReturnRC(autoCaller.rc());
[16205]1207
[16503]1208 AutoWriteLock(this);
1209
[16495]1210 HRESULT rc = S_OK;
[16205]1211
[16495]1212 /* Clear any previous virtual system descriptions */
1213 // @todo: have the entries deleted also?
1214 m->virtualSystemDescriptions.clear();
[16205]1215
[16495]1216 /* We need the default path for storing disk images */
1217 ComPtr<ISystemProperties> systemProps;
1218 rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
[16503]1219 CheckComRCReturnRC(rc);
[16495]1220 Bstr bstrDefaultHardDiskLocation;
1221 rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskLocation.asOutParam());
[16503]1222 CheckComRCReturnRC(rc);
[16205]1223
[16503]1224 try
[16495]1225 {
[16503]1226 list<VirtualSystem>::const_iterator it;
1227 /* Iterate through all appliances */
1228 for (it = m->llVirtualSystems.begin();
1229 it != m->llVirtualSystems.end();
1230 ++it)
1231 {
1232 const VirtualSystem &vsysThis = *it;
[16205]1233
[16503]1234 ComObjPtr<VirtualSystemDescription> pNewDesc;
1235 rc = pNewDesc.createObject();
1236 CheckComRCThrowRC(rc);
1237 rc = pNewDesc->init();
1238 CheckComRCThrowRC(rc);
[16495]1239
[16503]1240 /* Guest OS type */
1241 Utf8Str strOsTypeVBox,
1242 strCIMOSType = toString<ULONG>(vsysThis.cimos);
1243 convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos);
1244 pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
[16515]1245 "",
[16503]1246 strCIMOSType,
1247 strOsTypeVBox);
[16495]1248
[16503]1249 /* VM name */
1250 /* If the there isn't any name specified create a default one out of
1251 * the OS type */
1252 Utf8Str nameVBox = vsysThis.strName;
1253 if (nameVBox == "")
1254 nameVBox = strOsTypeVBox;
1255 searchUniqueVMName(nameVBox);
1256 pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
[16515]1257 "",
[16503]1258 vsysThis.strName,
1259 nameVBox);
[16218]1260
[16503]1261 /* Now that we know the OS type, get our internal defaults based on that. */
1262 ComPtr<IGuestOSType> pGuestOSType;
1263 rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), pGuestOSType.asOutParam());
[16234]1264 ComAssertComRCThrowRC(rc);
[16205]1265
[16503]1266 /* CPU count */
1267 /* @todo: check min/max requirements of VBox (SchemaDefs::Min/MaxCPUCount) */
1268 ULONG cpuCountVBox = vsysThis.cCPUs;
1269 if (vsysThis.cCPUs == 0)
1270 cpuCountVBox = 1;
1271 pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
[16515]1272 "",
[16503]1273 toString<ULONG>(vsysThis.cCPUs),
1274 toString<ULONG>(cpuCountVBox));
[16360]1275
[16503]1276 /* RAM */
1277 /* @todo: check min/max requirements of VBox (SchemaDefs::Min/MaxGuestRAM) */
1278 uint64_t ullMemSizeVBox = vsysThis.ullMemorySize;
1279 if (vsysThis.ullMemorySize == 0)
[16360]1280 {
[16503]1281 /* If the RAM of the OVF is zero, use our predefined values */
1282 ULONG memSizeVBox2;
1283 rc = pGuestOSType->COMGETTER(RecommendedRAM)(&memSizeVBox2);
1284 ComAssertComRCThrowRC(rc);
1285 /* VBox stores that in MByte */
1286 ullMemSizeVBox = (uint64_t)memSizeVBox2 * _1M;
[16360]1287 }
[16503]1288 pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
[16515]1289 "",
[16503]1290 toString<uint64_t>(vsysThis.ullMemorySize),
1291 toString<uint64_t>(ullMemSizeVBox));
[16360]1292
[16503]1293 /* Audio */
1294 if (!vsysThis.strSoundCardType.isNull())
1295 /* Currently we set the AC97 always.
1296 @todo: figure out the hardware which could be possible */
1297 pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
[16515]1298 "",
[16503]1299 vsysThis.strSoundCardType,
1300 "");
[16360]1301
[16503]1302 /* USB Controller */
1303 if (vsysThis.fHasUsbController)
[16515]1304 pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
[16360]1305
[16503]1306 /* Network Controller */
1307 // @todo: there is no hardware specification in the OVF file; supposedly the
1308 // hardware will then be determined by the VirtualSystemType element (e.g. "vmx-07")
1309 if (vsysThis.llNetworkNames.size() > 0)
[16205]1310 {
[16503]1311 /* Get the default network adapter type for the selected guest OS */
1312 NetworkAdapterType_T nwAdapterVBox = NetworkAdapterType_Am79C970A;
1313 rc = pGuestOSType->COMGETTER(AdapterType)(&nwAdapterVBox);
1314 ComAssertComRCThrowRC(rc);
1315 list<Utf8Str>::const_iterator nwIt;
1316 /* Iterate through all abstract networks. We support 8 network
1317 * adapters at the maximum. (@todo: warn if it are more!) */
1318 size_t a = 0;
1319 for (nwIt = vsysThis.llNetworkNames.begin();
1320 nwIt != vsysThis.llNetworkNames.end() && a < SchemaDefs::NetworkAdapterCount;
1321 ++nwIt, ++a)
[16495]1322 {
[16503]1323 Utf8Str nwController = *nwIt; // @todo: not used yet
[16515]1324 pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter, "", "", toString<ULONG>(nwAdapterVBox));
[16495]1325 }
[16503]1326 }
[16495]1327
[16503]1328 /* Floppy Drive */
1329 if (vsysThis.fHasFloppyDrive)
[16515]1330 pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy, "", "", "");
[16503]1331
1332 /* CD Drive */
1333 if (vsysThis.fHasCdromDrive)
[16515]1334 pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");
[16503]1335
1336 /* Hard disk Controller */
1337 ControllersMap::const_iterator hdcIt;
1338 /* Iterate through all hard disk controllers */
1339 for (hdcIt = vsysThis.mapControllers.begin();
1340 hdcIt != vsysThis.mapControllers.end();
1341 ++hdcIt)
1342 {
1343 const HardDiskController &hdc = hdcIt->second;
[16515]1344 Utf8Str strControllerID = toString<uint32_t>(hdc.idController);
1345
[16503]1346 switch (hdc.system)
[16495]1347 {
[16503]1348 case HardDiskController::IDE:
1349 {
1350 // @todo: figure out the IDE types
1351 /* Use PIIX4 as default */
[16515]1352// IDEControllerType_T hdcController = IDEControllerType_PIIX4;
1353 Utf8Str strType = "PIIX4";
[16503]1354 if (!RTStrICmp(hdc.strControllerType.c_str(), "PIIX3"))
[16515]1355 strType = "PIIX3";
1356// else // if (!RTStrICmp(hdc.strControllerType.c_str(), "PIIX4"))
1357// hdcController = IDEControllerType_PIIX4;
[16503]1358 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
[16515]1359 strControllerID,
[16503]1360 hdc.strControllerType,
[16515]1361 strType);
[16503]1362 break;
1363 }
[16495]1364
[16503]1365 case HardDiskController::SATA:
1366 {
1367 // @todo: figure out the SATA types
1368 /* We only support a plain AHCI controller, so use them always */
1369 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
[16515]1370 strControllerID,
[16503]1371 hdc.strControllerType,
1372 "AHCI");
1373 break;
1374 }
1375
1376 case HardDiskController::SCSI:
1377 {
1378 // @todo: figure out the SCSI types
1379 Utf8Str hdcController = "LsiLogic";
[16515]1380 /* if (!RTStrICmp(hdc.strControllerType.c_str(), "LsiLogic"))
[16503]1381 hdcController = "LsiLogic";
[16515]1382 else*/
1383 if (!RTStrICmp(hdc.strControllerType.c_str(), "BusLogic"))
[16503]1384 hdcController = "BusLogic";
1385 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
[16515]1386 strControllerID,
[16503]1387 hdc.strControllerType,
1388 hdcController);
1389 break;
1390 }
[16495]1391 }
[16205]1392 }
1393
[16503]1394 /* Hard disks */
1395 if (vsysThis.mapVirtualDisks.size() > 0)
[16205]1396 {
1397 // @todo:
[16503]1398 // - strHref could be empty (construct a new default file name)
1399 // - check that the filename is unique to vbox in any case
[16515]1400 VirtualDisksMap::const_iterator itVD;
[16503]1401 /* Iterate through all hard disks ()*/
[16515]1402 for (itVD = vsysThis.mapVirtualDisks.begin();
1403 itVD != vsysThis.mapVirtualDisks.end();
1404 ++itVD)
[16205]1405 {
[16515]1406 const VirtualDisk &hd = itVD->second;
[16503]1407 /* Get the associated disk image */
1408 const DiskImage &di = m->mapDisks[hd.strDiskId];
1409
1410 // @todo:
1411 // - figure out all possible vmdk formats we also support
1412 // - figure out if there is a url specifier for vhd already
1413 // - we need a url specifier for the vdi format
1414 if ( (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#sparse"))
[16515]1415 || (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#compressed"))
[16503]1416 )
1417 {
[16515]1418 // construct a unique target path
1419 Utf8StrFmt strPath("%ls%c%s",
1420 bstrDefaultHardDiskLocation.raw(),
1421 RTPATH_DELIMITER,
1422 di.strHref.c_str());
1423 searchUniqueDiskImageFilePath(strPath);
1424
1425 // find the description for the hard disk controller that has the
1426 // same ID as hd.idController
1427 const VirtualSystemDescriptionEntry *pController;
1428 if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
1429 throw setError(E_FAIL,
1430 tr("Internal inconsistency looking up hard disk controller."));
1431
1432 // controller to attach to @todo bus?
1433 Utf8StrFmt strExtraConfig("controller=%RI16",
1434 pController->ulIndex);
[16503]1435 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
[16517]1436 hd.strDiskId,
[16503]1437 di.strHref,
[16515]1438 strPath,
1439 strExtraConfig);
[16503]1440 }
[16205]1441 }
1442 }
[16503]1443
1444 m->virtualSystemDescriptions.push_back(pNewDesc);
[16205]1445 }
[16503]1446 }
1447 catch (HRESULT aRC)
1448 {
1449 /* On error we clear the list & return */
1450 //m->virtualSystemDescriptions.clear();
1451 rc = aRC;
1452 }
[16205]1453
[16503]1454 return rc;
1455}
1456
1457STDMETHODIMP Appliance::ImportAppliance(IProgress **aProgress)
1458{
1459 CheckComArgOutPointerValid(aProgress);
1460
1461 AutoCaller autoCaller(this);
1462 CheckComRCReturnRC(autoCaller.rc());
1463
1464 AutoReadLock(this);
1465
1466 HRESULT rc = S_OK;
1467
1468 ComObjPtr<Progress> progress;
1469
1470 try
1471 {
1472 /* Create the progress object */
1473 progress.createObject();
1474 rc = progress->init(mVirtualBox, static_cast<IAppliance *>(this),
1475 BstrFmt(tr("Import appliance '%ls'"),
1476 m->bstrPath.raw()),
1477 FALSE /* aCancelable */);
1478 CheckComRCThrowRC(rc);
1479
1480 /* Initialize our worker task */
1481 std::auto_ptr<Task> task(new Task(this, progress));
1482 //AssertComRCThrowRC (task->autoCaller.rc());
1483
1484 rc = task->startThread();
1485 CheckComRCThrowRC(rc);
1486
1487 task.release();
[16205]1488 }
[16503]1489 catch (HRESULT aRC)
1490 {
1491 rc = aRC;
1492 }
[16205]1493
[16503]1494 if (SUCCEEDED(rc))
1495 /* Return progress to the caller */
1496 progress.queryInterfaceTo(aProgress);
1497
1498 return rc;
1499}
1500
1501HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
1502{
1503 IMachine *machine = NULL;
1504 char *tmpName = RTStrDup(aName.c_str());
1505 int i = 1;
[16517]1506 /* @todo: Maybe too cost-intensive; try to find a lighter way */
[16503]1507 while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
1508 {
1509 RTStrFree(tmpName);
1510 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
1511 ++i;
1512 }
1513 aName = tmpName;
1514 RTStrFree(tmpName);
1515
[16205]1516 return S_OK;
1517}
1518
[16503]1519HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
[16248]1520{
[16503]1521 IHardDisk2 *harddisk = NULL;
1522 char *tmpName = RTStrDup(aName.c_str());
1523 int i = 1;
1524 /* Check if the file exists or if a file with this path is registered
1525 * already */
[16517]1526 /* @todo: Maybe too cost-intensive; try to find a lighter way */
[16503]1527 while (RTPathExists(tmpName) ||
1528 mVirtualBox->FindHardDisk2(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
1529 {
1530 RTStrFree(tmpName);
1531 char *tmpDir = RTStrDup(aName.c_str());
1532 RTPathStripFilename(tmpDir);;
1533 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
1534 RTPathStripExt(tmpFile);
[16517]1535 const char *tmpExt = RTPathExt(aName.c_str());
[16518]1536 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
[16503]1537 RTStrFree(tmpFile);
1538 RTStrFree(tmpDir);
1539 ++i;
1540 }
1541 aName = tmpName;
1542 RTStrFree(tmpName);
1543
1544 return S_OK;
1545}
1546
1547/* static */
1548DECLCALLBACK(int) Appliance::taskThread(RTTHREAD aThread, void *pvUser)
1549{
1550 std::auto_ptr <Task> task(static_cast<Task *>(pvUser));
1551 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
1552
1553 Appliance *app = task->that;
1554
1555 /// @todo ugly hack, fix ComAssert... (same as in HardDisk2::taskThread)
1556 #define setError app->setError
1557
1558 AutoCaller autoCaller(app);
[16298]1559 CheckComRCReturnRC(autoCaller.rc());
1560
[16503]1561 AutoWriteLock appLock(app);
1562
[16248]1563 HRESULT rc = S_OK;
1564
[16503]1565 /* For now we report 2 steps for every virtual system. Later we may add the
1566 progress of the image cloning. */
[16560]1567 float opCountMax = (float)100.0 / (app->m->llVirtualSystems.size() * 2);
[16503]1568 uint32_t opCount = 0;
1569
[16248]1570 list<VirtualSystem>::const_iterator it;
1571 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
[16298]1572 /* Iterate through all virtual systems of that appliance */
[16248]1573 size_t i = 0;
[16503]1574 for (it = app->m->llVirtualSystems.begin(),
1575 it1 = app->m->virtualSystemDescriptions.begin();
1576 it != app->m->llVirtualSystems.end();
[16248]1577 ++it, ++it1, ++i)
1578 {
[16495]1579 const VirtualSystem &vsysThis = *it;
1580 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it1);
[16248]1581
[16503]1582 /* Catch possible errors */
1583 try
1584 {
1585 /* Guest OS type */
1586 std::list<VirtualSystemDescriptionEntry*> vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
1587 Assert(vsdeOS.size() == 1);
[16517]1588 const Utf8Str &strOsTypeVBox = vsdeOS.front()->strConfig;
[16248]1589
[16503]1590 /* Now that we know the base system get our internal defaults based on that. */
1591 ComPtr<IGuestOSType> osType;
[16517]1592 rc = app->mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam());
[16503]1593 CheckComRCThrowRC(rc);
[16248]1594
[16503]1595 /* Create the machine */
1596 /* First get the name */
1597 std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
1598 Assert(vsdeName.size() == 1);
[16517]1599 const Utf8Str &strNameVBox = vsdeName.front()->strConfig;
1600 ComPtr<IMachine> pNewMachine;
1601 rc = app->mVirtualBox->CreateMachine(Bstr(strNameVBox), Bstr(strOsTypeVBox),
[16503]1602 Bstr(), Guid(),
[16517]1603 pNewMachine.asOutParam());
[16503]1604 CheckComRCThrowRC(rc);
[16248]1605
[16503]1606 /* CPU count (ignored for now) */
1607 /* @todo: check min/max requirements of VBox (SchemaDefs::Min/MaxCPUCount) */
1608 // EntriesList vsdeCPU = vsd->findByType (VirtualSystemDescriptionType_CPU);
[16248]1609
[16503]1610 /* RAM */
1611 /* @todo: check min/max requirements of VBox (SchemaDefs::Min/MaxGuestRAM) */
1612 std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
1613 Assert(vsdeRAM.size() == 1);
1614 const Utf8Str &memoryVBox = vsdeRAM.front()->strConfig;
[16560]1615 ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str()) / _1M;
[16248]1616
[16517]1617 rc = pNewMachine->COMSETTER(MemorySize)(tt);
[16503]1618 CheckComRCThrowRC(rc);
[16248]1619
[16503]1620 /* VRAM */
1621 /* Get the recommended VRAM for this guest OS type */
1622 /* @todo: check min/max requirements of VBox (SchemaDefs::Min/MaxGuestVRAM) */
1623 ULONG vramVBox;
1624 rc = osType->COMGETTER(RecommendedVRAM)(&vramVBox);
1625 CheckComRCThrowRC(rc);
1626 /* Set the VRAM */
[16517]1627 rc = pNewMachine->COMSETTER(VRAMSize)(vramVBox);
[16503]1628 CheckComRCThrowRC(rc);
[16248]1629
[16503]1630 /* Audio Adapter */
1631 std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
1632 /* @todo: we support one audio adapter only */
1633 if (vsdeAudioAdapter.size() > 0)
[16360]1634 {
[16503]1635 const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strConfig;
1636 if (RTStrICmp(audioAdapterVBox, "null") != 0)
1637 {
1638 uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str());
1639 ComPtr<IAudioAdapter> audioAdapter;
[16517]1640 rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
[16503]1641 CheckComRCThrowRC(rc);
1642 rc = audioAdapter->COMSETTER(Enabled)(true);
1643 CheckComRCThrowRC(rc);
1644 /* @todo: For now this is preselected, but on Linux for example
1645 more drivers are possible. The user should be able to change
1646 this also. */
1647 AudioDriverType_T adt = AudioDriverType_Null;
[16360]1648#if defined(RT_OS_WINDOWS)
1649# ifdef VBOX_WITH_WINMM
[16503]1650 adt = AudioDriverType_WinMM;
[16360]1651# else
[16503]1652 adt = AudioDriverType_DirectSound;
[16360]1653# endif
1654#elif defined(RT_OS_LINUX)
1655# ifdef VBOX_WITH_ALSA
[16503]1656 adt = AudioDriverType_ALSA;
[16360]1657# elif defined(VBOX_WITH_PULSE)
[16503]1658 adt = AudioDriverType_Pulse;
[16360]1659# else
[16503]1660 adt = AudioDriverType_OSS;
[16360]1661# endif
1662#elif defined(RT_OS_DARWIN)
[16503]1663 adt = AudioDriverType_CoreAudio;
[16360]1664#elif defined(RT_OS_SOLARIS)
[16503]1665 adt = AudioDriverType_SolAudio;
[16360]1666#elif defined(RT_OS_OS2)
[16503]1667 adt = AudioDriverType_MMPM;
[16360]1668#endif
[16503]1669 rc = audioAdapter->COMSETTER(AudioDriver)(adt);
1670 CheckComRCThrowRC(rc);
1671 rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio));
1672 CheckComRCThrowRC(rc);
1673 }
[16360]1674 }
1675
[16503]1676 /* USB Controller */
1677 std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
[16517]1678 // USB support is enabled if there's at least one such entry; to disable USB support,
1679 // the type of the USB item would have been changed to "ignore"
[16503]1680 bool fUSBEnabled = vsdeUSBController.size() > 0;
[16517]1681
[16503]1682 ComPtr<IUSBController> usbController;
[16517]1683 rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
[16503]1684 CheckComRCThrowRC(rc);
1685 rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
1686 CheckComRCThrowRC(rc);
[16360]1687
[16503]1688 /* Change the network adapters */
1689 std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
1690 if (vsdeNW.size() == 0)
[16248]1691 {
[16503]1692 /* No network adapters, so we have to disable our default one */
[16298]1693 ComPtr<INetworkAdapter> nwVBox;
[16517]1694 rc = pNewMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
[16503]1695 CheckComRCThrowRC(rc);
1696 rc = nwVBox->COMSETTER(Enabled)(false);
1697 CheckComRCThrowRC(rc);
[16248]1698 }
[16503]1699 else
1700 {
1701 list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
1702 /* Iterate through all network cards. We support 8 network adapters
[16517]1703 * at the maximum. (@todo: warn if there are more!) */
[16503]1704 size_t a = 0;
1705 for (nwIt = vsdeNW.begin();
1706 (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
1707 ++nwIt, ++a)
1708 {
1709 const Utf8Str &nwTypeVBox = (*nwIt)->strConfig;
1710 uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
1711 ComPtr<INetworkAdapter> nwVBox;
[16517]1712 rc = pNewMachine->GetNetworkAdapter((ULONG)a, nwVBox.asOutParam());
[16503]1713 CheckComRCThrowRC(rc);
1714 /* Enable the network card & set the adapter type */
1715 /* NAT is set as default */
1716 rc = nwVBox->COMSETTER(Enabled)(true);
1717 CheckComRCThrowRC(rc);
1718 rc = nwVBox->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
1719 CheckComRCThrowRC(rc);
1720 }
1721 }
[16298]1722
[16503]1723 /* Floppy drive */
1724 std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
[16517]1725 // Floppy support is enabled if there's at least one such entry; to disable floppy support,
1726 // the type of the floppy item would have been changed to "ignore"
[16503]1727 bool fFloppyEnabled = vsdeFloppy.size() > 0;
1728 ComPtr<IFloppyDrive> floppyDrive;
[16517]1729 rc = pNewMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
[16503]1730 CheckComRCThrowRC(rc);
1731 rc = floppyDrive->COMSETTER(Enabled)(fFloppyEnabled);
1732 CheckComRCThrowRC(rc);
[16360]1733
[16503]1734 /* CDROM drive */
1735 /* @todo: I can't disable the CDROM. So nothing to do for now */
1736 // std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_CDROM);
[16360]1737
[16503]1738 /* Hard disk controller IDE */
1739 std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
1740 /* @todo: we support one IDE controller only */
1741 if (vsdeHDCIDE.size() > 0)
[16298]1742 {
[16517]1743 // set the appropriate IDE controller in the virtual BIOS of the VM
[16503]1744 ComPtr<IBIOSSettings> biosSettings;
[16517]1745 rc = pNewMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam());
[16503]1746 CheckComRCThrowRC(rc);
[16517]1747 const char *pcszIDEType = vsdeHDCIDE.front()->strConfig.c_str();
1748 if (!strcmp(pcszIDEType, "PIIX3"))
1749 rc = biosSettings->COMSETTER(IDEControllerType)(IDEControllerType_PIIX3);
1750 else if (!strcmp(pcszIDEType, "PIIX4"))
1751 rc = biosSettings->COMSETTER(IDEControllerType)(IDEControllerType_PIIX4);
1752 else
1753 throw setError(VBOX_E_FILE_ERROR,
1754 tr("Invalid IDE controller type \"%s\""),
1755 pcszIDEType);
[16503]1756 CheckComRCThrowRC(rc);
[16298]1757 }
[16503]1758#ifdef VBOX_WITH_AHCI
1759 /* Hard disk controller SATA */
1760 std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
1761 /* @todo: we support one SATA controller only */
1762 if (vsdeHDCSATA.size() > 0)
[16298]1763 {
[16503]1764 const Utf8Str &hdcVBox = vsdeHDCIDE.front()->strConfig;
1765 if (hdcVBox == "AHCI")
1766 {
1767 /* For now we have just to enable the AHCI controller. */
1768 ComPtr<ISATAController> hdcSATAVBox;
[16517]1769 rc = pNewMachine->COMGETTER(SATAController)(hdcSATAVBox.asOutParam());
[16503]1770 CheckComRCThrowRC(rc);
1771 rc = hdcSATAVBox->COMSETTER(Enabled)(true);
1772 CheckComRCThrowRC(rc);
1773 }
1774 else
1775 {
1776 /* @todo: set an error if this is other than AHCI */
1777 }
[16298]1778 }
1779#endif /* VBOX_WITH_AHCI */
[16517]1780
[16503]1781 /* Hard disk controller SCSI */
[16517]1782 std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
[16503]1783 /* @todo: do we support more than one SCSI controller? */
1784 if (vsdeHDCSCSI.size() > 0)
1785 {
[16517]1786 /* @todo: revisit when Main support for SCSI is ready */
[16503]1787 }
[16298]1788
[16503]1789 /* Now its time to register the machine before we add any hard disks */
[16517]1790 rc = app->mVirtualBox->RegisterMachine(pNewMachine);
[16503]1791 CheckComRCThrowRC(rc);
[16248]1792
[16503]1793 if (!task->progress.isNull())
1794 task->progress->notifyProgress(static_cast<ULONG>(opCountMax * opCount++));
[16298]1795
[16503]1796 /* Create the hard disks & connect them to the appropriate controllers. */
1797 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
1798 if (avsdeHDs.size() > 0)
[16298]1799 {
[16503]1800 Guid newMachineId;
[16517]1801 rc = pNewMachine->COMGETTER(Id)(newMachineId.asOutParam());
[16503]1802 CheckComRCThrowRC(rc);
1803 /* If in the next block an error occur we have to deregister
1804 the machine, so make an extra try/catch block. */
1805 ComPtr<ISession> session;
1806 try
[16298]1807 {
[16517]1808 // in order to attach hard disks we need to open a session for the new machine
[16503]1809 rc = session.createInprocObject(CLSID_Session);
1810 CheckComRCThrowRC(rc);
1811 rc = app->mVirtualBox->OpenSession(session, newMachineId);
1812 CheckComRCThrowRC(rc);
[16495]1813
[16503]1814 int result;
1815 /* The disk image has to be on the same place as the OVF file. So
1816 * strip the filename out of the full file path. */
[16517]1817 Utf8Str strSrcDir = stripFilename(Utf8Str(app->m->bstrPath).raw());
[16503]1818
1819 /* Iterate over all given disk images */
[16515]1820 list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
1821 for (itHD = avsdeHDs.begin();
1822 itHD != avsdeHDs.end();
1823 ++itHD)
[16503]1824 {
[16515]1825 VirtualSystemDescriptionEntry *vsdeHD = *itHD;
1826
1827 const char *pcszDstFilePath = vsdeHD->strConfig.c_str();
[16503]1828 /* Check if the destination file exists already or the
1829 * destination path is empty. */
[16517]1830 if ( !(*pcszDstFilePath)
1831 || RTPathExists(pcszDstFilePath)
1832 )
[16503]1833 /* This isn't allowed */
1834 throw setError(VBOX_E_FILE_ERROR,
1835 tr("Destination file '%s' exists",
1836 pcszDstFilePath));
[16515]1837
1838 // find the disk from the OVF's disk list
1839 DiskImagesMap::const_iterator itDiskImage = app->m->mapDisks.find(vsdeHD->strRef);
[16517]1840 // vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1", which should exist
1841 // in the virtual system's disks map under that ID and also in the global images map
[16515]1842 VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
1843
1844 if ( itDiskImage == app->m->mapDisks.end()
1845 || itVirtualDisk == vsysThis.mapVirtualDisks.end()
1846 )
[16512]1847 throw setError(E_FAIL,
[16515]1848 tr("Internal inconsistency looking up disk images."));
1849
1850 const DiskImage &di = itDiskImage->second;
1851 const VirtualDisk &vd = itVirtualDisk->second;
1852
[16503]1853 /* Construct the source file path */
[16518]1854 Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
[16503]1855 /* Check if the source file exists */
1856 if (!RTPathExists(strSrcFilePath.c_str()))
1857 {
1858 /* @todo: we have to create a new one */
1859 }
1860 else
1861 {
1862 /* Make sure all target directories exists */
1863 rc = VirtualBox::ensureFilePathExists(pcszDstFilePath);
1864 CheckComRCThrowRC(rc);
1865 /* Clone the disk image (this is necessary cause the id has
1866 * to be recreated for the case the same hard disk is
1867 * attached already from a previous import) */
1868 /* First open the existing disk image */
1869 ComPtr<IHardDisk2> srcHdVBox;
1870 rc = app->mVirtualBox->OpenHardDisk2(Bstr(strSrcFilePath), srcHdVBox.asOutParam());
1871 CheckComRCThrowRC(rc);
1872 /* We need the format description of the source disk image */
1873 Bstr srcFormat;
1874 rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
1875 CheckComRCThrowRC(rc);
1876 /* Create a new hard disk interface for the destination disk image */
1877 ComPtr<IHardDisk2> dstHdVBox;
1878 rc = app->mVirtualBox->CreateHardDisk2(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
1879 CheckComRCThrowRC(rc);
1880 /* Clone the source disk image */
1881 ComPtr<IProgress> progress;
1882 rc = srcHdVBox->CloneTo(dstHdVBox, progress.asOutParam());
1883 CheckComRCThrowRC(rc);
1884 rc = progress->WaitForCompletion(-1);
1885 CheckComRCThrowRC(rc);
1886 /* We *must* close the source disk image in order to deregister it */
1887 rc = srcHdVBox->Close();
1888 CheckComRCThrowRC(rc);
1889 /* Now use the new uuid to attach the disk image to our new machine */
1890 ComPtr<IMachine> sMachine;
1891 rc = session->COMGETTER(Machine)(sMachine.asOutParam());
1892 Guid hdId;
1893 rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());;
1894 CheckComRCThrowRC(rc);
1895 /* For now we assume we have one controller of every type only */
1896 HardDiskController hdc = (*vsysThis.mapControllers.find(vd.idController)).second;
1897 StorageBus_T sbt = StorageBus_IDE;
1898 switch (hdc.system)
1899 {
1900 case HardDiskController::IDE: sbt = StorageBus_IDE; break;
1901 case HardDiskController::SATA: sbt = StorageBus_SATA; break;
1902 //case HardDiskController::SCSI: sbt = StorageBus_SCSI; break; // @todo: not available yet
1903 default: break;
1904 }
1905 rc = sMachine->AttachHardDisk2(hdId, sbt, hdc.ulBusNumber, 0);
1906 CheckComRCThrowRC(rc);
1907 rc = sMachine->SaveSettings();
1908 CheckComRCThrowRC(rc);
1909 rc = session->Close();
1910 CheckComRCThrowRC(rc);
1911 }
1912 }
[16298]1913 }
[16503]1914 catch(HRESULT aRC)
[16298]1915 {
[16503]1916 /* Unregister/Delete the failed machine */
1917 /* @todo: Not sure what to do when there are succesfully
1918 added disk images. Delete them also? For now we leave
1919 them. */
1920 if (!session.isNull())
[16360]1921 {
[16503]1922 /* If there is an open session, close them before doing
1923 anything further. */
1924 rc = session->Close();
1925 CheckComRCThrowRC(rc);
[16360]1926 }
[16503]1927 ComPtr<IMachine> failedMachine;
1928 rc = app->mVirtualBox->UnregisterMachine(newMachineId, failedMachine.asOutParam());
1929 CheckComRCThrowRC(rc);
1930 rc = failedMachine->DeleteSettings();
1931 CheckComRCThrowRC(rc);
1932 /* Throw the original error number */
1933 throw aRC;
[16298]1934 }
1935 }
[16503]1936 if (!task->progress.isNull())
1937 task->progress->notifyProgress(static_cast<ULONG>(opCountMax * opCount++));
[16298]1938 }
[16503]1939 catch(HRESULT aRC)
1940 {
1941 /* @todo: If we are here an error on importing of *one* virtual
1942 system has occured. We didn't break now, but try to import the
1943 other virtual systems. This needs some further discussion. */
1944 rc = aRC;
1945 }
[16248]1946 }
1947
[16503]1948 task->rc = rc;
[16248]1949
[16503]1950 if (!task->progress.isNull())
1951 task->progress->notifyComplete (rc);
[16218]1952
[16503]1953 /// @todo ugly hack, fix ComAssert... (same as in HardDisk2::taskThread)
1954 #undef setError
[16218]1955
[16503]1956 return VINF_SUCCESS;
[16298]1957}
1958
[16205]1959// IVirtualSystemDescription constructor / destructor
1960////////////////////////////////////////////////////////////////////////////////
1961
1962DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1963struct shutup3 {};
1964
1965struct VirtualSystemDescription::Data
1966{
1967 list<VirtualSystemDescriptionEntry> descriptions;
1968};
1969
1970HRESULT VirtualSystemDescription::init()
1971{
1972 /* Enclose the state transition NotReady->InInit->Ready */
[16234]1973 AutoInitSpan autoInitSpan(this);
1974 AssertReturn(autoInitSpan.isOk(), E_FAIL);
[16205]1975
1976 /* Initialize data */
1977 m = new Data();
1978
1979 /* Confirm a successful initialization */
1980 autoInitSpan.setSucceeded();
1981
1982 return S_OK;
1983}
1984
1985void VirtualSystemDescription::uninit()
1986{
1987 delete m;
1988 m = NULL;
1989}
1990
[16234]1991STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
[16515]1992 ComSafeArrayOut(BSTR, aRefs),
[16234]1993 ComSafeArrayOut(BSTR, aOrigValues),
[16495]1994 ComSafeArrayOut(BSTR, aConfigValues),
1995 ComSafeArrayOut(BSTR, aExtraConfigValues))
[16205]1996{
[16234]1997 if (ComSafeArrayOutIsNull(aTypes) ||
[16495]1998 ComSafeArrayOutIsNull(aRefs) ||
[16234]1999 ComSafeArrayOutIsNull(aOrigValues) ||
[16495]2000 ComSafeArrayOutIsNull(aConfigValues) ||
2001 ComSafeArrayOutIsNull(aExtraConfigValues))
[16205]2002 return E_POINTER;
2003
[16234]2004 AutoCaller autoCaller(this);
2005 CheckComRCReturnRC(autoCaller.rc());
[16205]2006
[16234]2007 AutoReadLock alock(this);
[16205]2008
2009 ULONG c = (ULONG)m->descriptions.size();
[16234]2010 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
[16515]2011 com::SafeArray<BSTR> sfaRefs(c);
[16234]2012 com::SafeArray<BSTR> sfaOrigValues(c);
[16495]2013 com::SafeArray<BSTR> sfaConfigValues(c);
2014 com::SafeArray<BSTR> sfaExtraConfigValues(c);
[16205]2015
2016 list<VirtualSystemDescriptionEntry>::const_iterator it;
2017 size_t i = 0;
2018 for (it = m->descriptions.begin();
2019 it != m->descriptions.end();
2020 ++it, ++i)
2021 {
[16325]2022 const VirtualSystemDescriptionEntry &vsde = (*it);
[16495]2023
2024 sfaTypes[i] = vsde.type;
2025
[16515]2026 Bstr bstr = vsde.strRef;
2027 bstr.cloneTo(&sfaRefs[i]);
[16495]2028
[16515]2029 bstr = vsde.strOrig;
[16325]2030 bstr.cloneTo(&sfaOrigValues[i]);
[16495]2031
2032 bstr = vsde.strConfig;
2033 bstr.cloneTo(&sfaConfigValues[i]);
2034
2035 bstr = vsde.strExtraConfig;
2036 bstr.cloneTo(&sfaExtraConfigValues[i]);
[16205]2037 }
2038
[16234]2039 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
[16495]2040 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
[16234]2041 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
[16495]2042 sfaConfigValues.detachTo(ComSafeArrayOutArg(aConfigValues));
2043 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
[16205]2044
2045 return S_OK;
2046}
2047
[16517]2048STDMETHODIMP VirtualSystemDescription::DisableItem(ULONG index)
2049{
2050 AutoCaller autoCaller(this);
2051 CheckComRCReturnRC(autoCaller.rc());
2052
2053 AutoWriteLock alock(this);
2054
2055 list<VirtualSystemDescriptionEntry>::iterator it;
2056 for (it = m->descriptions.begin();
2057 it != m->descriptions.end();
2058 ++it)
2059 {
2060 VirtualSystemDescriptionEntry &e = *it;
2061 if (e.ulIndex == index)
2062 {
2063 e.type = VirtualSystemDescriptionType_Ignore;
2064 return S_OK;
2065 }
2066 }
2067
2068 return setError(VBOX_E_OBJECT_NOT_FOUND,
2069 tr("Array item index %d not found"),
2070 index);
2071}
2072
[16234]2073STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(IN_BSTR, aFinalValues))
[16205]2074{
[16234]2075 CheckComArgSafeArrayNotNull(aFinalValues);
[16205]2076
[16234]2077 AutoCaller autoCaller(this);
2078 CheckComRCReturnRC(autoCaller.rc());
[16205]2079
[16234]2080 AutoWriteLock alock(this);
[16205]2081
[16234]2082 com::SafeArray <IN_BSTR> values(ComSafeArrayInArg(aFinalValues));
[16205]2083 if (values.size() != m->descriptions.size())
2084 return E_INVALIDARG;
2085
2086 list<VirtualSystemDescriptionEntry>::const_iterator it;
2087 size_t i = 0;
2088 for (it = m->descriptions.begin();
2089 it != m->descriptions.end();
2090 ++it, ++i)
2091 {
2092 VirtualSystemDescriptionEntry vsde = (*it);
[16495]2093 vsde.strConfig = values[i];
[16205]2094 }
2095
2096 return S_OK;
2097}
2098
[16309]2099void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
[16515]2100 const Utf8Str &strRef,
[16325]2101 const Utf8Str &aOrigValue,
[16515]2102 const Utf8Str &aAutoValue,
2103 const Utf8Str &strExtraConfig /*= ""*/)
[16205]2104{
2105 VirtualSystemDescriptionEntry vsde;
[16515]2106 vsde.ulIndex = m->descriptions.size(); // each entry gets an index so the client side can reference them
[16205]2107 vsde.type = aType;
[16515]2108 vsde.strRef = strRef;
[16495]2109 vsde.strOrig = aOrigValue;
2110 vsde.strConfig = aAutoValue;
[16515]2111 vsde.strExtraConfig = strExtraConfig;
[16205]2112
[16234]2113 m->descriptions.push_back(vsde);
[16205]2114}
2115
[16309]2116std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
[16205]2117{
[16309]2118 std::list<VirtualSystemDescriptionEntry*> vsd;
2119 list<VirtualSystemDescriptionEntry>::iterator it;
[16205]2120 for (it = m->descriptions.begin();
2121 it != m->descriptions.end();
2122 ++it)
2123 if (it->type == aType)
[16309]2124 vsd.push_back(&(*it));
[16205]2125
2126 return vsd;
2127}
2128
[16515]2129const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
2130{
2131 Utf8Str strRef = toString<uint32_t>(id);
2132 list<VirtualSystemDescriptionEntry>::const_iterator it;
2133 for (it = m->descriptions.begin();
2134 it != m->descriptions.end();
2135 ++it)
2136 {
2137 switch (it->type)
2138 {
2139 case VirtualSystemDescriptionType_HardDiskControllerIDE:
2140 case VirtualSystemDescriptionType_HardDiskControllerSATA:
2141 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
2142 if (it->strRef == strRef)
2143 return &(*it);
2144 break;
2145 }
2146 }
2147
2148 return NULL;
2149}
[16517]2150
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use