VirtualBox

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

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

typo

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.8 KB
Line 
1/* $Id: ApplianceImpl.cpp 16361 2009-01-29 10:59:19Z 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 ComPtr<IAudioAdapter> audioAdapter;
1454 rc = newMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
1455 ComAssertComRCThrowRC(rc);
1456 rc = audioAdapter->COMSETTER(Enabled)(true);
1457 ComAssertComRCThrowRC(rc);
1458 /* @todo: For now this is preselected, but on Linux for example
1459 more drivers are possible. The user should be able to change
1460 this also. */
1461 AudioDriverType_T adt = AudioDriverType_Null;
1462#if defined(RT_OS_WINDOWS)
1463# ifdef VBOX_WITH_WINMM
1464 adt = AudioDriverType_WinMM;
1465# else
1466 adt = AudioDriverType_DirectSound;
1467# endif
1468#elif defined(RT_OS_LINUX)
1469# ifdef VBOX_WITH_ALSA
1470 adt = AudioDriverType_ALSA;
1471# elif defined(VBOX_WITH_PULSE)
1472 adt = AudioDriverType_Pulse;
1473# else
1474 adt = AudioDriverType_OSS;
1475# endif
1476#elif defined(RT_OS_DARWIN)
1477 adt = AudioDriverType_CoreAudio;
1478#elif defined(RT_OS_SOLARIS)
1479 adt = AudioDriverType_SolAudio;
1480#elif defined(RT_OS_OS2)
1481 adt = AudioDriverType_MMPM;
1482#endif
1483 rc = audioAdapter->COMSETTER(AudioDriver)(adt);
1484 ComAssertComRCThrowRC(rc);
1485 rc = audioAdapter->COMSETTER(AudioController)(audioAdapterVBox);
1486 ComAssertComRCThrowRC(rc);
1487 }
1488 }
1489
1490 /* USB Controller */
1491 std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsd->findByType(VirtualSystemDescriptionType_USBController);
1492 /* If there is no USB controller entry it will be disabled */
1493 bool fUSBEnabled = vsdeUSBController.size() > 0;
1494 if (fUSBEnabled)
1495 {
1496 /* Check if the user has disabled the USB controller in the client */
1497 const Utf8Str& usbVBox = vsdeUSBController.front()->strFinalValue;
1498 fUSBEnabled = usbVBox == "1";
1499 }
1500 ComPtr<IUSBController> usbController;
1501 rc = newMachine->COMGETTER(USBController)(usbController.asOutParam());
1502 ComAssertComRCThrowRC(rc);
1503 rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
1504 ComAssertComRCThrowRC(rc);
1505
1506 /* Change the network adapters */
1507 std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsd->findByType(VirtualSystemDescriptionType_NetworkAdapter);
1508 if (vsdeNW.size() == 0)
1509 {
1510 /* No network adapters, so we have to disable our default one */
1511 ComPtr<INetworkAdapter> nwVBox;
1512 rc = newMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
1513 ComAssertComRCThrowRC(rc);
1514 rc = nwVBox->COMSETTER(Enabled)(false);
1515 ComAssertComRCThrowRC(rc);
1516 }
1517 else
1518 {
1519 list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
1520 /* Iterate through all network cards. We support 8 network adapters
1521 * at the maximum. (@todo: warn if it are more!) */
1522 size_t a = 0;
1523 for (nwIt = vsdeNW.begin();
1524 (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
1525 ++nwIt, ++a)
1526 {
1527 const Utf8Str &nwTypeVBox = (*nwIt)->strFinalValue;
1528 uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
1529 ComPtr<INetworkAdapter> nwVBox;
1530 rc = newMachine->GetNetworkAdapter((ULONG)a, nwVBox.asOutParam());
1531 ComAssertComRCThrowRC(rc);
1532 /* Enable the network card & set the adapter type */
1533 /* NAT is set as default */
1534 rc = nwVBox->COMSETTER(Enabled)(true);
1535 ComAssertComRCThrowRC(rc);
1536 rc = nwVBox->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
1537 ComAssertComRCThrowRC(rc);
1538 }
1539 }
1540
1541 /* Floppy drive */
1542 std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_Floppy);
1543 /* If there is no floppy drive entry it will be disabled */
1544 bool fFloppyEnabled = vsdeFloppy.size() > 0;
1545 if (fFloppyEnabled)
1546 {
1547 /* Check if the user has disabled the floppy drive in the client */
1548 const Utf8Str& floppyVBox = vsdeFloppy.front()->strFinalValue;
1549 fFloppyEnabled = floppyVBox == "1";
1550 }
1551 ComPtr<IFloppyDrive> floppyDrive;
1552 rc = newMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
1553 ComAssertComRCThrowRC(rc);
1554 rc = floppyDrive->COMSETTER(Enabled)(fFloppyEnabled);
1555 ComAssertComRCThrowRC(rc);
1556
1557 /* CDROM drive */
1558 /* @todo: I can't disable the CDROM. So nothing to do for now */
1559 // std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_CDROM);
1560
1561 /* Hard disk controller IDE */
1562 std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsd->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
1563 /* @todo: we support one IDE controller only */
1564 if (vsdeHDCIDE.size() > 0)
1565 {
1566 IDEControllerType_T hdcVBox = static_cast<IDEControllerType_T>(RTStrToUInt32(vsdeHDCIDE.front()->strFinalValue.c_str()));
1567 /* Set the appropriate IDE controller in the virtual BIOS of the
1568 * VM. */
1569 ComPtr<IBIOSSettings> biosSettings;
1570 rc = newMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam());
1571 CheckComRCReturnRC(rc);
1572 rc = biosSettings->COMSETTER(IDEControllerType)(hdcVBox);
1573 CheckComRCReturnRC(rc);
1574 }
1575#ifdef VBOX_WITH_AHCI
1576 /* Hard disk controller SATA */
1577 std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsd->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
1578 /* @todo: we support one SATA controller only */
1579 if (vsdeHDCSATA.size() > 0)
1580 {
1581 const Utf8Str &hdcVBox = vsdeHDCIDE.front()->strFinalValue;
1582 if (hdcVBox == "AHCI")
1583 {
1584 /* For now we have just to enable the AHCI controller. */
1585 ComPtr<ISATAController> hdcSATAVBox;
1586 rc = newMachine->COMGETTER(SATAController)(hdcSATAVBox.asOutParam());
1587 CheckComRCReturnRC(rc);
1588 rc = hdcSATAVBox->COMSETTER(Enabled)(true);
1589 CheckComRCReturnRC(rc);
1590 }
1591 else
1592 {
1593 /* @todo: set an error if this is other than AHCI */
1594 }
1595 }
1596#endif /* VBOX_WITH_AHCI */
1597#ifdef VBOX_WITH_SCSI
1598 /* Hard disk controller SCSI */
1599 EntriesList vsdeHDCSCSI = vsd->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
1600 /* @todo: do we support more than one SCSI controller? */
1601 if (vsdeHDCSCSI.size() > 0)
1602 {
1603 /* @todo: Currently I have no idea how to enable this. Someone has
1604 * to write main support for SCSI at all. */
1605 }
1606#endif /* VBOX_WITH_SCSI */
1607
1608 /* Now its time to register the machine before we add any hard disks */
1609 rc = mVirtualBox->RegisterMachine(newMachine);
1610 ComAssertComRCThrowRC(rc);
1611
1612 /* Create the hard disks & connect them to the appropriate controllers. */
1613 std::list<VirtualSystemDescriptionEntry*> vsdeHD = vsd->findByType(VirtualSystemDescriptionType_HardDiskImage);
1614 if (vsdeHD.size() > 0)
1615 {
1616 /* That we can attach hard disks we need to open a session for the
1617 * new machine */
1618 Guid newMachineId;
1619 rc = newMachine->COMGETTER(Id)(newMachineId.asOutParam());
1620 CheckComRCReturnRC(rc);
1621 ComPtr<ISession> session;
1622 rc = session.createInprocObject(CLSID_Session);
1623 CheckComRCReturnRC(rc);
1624 rc = mVirtualBox->OpenSession(session, newMachineId);
1625 CheckComRCReturnRC(rc);
1626
1627 int result;
1628 /* The disk image has to be on the same place as the OVF file. So
1629 * strip the filename out of the full file path. */
1630 char *srcDir = RTStrDup(Utf8Str(m->bstrPath).raw());
1631 RTPathStripFilename(srcDir);
1632 /* Iterate over all given disk images */
1633 list<VirtualSystemDescriptionEntry*>::const_iterator hdIt;
1634 for (hdIt = vsdeHD.begin();
1635 hdIt != vsdeHD.end();
1636 ++hdIt)
1637 {
1638 char *dstFilePath = RTStrDup((*hdIt)->strFinalValue.c_str());
1639 /* Check if the destination file exists already or the
1640 * destination path is empty. */
1641 if (RTPathExists(dstFilePath) ||
1642 !RTStrCmp(dstFilePath, ""))
1643 {
1644 /* @todo: what now? For now we override in no
1645 * circumstances. */
1646 continue;
1647 }
1648 const Utf8Str &strRef = (*hdIt)->strRef;
1649 /* Get the associated disk image */
1650 if (m->mapDisks.find(strRef) == m->mapDisks.end() ||
1651 vs.mapVirtualDisks.find(strRef) == vs.mapVirtualDisks.end())
1652 {
1653 /* @todo: error: entry doesn't exists */
1654 }
1655 DiskImage di = m->mapDisks[strRef];
1656 VirtualDisk vd = (*vs.mapVirtualDisks.find(strRef)).second;
1657 /* Construct the source file path */
1658 char *srcFilePath;
1659 RTStrAPrintf(&srcFilePath, "%s/%s", srcDir, di.strHref.c_str());
1660 /* Check if the source file exists */
1661 if (!RTPathExists(srcFilePath))
1662 {
1663 /* @todo: we have to create a new one */
1664 }
1665 else
1666 {
1667 /* Make sure all target directories exists */
1668 rc = VirtualBox::ensureFilePathExists(dstFilePath);
1669 CheckComRCThrowRC(rc);
1670 /* Clone the disk image (this is necessary cause the id has
1671 * to be recreated for the case the same hard disk is
1672 * attached already from a previous import) */
1673 /* First open the existing disk image */
1674 ComPtr<IHardDisk2> srcHdVBox;
1675 rc = mVirtualBox->OpenHardDisk2(Bstr(srcFilePath), srcHdVBox.asOutParam());
1676 CheckComRCReturnRC(rc);
1677 /* We need the format description of the source disk image */
1678 Bstr srcFormat;
1679 rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
1680 CheckComRCReturnRC(rc);
1681 /* Create a new hard disk interface for the destination disk image */
1682 ComPtr<IHardDisk2> dstHdVBox;
1683 rc = mVirtualBox->CreateHardDisk2(srcFormat, Bstr(dstFilePath), dstHdVBox.asOutParam());
1684 CheckComRCReturnRC(rc);
1685 /* Clone the source disk image */
1686 ComPtr<IProgress> progress;
1687 rc = srcHdVBox->CloneTo(dstHdVBox, progress.asOutParam());
1688 CheckComRCReturnRC(rc);
1689 rc = progress->WaitForCompletion(-1);
1690 CheckComRCReturnRC(rc);
1691 /* We *must* close the source disk image in order to deregister it */
1692 rc = srcHdVBox->Close();
1693 CheckComRCReturnRC(rc);
1694 /* Now use the new uuid to attach the disk image to our new machine */
1695 ComPtr<IMachine> sMachine;
1696 rc = session->COMGETTER(Machine)(sMachine.asOutParam());
1697 Guid hdId;
1698 rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());;
1699 CheckComRCReturnRC(rc);
1700 /* For now we assume we have one controller of every type only */
1701 HardDiskController hdc = (*vs.mapControllers.find(vd.idController)).second;
1702 StorageBus_T sbt = StorageBus_IDE;
1703 switch (hdc.controllerSystem)
1704 {
1705 case IDE: sbt = StorageBus_IDE; break;
1706 case SATA: sbt = StorageBus_SATA; break;
1707 //case SCSI: sbt = StorageBus_SCSI; break; // @todo: not available yet
1708 default: break;
1709 }
1710 rc = sMachine->AttachHardDisk2(hdId, sbt, hdc.ulBusNumber, 0);
1711 CheckComRCReturnRC(rc);
1712 rc = sMachine->SaveSettings();
1713 CheckComRCReturnRC(rc);
1714 rc = session->Close();
1715 CheckComRCReturnRC(rc);
1716 }
1717 RTStrFree(srcFilePath);
1718 RTStrFree(dstFilePath);
1719 }
1720 RTStrFree(srcDir);
1721 }
1722 /* @todo: Unregister on failure */
1723#if 0
1724 vbox.UnregisterMachine (machineId);
1725 if (vbox.isOk())
1726 mMachine.DeleteSettings();
1727 return false;
1728#endif
1729 }
1730
1731 return S_OK;
1732}
1733
1734HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
1735{
1736 IMachine *machine = NULL;
1737 char *tmpName = RTStrDup(aName.c_str());
1738 int i = 1;
1739 /* @todo: Maybe to cost intensive; try to find a lighter way */
1740 while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
1741 {
1742 RTStrFree(tmpName);
1743 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
1744 ++i;
1745 }
1746 aName = tmpName;
1747 RTStrFree(tmpName);
1748
1749 return S_OK;
1750}
1751
1752HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
1753{
1754 IHardDisk2 *harddisk = NULL;
1755 char *tmpName = RTStrDup(aName.c_str());
1756 int i = 1;
1757 /* Check if the file exists or if a file with this path is registered
1758 * already */
1759 /* @todo: Maybe to cost intensive; try to find a lighter way */
1760 while (RTPathExists(tmpName) ||
1761 mVirtualBox->FindHardDisk2(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
1762 {
1763 RTStrFree(tmpName);
1764 char *tmpDir = RTStrDup(aName.c_str());
1765 RTPathStripFilename(tmpDir);;
1766 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
1767 RTPathStripExt(tmpFile);
1768 char *tmpExt = RTPathExt(aName.c_str());
1769 RTStrAPrintf(&tmpName, "%s/%s_%d%s", tmpDir, tmpFile, i, tmpExt);
1770 RTStrFree(tmpFile);
1771 RTStrFree(tmpDir);
1772 ++i;
1773 }
1774 aName = tmpName;
1775 RTStrFree(tmpName);
1776
1777 return S_OK;
1778}
1779
1780// IVirtualSystemDescription constructor / destructor
1781////////////////////////////////////////////////////////////////////////////////
1782
1783DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1784struct shutup3 {};
1785
1786struct VirtualSystemDescription::Data
1787{
1788 list<VirtualSystemDescriptionEntry> descriptions;
1789};
1790
1791HRESULT VirtualSystemDescription::init()
1792{
1793 /* Enclose the state transition NotReady->InInit->Ready */
1794 AutoInitSpan autoInitSpan(this);
1795 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1796
1797 /* Initialize data */
1798 m = new Data();
1799
1800 /* Confirm a successful initialization */
1801 autoInitSpan.setSucceeded();
1802
1803 return S_OK;
1804}
1805
1806void VirtualSystemDescription::uninit()
1807{
1808 delete m;
1809 m = NULL;
1810}
1811
1812STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1813 ComSafeArrayOut(BSTR, aOrigValues),
1814 ComSafeArrayOut(BSTR, aAutoValues),
1815 ComSafeArrayOut(BSTR, aConfigurations))
1816{
1817 if (ComSafeArrayOutIsNull(aTypes) ||
1818 ComSafeArrayOutIsNull(aOrigValues) ||
1819 ComSafeArrayOutIsNull(aAutoValues) ||
1820 ComSafeArrayOutIsNull(aConfigurations))
1821 return E_POINTER;
1822
1823 AutoCaller autoCaller(this);
1824 CheckComRCReturnRC(autoCaller.rc());
1825
1826 AutoReadLock alock(this);
1827
1828 ULONG c = (ULONG)m->descriptions.size();
1829 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1830 com::SafeArray<BSTR> sfaOrigValues(c);
1831 com::SafeArray<BSTR> sfaAutoValues(c);
1832 com::SafeArray<BSTR> sfaConfigurations(c);
1833
1834 list<VirtualSystemDescriptionEntry>::const_iterator it;
1835 size_t i = 0;
1836 for (it = m->descriptions.begin();
1837 it != m->descriptions.end();
1838 ++it, ++i)
1839 {
1840 const VirtualSystemDescriptionEntry &vsde = (*it);
1841 /* Types */
1842 sfaTypes [i] = vsde.type;
1843 /* Original value */
1844 Bstr bstr = vsde.strOriginalValue;
1845 bstr.cloneTo(&sfaOrigValues[i]);
1846 /* Auto value */
1847 bstr = vsde.strAutoValue;
1848 bstr.cloneTo(&sfaAutoValues[i]);
1849 /* Configuration */
1850 bstr = vsde.strConfiguration;
1851 bstr.cloneTo(&sfaConfigurations[i]);
1852 }
1853
1854 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1855 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1856 sfaAutoValues.detachTo(ComSafeArrayOutArg(aAutoValues));
1857 sfaConfigurations.detachTo(ComSafeArrayOutArg(aConfigurations));
1858
1859 return S_OK;
1860}
1861
1862STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(IN_BSTR, aFinalValues))
1863{
1864 CheckComArgSafeArrayNotNull(aFinalValues);
1865
1866 AutoCaller autoCaller(this);
1867 CheckComRCReturnRC(autoCaller.rc());
1868
1869 AutoWriteLock alock(this);
1870
1871 com::SafeArray <IN_BSTR> values(ComSafeArrayInArg(aFinalValues));
1872 if (values.size() != m->descriptions.size())
1873 return E_INVALIDARG;
1874
1875 list<VirtualSystemDescriptionEntry>::const_iterator it;
1876 size_t i = 0;
1877 for (it = m->descriptions.begin();
1878 it != m->descriptions.end();
1879 ++it, ++i)
1880 {
1881 VirtualSystemDescriptionEntry vsde = (*it);
1882 vsde.strFinalValue = values[i];
1883 }
1884
1885 return S_OK;
1886}
1887
1888void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1889 const Utf8Str &aRef,
1890 const Utf8Str &aOrigValue,
1891 const Utf8Str &aAutoValue,
1892 const Utf8Str &aConfig /* = "" */)
1893{
1894 VirtualSystemDescriptionEntry vsde;
1895 vsde.type = aType;
1896 vsde.strRef = aRef;
1897 vsde.strOriginalValue = aOrigValue;
1898 vsde.strAutoValue = aAutoValue;
1899 vsde.strConfiguration = aConfig;
1900 /* For now we add the auto value as final value also */
1901 vsde.strFinalValue = aAutoValue;
1902
1903 m->descriptions.push_back(vsde);
1904}
1905
1906std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1907{
1908 std::list<VirtualSystemDescriptionEntry*> vsd;
1909 list<VirtualSystemDescriptionEntry>::iterator it;
1910 for (it = m->descriptions.begin();
1911 it != m->descriptions.end();
1912 ++it)
1913 if (it->type == aType)
1914 vsd.push_back(&(*it));
1915
1916 return vsd;
1917}
1918
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