VirtualBox

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

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

appliance to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.5 KB
Line 
1/* $Id: ApplianceImpl.cpp 16205 2009-01-23 17:11: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
26#include "ApplianceImpl.h"
27#include "VirtualBoxImpl.h"
28#include "GuestOSTypeImpl.h"
29
30#include "Logging.h"
31
32#include "VBox/xml.h"
33
34#include <iostream>
35#include <sstream>
36
37using namespace std;
38
39// defines
40////////////////////////////////////////////////////////////////////////////////
41
42struct DiskImage
43{
44 string strDiskId; // value from DiskSection/Disk/@diskId
45 int64_t iCapacity; // value from DiskSection/Disk/@capacity;
46 // (maximum size for dynamic images, I guess; we always translate this to bytes)
47 int64_t iPopulatedSize; // value from DiskSection/Disk/@populatedSize
48 // (actual used size of disk, always in bytes; can be an estimate of used disk
49 // space, but cannot be larger than iCapacity)
50 string strFormat; // value from DiskSection/Disk/@format
51 // typically http://www.vmware.com/specifications/vmdk.html#sparse
52
53 // fields from /References/File; the spec says the file reference from disk can be empty,
54 // so in that case, strFilename will be empty, then a new disk should be created
55 string strHref; // value from /References/File/@href (filename); if empty, then the remaining fields are ignored
56 int64_t iSize; // value from /References/File/@size (optional according to spec; then we set -1 here)
57 int64_t iChunkSize; // value from /References/File/@chunkSize (optional, unsupported)
58 string strCompression; // value from /References/File/@compression (optional, can be "gzip" according to spec)
59};
60
61struct Network
62{
63 string strNetworkName; // value from NetworkSection/Network/@name
64 // unfortunately the OVF spec is unspecific about how networks should be specified further
65};
66
67struct VirtualHardwareItem
68{
69 string strDescription;
70 string strCaption;
71 string strElementName;
72
73 uint32_t ulInstanceID;
74 uint32_t ulParent;
75
76 string strHostResource;
77 OVFResourceType_T resourceType;
78 string strOtherResourceType;
79 string strResourceSubType;
80 bool fAutomaticAllocation;
81 bool fAutomaticDeallocation;
82 string strConnection; // for ethernet
83 string strAddress;
84 string strAddressOnParent;
85 string strAllocationUnits;
86 uint64_t ullVirtualQuantity;
87 uint64_t ullReservation;
88 uint64_t ullLimit;
89 uint64_t ullWeight;
90 string strConsumerVisibility;
91 string strMappingBehavior;
92 string strPoolID;
93
94 uint32_t ulLineNumber; // line number of <Item> element in XML source
95
96 VirtualHardwareItem()
97 : ulInstanceID(0), fAutomaticAllocation(false), fAutomaticDeallocation(false), ullVirtualQuantity(0), ullReservation(0), ullLimit(0), ullWeight(0)
98 {};
99};
100
101typedef map<string, DiskImage> DiskImagesMap;
102typedef map<string, Network> NetworksMap;
103
104struct VirtualSystem;
105
106// opaque private instance data of Appliance class
107struct Appliance::Data
108{
109 Bstr bstrPath;
110
111 DiskImagesMap mapDisks; // map of DiskImage structs, sorted by DiskImage.strDiskId
112
113 NetworksMap mapNetworks; // map of Network structs, sorted by Network.strNetworkName
114
115 list<VirtualSystem> llVirtualSystems;
116
117 list< ComObjPtr<VirtualSystemDescription> > virtualSystemDescriptions;
118};
119
120typedef map<uint32_t, VirtualHardwareItem> HardwareItemsMap;
121
122enum ControllerSystemType { IDE, SATA, SCSI };
123struct HardDiskController
124{
125 uint32_t idController; // instance ID (Item/InstanceId); this gets referenced from HardDisk
126 ControllerSystemType controllerSystem; // @todo: figure out of OVF (IDE;SATA;SCSI)
127 string strControllerType; // controller type (Item/ResourceSubType); e.g. "LsiLogic"
128};
129
130typedef map<uint32_t, HardDiskController> ControllersMap;
131
132struct VirtualDisk
133{
134 uint32_t idController; // SCSI (or IDE) controller this disk is connected to;
135 // points into VirtualSystem.mapControllers
136 string strDiskId; // if the hard disk has an ovf:/disk/<id> reference,
137 // this receives the <id> component; points to one of the
138 // references in Appliance::Data.mapDisks
139};
140
141struct VirtualSystem
142{
143 CIMOSType_T cimos;
144 string strVirtualSystemType;
145
146 HardwareItemsMap mapHardwareItems; // map of virtual hardware items, sorted by unique instance ID
147
148 uint64_t ullMemorySize; // always in bytes, copied from llHardwareItems; default = 0 (unspecified)
149 uint16_t cCPUs; // no. of CPUs, copied from llHardwareItems; default = 1
150
151 list<string> llNetworkNames;
152 // list of strings referring to network names
153 // (one for each VirtualSystem/Item[@ResourceType=10]/Connection element)
154
155 ControllersMap mapControllers;
156 // list of hard disk controllers
157 // (one for each VirtualSystem/Item[@ResourceType=6] element with accumulated data from children)
158
159 list<VirtualDisk> llVirtualDisks;
160 // (one for each VirtualSystem/Item[@ResourceType=17] element with accumulated data from children)
161
162 VirtualSystem()
163 : ullMemorySize(0), cCPUs(1)
164 {
165 }
166};
167
168// globals
169////////////////////////////////////////////////////////////////////////////////
170
171template <class T> inline std::string toString(const T& val)
172{
173 std::ostringstream ss;
174 ss << val;
175 return ss.str();
176}
177
178// IVirtualBox public methods
179////////////////////////////////////////////////////////////////////////////////
180
181/**
182 * Implementation for IAppliance::openAppliance. Loads the given appliance (see API reference).
183 *
184 * @param bstrPath Appliance to open (either .ovf or .ova file, see API reference)
185 * @param anAppliance IAppliance object created if S_OK is returned.
186 * @return S_OK or error.
187 */
188STDMETHODIMP VirtualBox::OpenAppliance(IN_BSTR bstrPath, IAppliance** anAppliance)
189{
190 HRESULT rc;
191
192 ComObjPtr<Appliance> appliance;
193 appliance.createObject();
194 rc = appliance->init(bstrPath);
195// ComAssertComRCThrowRC(rc);
196
197 if (SUCCEEDED(rc))
198 {
199 appliance.queryInterfaceTo(anAppliance);
200 }
201
202 return rc;
203}
204
205// IAppliance constructor / destructor
206////////////////////////////////////////////////////////////////////////////////
207
208DEFINE_EMPTY_CTOR_DTOR(Appliance)
209struct shutup {};
210
211// IAppliance private methods
212////////////////////////////////////////////////////////////////////////////////
213
214/**
215 * Private helper method that goes thru the elements of the given "current" element in the OVF XML
216 * and handles the contained child elements (which can be "Section" or "Content" elements).
217 *
218 * @param pcszPath Path spec of the XML file, for error messages.
219 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
220 * @param pCurElem Element whose children are to be analyzed here.
221 * @return
222 */
223HRESULT Appliance::LoopThruSections(const char *pcszPath,
224 const xml::Node *pReferencesElem,
225 const xml::Node *pCurElem)
226{
227 HRESULT rc;
228
229 xml::NodesLoop loopChildren(*pCurElem);
230 const xml::Node *pElem;
231 while ((pElem = loopChildren.forAllNodes()))
232 {
233 const char *pcszElemName = pElem->getName();
234 const char *pcszTypeAttr = "";
235 const xml::Node *pTypeAttr;
236 if ((pTypeAttr = pElem->findAttribute("type")))
237 pcszTypeAttr = pTypeAttr->getValue();
238
239 if ( (!strcmp(pcszElemName, "DiskSection"))
240 || ( (!strcmp(pcszElemName, "Section"))
241 && (!strcmp(pcszTypeAttr, "ovf:DiskSection_Type"))
242 )
243 )
244 {
245 if (!(SUCCEEDED((rc = HandleDiskSection(pcszPath, pReferencesElem, pElem)))))
246 return rc;
247 }
248 else if ( (!strcmp(pcszElemName, "NetworkSection"))
249 || ( (!strcmp(pcszElemName, "Section"))
250 && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type"))
251 )
252 )
253 {
254 if (!(SUCCEEDED((rc = HandleNetworkSection(pcszPath, pElem)))))
255 return rc;
256 }
257 else if ( (!strcmp(pcszElemName, "DeploymentOptionSection>")))
258 {
259 // TODO
260 }
261 else if ( (!strcmp(pcszElemName, "Info")))
262 {
263 // child of VirtualSystemCollection -- TODO
264 }
265 else if ( (!strcmp(pcszElemName, "ResourceAllocationSection")))
266 {
267 // child of VirtualSystemCollection -- TODO
268 }
269 else if ( (!strcmp(pcszElemName, "StartupSection")))
270 {
271 // child of VirtualSystemCollection -- TODO
272 }
273 else if ( (!strcmp(pcszElemName, "VirtualSystem"))
274 || ( (!strcmp(pcszElemName, "Content"))
275 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type"))
276 )
277 )
278 {
279 if (!(SUCCEEDED((rc = HandleVirtualSystemContent(pcszPath, pElem)))))
280 return rc;
281 }
282 else if ( (!strcmp(pcszElemName, "VirtualSystemCollection"))
283 || ( (!strcmp(pcszElemName, "Content"))
284 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type"))
285 )
286 )
287 {
288 // TODO ResourceAllocationSection
289
290 // recurse for this, since it has VirtualSystem elements as children
291 if (!(SUCCEEDED((rc = LoopThruSections(pcszPath, pReferencesElem, pElem)))))
292 return rc;
293 }
294 }
295
296 return S_OK;
297}
298
299/**
300 * Private helper method that handles disk sections in the OVF XML.
301 * @param pcszPath Path spec of the XML file, for error messages.
302 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
303 * @param pSectionElem Section element for which this helper is getting called.
304 * @return
305 */
306HRESULT Appliance::HandleDiskSection(const char *pcszPath,
307 const xml::Node *pReferencesElem,
308 const xml::Node *pSectionElem)
309{
310 // contains "Disk" child elements
311 xml::NodesLoop loopDisks(*pSectionElem, "Disk");
312 const xml::Node *pelmDisk;
313 while ((pelmDisk = loopDisks.forAllNodes()))
314 {
315 DiskImage d;
316 const char *pcszBad = NULL;
317 if (!(pelmDisk->getAttributeValue("diskId", d.strDiskId)))
318 pcszBad = "diskId";
319 else if (!(pelmDisk->getAttributeValue("format", d.strFormat)))
320 pcszBad = "format";
321 else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity)))
322 pcszBad = "capacity";
323 else
324 {
325 if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)))
326 // optional
327 d.iPopulatedSize = -1;
328
329 string strFileRef;
330 if (pelmDisk->getAttributeValue("fileRef", strFileRef)) // optional
331 {
332 // look up corresponding /References/File nodes (list built above)
333 const xml::Node *pFileElem;
334 if ( pReferencesElem
335 && ((pFileElem = pReferencesElem->findChildElementFromId(strFileRef.c_str())))
336 )
337 {
338 // copy remaining values from file node then
339 const char *pcszBadInFile = NULL;
340 if (!(pFileElem->getAttributeValue("href", d.strHref)))
341 pcszBadInFile = "href";
342 else if (!(pFileElem->getAttributeValue("size", d.iSize)))
343 d.iSize = -1; // optional
344 // if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
345 d.iChunkSize = -1; // optional
346 pFileElem->getAttributeValue("compression", d.strCompression);
347
348 if (pcszBadInFile)
349 return setError(VBOX_E_FILE_ERROR,
350 tr("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
351 pcszPath,
352 pcszBadInFile,
353 pFileElem->getLineNumber());
354 }
355 else
356 return setError(VBOX_E_FILE_ERROR,
357 tr("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
358 pcszPath,
359 strFileRef.c_str(),
360 pelmDisk->getLineNumber());
361 }
362 }
363
364 if (pcszBad)
365 return setError(VBOX_E_FILE_ERROR,
366 tr("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
367 pcszPath,
368 pcszBad,
369 pelmDisk->getLineNumber());
370
371 // RTPrintf(" found disk: %s\n", d.strDiskId.c_str());
372 m->mapDisks[d.strDiskId] = d;
373 }
374
375 return S_OK;
376}
377
378/**
379 * Private helper method that handles network sections in the OVF XML.
380 * @param pcszPath Path spec of the XML file, for error messages.
381 * @param pSectionElem Section element for which this helper is getting called.
382 * @return
383 */
384HRESULT Appliance::HandleNetworkSection(const char *pcszPath,
385 const xml::Node *pSectionElem)
386{
387 // contains "Disk" child elements
388 xml::NodesLoop loopNetworks(*pSectionElem, "Network");
389 const xml::Node *pelmNetwork;
390 while ((pelmNetwork = loopNetworks.forAllNodes()))
391 {
392 Network n;
393 if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
394 return setError(VBOX_E_FILE_ERROR,
395 tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
396 pcszPath,
397 pelmNetwork->getLineNumber());
398
399 m->mapNetworks[n.strNetworkName] = n;
400 }
401
402 return S_OK;
403}
404
405/**
406 * Private helper method that handles a "VirtualSystem" element in the OVF XML.
407 *
408 * @param pcszPath
409 * @param pContentElem
410 * @return
411 */
412HRESULT Appliance::HandleVirtualSystemContent(const char *pcszPath,
413 const xml::Node *pelmVirtualSystem)
414{
415 VirtualSystem d;
416
417 xml::NodesLoop loop(*pelmVirtualSystem); // all child elements
418 const xml::Node *pelmThis;
419 while ((pelmThis = loop.forAllNodes()))
420 {
421 const char *pcszElemName = pelmThis->getName();
422 const xml::Node *pTypeAttr = pelmThis->findAttribute("type");
423 const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : "";
424
425 if (!strcmp(pcszElemName, "EulaSection"))
426 {
427 // TODO
428 }
429 else if ( (!strcmp(pcszElemName, "VirtualHardwareSection"))
430 || (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type"))
431 )
432 {
433 const xml::Node *pelmSystem, *pelmVirtualSystemType;
434 if ((pelmSystem = pelmThis->findChildElement("System")))
435 {
436 /* <System>
437 <vssd:Description>Description of the virtual hardware section.</vssd:Description>
438 <vssd:ElementName>vmware</vssd:ElementName>
439 <vssd:InstanceID>1</vssd:InstanceID>
440 <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
441 <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
442 </System>*/
443 if ((pelmVirtualSystemType = pelmSystem->findChildElement("VirtualSystemType")))
444 d.strVirtualSystemType = pelmVirtualSystemType->getValue();
445 }
446
447 xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements
448 const xml::Node *pelmItem;
449 while ((pelmItem = loopVirtualHardwareItems.forAllNodes()))
450 {
451 VirtualHardwareItem i;
452
453 i.ulLineNumber = pelmItem->getLineNumber();
454
455 xml::NodesLoop loopItemChildren(*pelmItem); // all child elements
456 const xml::Node *pelmItemChild;
457 while ((pelmItemChild = loopItemChildren.forAllNodes()))
458 {
459 const char *pcszItemChildName = pelmItemChild->getName();
460 if (!strcmp(pcszItemChildName, "Description"))
461 i.strDescription = pelmItemChild->getValue();
462 else if (!strcmp(pcszItemChildName, "Caption"))
463 i.strCaption = pelmItemChild->getValue();
464 else if (!strcmp(pcszItemChildName, "ElementName"))
465 i.strElementName = pelmItemChild->getValue();
466 else if (!strcmp(pcszItemChildName, "InstanceID"))
467 pelmItemChild->copyValue(i.ulInstanceID);
468 else if (!strcmp(pcszItemChildName, "HostResource"))
469 i.strHostResource = pelmItemChild->getValue();
470 else if (!strcmp(pcszItemChildName, "ResourceType"))
471 {
472 int32_t iType; /** @todo how to fix correctly? (enum fun.) */
473 pelmItemChild->copyValue(iType);
474 i.resourceType = (OVFResourceType_T)iType;
475 }
476 else if (!strcmp(pcszItemChildName, "OtherResourceType"))
477 i.strOtherResourceType = pelmItemChild->getValue();
478 else if (!strcmp(pcszItemChildName, "ResourceSubType"))
479 i.strResourceSubType = pelmItemChild->getValue();
480 else if (!strcmp(pcszItemChildName, "AutomaticAllocation"))
481 i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
482 else if (!strcmp(pcszItemChildName, "AutomaticDeallocation"))
483 i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
484 else if (!strcmp(pcszItemChildName, "Parent"))
485 pelmItemChild->copyValue(i.ulParent);
486 else if (!strcmp(pcszItemChildName, "Connection"))
487 i.strConnection = pelmItemChild->getValue();
488 else if (!strcmp(pcszItemChildName, "Address"))
489 i.strAddress = pelmItemChild->getValue();
490 else if (!strcmp(pcszItemChildName, "AddressOnParent"))
491 i.strAddressOnParent = pelmItemChild->getValue();
492 else if (!strcmp(pcszItemChildName, "AllocationUnits"))
493 i.strAllocationUnits = pelmItemChild->getValue();
494 else if (!strcmp(pcszItemChildName, "VirtualQuantity"))
495 pelmItemChild->copyValue(i.ullVirtualQuantity);
496 else if (!strcmp(pcszItemChildName, "Reservation"))
497 pelmItemChild->copyValue(i.ullReservation);
498 else if (!strcmp(pcszItemChildName, "Limit"))
499 pelmItemChild->copyValue(i.ullLimit);
500 else if (!strcmp(pcszItemChildName, "Weight"))
501 pelmItemChild->copyValue(i.ullWeight);
502 else if (!strcmp(pcszItemChildName, "ConsumerVisibility"))
503 i.strConsumerVisibility = pelmItemChild->getValue();
504 else if (!strcmp(pcszItemChildName, "MappingBehavior"))
505 i.strMappingBehavior = pelmItemChild->getValue();
506 else if (!strcmp(pcszItemChildName, "PoolID"))
507 i.strPoolID = pelmItemChild->getValue();
508 else
509 return setError(VBOX_E_FILE_ERROR,
510 tr("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
511 pcszPath,
512 pcszItemChildName,
513 i.ulLineNumber);
514 }
515
516 // store!
517 d.mapHardwareItems[i.ulInstanceID] = i;
518 }
519
520 HardwareItemsMap::const_iterator itH;
521
522 for (itH = d.mapHardwareItems.begin();
523 itH != d.mapHardwareItems.end();
524 ++itH)
525 {
526 const VirtualHardwareItem &i = itH->second;
527
528 // do some analysis
529 switch (i.resourceType)
530 {
531 case OVFResourceType_Processor: // 3
532 /* <rasd:Caption>1 virtual CPU</rasd:Caption>
533 <rasd:Description>Number of virtual CPUs</rasd:Description>
534 <rasd:ElementName>virtual CPU</rasd:ElementName>
535 <rasd:InstanceID>1</rasd:InstanceID>
536 <rasd:ResourceType>3</rasd:ResourceType>
537 <rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
538 if (i.ullVirtualQuantity < UINT16_MAX)
539 d.cCPUs = (uint16_t)i.ullVirtualQuantity;
540 else
541 return setError(VBOX_E_FILE_ERROR,
542 tr("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
543 pcszPath,
544 i.ullVirtualQuantity,
545 UINT16_MAX,
546 i.ulLineNumber);
547 break;
548
549 case OVFResourceType_Memory: // 4
550 if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit
551 || (i.strAllocationUnits == "MB") // found in MS docs
552 || (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21
553 )
554 d.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024;
555 else
556 return setError(VBOX_E_FILE_ERROR,
557 tr("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
558 pcszPath,
559 i.strAllocationUnits.c_str(),
560 i.ulLineNumber);
561 break;
562
563 case OVFResourceType_ParallelScsiHba: // 6 SCSI controller
564 {
565 /* <Item>
566 <rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
567 <rasd:Description>SCI Controller</rasd:Description>
568 <rasd:ElementName>SCSI controller</rasd:ElementName>
569 <rasd:InstanceID>4</rasd:InstanceID>
570 <rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
571 <rasd:ResourceType>6</rasd:ResourceType>
572 </Item> */
573 HardDiskController hdc;
574 hdc.idController = i.ulInstanceID;
575 hdc.controllerSystem = SCSI;
576 hdc.strControllerType = i.strResourceSubType;
577
578 d.mapControllers[i.ulInstanceID] = hdc;
579 }
580 break;
581
582 case OVFResourceType_EthernetAdapter: // 10
583 {
584 /* <Item>
585 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
586 <rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
587 <rasd:Connection>VM Network</rasd:Connection>
588 <rasd:Description>VM Network?</rasd:Description>
589 <rasd:ElementName>Ethernet adapter</rasd:ElementName>
590 <rasd:InstanceID>3</rasd:InstanceID>
591 <rasd:ResourceType>10</rasd:ResourceType>
592 </Item>
593
594 OVF spec DSP 0243 page 21:
595 "For an Ethernet adapter, this specifies the abstract network connection name
596 for the virtual machine. All Ethernet adapters that specify the same abstract
597 network connection name within an OVF package shall be deployed on the same
598 network. The abstract network connection name shall be listed in the NetworkSection
599 at the outermost envelope level." */
600
601 // make sure we have a matching NetworkSection/Network
602 NetworksMap::iterator it = m->mapNetworks.find(i.strConnection);
603 if (it == m->mapNetworks.end())
604 return setError(VBOX_E_FILE_ERROR,
605 tr("Error reading \"%s\": Invalid connection \"%s\"; cannot find matching NetworkSection/Network element, line %d"),
606 pcszPath,
607 i.strConnection.c_str(),
608 i.ulLineNumber);
609
610 d.llNetworkNames.push_back(i.strConnection);
611 }
612 break;
613
614 case OVFResourceType_HardDisk: // 17
615 {
616 /* <Item>
617 <rasd:Caption>Harddisk 1</rasd:Caption>
618 <rasd:Description>HD</rasd:Description>
619 <rasd:ElementName>Hard Disk</rasd:ElementName>
620 <rasd:HostResource>ovf://disk/lamp</rasd:HostResource>
621 <rasd:InstanceID>5</rasd:InstanceID>
622 <rasd:Parent>4</rasd:Parent>
623 <rasd:ResourceType>17</rasd:ResourceType>
624 </Item> */
625
626 // look up the hard disk controller element whose InstanceID equals our Parent;
627 // this is how the connection is specified in OVF
628 ControllersMap::const_iterator it = d.mapControllers.find(i.ulParent);
629 if (it == d.mapControllers.end())
630 return setError(VBOX_E_FILE_ERROR,
631 tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
632 pcszPath,
633 i.ulInstanceID,
634 i.ulParent,
635 i.ulLineNumber);
636 const HardDiskController &hdc = it->second;
637
638 VirtualDisk vd;
639 vd.idController = i.ulParent;
640 bool fFound = false;
641 // ovf://disk/lamp
642 // 12345678901234
643 if (i.strHostResource.substr(0, 11) == "ovf://disk/")
644 {
645 vd.strDiskId = i.strHostResource.substr(11);
646 if (m->mapDisks.find(vd.strDiskId) != m->mapDisks.end())
647 fFound = true;
648 }
649
650 if (!fFound)
651 return setError(VBOX_E_FILE_ERROR,
652 tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
653 pcszPath,
654 i.ulInstanceID,
655 i.strHostResource.c_str(),
656 i.ulLineNumber);
657
658 d.llVirtualDisks.push_back(vd);
659 }
660 break;
661 }
662 }
663 }
664 else if ( (!strcmp(pcszElemName, "OperatingSystemSection"))
665 || (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type"))
666 )
667 {
668 uint64_t cimos64;
669 if (!(pelmThis->getAttributeValue("id", cimos64)))
670 return setError(VBOX_E_FILE_ERROR,
671 tr("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
672 pcszPath,
673 pelmThis->getLineNumber());
674
675 d.cimos = (CIMOSType_T)cimos64;
676 }
677 }
678
679 // now create the virtual system
680 m->llVirtualSystems.push_back(d);
681
682 return S_OK;
683}
684
685// IAppliance public methods
686////////////////////////////////////////////////////////////////////////////////
687
688/**
689 * Appliance initializer.
690 *
691 * This loads the given appliance.
692 * @param
693 * @return
694 */
695
696HRESULT Appliance::init(IN_BSTR &path)
697{
698 HRESULT rc;
699
700 /* Enclose the state transition NotReady->InInit->Ready */
701 AutoInitSpan autoInitSpan(this);
702 AssertReturn (autoInitSpan.isOk(), E_FAIL);
703
704 // initialize data
705 m = new Data;
706 m->bstrPath = path;
707
708 // see if we can handle this file; for now we insist it has an ".ovf" extension
709 Utf8Str utf8Path(path);
710 const char *pcszLastDot = strrchr(utf8Path, '.');
711 if ( (!pcszLastDot)
712 || ( strcmp(pcszLastDot, ".ovf")
713 && strcmp(pcszLastDot, ".OVF")
714 )
715 )
716 return setError(VBOX_E_FILE_ERROR,
717 tr("Appliance file must have .ovf extension"));
718
719 try
720 {
721 xml::XmlFileParser parser;
722 xml::Document doc;
723 parser.read(utf8Path.raw(),
724 doc);
725
726 const xml::Node *pRootElem = doc.getRootElement();
727 if (strcmp(pRootElem->getName(), "Envelope"))
728 return setError(VBOX_E_FILE_ERROR,
729 tr("Root element in OVF file must be \"Envelope\"."));
730
731 // OVF has the following rough layout:
732 /*
733 -- <References> .... files referenced from other parts of the file, such as VMDK images
734 -- Metadata, comprised of several section commands
735 -- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
736 -- optionally <Strings> for localization
737 */
738
739 // get all "File" child elements of "References" section so we can look up files easily;
740 // first find the "References" sections so we can look up files
741 xml::NodesList listFileElements; // receives all /Envelope/References/File nodes
742 const xml::Node *pReferencesElem;
743 if ((pReferencesElem = pRootElem->findChildElement("References")))
744 pReferencesElem->getChildElements(listFileElements, "File");
745
746 // now go though the sections
747 if (!(SUCCEEDED(rc = LoopThruSections(utf8Path.raw(), pReferencesElem, pRootElem))))
748 return rc;
749 }
750 catch(xml::Error &x)
751 {
752 return setError(VBOX_E_FILE_ERROR,
753 x.what());
754 }
755
756 rc = construeAppliance();
757 if (FAILED (rc))
758 return rc;
759
760 /* Confirm a successful initialization */
761 autoInitSpan.setSucceeded();
762
763 return S_OK;
764}
765
766void Appliance::uninit()
767{
768 delete m;
769 m = NULL;
770}
771
772STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
773{
774 if (!aPath)
775 return E_POINTER;
776
777 AutoCaller autoCaller(this);
778 CheckComRCReturnRC(autoCaller.rc());
779
780 AutoReadLock alock(this);
781
782 m->bstrPath.cloneTo(aPath);
783
784 return S_OK;
785}
786
787STDMETHODIMP Appliance::GetDisks (ComSafeArrayOut(BSTR, aDisks), ULONG *cDisks)
788{
789 CheckComArgOutSafeArrayPointerValid(aDisks);
790
791 AutoCaller autoCaller(this);
792 CheckComRCReturnRC(autoCaller.rc());
793
794 AutoReadLock alock(this);
795
796 size_t c = m->mapDisks.size();
797 com::SafeArray<BSTR> sfaDisks(c);
798
799 DiskImagesMap::const_iterator it;
800 size_t i = 0;
801 for (it = m->mapDisks.begin();
802 it != m->mapDisks.end();
803 ++it, ++i)
804 {
805 // create a string representing this disk
806 const DiskImage &d = it->second;
807 char *psz = NULL;
808 RTStrAPrintf(&psz,
809 "%s\t"
810 "%RI64\t"
811 "%RI64\t"
812 "%s\t"
813 "%s\t"
814 "%RI64\t"
815 "%RI64\t"
816 "%s",
817 d.strDiskId.c_str(),
818 d.iCapacity,
819 d.iPopulatedSize,
820 d.strFormat.c_str(),
821 d.strHref.c_str(),
822 d.iSize,
823 d.iChunkSize,
824 d.strCompression.c_str());
825 Utf8Str utf(psz);
826 Bstr bstr(utf);
827 // push to safearray
828 bstr.cloneTo(&sfaDisks[i]);
829 RTStrFree(psz);
830 }
831
832 *cDisks = (ULONG)i;
833
834 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
835
836 return S_OK;
837}
838
839STDMETHODIMP Appliance::COMGETTER (VirtualSystemDescriptions)(ComSafeArrayOut (IVirtualSystemDescription*, aVirtualSystemDescriptions))
840{
841 CheckComArgOutSafeArrayPointerValid (aVirtualSystemDescriptions);
842
843 AutoCaller autoCaller (this);
844 CheckComRCReturnRC (autoCaller.rc());
845
846 AutoReadLock alock (this);
847
848 SafeIfaceArray<IVirtualSystemDescription> sfaVSD (m->virtualSystemDescriptions);
849 sfaVSD.detachTo (ComSafeArrayOutArg (aVirtualSystemDescriptions));
850
851 return S_OK;
852}
853
854STDMETHODIMP Appliance::ImportAppliance()
855{
856 /* We need a virtualbox object */
857 ComPtr <IVirtualBox> virtualBox;
858 HRESULT rc = virtualBox.createLocalObject (CLSID_VirtualBox);
859 ComAssertComRCThrowRC (rc);
860
861 list<VirtualSystem>::const_iterator it;
862 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
863 /* Iterate through all appliances */
864 size_t i = 0;
865 for (it = m->llVirtualSystems.begin(),
866 it1 = m->virtualSystemDescriptions.begin();
867 it != m->llVirtualSystems.end();
868 ++it, ++it1, ++i)
869 {
870 const VirtualSystem &vs = *it;
871 ComObjPtr<VirtualSystemDescription> vsd = (*it1);
872
873 /* Guest OS type */
874 list<VirtualSystemDescriptionEntry> vsdeOS = vsd->findByType (VirtualSystemDescriptionType_OS);
875 Assert (vsdeOS.size() == 1);
876 string osTypeVBox = vsdeOS.front().strFinalValue;
877
878 /* Now that we know the base system get our internal defaults based on that. */
879 IGuestOSType *osType = NULL;
880 rc = virtualBox->GetGuestOSType (Bstr (Utf8Str (osTypeVBox.c_str())), &osType);
881 ComAssertComRCThrowRC (rc);
882
883 /* Create the machine */
884 IMachine *newMachine = NULL;
885 rc = virtualBox->CreateMachine (Bstr (Utf8StrFmt ("tescht_%d", i)), Bstr (Utf8Str (osTypeVBox.c_str())),
886 Bstr (), Guid(),
887 &newMachine);
888 ComAssertComRCThrowRC (rc);
889
890 /* CPU count (ignored for now) */
891 // list<VirtualSystemDescriptionEntry> vsdeCPU = vsd->findByType (VirtualSystemDescriptionType_CPU);
892
893 /* RAM */
894 list<VirtualSystemDescriptionEntry> vsdeRAM = vsd->findByType (VirtualSystemDescriptionType_Memory);
895 Assert (vsdeRAM.size() == 1);
896 string memoryVBox = vsdeRAM.front().strFinalValue;
897 uint32_t tt = RTStrToUInt32 (memoryVBox.c_str()) / _1M;
898
899 rc = newMachine->COMSETTER(MemorySize)(tt);
900 ComAssertComRCThrowRC (rc);
901
902 /* VRAM */
903 /* Get the recommended VRAM for this guest os type */
904 ULONG vramVBox;
905 rc = osType->COMGETTER(RecommendedVRAM) (&vramVBox);
906 ComAssertComRCThrowRC (rc);
907 /* Set the VRAM */
908 rc = newMachine->COMSETTER(VRAMSize) (vramVBox);
909 ComAssertComRCThrowRC (rc);
910
911 /* Change the network adapters */
912 list<VirtualSystemDescriptionEntry> vsdeNW = vsd->findByType (VirtualSystemDescriptionType_NetworkAdapter);
913 if (vsdeNW.size() == 0)
914 {
915 /* No network adapters, so we have to disable our default one */
916 INetworkAdapter *nwVBox = NULL;
917 rc = newMachine->GetNetworkAdapter (0, &nwVBox);
918 ComAssertComRCThrowRC (rc);
919 rc = nwVBox->COMSETTER(Enabled) (false);
920 ComAssertComRCThrowRC (rc);
921 }
922 else
923 {
924 list<VirtualSystemDescriptionEntry>::const_iterator nwIt;
925 size_t a = 0;
926 for (nwIt = vsdeNW.begin();
927 (nwIt != vsdeNW.end() && a < 9);
928 ++nwIt, ++a)
929 {
930 string nwTypeVBox = nwIt->strFinalValue;
931 uint32_t tt1 = RTStrToUInt32 (nwTypeVBox.c_str());
932 INetworkAdapter *nwVBox = NULL;
933 rc = newMachine->GetNetworkAdapter ((ULONG)a, &nwVBox);
934 ComAssertComRCThrowRC (rc);
935 /* Enable the network card & set the adapter type */
936 /* NAT is set as default */
937 rc = nwVBox->COMSETTER(Enabled) (true);
938 ComAssertComRCThrowRC (rc);
939 rc = nwVBox->COMSETTER(AdapterType) (static_cast<NetworkAdapterType_T> (tt1));
940 ComAssertComRCThrowRC (rc);
941 }
942 }
943 /* Now its time to register the machine before we add any hard disks */
944 rc = virtualBox->RegisterMachine (newMachine);
945 ComAssertComRCThrowRC (rc);
946
947 /* @todo: Unregister on failure */
948#if 0
949 vbox.UnregisterMachine (machineId);
950 if (vbox.isOk())
951 mMachine.DeleteSettings();
952 return false;
953#endif
954 }
955
956 return S_OK;
957}
958
959HRESULT Appliance::construeAppliance()
960{
961 // @todo:
962 // - Locking
963 // - COM error handling
964 // - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk2))
965 // - Appropriate handle errors like not supported file formats
966 // - Maybe it is better to replace std::string with Utf8Str's on some places?
967
968 /* Clear any previous virtual system descriptions */
969 // @todo: have the entries deleted also?
970 m->virtualSystemDescriptions.clear();
971
972 /* We need a virtualbox object */
973 ComPtr <IVirtualBox> virtualBox;
974 HRESULT rc = virtualBox.createLocalObject (CLSID_VirtualBox);
975 ComAssertComRCThrowRC (rc);
976
977 /* We need the default path for storing disk images */
978 ISystemProperties *systemProps = NULL;
979 rc = virtualBox->COMGETTER(SystemProperties) (&systemProps);
980 ComAssertComRCThrowRC (rc);
981 BSTR defaultHardDiskLocation;
982 rc = systemProps->COMGETTER(DefaultHardDiskFolder) (&defaultHardDiskLocation);
983 ComAssertComRCThrowRC (rc);
984
985 list<VirtualSystem>::const_iterator it;
986 /* Iterate through all appliances */
987 for (it = m->llVirtualSystems.begin();
988 it != m->llVirtualSystems.end();
989 ++it)
990 {
991 const VirtualSystem &vs = *it;
992 ComObjPtr <VirtualSystemDescription> vsd;
993 vsd.createObject();
994 rc = vsd->init();
995 ComAssertComRCThrowRC(rc);
996
997 string osTypeVBox = SchemaDefs_OSTypeId_Other;
998 /* Guest OS type */
999 switch (vs.cimos)
1000 {
1001 case CIMOSType_CIMOS_Unknown: // 0 - Unknown
1002 osTypeVBox = SchemaDefs_OSTypeId_Other;
1003 break;
1004
1005 case CIMOSType_CIMOS_OS2: // 12 - OS/2
1006 osTypeVBox = SchemaDefs_OSTypeId_OS2;
1007 break;
1008
1009 case CIMOSType_CIMOS_MSDOS: // 14 - MSDOS
1010 osTypeVBox = SchemaDefs_OSTypeId_DOS;
1011 break;
1012
1013 case CIMOSType_CIMOS_WIN3x: // 15 - WIN3x
1014 osTypeVBox = SchemaDefs_OSTypeId_Windows31;
1015 break;
1016
1017 case CIMOSType_CIMOS_WIN95: // 16 - WIN95
1018 osTypeVBox = SchemaDefs_OSTypeId_Windows95;
1019 break;
1020
1021 case CIMOSType_CIMOS_WIN98: // 17 - WIN98
1022 osTypeVBox = SchemaDefs_OSTypeId_Windows98;
1023 break;
1024
1025 case CIMOSType_CIMOS_WINNT: // 18 - WINNT
1026 osTypeVBox = SchemaDefs_OSTypeId_WindowsNT4;
1027 break;
1028
1029 case CIMOSType_CIMOS_NetWare: // 21 - NetWare
1030 case CIMOSType_CIMOS_NovellOES: // 86 - Novell OES
1031 osTypeVBox = SchemaDefs_OSTypeId_Netware;
1032 break;
1033
1034 case CIMOSType_CIMOS_Solaris: // 29 - Solaris
1035 case CIMOSType_CIMOS_SunOS: // 30 - SunOS
1036 osTypeVBox = SchemaDefs_OSTypeId_Solaris;
1037 break;
1038
1039 case CIMOSType_CIMOS_FreeBSD: // 42 - FreeBSD
1040 osTypeVBox = SchemaDefs_OSTypeId_FreeBSD;
1041 break;
1042
1043 case CIMOSType_CIMOS_NetBSD: // 43 - NetBSD
1044 osTypeVBox = SchemaDefs_OSTypeId_NetBSD;
1045 break;
1046
1047 case CIMOSType_CIMOS_QNX: // 48 - QNX
1048 osTypeVBox = SchemaDefs_OSTypeId_QNX;
1049 break;
1050
1051 case CIMOSType_CIMOS_Windows2000: // 58 - Windows 2000
1052 osTypeVBox = SchemaDefs_OSTypeId_Windows2000;
1053 break;
1054
1055 case CIMOSType_CIMOS_WindowsMe: // 63 - Windows (R) Me
1056 osTypeVBox = SchemaDefs_OSTypeId_WindowsMe;
1057 break;
1058
1059 case CIMOSType_CIMOS_OpenBSD: // 65 - OpenBSD
1060 osTypeVBox = SchemaDefs_OSTypeId_OpenBSD;
1061 break;
1062
1063 case CIMOSType_CIMOS_WindowsXP: // 67 - Windows XP
1064 case CIMOSType_CIMOS_WindowsXPEmbedded: // 72 - Windows XP Embedded
1065 case CIMOSType_CIMOS_WindowsEmbeddedforPointofService: // 75 - Windows Embedded for Point of Service
1066 osTypeVBox = SchemaDefs_OSTypeId_WindowsXP;
1067 break;
1068
1069 case CIMOSType_CIMOS_MicrosoftWindowsServer2003: // 69 - Microsoft Windows Server 2003
1070 osTypeVBox = SchemaDefs_OSTypeId_Windows2003;
1071 break;
1072
1073 case CIMOSType_CIMOS_MicrosoftWindowsServer2003_64: // 70 - Microsoft Windows Server 2003 64-Bit
1074 osTypeVBox = SchemaDefs_OSTypeId_Windows2003_64;
1075 break;
1076
1077 case CIMOSType_CIMOS_WindowsXP_64: // 71 - Windows XP 64-Bit
1078 osTypeVBox = SchemaDefs_OSTypeId_WindowsXP_64;
1079 break;
1080
1081 case CIMOSType_CIMOS_WindowsVista: // 73 - Windows Vista
1082 osTypeVBox = SchemaDefs_OSTypeId_WindowsVista;
1083 break;
1084
1085 case CIMOSType_CIMOS_WindowsVista_64: // 74 - Windows Vista 64-Bit
1086 osTypeVBox = SchemaDefs_OSTypeId_WindowsVista_64;
1087 break;
1088
1089 case CIMOSType_CIMOS_MicrosoftWindowsServer2008: // 76 - Microsoft Windows Server 2008
1090 osTypeVBox = SchemaDefs_OSTypeId_Windows2008;
1091 break;
1092
1093 case CIMOSType_CIMOS_MicrosoftWindowsServer2008_64: // 77 - Microsoft Windows Server 2008 64-Bit
1094 osTypeVBox = SchemaDefs_OSTypeId_Windows2008_64;
1095 break;
1096
1097 case CIMOSType_CIMOS_FreeBSD_64: // 78 - FreeBSD 64-Bit
1098 osTypeVBox = SchemaDefs_OSTypeId_FreeBSD_64;
1099 break;
1100
1101 case CIMOSType_CIMOS_RedHatEnterpriseLinux: // 79 - RedHat Enterprise Linux
1102 osTypeVBox = SchemaDefs_OSTypeId_RedHat;
1103 break;
1104
1105 case CIMOSType_CIMOS_RedHatEnterpriseLinux_64: // 80 - RedHat Enterprise Linux 64-Bit
1106 osTypeVBox = SchemaDefs_OSTypeId_RedHat_64;
1107 break;
1108
1109 case CIMOSType_CIMOS_Solaris_64: // 81 - Solaris 64-Bit
1110 osTypeVBox = SchemaDefs_OSTypeId_Solaris_64;
1111 break;
1112
1113 case CIMOSType_CIMOS_SUSE: // 82 - SUSE
1114 case CIMOSType_CIMOS_SLES: // 84 - SLES
1115 case CIMOSType_CIMOS_NovellLinuxDesktop: // 87 - Novell Linux Desktop
1116 osTypeVBox = SchemaDefs_OSTypeId_OpenSUSE;
1117 break;
1118
1119 case CIMOSType_CIMOS_SUSE_64: // 83 - SUSE 64-Bit
1120 case CIMOSType_CIMOS_SLES_64: // 85 - SLES 64-Bit
1121 osTypeVBox = SchemaDefs_OSTypeId_OpenSUSE_64;
1122 break;
1123
1124 case CIMOSType_CIMOS_LINUX: // 36 - LINUX
1125 case CIMOSType_CIMOS_SunJavaDesktopSystem: // 88 - Sun Java Desktop System
1126 case CIMOSType_CIMOS_TurboLinux: // 91 - TurboLinux
1127 osTypeVBox = SchemaDefs_OSTypeId_Linux;
1128 break;
1129
1130 // case CIMOSType_CIMOS_TurboLinux_64: // 92 - TurboLinux 64-Bit
1131 // case CIMOSType_CIMOS_Linux_64: // 101 - Linux 64-Bit
1132 // osTypeVBox = VBOXOSTYPE_Linux_x64;
1133 // break;
1134
1135 case CIMOSType_CIMOS_Mandriva: // 89 - Mandriva
1136 osTypeVBox = SchemaDefs_OSTypeId_Mandriva;
1137 break;
1138
1139 case CIMOSType_CIMOS_Mandriva_64: // 90 - Mandriva 64-Bit
1140 osTypeVBox = SchemaDefs_OSTypeId_Mandriva_64;
1141 break;
1142
1143 case CIMOSType_CIMOS_Ubuntu: // 93 - Ubuntu
1144 osTypeVBox = SchemaDefs_OSTypeId_Ubuntu;
1145 break;
1146
1147 case CIMOSType_CIMOS_Ubuntu_64: // 94 - Ubuntu 64-Bit
1148 osTypeVBox = SchemaDefs_OSTypeId_Ubuntu_64;
1149 break;
1150
1151 case CIMOSType_CIMOS_Debian: // 95 - Debian
1152 osTypeVBox = SchemaDefs_OSTypeId_Debian;
1153 break;
1154
1155 case CIMOSType_CIMOS_Debian_64: // 96 - Debian 64-Bit
1156 osTypeVBox = SchemaDefs_OSTypeId_Debian_64;
1157 break;
1158
1159 case CIMOSType_CIMOS_Linux_2_4_x: // 97 - Linux 2.4.x
1160 osTypeVBox = SchemaDefs_OSTypeId_Linux24;
1161 break;
1162
1163 case CIMOSType_CIMOS_Linux_2_4_x_64: // 98 - Linux 2.4.x 64-Bit
1164 osTypeVBox = SchemaDefs_OSTypeId_Linux24_64;
1165 break;
1166
1167 case CIMOSType_CIMOS_Linux_2_6_x: // 99 - Linux 2.6.x
1168 osTypeVBox = SchemaDefs_OSTypeId_Linux26;
1169 break;
1170
1171 case CIMOSType_CIMOS_Linux_2_6_x_64: // 100 - Linux 2.6.x 64-Bit
1172 osTypeVBox = SchemaDefs_OSTypeId_Linux26_64;
1173 break;
1174 default:
1175 {
1176 /* If we are here we have no clue what OS this should be. Set to
1177 * other type as default. */
1178 osTypeVBox = SchemaDefs_OSTypeId_Other;
1179 }
1180 }
1181 vsd->addEntry (VirtualSystemDescriptionType_OS, 0, toString<ULONG> (vs.cimos), osTypeVBox);
1182
1183 /* Now that we know the base system get our internal defaults based on that. */
1184 IGuestOSType *osType = NULL;
1185 rc = virtualBox->GetGuestOSType (Bstr (Utf8Str (osTypeVBox.c_str())), &osType);
1186 ComAssertComRCThrowRC (rc);
1187
1188 /* CPU count */
1189 ULONG cpuCountVBox = vs.cCPUs;
1190 if (vs.cCPUs == 0)
1191 cpuCountVBox = 1;
1192 vsd->addEntry (VirtualSystemDescriptionType_CPU, 0, toString<ULONG> (vs.cCPUs), toString<ULONG> (cpuCountVBox));
1193
1194 /* RAM */
1195 ULONG memSizeVBox = vs.ullMemorySize; /** @todo r=bird/MSC: this will overflow at 4GB, use 64-bit type. */
1196 if (vs.ullMemorySize == 0)
1197 {
1198 /* If the RAM of the OVF is zero, use our predefined values */
1199 rc = osType->COMGETTER(RecommendedRAM) (&memSizeVBox);
1200 ComAssertComRCThrowRC (rc);
1201 /* VBox stores that in MByte */
1202 memSizeVBox *= _1M;
1203 }
1204 vsd->addEntry (VirtualSystemDescriptionType_Memory, 0, toString<ULONG> (vs.ullMemorySize), toString<ULONG> (memSizeVBox));
1205
1206 /* Hard disk Controller */
1207 ControllersMap::const_iterator hdcIt;
1208 /* Iterate through all hard disk controllers */
1209 for (hdcIt = vs.mapControllers.begin();
1210 hdcIt != vs.mapControllers.end();
1211 ++hdcIt)
1212 {
1213 HardDiskController hdc = hdcIt->second;
1214 switch (hdc.controllerSystem)
1215 {
1216 case IDE:
1217 {
1218 // @todo: figure out the IDE types
1219 /* Use PIIX4 as default */
1220 IDEControllerType_T hdcController = IDEControllerType_PIIX4;
1221 if (!RTStrICmp(hdc.strControllerType.c_str(), "PIIX3"))
1222 hdcController = IDEControllerType_PIIX3;
1223 else if (!RTStrICmp(hdc.strControllerType.c_str(), "PIIX4"))
1224 hdcController = IDEControllerType_PIIX4;
1225 vsd->addEntry (VirtualSystemDescriptionType_HarddiskControllerIDE, hdc.idController, hdc.strControllerType, toString<ULONG> (hdcController));
1226 break;
1227 }
1228 case SATA:
1229 {
1230 // @todo: figure out the SATA types
1231 /* We only support a plain AHCI controller, so use them always */
1232 vsd->addEntry (VirtualSystemDescriptionType_HarddiskControllerSATA, hdc.idController, hdc.strControllerType, "AHCI");
1233 break;
1234 }
1235 case SCSI:
1236 {
1237 string hdcController = "LsiLogic";
1238 // @todo: figure out the SCSI types
1239 if (!RTStrICmp(hdc.strControllerType.c_str(), "LsiLogic"))
1240 hdcController = "LsiLogic";
1241 else if (!RTStrICmp(hdc.strControllerType.c_str(), "BusLogic"))
1242 hdcController = "BusLogic";
1243 vsd->addEntry (VirtualSystemDescriptionType_HarddiskControllerSCSI, hdc.idController, hdc.strControllerType, hdcController);
1244 break;
1245 }
1246 }
1247 }
1248
1249 /* Hard disks */
1250 if (vs.llVirtualDisks.size() > 0)
1251 {
1252 // @todo:
1253 // - strHref could be empty (construct a new default file name)
1254 // - check that the filename is unique to vbox in any case
1255 list<VirtualDisk>::const_iterator hdIt;
1256 /* Iterate through all hard disks */
1257 for (hdIt = vs.llVirtualDisks.begin();
1258 hdIt != vs.llVirtualDisks.end();
1259 ++hdIt)
1260 {
1261 VirtualDisk hd = *hdIt;
1262 /* Get the associated disk image */
1263 DiskImage di = m->mapDisks [hd.strDiskId];
1264 /* We have to check if we support this format */
1265 bool fSupported = false;
1266 // @todo:
1267 // - figure out all possible vmdk formats we also support
1268 // - figure out if there is a url specifier for vhd already
1269 // - we need a url specifier for the vdi format
1270 if (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#sparse"))
1271 fSupported = true;
1272 /* enable compressed formats for the first tests also */
1273 else if (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#compressed"))
1274 fSupported = true;
1275 if (fSupported)
1276 {
1277 /* Construct the path */
1278 string path = Utf8StrFmt ("%ls%c%s", defaultHardDiskLocation, RTPATH_DELIMITER, di.strHref.c_str()).raw();
1279 vsd->addEntry (VirtualSystemDescriptionType_Harddisk, hd.idController, di.strHref, path);
1280 }
1281 }
1282 }
1283
1284 /* Network Controller */
1285 // @todo: is there no hardware specified in the OVF-Format?
1286 if (vs.llNetworkNames.size() > 0)
1287 {
1288 /* Get the default network adapter type for the selected guest os */
1289 NetworkAdapterType_T nwAdapterVBox = NetworkAdapterType_Am79C970A;
1290 rc = osType->COMGETTER(AdapterType) (&nwAdapterVBox);
1291 ComAssertComRCThrowRC (rc);
1292 list<string>::const_iterator nwIt;
1293 /* Iterate through all abstract networks */
1294 for (nwIt = vs.llNetworkNames.begin();
1295 nwIt != vs.llNetworkNames.end();
1296 ++nwIt)
1297 {
1298 // string nwController = *nwIt; // @todo: not used yet
1299 vsd->addEntry (VirtualSystemDescriptionType_NetworkAdapter, 0, "", toString<ULONG> (nwAdapterVBox));
1300 }
1301 }
1302 m->virtualSystemDescriptions.push_back (vsd);
1303 }
1304
1305 return S_OK;
1306}
1307
1308// IVirtualSystemDescription constructor / destructor
1309////////////////////////////////////////////////////////////////////////////////
1310
1311DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1312struct shutup3 {};
1313
1314struct VirtualSystemDescription::Data
1315{
1316 list<VirtualSystemDescriptionEntry> descriptions;
1317};
1318
1319HRESULT VirtualSystemDescription::init()
1320{
1321 /* Enclose the state transition NotReady->InInit->Ready */
1322 AutoInitSpan autoInitSpan (this);
1323 AssertReturn (autoInitSpan.isOk(), E_FAIL);
1324
1325 /* Initialize data */
1326 m = new Data();
1327
1328 /* Confirm a successful initialization */
1329 autoInitSpan.setSucceeded();
1330
1331 return S_OK;
1332}
1333
1334void VirtualSystemDescription::uninit()
1335{
1336 delete m;
1337 m = NULL;
1338}
1339
1340STDMETHODIMP VirtualSystemDescription::GetDescription (ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1341 ComSafeArrayOut(ULONG, aRefs),
1342 ComSafeArrayOut(BSTR, aOrigValues),
1343 ComSafeArrayOut(BSTR, aAutoValues),
1344 ComSafeArrayOut(BSTR, aConfigurations))
1345{
1346 if (ComSafeArrayOutIsNull (aTypes) ||
1347 ComSafeArrayOutIsNull (aRefs) ||
1348 ComSafeArrayOutIsNull (aOrigValues) ||
1349 ComSafeArrayOutIsNull (aAutoValues) ||
1350 ComSafeArrayOutIsNull (aConfigurations))
1351 return E_POINTER;
1352
1353 AutoCaller autoCaller (this);
1354 CheckComRCReturnRC (autoCaller.rc());
1355
1356 AutoReadLock alock (this);
1357
1358 ULONG c = (ULONG)m->descriptions.size();
1359 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes (c);
1360 com::SafeArray<ULONG> sfaRefs (c);
1361 com::SafeArray<BSTR> sfaOrigValues (c);
1362 com::SafeArray<BSTR> sfaAutoValues (c);
1363 com::SafeArray<BSTR> sfaConfigurations (c);
1364
1365 list<VirtualSystemDescriptionEntry>::const_iterator it;
1366 size_t i = 0;
1367 for (it = m->descriptions.begin();
1368 it != m->descriptions.end();
1369 ++it, ++i)
1370 {
1371 VirtualSystemDescriptionEntry vsde = (*it);
1372 /* Types */
1373 sfaTypes [i] = vsde.type;
1374 /* Refs */
1375 sfaRefs [i] = vsde.ref;
1376 /* Original value */
1377 Bstr bstr = Utf8Str (vsde.strOriginalValue.c_str());
1378 bstr.cloneTo (&sfaOrigValues [i]);
1379 /* Auto value */
1380 bstr = Utf8Str (vsde.strAutoValue.c_str());
1381 bstr.cloneTo (&sfaAutoValues [i]);
1382 /* Configuration */
1383 bstr = Utf8Str (vsde.strConfiguration.c_str());
1384 bstr.cloneTo (&sfaConfigurations [i]);
1385 }
1386
1387 sfaTypes.detachTo (ComSafeArrayOutArg (aTypes));
1388 sfaRefs.detachTo (ComSafeArrayOutArg (aRefs));
1389 sfaOrigValues.detachTo (ComSafeArrayOutArg (aOrigValues));
1390 sfaAutoValues.detachTo (ComSafeArrayOutArg (aAutoValues));
1391 sfaConfigurations.detachTo (ComSafeArrayOutArg (aConfigurations));
1392
1393 return S_OK;
1394}
1395
1396STDMETHODIMP VirtualSystemDescription::SetFinalValues (ComSafeArrayIn (IN_BSTR, aFinalValues))
1397{
1398 CheckComArgSafeArrayNotNull (aFinalValues);
1399
1400 AutoCaller autoCaller (this);
1401 CheckComRCReturnRC (autoCaller.rc());
1402
1403 AutoWriteLock alock (this);
1404
1405 com::SafeArray <IN_BSTR> values (ComSafeArrayInArg (aFinalValues));
1406 if (values.size() != m->descriptions.size())
1407 return E_INVALIDARG;
1408
1409 list<VirtualSystemDescriptionEntry>::const_iterator it;
1410 size_t i = 0;
1411 for (it = m->descriptions.begin();
1412 it != m->descriptions.end();
1413 ++it, ++i)
1414 {
1415 VirtualSystemDescriptionEntry vsde = (*it);
1416 vsde.strFinalValue = Utf8Str (values [i]).raw();
1417 }
1418
1419 return S_OK;
1420}
1421
1422void VirtualSystemDescription::addEntry (VirtualSystemDescriptionType_T aType, ULONG aRef, std::string aOrigValue, std::string aAutoValue)
1423{
1424 VirtualSystemDescriptionEntry vsde;
1425 vsde.type = aType;
1426 vsde.ref = aRef;
1427 vsde.strOriginalValue = aOrigValue;
1428 vsde.strAutoValue = aAutoValue;
1429 /* For now we add the auto value as final value also */
1430 vsde.strFinalValue = aAutoValue;
1431
1432 m->descriptions.push_back (vsde);
1433}
1434
1435list<VirtualSystemDescriptionEntry> VirtualSystemDescription::findByType (VirtualSystemDescriptionType_T aType)
1436{
1437 list<VirtualSystemDescriptionEntry> vsd;
1438
1439 list<VirtualSystemDescriptionEntry>::const_iterator it;
1440 for (it = m->descriptions.begin();
1441 it != m->descriptions.end();
1442 ++it)
1443 if (it->type == aType)
1444 vsd.push_back (*it);
1445
1446 return vsd;
1447}
1448
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