VirtualBox

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

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

OVF: parse VirtualSystem/@id as machine name

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