VirtualBox

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

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

OVF: make com::xml and IAppliance use Utf8Str instead of std::string

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