VirtualBox

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

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

OVF: fix ulong overflow

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