VirtualBox

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

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

Main: rename IDVDImage2 to IDVDImage

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