VirtualBox

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

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

OVF: win fix

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