VirtualBox

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

Last change on this file since 17075 was 17075, checked in by vboxsync, 16 years ago

ICH6 controller in UI and configs (don't think amount of work required to add
just new IDE controller type is adequate)

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette