VirtualBox

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

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

OVF: ensure 64-bit math

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