VirtualBox

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

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

OVF: no USB support if USB is disabled (OSE)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 112.3 KB
Line 
1/* $Id: ApplianceImpl.cpp 17109 2009-02-25 08:18:39Z 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#include "ProgressImpl.h"
32#include "MachineImpl.h"
33
34#include "Logging.h"
35
36#include "VBox/xml.h"
37
38using namespace std;
39
40// defines
41////////////////////////////////////////////////////////////////////////////////
42
43struct DiskImage
44{
45 Utf8Str strDiskId; // value from DiskSection/Disk/@diskId
46 int64_t iCapacity; // value from DiskSection/Disk/@capacity;
47 // (maximum size for dynamic images, I guess; we always translate this to bytes)
48 int64_t iPopulatedSize; // value from DiskSection/Disk/@populatedSize
49 // (actual used size of disk, always in bytes; can be an estimate of used disk
50 // space, but cannot be larger than iCapacity)
51 Utf8Str strFormat; // value from DiskSection/Disk/@format
52 // typically http://www.vmware.com/specifications/vmdk.html#sparse
53
54 // fields from /References/File; the spec says the file reference from disk can be empty,
55 // so in that case, strFilename will be empty, then a new disk should be created
56 Utf8Str strHref; // value from /References/File/@href (filename); if empty, then the remaining fields are ignored
57 int64_t iSize; // value from /References/File/@size (optional according to spec; then we set -1 here)
58 int64_t iChunkSize; // value from /References/File/@chunkSize (optional, unsupported)
59 Utf8Str strCompression; // value from /References/File/@compression (optional, can be "gzip" according to spec)
60};
61
62struct Network
63{
64 Utf8Str strNetworkName; // value from NetworkSection/Network/@name
65 // unfortunately the OVF spec is unspecific about how networks should be specified further
66};
67
68struct VirtualHardwareItem
69{
70 Utf8Str strDescription;
71 Utf8Str strCaption;
72 Utf8Str strElementName;
73
74 uint32_t ulInstanceID;
75 uint32_t ulParent;
76
77 OVFResourceType_T resourceType;
78 Utf8Str strOtherResourceType;
79 Utf8Str strResourceSubType;
80
81 Utf8Str strHostResource; // "Abstractly specifies how a device shall connect to a resource on the deployment platform.
82 // Not all devices need a backing." Used with disk items, for which this references a virtual
83 // disk from the Disks section.
84 bool fAutomaticAllocation;
85 bool fAutomaticDeallocation;
86 Utf8Str strConnection; // "All Ethernet adapters that specify the same abstract network connection name within an OVF
87 // package shall be deployed on the same network. The abstract network connection name shall be
88 // listed in the NetworkSection at the outermost envelope level."
89 Utf8Str strAddress; // "Device-specific. For an Ethernet adapter, this specifies the MAC address."
90 Utf8Str strAddressOnParent; // "For a device, this specifies its location on the controller."
91 Utf8Str strAllocationUnits; // "Specifies the units of allocation used. For example, “byte * 2^20”."
92 uint64_t ullVirtualQuantity; // "Specifies the quantity of resources presented. For example, “256”."
93 uint64_t ullReservation; // "Specifies the minimum quantity of resources guaranteed to be available."
94 uint64_t ullLimit; // "Specifies the maximum quantity of resources that will be granted."
95 uint64_t ullWeight; // "Specifies a relative priority for this allocation in relation to other allocations."
96
97 Utf8Str strConsumerVisibility;
98 Utf8Str strMappingBehavior;
99 Utf8Str strPoolID;
100 uint32_t ulBusNumber; // seen with IDE controllers, but not listed in OVF spec
101
102 uint32_t ulLineNumber; // line number of <Item> element in XML source; cached for error messages
103
104 VirtualHardwareItem()
105 : ulInstanceID(0), fAutomaticAllocation(false), fAutomaticDeallocation(false), ullVirtualQuantity(0), ullReservation(0), ullLimit(0), ullWeight(0), ulBusNumber(0), ulLineNumber(0)
106 {};
107};
108
109typedef map<Utf8Str, DiskImage> DiskImagesMap;
110typedef map<Utf8Str, Network> NetworksMap;
111
112struct VirtualSystem;
113
114// opaque private instance data of Appliance class
115struct Appliance::Data
116{
117 Bstr bstrPath;
118
119 DiskImagesMap mapDisks; // map of DiskImage structs, sorted by DiskImage.strDiskId
120
121 NetworksMap mapNetworks; // map of Network structs, sorted by Network.strNetworkName
122
123 list<VirtualSystem> llVirtualSystems;
124
125 list< ComObjPtr<VirtualSystemDescription> > virtualSystemDescriptions;
126};
127
128typedef map<uint32_t, VirtualHardwareItem> HardwareItemsMap;
129
130struct HardDiskController
131{
132 uint32_t idController; // instance ID (Item/InstanceId); this gets referenced from HardDisk
133 enum ControllerSystemType { IDE, SATA, SCSI };
134 ControllerSystemType system; // one of IDE, SATA, SCSI
135 Utf8Str strControllerType; // controller subtype (Item/ResourceSubType); e.g. "LsiLogic"; can be empty (esp. for IDE)
136 Utf8Str strAddress; // for IDE
137 uint32_t ulBusNumber; // for IDE
138
139 HardDiskController()
140 : idController(0),
141 ulBusNumber(0)
142 {
143 }
144};
145
146typedef map<uint32_t, HardDiskController> ControllersMap;
147
148struct VirtualDisk
149{
150 uint32_t idController; // SCSI (or IDE) controller this disk is connected to;
151 // points into VirtualSystem.mapControllers
152 uint32_t ulAddressOnParent; // parsed strAddressOnParent of hardware item; will be 0 or 1 for IDE
153 // and possibly higher for disks attached to SCSI controllers (untested)
154 Utf8Str strDiskId; // if the hard disk has an ovf:/disk/<id> reference,
155 // this receives the <id> component; points to one of the
156 // references in Appliance::Data.mapDisks
157};
158
159typedef map<Utf8Str, VirtualDisk> VirtualDisksMap;
160
161struct VirtualSystem
162{
163 Utf8Str strName; // copy of VirtualSystem/@id
164
165 CIMOSType_T cimos;
166 Utf8Str strVirtualSystemType; // generic hardware description; OVF says this can be something like "vmx-4" or "xen";
167 // VMware Workstation 6.5 is "vmx-07"
168
169 HardwareItemsMap mapHardwareItems; // map of virtual hardware items, sorted by unique instance ID
170
171 uint64_t ullMemorySize; // always in bytes, copied from llHardwareItems; default = 0 (unspecified)
172 uint16_t cCPUs; // no. of CPUs, copied from llHardwareItems; default = 1
173
174 list<Utf8Str> llNetworkNames;
175 // list of strings referring to network names
176 // (one for each VirtualSystem/Item[@ResourceType=10]/Connection element)
177
178 ControllersMap mapControllers;
179 // list of hard disk controllers
180 // (one for each VirtualSystem/Item[@ResourceType=6] element with accumulated data from children)
181
182 VirtualDisksMap mapVirtualDisks;
183 // (one for each VirtualSystem/Item[@ResourceType=17] element with accumulated data from children)
184
185 bool fHasFloppyDrive; // true if there's a floppy item in mapHardwareItems
186 bool fHasCdromDrive; // true if there's a CD-ROM item in mapHardwareItems; ISO images are not yet supported by OVFtool
187 bool fHasUsbController; // true if there's a USB controller item in mapHardwareItems
188
189 Utf8Str strSoundCardType; // if not empty, then the system wants a soundcard; this then specifies the hardware;
190 // VMware Workstation 6.5 uses "ensoniq1371" for example
191
192 Utf8Str strLicenceInfo; // license info if any; receives contents of VirtualSystem/EulaSection/Info
193 Utf8Str strLicenceText; // license info if any; receives contents of VirtualSystem/EulaSection/License
194
195 VirtualSystem()
196 : ullMemorySize(0), cCPUs(1), fHasFloppyDrive(false), fHasCdromDrive(false), fHasUsbController(false)
197 {
198 }
199};
200
201struct Appliance::Task
202{
203 Task(Appliance *aThat, Progress *aProgress)
204 : that(aThat)
205 , progress(aProgress)
206 , rc(S_OK)
207 {}
208 ~Task() {}
209
210 HRESULT startThread();
211
212 Appliance *that;
213 ComObjPtr<Progress> progress;
214 HRESULT rc;
215};
216
217////////////////////////////////////////////////////////////////////////////////
218//
219// globals
220//
221////////////////////////////////////////////////////////////////////////////////
222
223static Utf8Str stripFilename(const Utf8Str &strFile)
224{
225 Utf8Str str2(strFile);
226 RTPathStripFilename(str2.mutableRaw());
227 return str2;
228}
229
230////////////////////////////////////////////////////////////////////////////////
231//
232// IVirtualBox public methods
233//
234////////////////////////////////////////////////////////////////////////////////
235
236// This code is here so we won't have to include the appliance headers in the
237// IVirtualBox implementation.
238
239/**
240 * Implementation for IVirtualBox::createAppliance.
241 *
242 * @param anAppliance IAppliance object created if S_OK is returned.
243 * @return S_OK or error.
244 */
245STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
246{
247 HRESULT rc;
248
249 ComObjPtr<Appliance> appliance;
250 appliance.createObject();
251 rc = appliance->init(this);
252
253 if (SUCCEEDED(rc))
254 appliance.queryInterfaceTo(anAppliance);
255
256 return rc;
257}
258
259////////////////////////////////////////////////////////////////////////////////
260//
261// Appliance::task methods
262//
263////////////////////////////////////////////////////////////////////////////////
264
265HRESULT Appliance::Task::startThread()
266{
267 int vrc = RTThreadCreate(NULL, Appliance::taskThread, this,
268 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
269 "Appliance::Task");
270 ComAssertMsgRCRet(vrc,
271 ("Could not create Appliance::Task thread (%Rrc)\n", vrc), E_FAIL);
272
273 return S_OK;
274}
275
276////////////////////////////////////////////////////////////////////////////////
277//
278// Appliance constructor / destructor
279//
280////////////////////////////////////////////////////////////////////////////////
281
282DEFINE_EMPTY_CTOR_DTOR(Appliance)
283struct shutup {};
284
285/**
286 * Appliance COM initializer.
287 * @param
288 * @return
289 */
290
291HRESULT Appliance::init(VirtualBox *aVirtualBox)
292{
293 HRESULT rc;
294
295 /* Enclose the state transition NotReady->InInit->Ready */
296 AutoInitSpan autoInitSpan(this);
297 AssertReturn(autoInitSpan.isOk(), E_FAIL);
298
299 /* Weak reference to a VirtualBox object */
300 unconst(mVirtualBox) = aVirtualBox;
301
302 // initialize data
303 m = new Data;
304
305 /* Confirm a successful initialization */
306 autoInitSpan.setSucceeded();
307
308 return S_OK;
309}
310
311/**
312 * Appliance COM uninitializer.
313 * @return
314 */
315void Appliance::uninit()
316{
317 delete m;
318 m = NULL;
319}
320
321////////////////////////////////////////////////////////////////////////////////
322//
323// Appliance private methods
324//
325////////////////////////////////////////////////////////////////////////////////
326
327/**
328 * Private helper method that goes thru the elements of the given "current" element in the OVF XML
329 * and handles the contained child elements (which can be "Section" or "Content" elements).
330 *
331 * @param pcszPath Path spec of the XML file, for error messages.
332 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
333 * @param pCurElem Element whose children are to be analyzed here.
334 * @return
335 */
336HRESULT Appliance::LoopThruSections(const char *pcszPath,
337 const xml::Node *pReferencesElem,
338 const xml::Node *pCurElem)
339{
340 HRESULT rc;
341
342 xml::NodesLoop loopChildren(*pCurElem);
343 const xml::Node *pElem;
344 while ((pElem = loopChildren.forAllNodes()))
345 {
346 const char *pcszElemName = pElem->getName();
347 const char *pcszTypeAttr = "";
348 const xml::Node *pTypeAttr;
349 if ((pTypeAttr = pElem->findAttribute("type")))
350 pcszTypeAttr = pTypeAttr->getValue();
351
352 if ( (!strcmp(pcszElemName, "DiskSection"))
353 || ( (!strcmp(pcszElemName, "Section"))
354 && (!strcmp(pcszTypeAttr, "ovf:DiskSection_Type"))
355 )
356 )
357 {
358 if (!(SUCCEEDED((rc = HandleDiskSection(pcszPath, pReferencesElem, pElem)))))
359 return rc;
360 }
361 else if ( (!strcmp(pcszElemName, "NetworkSection"))
362 || ( (!strcmp(pcszElemName, "Section"))
363 && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type"))
364 )
365 )
366 {
367 if (!(SUCCEEDED((rc = HandleNetworkSection(pcszPath, pElem)))))
368 return rc;
369 }
370 else if ( (!strcmp(pcszElemName, "DeploymentOptionSection>")))
371 {
372 // TODO
373 }
374 else if ( (!strcmp(pcszElemName, "Info")))
375 {
376 // child of VirtualSystemCollection -- TODO
377 }
378 else if ( (!strcmp(pcszElemName, "ResourceAllocationSection")))
379 {
380 // child of VirtualSystemCollection -- TODO
381 }
382 else if ( (!strcmp(pcszElemName, "StartupSection")))
383 {
384 // child of VirtualSystemCollection -- TODO
385 }
386 else if ( (!strcmp(pcszElemName, "VirtualSystem"))
387 || ( (!strcmp(pcszElemName, "Content"))
388 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type"))
389 )
390 )
391 {
392 if (!(SUCCEEDED((rc = HandleVirtualSystemContent(pcszPath, pElem)))))
393 return rc;
394 }
395 else if ( (!strcmp(pcszElemName, "VirtualSystemCollection"))
396 || ( (!strcmp(pcszElemName, "Content"))
397 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type"))
398 )
399 )
400 {
401 // TODO ResourceAllocationSection
402
403 // recurse for this, since it has VirtualSystem elements as children
404 if (!(SUCCEEDED((rc = LoopThruSections(pcszPath, pReferencesElem, pElem)))))
405 return rc;
406 }
407 }
408
409 return S_OK;
410}
411
412/**
413 * Private helper method that handles disk sections in the OVF XML.
414 * Gets called indirectly from IAppliance::read().
415 *
416 * @param pcszPath Path spec of the XML file, for error messages.
417 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
418 * @param pSectionElem Section element for which this helper is getting called.
419 * @return
420 */
421HRESULT Appliance::HandleDiskSection(const char *pcszPath,
422 const xml::Node *pReferencesElem,
423 const xml::Node *pSectionElem)
424{
425 // contains "Disk" child elements
426 xml::NodesLoop loopDisks(*pSectionElem, "Disk");
427 const xml::Node *pelmDisk;
428 while ((pelmDisk = loopDisks.forAllNodes()))
429 {
430 DiskImage d;
431 const char *pcszBad = NULL;
432 if (!(pelmDisk->getAttributeValue("diskId", d.strDiskId)))
433 pcszBad = "diskId";
434 else if (!(pelmDisk->getAttributeValue("format", d.strFormat)))
435 pcszBad = "format";
436 else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity)))
437 pcszBad = "capacity";
438 else
439 {
440 if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)))
441 // optional
442 d.iPopulatedSize = -1;
443
444 Utf8Str strFileRef;
445 if (pelmDisk->getAttributeValue("fileRef", strFileRef)) // optional
446 {
447 // look up corresponding /References/File nodes (list built above)
448 const xml::Node *pFileElem;
449 if ( pReferencesElem
450 && ((pFileElem = pReferencesElem->findChildElementFromId(strFileRef.c_str())))
451 )
452 {
453 // copy remaining values from file node then
454 const char *pcszBadInFile = NULL;
455 if (!(pFileElem->getAttributeValue("href", d.strHref)))
456 pcszBadInFile = "href";
457 else if (!(pFileElem->getAttributeValue("size", d.iSize)))
458 d.iSize = -1; // optional
459 // if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
460 d.iChunkSize = -1; // optional
461 pFileElem->getAttributeValue("compression", d.strCompression);
462
463 if (pcszBadInFile)
464 return setError(VBOX_E_FILE_ERROR,
465 tr("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
466 pcszPath,
467 pcszBadInFile,
468 pFileElem->getLineNumber());
469 }
470 else
471 return setError(VBOX_E_FILE_ERROR,
472 tr("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
473 pcszPath,
474 strFileRef.c_str(),
475 pelmDisk->getLineNumber());
476 }
477 }
478
479 if (pcszBad)
480 return setError(VBOX_E_FILE_ERROR,
481 tr("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
482 pcszPath,
483 pcszBad,
484 pelmDisk->getLineNumber());
485
486 m->mapDisks[d.strDiskId] = d;
487 }
488
489 return S_OK;
490}
491
492/**
493 * Private helper method that handles network sections in the OVF XML.
494 * Gets called indirectly from IAppliance::read().
495 *
496 * @param pcszPath Path spec of the XML file, for error messages.
497 * @param pSectionElem Section element for which this helper is getting called.
498 * @return
499 */
500HRESULT Appliance::HandleNetworkSection(const char *pcszPath,
501 const xml::Node *pSectionElem)
502{
503 // contains "Disk" child elements
504 xml::NodesLoop loopNetworks(*pSectionElem, "Network");
505 const xml::Node *pelmNetwork;
506 while ((pelmNetwork = loopNetworks.forAllNodes()))
507 {
508 Network n;
509 if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
510 return setError(VBOX_E_FILE_ERROR,
511 tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
512 pcszPath,
513 pelmNetwork->getLineNumber());
514
515 m->mapNetworks[n.strNetworkName] = n;
516 }
517
518 return S_OK;
519}
520
521/**
522 * Private helper method that handles a "VirtualSystem" element in the OVF XML.
523 * Gets called indirectly from IAppliance::read().
524 *
525 * @param pcszPath
526 * @param pContentElem
527 * @return
528 */
529HRESULT Appliance::HandleVirtualSystemContent(const char *pcszPath,
530 const xml::Node *pelmVirtualSystem)
531{
532 VirtualSystem vsys;
533
534 const xml::Node *pIdAttr = pelmVirtualSystem->findAttribute("id");
535 if (pIdAttr)
536 vsys.strName = pIdAttr->getValue();
537
538 xml::NodesLoop loop(*pelmVirtualSystem); // all child elements
539 const xml::Node *pelmThis;
540 while ((pelmThis = loop.forAllNodes()))
541 {
542 const char *pcszElemName = pelmThis->getName();
543 const xml::Node *pTypeAttr = pelmThis->findAttribute("type");
544 const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : "";
545
546 if (!strcmp(pcszElemName, "EulaSection"))
547 {
548 /* <EulaSection>
549 <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
550 <License ovf:msgid="1">License terms can go in here.</License>
551 </EulaSection> */
552
553 const xml::Node *pelmInfo, *pelmLicense;
554 if ( ((pelmInfo = pelmThis->findChildElement("Info")))
555 && ((pelmLicense = pelmThis->findChildElement("License")))
556 )
557 {
558 vsys.strLicenceInfo = pelmInfo->getValue();
559 vsys.strLicenceText = pelmLicense->getValue();
560 }
561 }
562 else if ( (!strcmp(pcszElemName, "VirtualHardwareSection"))
563 || (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type"))
564 )
565 {
566 const xml::Node *pelmSystem, *pelmVirtualSystemType;
567 if ((pelmSystem = pelmThis->findChildElement("System")))
568 {
569 /* <System>
570 <vssd:Description>Description of the virtual hardware section.</vssd:Description>
571 <vssd:ElementName>vmware</vssd:ElementName>
572 <vssd:InstanceID>1</vssd:InstanceID>
573 <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
574 <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
575 </System>*/
576 if ((pelmVirtualSystemType = pelmSystem->findChildElement("VirtualSystemType")))
577 vsys.strVirtualSystemType = pelmVirtualSystemType->getValue();
578 }
579
580 xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements
581 const xml::Node *pelmItem;
582 while ((pelmItem = loopVirtualHardwareItems.forAllNodes()))
583 {
584 VirtualHardwareItem i;
585
586 i.ulLineNumber = pelmItem->getLineNumber();
587
588 xml::NodesLoop loopItemChildren(*pelmItem); // all child elements
589 const xml::Node *pelmItemChild;
590 while ((pelmItemChild = loopItemChildren.forAllNodes()))
591 {
592 const char *pcszItemChildName = pelmItemChild->getName();
593 if (!strcmp(pcszItemChildName, "Description"))
594 i.strDescription = pelmItemChild->getValue();
595 else if (!strcmp(pcszItemChildName, "Caption"))
596 i.strCaption = pelmItemChild->getValue();
597 else if (!strcmp(pcszItemChildName, "ElementName"))
598 i.strElementName = pelmItemChild->getValue();
599 else if ( (!strcmp(pcszItemChildName, "InstanceID"))
600 || (!strcmp(pcszItemChildName, "InstanceId"))
601 )
602 pelmItemChild->copyValue(i.ulInstanceID);
603 else if (!strcmp(pcszItemChildName, "HostResource"))
604 i.strHostResource = pelmItemChild->getValue();
605 else if (!strcmp(pcszItemChildName, "ResourceType"))
606 {
607 int32_t iType; /** @todo how to fix correctly? (enum fun.) */
608 pelmItemChild->copyValue(iType);
609 i.resourceType = (OVFResourceType_T)iType;
610 }
611 else if (!strcmp(pcszItemChildName, "OtherResourceType"))
612 i.strOtherResourceType = pelmItemChild->getValue();
613 else if (!strcmp(pcszItemChildName, "ResourceSubType"))
614 i.strResourceSubType = pelmItemChild->getValue();
615 else if (!strcmp(pcszItemChildName, "AutomaticAllocation"))
616 i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
617 else if (!strcmp(pcszItemChildName, "AutomaticDeallocation"))
618 i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
619 else if (!strcmp(pcszItemChildName, "Parent"))
620 pelmItemChild->copyValue(i.ulParent);
621 else if (!strcmp(pcszItemChildName, "Connection"))
622 i.strConnection = pelmItemChild->getValue();
623 else if (!strcmp(pcszItemChildName, "Address"))
624 i.strAddress = pelmItemChild->getValue();
625 else if (!strcmp(pcszItemChildName, "AddressOnParent"))
626 i.strAddressOnParent = pelmItemChild->getValue();
627 else if (!strcmp(pcszItemChildName, "AllocationUnits"))
628 i.strAllocationUnits = pelmItemChild->getValue();
629 else if (!strcmp(pcszItemChildName, "VirtualQuantity"))
630 pelmItemChild->copyValue(i.ullVirtualQuantity);
631 else if (!strcmp(pcszItemChildName, "Reservation"))
632 pelmItemChild->copyValue(i.ullReservation);
633 else if (!strcmp(pcszItemChildName, "Limit"))
634 pelmItemChild->copyValue(i.ullLimit);
635 else if (!strcmp(pcszItemChildName, "Weight"))
636 pelmItemChild->copyValue(i.ullWeight);
637 else if (!strcmp(pcszItemChildName, "ConsumerVisibility"))
638 i.strConsumerVisibility = pelmItemChild->getValue();
639 else if (!strcmp(pcszItemChildName, "MappingBehavior"))
640 i.strMappingBehavior = pelmItemChild->getValue();
641 else if (!strcmp(pcszItemChildName, "PoolID"))
642 i.strPoolID = pelmItemChild->getValue();
643 else if (!strcmp(pcszItemChildName, "BusNumber"))
644 pelmItemChild->copyValue(i.ulBusNumber);
645 else
646 return setError(VBOX_E_FILE_ERROR,
647 tr("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
648 pcszPath,
649 pcszItemChildName,
650 i.ulLineNumber);
651 }
652
653 // store!
654 vsys.mapHardwareItems[i.ulInstanceID] = i;
655 }
656
657 HardwareItemsMap::const_iterator itH;
658
659 for (itH = vsys.mapHardwareItems.begin();
660 itH != vsys.mapHardwareItems.end();
661 ++itH)
662 {
663 const VirtualHardwareItem &i = itH->second;
664
665 // do some analysis
666 switch (i.resourceType)
667 {
668 case OVFResourceType_Processor: // 3
669 /* <rasd:Caption>1 virtual CPU</rasd:Caption>
670 <rasd:Description>Number of virtual CPUs</rasd:Description>
671 <rasd:ElementName>virtual CPU</rasd:ElementName>
672 <rasd:InstanceID>1</rasd:InstanceID>
673 <rasd:ResourceType>3</rasd:ResourceType>
674 <rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
675 if (i.ullVirtualQuantity < UINT16_MAX)
676 vsys.cCPUs = (uint16_t)i.ullVirtualQuantity;
677 else
678 return setError(VBOX_E_FILE_ERROR,
679 tr("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
680 pcszPath,
681 i.ullVirtualQuantity,
682 UINT16_MAX,
683 i.ulLineNumber);
684 break;
685
686 case OVFResourceType_Memory: // 4
687 if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit
688 || (i.strAllocationUnits == "MB") // found in MS docs
689 || (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21
690 )
691 vsys.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024;
692 else
693 return setError(VBOX_E_FILE_ERROR,
694 tr("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
695 pcszPath,
696 i.strAllocationUnits.c_str(),
697 i.ulLineNumber);
698 break;
699
700 case OVFResourceType_IdeController: // 5 IdeController
701 {
702 /* <Item>
703 <rasd:Caption>ideController0</rasd:Caption>
704 <rasd:Description>IDE Controller</rasd:Description>
705 <rasd:InstanceId>5</rasd:InstanceId>
706 <rasd:ResourceType>5</rasd:ResourceType>
707 <rasd:Address>0</rasd:Address>
708 <rasd:BusNumber>0</rasd:BusNumber>
709 </Item> */
710 HardDiskController hdc;
711 hdc.system = HardDiskController::IDE;
712 hdc.idController = i.ulInstanceID;
713 hdc.strAddress = i.strAddress;
714 hdc.ulBusNumber = i.ulBusNumber;
715
716 vsys.mapControllers[i.ulInstanceID] = hdc;
717 }
718 break;
719
720 case OVFResourceType_ParallelScsiHba: // 6 SCSI controller
721 {
722 /* <Item>
723 <rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
724 <rasd:Description>SCI Controller</rasd:Description>
725 <rasd:ElementName>SCSI controller</rasd:ElementName>
726 <rasd:InstanceID>4</rasd:InstanceID>
727 <rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
728 <rasd:ResourceType>6</rasd:ResourceType>
729 </Item> */
730 HardDiskController hdc;
731 hdc.system = HardDiskController::SCSI;
732 hdc.idController = i.ulInstanceID;
733 hdc.strControllerType = i.strResourceSubType;
734
735 vsys.mapControllers[i.ulInstanceID] = hdc;
736 }
737 break;
738
739 case OVFResourceType_EthernetAdapter: // 10
740 {
741 /* <Item>
742 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
743 <rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
744 <rasd:Connection>VM Network</rasd:Connection>
745 <rasd:Description>VM Network?</rasd:Description>
746 <rasd:ElementName>Ethernet adapter</rasd:ElementName>
747 <rasd:InstanceID>3</rasd:InstanceID>
748 <rasd:ResourceType>10</rasd:ResourceType>
749 </Item>
750
751 OVF spec DSP 0243 page 21:
752 "For an Ethernet adapter, this specifies the abstract network connection name
753 for the virtual machine. All Ethernet adapters that specify the same abstract
754 network connection name within an OVF package shall be deployed on the same
755 network. The abstract network connection name shall be listed in the NetworkSection
756 at the outermost envelope level." */
757
758 // make sure we have a matching NetworkSection/Network
759 NetworksMap::iterator it = m->mapNetworks.find(i.strConnection);
760 if (it == m->mapNetworks.end())
761 return setError(VBOX_E_FILE_ERROR,
762 tr("Error reading \"%s\": Invalid connection \"%s\"; cannot find matching NetworkSection/Network element, line %d"),
763 pcszPath,
764 i.strConnection.c_str(),
765 i.ulLineNumber);
766
767 vsys.llNetworkNames.push_back(i.strConnection);
768 }
769 break;
770
771 case OVFResourceType_FloppyDrive: // 14
772 vsys.fHasFloppyDrive = true; // we have no additional information
773 break;
774
775 case OVFResourceType_CdDrive: // 15
776 /* <Item ovf:required="false">
777 <rasd:Caption>cdrom1</rasd:Caption>
778 <rasd:InstanceId>7</rasd:InstanceId>
779 <rasd:ResourceType>15</rasd:ResourceType>
780 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
781 <rasd:Parent>5</rasd:Parent>
782 <rasd:AddressOnParent>0</rasd:AddressOnParent>
783 </Item> */
784 // I tried to see what happens if I set an ISO for the CD-ROM in VMware Workstation,
785 // but then the ovftool dies with "Device backing not supported". So I guess if
786 // VMware can't export ISOs, then we don't need to be able to import them right now.
787 vsys.fHasCdromDrive = true; // we have no additional information
788 break;
789
790 case OVFResourceType_HardDisk: // 17
791 {
792 /* <Item>
793 <rasd:Caption>Harddisk 1</rasd:Caption>
794 <rasd:Description>HD</rasd:Description>
795 <rasd:ElementName>Hard Disk</rasd:ElementName>
796 <rasd:HostResource>ovf://disk/lamp</rasd:HostResource>
797 <rasd:InstanceID>5</rasd:InstanceID>
798 <rasd:Parent>4</rasd:Parent>
799 <rasd:ResourceType>17</rasd:ResourceType>
800 </Item> */
801
802 // look up the hard disk controller element whose InstanceID equals our Parent;
803 // this is how the connection is specified in OVF
804 ControllersMap::const_iterator it = vsys.mapControllers.find(i.ulParent);
805 if (it == vsys.mapControllers.end())
806 return setError(VBOX_E_FILE_ERROR,
807 tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
808 pcszPath,
809 i.ulInstanceID,
810 i.ulParent,
811 i.ulLineNumber);
812 const HardDiskController &hdc = it->second;
813
814 VirtualDisk vd;
815 vd.idController = i.ulParent;
816 i.strAddressOnParent.toInt(vd.ulAddressOnParent);
817 bool fFound = false;
818 // ovf://disk/lamp
819 // 12345678901234
820 if (i.strHostResource.substr(0, 11) == "ovf://disk/")
821 vd.strDiskId = i.strHostResource.substr(11);
822 else if (i.strHostResource.substr(0, 6) == "/disk/")
823 vd.strDiskId = i.strHostResource.substr(6);
824
825 if ( !(vd.strDiskId.length())
826 || (m->mapDisks.find(vd.strDiskId) == m->mapDisks.end())
827 )
828 return setError(VBOX_E_FILE_ERROR,
829 tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
830 pcszPath,
831 i.ulInstanceID,
832 i.strHostResource.c_str(),
833 i.ulLineNumber);
834
835 vsys.mapVirtualDisks[vd.strDiskId] = vd;
836 }
837 break;
838
839 case OVFResourceType_UsbController: // 23
840 /* <Item ovf:required="false">
841 <rasd:Caption>usb</rasd:Caption>
842 <rasd:Description>USB Controller</rasd:Description>
843 <rasd:InstanceId>3</rasd:InstanceId>
844 <rasd:ResourceType>23</rasd:ResourceType>
845 <rasd:Address>0</rasd:Address>
846 <rasd:BusNumber>0</rasd:BusNumber>
847 </Item> */
848 vsys.fHasUsbController = true; // we have no additional information
849 break;
850
851 case OVFResourceType_SoundCard: // 35
852 /* <Item ovf:required="false">
853 <rasd:Caption>sound</rasd:Caption>
854 <rasd:Description>Sound Card</rasd:Description>
855 <rasd:InstanceId>10</rasd:InstanceId>
856 <rasd:ResourceType>35</rasd:ResourceType>
857 <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
858 <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
859 <rasd:AddressOnParent>3</rasd:AddressOnParent>
860 </Item> */
861 vsys.strSoundCardType = i.strResourceSubType;
862 break;
863
864 default:
865 return setError(VBOX_E_FILE_ERROR,
866 tr("Error reading \"%s\": Unknown resource type %d in hardware item, line %d"),
867 pcszPath,
868 i.resourceType,
869 i.ulLineNumber);
870 }
871 }
872 }
873 else if ( (!strcmp(pcszElemName, "OperatingSystemSection"))
874 || (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type"))
875 )
876 {
877 uint64_t cimos64;
878 if (!(pelmThis->getAttributeValue("id", cimos64)))
879 return setError(VBOX_E_FILE_ERROR,
880 tr("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
881 pcszPath,
882 pelmThis->getLineNumber());
883
884 vsys.cimos = (CIMOSType_T)cimos64;
885 }
886 }
887
888 // now create the virtual system
889 m->llVirtualSystems.push_back(vsys);
890
891 return S_OK;
892}
893
894////////////////////////////////////////////////////////////////////////////////
895//
896// IAppliance public methods
897//
898////////////////////////////////////////////////////////////////////////////////
899
900/**
901 * Public method implementation.
902 * @param
903 * @return
904 */
905STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
906{
907 if (!aPath)
908 return E_POINTER;
909
910 AutoCaller autoCaller(this);
911 CheckComRCReturnRC(autoCaller.rc());
912
913 AutoReadLock alock(this);
914
915 m->bstrPath.cloneTo(aPath);
916
917 return S_OK;
918}
919
920/**
921 * Public method implementation.
922 * @param
923 * @return
924 */
925STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
926{
927 CheckComArgOutSafeArrayPointerValid(aDisks);
928
929 AutoCaller autoCaller(this);
930 CheckComRCReturnRC(autoCaller.rc());
931
932 AutoReadLock alock(this);
933
934 size_t c = m->mapDisks.size();
935 com::SafeArray<BSTR> sfaDisks(c);
936
937 DiskImagesMap::const_iterator it;
938 size_t i = 0;
939 for (it = m->mapDisks.begin();
940 it != m->mapDisks.end();
941 ++it, ++i)
942 {
943 // create a string representing this disk
944 const DiskImage &d = it->second;
945 char *psz = NULL;
946 RTStrAPrintf(&psz,
947 "%s\t"
948 "%RI64\t"
949 "%RI64\t"
950 "%s\t"
951 "%s\t"
952 "%RI64\t"
953 "%RI64\t"
954 "%s",
955 d.strDiskId.c_str(),
956 d.iCapacity,
957 d.iPopulatedSize,
958 d.strFormat.c_str(),
959 d.strHref.c_str(),
960 d.iSize,
961 d.iChunkSize,
962 d.strCompression.c_str());
963 Utf8Str utf(psz);
964 Bstr bstr(utf);
965 // push to safearray
966 bstr.cloneTo(&sfaDisks[i]);
967 RTStrFree(psz);
968 }
969
970 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
971
972 return S_OK;
973}
974
975/**
976 * Public method implementation.
977 * @param
978 * @return
979 */
980STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
981{
982 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
983
984 AutoCaller autoCaller(this);
985 CheckComRCReturnRC(autoCaller.rc());
986
987 AutoReadLock alock(this);
988
989 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
990 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
991
992 return S_OK;
993}
994
995/**
996 * Private helper func that suggests a VirtualBox guest OS type
997 * for the given OVF operating system type.
998 * @param osTypeVBox
999 * @param c
1000 */
1001static void convertCIMOSType2VBoxOSType(Utf8Str &osTypeVBox, CIMOSType_T c)
1002{
1003 switch (c)
1004 {
1005 case CIMOSType_CIMOS_Unknown: // 0 - Unknown
1006 osTypeVBox = SchemaDefs_OSTypeId_Other;
1007 break;
1008
1009 case CIMOSType_CIMOS_OS2: // 12 - OS/2
1010 osTypeVBox = SchemaDefs_OSTypeId_OS2;
1011 break;
1012
1013 case CIMOSType_CIMOS_MSDOS: // 14 - MSDOS
1014 osTypeVBox = SchemaDefs_OSTypeId_DOS;
1015 break;
1016
1017 case CIMOSType_CIMOS_WIN3x: // 15 - WIN3x
1018 osTypeVBox = SchemaDefs_OSTypeId_Windows31;
1019 break;
1020
1021 case CIMOSType_CIMOS_WIN95: // 16 - WIN95
1022 osTypeVBox = SchemaDefs_OSTypeId_Windows95;
1023 break;
1024
1025 case CIMOSType_CIMOS_WIN98: // 17 - WIN98
1026 osTypeVBox = SchemaDefs_OSTypeId_Windows98;
1027 break;
1028
1029 case CIMOSType_CIMOS_WINNT: // 18 - WINNT
1030 osTypeVBox = SchemaDefs_OSTypeId_WindowsNT4;
1031 break;
1032
1033 case CIMOSType_CIMOS_NetWare: // 21 - NetWare
1034 case CIMOSType_CIMOS_NovellOES: // 86 - Novell OES
1035 osTypeVBox = SchemaDefs_OSTypeId_Netware;
1036 break;
1037
1038 case CIMOSType_CIMOS_Solaris: // 29 - Solaris
1039 case CIMOSType_CIMOS_SunOS: // 30 - SunOS
1040 osTypeVBox = SchemaDefs_OSTypeId_Solaris;
1041 break;
1042
1043 case CIMOSType_CIMOS_FreeBSD: // 42 - FreeBSD
1044 osTypeVBox = SchemaDefs_OSTypeId_FreeBSD;
1045 break;
1046
1047 case CIMOSType_CIMOS_NetBSD: // 43 - NetBSD
1048 osTypeVBox = SchemaDefs_OSTypeId_NetBSD;
1049 break;
1050
1051 case CIMOSType_CIMOS_QNX: // 48 - QNX
1052 osTypeVBox = SchemaDefs_OSTypeId_QNX;
1053 break;
1054
1055 case CIMOSType_CIMOS_Windows2000: // 58 - Windows 2000
1056 osTypeVBox = SchemaDefs_OSTypeId_Windows2000;
1057 break;
1058
1059 case CIMOSType_CIMOS_WindowsMe: // 63 - Windows (R) Me
1060 osTypeVBox = SchemaDefs_OSTypeId_WindowsMe;
1061 break;
1062
1063 case CIMOSType_CIMOS_OpenBSD: // 65 - OpenBSD
1064 osTypeVBox = SchemaDefs_OSTypeId_OpenBSD;
1065 break;
1066
1067 case CIMOSType_CIMOS_WindowsXP: // 67 - Windows XP
1068 case CIMOSType_CIMOS_WindowsXPEmbedded: // 72 - Windows XP Embedded
1069 case CIMOSType_CIMOS_WindowsEmbeddedforPointofService: // 75 - Windows Embedded for Point of Service
1070 osTypeVBox = SchemaDefs_OSTypeId_WindowsXP;
1071 break;
1072
1073 case CIMOSType_CIMOS_MicrosoftWindowsServer2003: // 69 - Microsoft Windows Server 2003
1074 osTypeVBox = SchemaDefs_OSTypeId_Windows2003;
1075 break;
1076
1077 case CIMOSType_CIMOS_MicrosoftWindowsServer2003_64: // 70 - Microsoft Windows Server 2003 64-Bit
1078 osTypeVBox = SchemaDefs_OSTypeId_Windows2003_64;
1079 break;
1080
1081 case CIMOSType_CIMOS_WindowsXP_64: // 71 - Windows XP 64-Bit
1082 osTypeVBox = SchemaDefs_OSTypeId_WindowsXP_64;
1083 break;
1084
1085 case CIMOSType_CIMOS_WindowsVista: // 73 - Windows Vista
1086 osTypeVBox = SchemaDefs_OSTypeId_WindowsVista;
1087 break;
1088
1089 case CIMOSType_CIMOS_WindowsVista_64: // 74 - Windows Vista 64-Bit
1090 osTypeVBox = SchemaDefs_OSTypeId_WindowsVista_64;
1091 break;
1092
1093 case CIMOSType_CIMOS_MicrosoftWindowsServer2008: // 76 - Microsoft Windows Server 2008
1094 osTypeVBox = SchemaDefs_OSTypeId_Windows2008;
1095 break;
1096
1097 case CIMOSType_CIMOS_MicrosoftWindowsServer2008_64: // 77 - Microsoft Windows Server 2008 64-Bit
1098 osTypeVBox = SchemaDefs_OSTypeId_Windows2008_64;
1099 break;
1100
1101 case CIMOSType_CIMOS_FreeBSD_64: // 78 - FreeBSD 64-Bit
1102 osTypeVBox = SchemaDefs_OSTypeId_FreeBSD_64;
1103 break;
1104
1105 case CIMOSType_CIMOS_RedHatEnterpriseLinux: // 79 - RedHat Enterprise Linux
1106 osTypeVBox = SchemaDefs_OSTypeId_RedHat;
1107 break;
1108
1109 case CIMOSType_CIMOS_RedHatEnterpriseLinux_64: // 80 - RedHat Enterprise Linux 64-Bit
1110 osTypeVBox = SchemaDefs_OSTypeId_RedHat_64;
1111 break;
1112
1113 case CIMOSType_CIMOS_Solaris_64: // 81 - Solaris 64-Bit
1114 osTypeVBox = SchemaDefs_OSTypeId_Solaris_64;
1115 break;
1116
1117 case CIMOSType_CIMOS_SUSE: // 82 - SUSE
1118 case CIMOSType_CIMOS_SLES: // 84 - SLES
1119 case CIMOSType_CIMOS_NovellLinuxDesktop: // 87 - Novell Linux Desktop
1120 osTypeVBox = SchemaDefs_OSTypeId_OpenSUSE;
1121 break;
1122
1123 case CIMOSType_CIMOS_SUSE_64: // 83 - SUSE 64-Bit
1124 case CIMOSType_CIMOS_SLES_64: // 85 - SLES 64-Bit
1125 osTypeVBox = SchemaDefs_OSTypeId_OpenSUSE_64;
1126 break;
1127
1128 case CIMOSType_CIMOS_LINUX: // 36 - LINUX
1129 case CIMOSType_CIMOS_SunJavaDesktopSystem: // 88 - Sun Java Desktop System
1130 case CIMOSType_CIMOS_TurboLinux: // 91 - TurboLinux
1131 osTypeVBox = SchemaDefs_OSTypeId_Linux;
1132 break;
1133
1134 // case CIMOSType_CIMOS_TurboLinux_64: // 92 - TurboLinux 64-Bit
1135 // case CIMOSType_CIMOS_Linux_64: // 101 - Linux 64-Bit
1136 // osTypeVBox = VBOXOSTYPE_Linux_x64;
1137 // break;
1138
1139 case CIMOSType_CIMOS_Mandriva: // 89 - Mandriva
1140 osTypeVBox = SchemaDefs_OSTypeId_Mandriva;
1141 break;
1142
1143 case CIMOSType_CIMOS_Mandriva_64: // 90 - Mandriva 64-Bit
1144 osTypeVBox = SchemaDefs_OSTypeId_Mandriva_64;
1145 break;
1146
1147 case CIMOSType_CIMOS_Ubuntu: // 93 - Ubuntu
1148 osTypeVBox = SchemaDefs_OSTypeId_Ubuntu;
1149 break;
1150
1151 case CIMOSType_CIMOS_Ubuntu_64: // 94 - Ubuntu 64-Bit
1152 osTypeVBox = SchemaDefs_OSTypeId_Ubuntu_64;
1153 break;
1154
1155 case CIMOSType_CIMOS_Debian: // 95 - Debian
1156 osTypeVBox = SchemaDefs_OSTypeId_Debian;
1157 break;
1158
1159 case CIMOSType_CIMOS_Debian_64: // 96 - Debian 64-Bit
1160 osTypeVBox = SchemaDefs_OSTypeId_Debian_64;
1161 break;
1162
1163 case CIMOSType_CIMOS_Linux_2_4_x: // 97 - Linux 2.4.x
1164 osTypeVBox = SchemaDefs_OSTypeId_Linux24;
1165 break;
1166
1167 case CIMOSType_CIMOS_Linux_2_4_x_64: // 98 - Linux 2.4.x 64-Bit
1168 osTypeVBox = SchemaDefs_OSTypeId_Linux24_64;
1169 break;
1170
1171 case CIMOSType_CIMOS_Linux_2_6_x: // 99 - Linux 2.6.x
1172 osTypeVBox = SchemaDefs_OSTypeId_Linux26;
1173 break;
1174
1175 case CIMOSType_CIMOS_Linux_2_6_x_64: // 100 - Linux 2.6.x 64-Bit
1176 osTypeVBox = SchemaDefs_OSTypeId_Linux26_64;
1177 break;
1178 default:
1179 {
1180 /* If we are here we have no clue what OS this should be. Set
1181 to other type as default. */
1182 osTypeVBox = SchemaDefs_OSTypeId_Other;
1183 }
1184 }
1185}
1186
1187/**
1188 * Public method implementation.
1189 * @param path
1190 * @return
1191 */
1192STDMETHODIMP Appliance::Read(IN_BSTR path)
1193{
1194 HRESULT rc = S_OK;
1195
1196 if (!path)
1197 return E_POINTER;
1198
1199 AutoCaller autoCaller(this);
1200 CheckComRCReturnRC(autoCaller.rc());
1201
1202 AutoWriteLock alock(this);
1203 m->bstrPath = path;
1204
1205 // see if we can handle this file; for now we insist it has an ".ovf" extension
1206 Utf8Str utf8Path(path);
1207 const char *pcszLastDot = strrchr(utf8Path, '.');
1208 if ( (!pcszLastDot)
1209 || ( strcmp(pcszLastDot, ".ovf")
1210 && strcmp(pcszLastDot, ".OVF")
1211 )
1212 )
1213 return setError(VBOX_E_FILE_ERROR,
1214 tr("Appliance file must have .ovf extension"));
1215
1216 try
1217 {
1218 xml::XmlFileParser parser;
1219 xml::Document doc;
1220 parser.read(utf8Path.raw(),
1221 doc);
1222
1223 const xml::Node *pRootElem = doc.getRootElement();
1224 if (strcmp(pRootElem->getName(), "Envelope"))
1225 return setError(VBOX_E_FILE_ERROR,
1226 tr("Root element in OVF file must be \"Envelope\"."));
1227
1228 // OVF has the following rough layout:
1229 /*
1230 -- <References> .... files referenced from other parts of the file, such as VMDK images
1231 -- Metadata, comprised of several section commands
1232 -- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
1233 -- optionally <Strings> for localization
1234 */
1235
1236 // get all "File" child elements of "References" section so we can look up files easily;
1237 // first find the "References" sections so we can look up files
1238 xml::NodesList listFileElements; // receives all /Envelope/References/File nodes
1239 const xml::Node *pReferencesElem;
1240 if ((pReferencesElem = pRootElem->findChildElement("References")))
1241 pReferencesElem->getChildElements(listFileElements, "File");
1242
1243 // now go though the sections
1244 if (!(SUCCEEDED(rc = LoopThruSections(utf8Path.raw(), pReferencesElem, pRootElem))))
1245 return rc;
1246 }
1247 catch(xml::Error &x)
1248 {
1249 return setError(VBOX_E_FILE_ERROR,
1250 x.what());
1251 }
1252
1253 return S_OK;
1254}
1255
1256/**
1257 * Public method implementation.
1258 * @return
1259 */
1260STDMETHODIMP Appliance::Interpret()
1261{
1262 // @todo:
1263 // - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
1264 // - Appropriate handle errors like not supported file formats
1265 AutoCaller autoCaller(this);
1266 CheckComRCReturnRC(autoCaller.rc());
1267
1268 AutoWriteLock(this);
1269
1270 HRESULT rc = S_OK;
1271
1272 /* Clear any previous virtual system descriptions */
1273 // @todo: have the entries deleted also?
1274 m->virtualSystemDescriptions.clear();
1275
1276 /* We need the default path for storing disk images */
1277 ComPtr<ISystemProperties> systemProps;
1278 rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
1279 CheckComRCReturnRC(rc);
1280 Bstr bstrDefaultHardDiskLocation;
1281 rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskLocation.asOutParam());
1282 CheckComRCReturnRC(rc);
1283
1284 /* Try/catch so we can clean up on error */
1285 try
1286 {
1287 list<VirtualSystem>::const_iterator it;
1288 /* Iterate through all virtual systems */
1289 for (it = m->llVirtualSystems.begin();
1290 it != m->llVirtualSystems.end();
1291 ++it)
1292 {
1293 const VirtualSystem &vsysThis = *it;
1294
1295 ComObjPtr<VirtualSystemDescription> pNewDesc;
1296 rc = pNewDesc.createObject();
1297 CheckComRCThrowRC(rc);
1298 rc = pNewDesc->init();
1299 CheckComRCThrowRC(rc);
1300
1301 /* Guest OS type */
1302 Utf8Str strOsTypeVBox,
1303 strCIMOSType = Utf8StrFmt("%RI32", (uint32_t)vsysThis.cimos);
1304 convertCIMOSType2VBoxOSType(strOsTypeVBox, vsysThis.cimos);
1305 pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
1306 "",
1307 strCIMOSType,
1308 strOsTypeVBox);
1309
1310 /* VM name */
1311 /* If the there isn't any name specified create a default one out of
1312 * the OS type */
1313 Utf8Str nameVBox = vsysThis.strName;
1314 if (nameVBox == "")
1315 nameVBox = strOsTypeVBox;
1316 searchUniqueVMName(nameVBox);
1317 pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
1318 "",
1319 vsysThis.strName,
1320 nameVBox);
1321
1322 /* Now that we know the OS type, get our internal defaults based on that. */
1323 ComPtr<IGuestOSType> pGuestOSType;
1324 rc = mVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), pGuestOSType.asOutParam());
1325 CheckComRCThrowRC(rc);
1326
1327 /* CPU count */
1328 ULONG cpuCountVBox = vsysThis.cCPUs;
1329 /* Check for the constrains */
1330 if (cpuCountVBox > 1) //SchemaDefs::MaxCPUCount)
1331 {
1332 pNewDesc->addWarning(tr("The virtual system claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
1333 cpuCountVBox, 1); //SchemaDefs::MaxCPUCount);
1334 cpuCountVBox = 1; //SchemaDefs::MaxCPUCount;
1335 }
1336 if (vsysThis.cCPUs == 0)
1337 cpuCountVBox = 1;
1338 pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
1339 "",
1340 Utf8StrFmt("%RI32", (uint32_t)vsysThis.cCPUs),
1341 Utf8StrFmt("%RI32", (uint32_t)cpuCountVBox));
1342
1343 /* RAM */
1344 uint64_t ullMemSizeVBox = vsysThis.ullMemorySize / _1M;
1345 /* Check for the constrains */
1346 if (ullMemSizeVBox != 0 &&
1347 (ullMemSizeVBox < static_cast<uint64_t>(SchemaDefs::MinGuestRAM) ||
1348 ullMemSizeVBox > static_cast<uint64_t>(SchemaDefs::MaxGuestRAM)))
1349 {
1350 pNewDesc->addWarning(tr("The virtual system claims support for %llu MB RAM size, but VirtualBox has support for min %u & max %u MB RAM size only."),
1351 ullMemSizeVBox, SchemaDefs::MinGuestRAM, SchemaDefs::MaxGuestRAM);
1352 ullMemSizeVBox = RT_MIN(RT_MAX(ullMemSizeVBox, static_cast<uint64_t>(SchemaDefs::MinGuestRAM)), static_cast<uint64_t>(SchemaDefs::MaxGuestRAM));
1353 }
1354 if (vsysThis.ullMemorySize == 0)
1355 {
1356 /* If the RAM of the OVF is zero, use our predefined values */
1357 ULONG memSizeVBox2;
1358 rc = pGuestOSType->COMGETTER(RecommendedRAM)(&memSizeVBox2);
1359 CheckComRCThrowRC(rc);
1360 /* VBox stores that in MByte */
1361 ullMemSizeVBox = (uint64_t)memSizeVBox2;
1362 }
1363 pNewDesc->addEntry(VirtualSystemDescriptionType_Memory,
1364 "",
1365 Utf8StrFmt("%RI64", (uint64_t)vsysThis.ullMemorySize),
1366 Utf8StrFmt("%RI64", (uint64_t)ullMemSizeVBox));
1367
1368 /* Audio */
1369 if (!vsysThis.strSoundCardType.isNull())
1370 /* Currently we set the AC97 always.
1371 @todo: figure out the hardware which could be possible */
1372 pNewDesc->addEntry(VirtualSystemDescriptionType_SoundCard,
1373 "",
1374 vsysThis.strSoundCardType,
1375 Utf8StrFmt("%RI32", (uint32_t)AudioControllerType_AC97));
1376
1377 #ifdef VBOX_WITH_USB
1378 /* USB Controller */
1379 if (vsysThis.fHasUsbController)
1380 pNewDesc->addEntry(VirtualSystemDescriptionType_USBController, "", "", "");
1381 #endif /* VBOX_WITH_USB */
1382
1383 NetworksMap::const_iterator itN;
1384 for (itN = m->mapNetworks.begin();
1385 itN != m->mapNetworks.end();
1386 ++itN)
1387 {
1388 const Network &nw = itN->second;
1389 pNewDesc->addEntry(VirtualSystemDescriptionType_LogicalNetwork,
1390 "",
1391 nw.strNetworkName,
1392 nw.strNetworkName);
1393 }
1394
1395 /* Network Controller */
1396 // @todo: there is no hardware specification in the OVF file; supposedly the
1397 // hardware will then be determined by the VirtualSystemType element (e.g. "vmx-07")
1398 if (vsysThis.llNetworkNames.size() > 0)
1399 {
1400 /* Check for the constrains */
1401 if (vsysThis.llNetworkNames.size() > SchemaDefs::NetworkAdapterCount)
1402 {
1403 pNewDesc->addWarning(tr("The virtual system claims support for %u network adapters, but VirtualBox has support for max %u network adapter only."),
1404 vsysThis.llNetworkNames.size(), SchemaDefs::NetworkAdapterCount);
1405
1406 }
1407 /* Get the default network adapter type for the selected guest OS */
1408 NetworkAdapterType_T nwAdapterVBox = NetworkAdapterType_Am79C970A;
1409 rc = pGuestOSType->COMGETTER(AdapterType)(&nwAdapterVBox);
1410 CheckComRCThrowRC(rc);
1411 list<Utf8Str>::const_iterator nwIt;
1412 /* Iterate through all abstract networks. We support 8 network
1413 * adapters at the maximum, so the first 8 will be added only. */
1414 size_t a = 0;
1415 for (nwIt = vsysThis.llNetworkNames.begin();
1416 nwIt != vsysThis.llNetworkNames.end() && a < SchemaDefs::NetworkAdapterCount;
1417 ++nwIt, ++a)
1418 {
1419 Utf8Str strNetwork = *nwIt; // logical network to connect to
1420 pNewDesc->addEntry(VirtualSystemDescriptionType_NetworkAdapter,
1421 "", // ref
1422 strNetwork, // orig
1423 Utf8StrFmt("%RI32", (uint32_t)nwAdapterVBox), // conf
1424 Utf8StrFmt("network=%s", strNetwork.c_str())); // extra conf
1425 }
1426 }
1427
1428 /* Floppy Drive */
1429 if (vsysThis.fHasFloppyDrive)
1430 pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy, "", "", "");
1431
1432 /* CD Drive */
1433 /* @todo: I can't disable the CDROM. So nothing to do for now */
1434 /*
1435 if (vsysThis.fHasCdromDrive)
1436 pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");*/
1437
1438 /* Hard disk Controller */
1439 uint16_t cIDEused = 0;
1440 uint16_t cSATAused = 0;
1441 uint16_t cSCSIused = 0;
1442 ControllersMap::const_iterator hdcIt;
1443 /* Iterate through all hard disk controllers */
1444 for (hdcIt = vsysThis.mapControllers.begin();
1445 hdcIt != vsysThis.mapControllers.end();
1446 ++hdcIt)
1447 {
1448 const HardDiskController &hdc = hdcIt->second;
1449 Utf8Str strControllerID = Utf8StrFmt("%RI32", (uint32_t)hdc.idController);
1450
1451 switch (hdc.system)
1452 {
1453 case HardDiskController::IDE:
1454 {
1455 /* Check for the constrains */
1456 /* @todo: I'm very confused! Are these bits *one* controller or
1457 is every port/bus declared as an extra controller. */
1458 if (cIDEused < 4)
1459 {
1460 // @todo: figure out the IDE types
1461 /* Use PIIX4 as default */
1462 Utf8Str strType = "PIIX4";
1463 if (!RTStrICmp(hdc.strControllerType.c_str(), "PIIX3"))
1464 strType = "PIIX3";
1465 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE,
1466 strControllerID,
1467 hdc.strControllerType,
1468 strType);
1469 }
1470 else
1471 {
1472 /* Warn only once */
1473 if (cIDEused == 1)
1474 pNewDesc->addWarning(tr("The virtual system claims support for more than one IDE controller, but VirtualBox has support for only one."));
1475
1476 }
1477 ++cIDEused;
1478 break;
1479 }
1480
1481#ifdef VBOX_WITH_AHCI
1482 case HardDiskController::SATA:
1483 {
1484 /* Check for the constrains */
1485 if (cSATAused < 1)
1486 {
1487 // @todo: figure out the SATA types
1488 /* We only support a plain AHCI controller, so use them always */
1489 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA,
1490 strControllerID,
1491 hdc.strControllerType,
1492 "AHCI");
1493 }
1494 else
1495 {
1496 /* Warn only once */
1497 if (cSATAused == 1)
1498 pNewDesc->addWarning(tr("The virtual system claims support for more than one SATA controller, but VirtualBox has support for only one."));
1499
1500 }
1501 ++cSATAused;
1502 break;
1503 }
1504#endif /* VBOX_WITH_AHCI */
1505
1506 case HardDiskController::SCSI:
1507 {
1508 /* Check for the constrains */
1509 if (cSCSIused < 1)
1510 {
1511 // @todo: figure out the SCSI types
1512 Utf8Str hdcController = "LsiLogic";
1513 /* if (!RTStrICmp(hdc.strControllerType.c_str(), "LsiLogic"))
1514 hdcController = "LsiLogic";
1515 else*/
1516 if (!RTStrICmp(hdc.strControllerType.c_str(), "BusLogic"))
1517 hdcController = "BusLogic";
1518 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSCSI,
1519 strControllerID,
1520 hdc.strControllerType,
1521 hdcController);
1522 }
1523 else
1524 {
1525 /* Warn only once */
1526 if (cSCSIused == 1)
1527 pNewDesc->addWarning(tr("The virtual system claims support for more than one SCSI controller, but VirtualBox has support for only one."));
1528
1529 }
1530 ++cSCSIused;
1531 break;
1532 }
1533 default:
1534 {
1535 /* @todo: should we stop? */
1536 }
1537 }
1538 }
1539
1540 /* Hard disks */
1541 if (vsysThis.mapVirtualDisks.size() > 0)
1542 {
1543 VirtualDisksMap::const_iterator itVD;
1544 /* Iterate through all hard disks ()*/
1545 for (itVD = vsysThis.mapVirtualDisks.begin();
1546 itVD != vsysThis.mapVirtualDisks.end();
1547 ++itVD)
1548 {
1549 const VirtualDisk &hd = itVD->second;
1550 /* Get the associated disk image */
1551 const DiskImage &di = m->mapDisks[hd.strDiskId];
1552
1553 // @todo:
1554 // - figure out all possible vmdk formats we also support
1555 // - figure out if there is a url specifier for vhd already
1556 // - we need a url specifier for the vdi format
1557 if ( (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#sparse"))
1558 || (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#compressed"))
1559 )
1560 {
1561 /* If the href is empty use the VM name as filename */
1562 Utf8Str strFilename = di.strHref;
1563 if (!strFilename.length())
1564 strFilename = Utf8StrFmt("%s.vmdk", nameVBox.c_str());
1565 /* Construct a unique target path */
1566 Utf8StrFmt strPath("%ls%c%s",
1567 bstrDefaultHardDiskLocation.raw(),
1568 RTPATH_DELIMITER,
1569 strFilename.c_str());
1570 searchUniqueDiskImageFilePath(strPath);
1571
1572 /* find the description for the hard disk controller
1573 * that has the same ID as hd.idController */
1574 const VirtualSystemDescriptionEntry *pController;
1575 if (!(pController = pNewDesc->findControllerFromID(hd.idController)))
1576 throw setError(E_FAIL,
1577 tr("Internal inconsistency looking up hard disk controller."));
1578
1579 /* controller to attach to, and the bus within that controller */
1580 Utf8StrFmt strExtraConfig("controller=%RI16;channel=%RI16",
1581 pController->ulIndex,
1582 hd.ulAddressOnParent);
1583 pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
1584 hd.strDiskId,
1585 di.strHref,
1586 strPath,
1587 strExtraConfig);
1588 }
1589 else
1590 {
1591 /* @todo: should we stop here? */
1592 pNewDesc->addWarning(tr("The virtual system claims support for the following virtual disk image format which VirtualBox not support: %s"),
1593 di.strFormat.c_str());
1594 }
1595 }
1596 }
1597
1598 m->virtualSystemDescriptions.push_back(pNewDesc);
1599 }
1600 }
1601 catch (HRESULT aRC)
1602 {
1603 /* On error we clear the list & return */
1604 m->virtualSystemDescriptions.clear();
1605 rc = aRC;
1606 }
1607
1608 return rc;
1609}
1610
1611/**
1612 * Public method implementation.
1613 * @param aProgress
1614 * @return
1615 */
1616STDMETHODIMP Appliance::ImportMachines(IProgress **aProgress)
1617{
1618 CheckComArgOutPointerValid(aProgress);
1619
1620 AutoCaller autoCaller(this);
1621 CheckComRCReturnRC(autoCaller.rc());
1622
1623 AutoReadLock(this);
1624
1625 HRESULT rc = S_OK;
1626
1627 ComObjPtr<Progress> progress;
1628 try
1629 {
1630 /* Figure out how many sub operation the import will need */
1631 /* One for the appliance */
1632 int opCount = 1;
1633 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
1634 for (it = m->virtualSystemDescriptions.begin();
1635 it != m->virtualSystemDescriptions.end();
1636 ++it)
1637 {
1638 /* One for every Virtual System */
1639 ++opCount;
1640 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
1641 /* One for every hard disk of the Virtual System */
1642 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
1643 opCount += avsdeHDs.size();
1644 }
1645 Bstr progressDesc = BstrFmt(tr("Import appliance '%ls'"),
1646 m->bstrPath.raw());
1647 /* Create the progress object */
1648 progress.createObject();
1649 rc = progress->init(mVirtualBox, static_cast<IAppliance *>(this),
1650 progressDesc,
1651 FALSE /* aCancelable */,
1652 opCount,
1653 progressDesc);
1654 CheckComRCThrowRC(rc);
1655
1656 /* Initialize our worker task */
1657 std::auto_ptr<Task> task(new Task(this, progress));
1658 //AssertComRCThrowRC (task->autoCaller.rc());
1659
1660 rc = task->startThread();
1661 CheckComRCThrowRC(rc);
1662
1663 task.release();
1664 }
1665 catch (HRESULT aRC)
1666 {
1667 rc = aRC;
1668 }
1669
1670 if (SUCCEEDED(rc))
1671 /* Return progress to the caller */
1672 progress.queryInterfaceTo(aProgress);
1673
1674 return rc;
1675}
1676
1677STDMETHODIMP Appliance::Write(IN_BSTR path)
1678{
1679 HRESULT rc = S_OK;
1680 return rc;
1681}
1682
1683HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
1684{
1685 IMachine *machine = NULL;
1686 char *tmpName = RTStrDup(aName.c_str());
1687 int i = 1;
1688 /* @todo: Maybe too cost-intensive; try to find a lighter way */
1689 while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
1690 {
1691 RTStrFree(tmpName);
1692 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
1693 ++i;
1694 }
1695 aName = tmpName;
1696 RTStrFree(tmpName);
1697
1698 return S_OK;
1699}
1700
1701HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
1702{
1703 IHardDisk *harddisk = NULL;
1704 char *tmpName = RTStrDup(aName.c_str());
1705 int i = 1;
1706 /* Check if the file exists or if a file with this path is registered
1707 * already */
1708 /* @todo: Maybe too cost-intensive; try to find a lighter way */
1709 while (RTPathExists(tmpName) ||
1710 mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
1711 {
1712 RTStrFree(tmpName);
1713 char *tmpDir = RTStrDup(aName.c_str());
1714 RTPathStripFilename(tmpDir);;
1715 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
1716 RTPathStripExt(tmpFile);
1717 const char *tmpExt = RTPathExt(aName.c_str());
1718 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
1719 RTStrFree(tmpFile);
1720 RTStrFree(tmpDir);
1721 ++i;
1722 }
1723 aName = tmpName;
1724 RTStrFree(tmpName);
1725
1726 return S_OK;
1727}
1728
1729struct MyHardDiskAttachment
1730{
1731 Guid uuid;
1732 ComPtr<IMachine> pMachine;
1733 StorageBus_T busType;
1734 int32_t lChannel;
1735 int32_t lDevice;
1736};
1737
1738/**
1739 * Worker thread implementation for ImportMachines().
1740 * @param aThread
1741 * @param pvUser
1742 */
1743/* static */
1744DECLCALLBACK(int) Appliance::taskThread(RTTHREAD aThread, void *pvUser)
1745{
1746 std::auto_ptr<Task> task(static_cast<Task *>(pvUser));
1747 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
1748
1749 Appliance *app = task->that;
1750
1751 LogFlowFuncEnter();
1752 LogFlowFunc(("Appliance %p\n", app));
1753
1754 AutoCaller autoCaller(app);
1755 CheckComRCReturnRC(autoCaller.rc());
1756
1757 AutoWriteLock appLock(app);
1758
1759 HRESULT rc = S_OK;
1760
1761 ComPtr<IVirtualBox> pVirtualBox(app->mVirtualBox);
1762
1763 // rollback for errors:
1764 // 1) a list of images that we created/imported
1765 list<MyHardDiskAttachment> llHardDiskAttachments;
1766 list< ComPtr<IHardDisk> > llHardDisksCreated;
1767 list<Guid> llMachinesRegistered;
1768
1769 ComPtr<ISession> session;
1770 bool fSessionOpen = false;
1771 rc = session.createInprocObject(CLSID_Session);
1772 CheckComRCReturnRC(rc);
1773
1774 list<VirtualSystem>::const_iterator it;
1775 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
1776 /* Iterate through all virtual systems of that appliance */
1777 size_t i = 0;
1778 for (it = app->m->llVirtualSystems.begin(),
1779 it1 = app->m->virtualSystemDescriptions.begin();
1780 it != app->m->llVirtualSystems.end();
1781 ++it, ++it1, ++i)
1782 {
1783 const VirtualSystem &vsysThis = *it;
1784 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it1);
1785
1786 ComPtr<IMachine> pNewMachine;
1787
1788 /* Catch possible errors */
1789 try
1790 {
1791 if (!task->progress.isNull())
1792 task->progress->advanceOperation(BstrFmt(tr("Importing Virtual System %d"), i + 1));
1793
1794 /* How many sub notifications are necessary? */
1795 const float opCountMax = 100.0/5;
1796 uint32_t opCount = 0;
1797
1798 /* Guest OS type */
1799 std::list<VirtualSystemDescriptionEntry*> vsdeOS;
1800 vsdeOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
1801 if (vsdeOS.size() < 1)
1802 throw setError(VBOX_E_FILE_ERROR,
1803 tr("Missing guest OS type"));
1804 const Utf8Str &strOsTypeVBox = vsdeOS.front()->strConfig;
1805
1806 /* Now that we know the base system get our internal defaults based on that. */
1807 ComPtr<IGuestOSType> osType;
1808 rc = pVirtualBox->GetGuestOSType(Bstr(strOsTypeVBox), osType.asOutParam());
1809 if (FAILED(rc)) throw rc;
1810
1811 /* Create the machine */
1812 /* First get the name */
1813 std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
1814 if (vsdeName.size() < 1)
1815 throw setError(VBOX_E_FILE_ERROR,
1816 tr("Missing VM name"));
1817 const Utf8Str &strNameVBox = vsdeName.front()->strConfig;
1818 rc = pVirtualBox->CreateMachine(Bstr(strNameVBox), Bstr(strOsTypeVBox),
1819 Bstr(), Guid(),
1820 pNewMachine.asOutParam());
1821 if (FAILED(rc)) throw rc;
1822
1823 if (!task->progress.isNull())
1824 rc = task->progress->notifyProgress((uint32_t)(opCountMax * opCount++));
1825
1826 /* CPU count (ignored for now) */
1827 // EntriesList vsdeCPU = vsd->findByType (VirtualSystemDescriptionType_CPU);
1828
1829 /* RAM */
1830 std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
1831 ComAssertMsgThrow(vsdeRAM.size() == 1, ("RAM size missing"), E_FAIL);
1832 const Utf8Str &memoryVBox = vsdeRAM.front()->strConfig;
1833 ULONG tt = (ULONG)RTStrToUInt64(memoryVBox.c_str());
1834 rc = pNewMachine->COMSETTER(MemorySize)(tt);
1835 if (FAILED(rc)) throw rc;
1836
1837 /* VRAM */
1838 /* Get the recommended VRAM for this guest OS type */
1839 ULONG vramVBox;
1840 rc = osType->COMGETTER(RecommendedVRAM)(&vramVBox);
1841 if (FAILED(rc)) throw rc;
1842
1843 /* Set the VRAM */
1844 rc = pNewMachine->COMSETTER(VRAMSize)(vramVBox);
1845 if (FAILED(rc)) throw rc;
1846
1847 if (!task->progress.isNull())
1848 task->progress->notifyProgress((uint32_t)(opCountMax * opCount++));
1849
1850 /* Audio Adapter */
1851 std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
1852 /* @todo: we support one audio adapter only */
1853 if (vsdeAudioAdapter.size() > 0)
1854 {
1855 const Utf8Str& audioAdapterVBox = vsdeAudioAdapter.front()->strConfig;
1856 if (RTStrICmp(audioAdapterVBox, "null") != 0)
1857 {
1858 uint32_t audio = RTStrToUInt32(audioAdapterVBox.c_str());
1859 ComPtr<IAudioAdapter> audioAdapter;
1860 rc = pNewMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
1861 if (FAILED(rc)) throw rc;
1862 rc = audioAdapter->COMSETTER(Enabled)(true);
1863 if (FAILED(rc)) throw rc;
1864 rc = audioAdapter->COMSETTER(AudioController)(static_cast<AudioControllerType_T>(audio));
1865 if (FAILED(rc)) throw rc;
1866 }
1867 }
1868
1869#ifdef VBOX_WITH_USB
1870 /* USB Controller */
1871 std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
1872 // USB support is enabled if there's at least one such entry; to disable USB support,
1873 // the type of the USB item would have been changed to "ignore"
1874 bool fUSBEnabled = vsdeUSBController.size() > 0;
1875
1876 ComPtr<IUSBController> usbController;
1877 rc = pNewMachine->COMGETTER(USBController)(usbController.asOutParam());
1878 if (FAILED(rc)) throw rc;
1879 rc = usbController->COMSETTER(Enabled)(fUSBEnabled);
1880 if (FAILED(rc)) throw rc;
1881#endif /* VBOX_WITH_USB */
1882
1883 if (!task->progress.isNull())
1884 task->progress->notifyProgress((uint32_t)(opCountMax * opCount++));
1885
1886 /* Change the network adapters */
1887 std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
1888 if (vsdeNW.size() == 0)
1889 {
1890 /* No network adapters, so we have to disable our default one */
1891 ComPtr<INetworkAdapter> nwVBox;
1892 rc = pNewMachine->GetNetworkAdapter(0, nwVBox.asOutParam());
1893 if (FAILED(rc)) throw rc;
1894 rc = nwVBox->COMSETTER(Enabled)(false);
1895 if (FAILED(rc)) throw rc;
1896 }
1897 else
1898 {
1899 list<VirtualSystemDescriptionEntry*>::const_iterator nwIt;
1900 /* Iterate through all network cards. We support 8 network adapters
1901 * at the maximum. (@todo: warn if there are more!) */
1902 size_t a = 0;
1903 for (nwIt = vsdeNW.begin();
1904 (nwIt != vsdeNW.end() && a < SchemaDefs::NetworkAdapterCount);
1905 ++nwIt, ++a)
1906 {
1907 const Utf8Str &nwTypeVBox = (*nwIt)->strConfig;
1908 uint32_t tt1 = RTStrToUInt32(nwTypeVBox.c_str());
1909 ComPtr<INetworkAdapter> nwVBox;
1910 rc = pNewMachine->GetNetworkAdapter((ULONG)a, nwVBox.asOutParam());
1911 if (FAILED(rc)) throw rc;
1912 /* Enable the network card & set the adapter type */
1913 /* NAT is set as default */
1914 rc = nwVBox->COMSETTER(Enabled)(true);
1915 if (FAILED(rc)) throw rc;
1916 rc = nwVBox->COMSETTER(AdapterType)(static_cast<NetworkAdapterType_T>(tt1));
1917 if (FAILED(rc)) throw rc;
1918 }
1919 }
1920
1921 /* Floppy drive */
1922 std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
1923 // Floppy support is enabled if there's at least one such entry; to disable floppy support,
1924 // the type of the floppy item would have been changed to "ignore"
1925 bool fFloppyEnabled = vsdeFloppy.size() > 0;
1926 ComPtr<IFloppyDrive> floppyDrive;
1927 rc = pNewMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
1928 if (FAILED(rc)) throw rc;
1929 rc = floppyDrive->COMSETTER(Enabled)(fFloppyEnabled);
1930 if (FAILED(rc)) throw rc;
1931
1932 if (!task->progress.isNull())
1933 task->progress->notifyProgress((uint32_t)(opCountMax * opCount++));
1934
1935 /* CDROM drive */
1936 /* @todo: I can't disable the CDROM. So nothing to do for now */
1937 // std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_CDROM);
1938
1939 /* Hard disk controller IDE */
1940 std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
1941 /* @todo: we support one IDE controller only */
1942 if (vsdeHDCIDE.size() > 0)
1943 {
1944 /* Set the appropriate IDE controller in the virtual BIOS of the VM */
1945 ComPtr<IBIOSSettings> biosSettings;
1946 rc = pNewMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam());
1947 if (FAILED(rc)) throw rc;
1948
1949 const char *pcszIDEType = vsdeHDCIDE.front()->strConfig.c_str();
1950 if (!strcmp(pcszIDEType, "PIIX3"))
1951 rc = biosSettings->COMSETTER(IDEControllerType)(IDEControllerType_PIIX3);
1952 else if (!strcmp(pcszIDEType, "PIIX4"))
1953 rc = biosSettings->COMSETTER(IDEControllerType)(IDEControllerType_PIIX4);
1954 else if (!strcmp(pcszIDEType, "ICH6"))
1955 rc = biosSettings->COMSETTER(IDEControllerType)(IDEControllerType_ICH6);
1956 else
1957 throw setError(VBOX_E_FILE_ERROR,
1958 tr("Invalid IDE controller type \"%s\""),
1959 pcszIDEType);
1960 if (FAILED(rc)) throw rc;
1961 }
1962#ifdef VBOX_WITH_AHCI
1963 /* Hard disk controller SATA */
1964 std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
1965 /* @todo: we support one SATA controller only */
1966 if (vsdeHDCSATA.size() > 0)
1967 {
1968 const Utf8Str &hdcVBox = vsdeHDCIDE.front()->strConfig;
1969 if (hdcVBox == "AHCI")
1970 {
1971 /* For now we have just to enable the AHCI controller. */
1972 ComPtr<ISATAController> hdcSATAVBox;
1973 rc = pNewMachine->COMGETTER(SATAController)(hdcSATAVBox.asOutParam());
1974 if (FAILED(rc)) throw rc;
1975 rc = hdcSATAVBox->COMSETTER(Enabled)(true);
1976 if (FAILED(rc)) throw rc;
1977 }
1978 else
1979 {
1980 throw setError(VBOX_E_FILE_ERROR,
1981 tr("Invalid SATA controller type \"%s\""),
1982 hdcVBox.c_str());
1983 }
1984 }
1985#endif /* VBOX_WITH_AHCI */
1986
1987 /* Hard disk controller SCSI */
1988 std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
1989 /* @todo: do we support more than one SCSI controller? */
1990 if (vsdeHDCSCSI.size() > 0)
1991 {
1992 /* @todo: revisit when Main support for SCSI is ready */
1993 }
1994
1995 /* Now its time to register the machine before we add any hard disks */
1996 rc = pVirtualBox->RegisterMachine(pNewMachine);
1997 if (FAILED(rc)) throw rc;
1998
1999 Guid newMachineId;
2000 rc = pNewMachine->COMGETTER(Id)(newMachineId.asOutParam());
2001 if (FAILED(rc)) throw rc;
2002
2003 if (!task->progress.isNull())
2004 task->progress->notifyProgress((uint32_t)(opCountMax * opCount++));
2005
2006 // store new machine for roll-back in case of errors
2007 llMachinesRegistered.push_back(newMachineId);
2008
2009 /* Create the hard disks & connect them to the appropriate controllers. */
2010 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
2011 if (avsdeHDs.size() > 0)
2012 {
2013 /* If in the next block an error occur we have to deregister
2014 the machine, so make an extra try/catch block. */
2015 ComPtr<IHardDisk> srcHdVBox;
2016 bool fSourceHdNeedsClosing = false;
2017
2018 try
2019 {
2020 /* In order to attach hard disks we need to open a session
2021 * for the new machine */
2022 rc = pVirtualBox->OpenSession(session, newMachineId);
2023 if (FAILED(rc)) throw rc;
2024 fSessionOpen = true;
2025
2026 int result;
2027 /* The disk image has to be on the same place as the OVF file. So
2028 * strip the filename out of the full file path. */
2029 Utf8Str strSrcDir = stripFilename(Utf8Str(app->m->bstrPath).raw());
2030
2031 /* Iterate over all given disk images */
2032 list<VirtualSystemDescriptionEntry*>::const_iterator itHD;
2033 for (itHD = avsdeHDs.begin();
2034 itHD != avsdeHDs.end();
2035 ++itHD)
2036 {
2037 VirtualSystemDescriptionEntry *vsdeHD = *itHD;
2038
2039 const char *pcszDstFilePath = vsdeHD->strConfig.c_str();
2040 /* Check if the destination file exists already or the
2041 * destination path is empty. */
2042 if ( !(*pcszDstFilePath)
2043 || RTPathExists(pcszDstFilePath)
2044 )
2045 /* This isn't allowed */
2046 throw setError(VBOX_E_FILE_ERROR,
2047 tr("Destination file '%s' exists",
2048 pcszDstFilePath));
2049
2050 /* Find the disk from the OVF's disk list */
2051 DiskImagesMap::const_iterator itDiskImage = app->m->mapDisks.find(vsdeHD->strRef);
2052 /* vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
2053 in the virtual system's disks map under that ID and also in the global images map. */
2054 VirtualDisksMap::const_iterator itVirtualDisk = vsysThis.mapVirtualDisks.find(vsdeHD->strRef);
2055
2056 if ( itDiskImage == app->m->mapDisks.end()
2057 || itVirtualDisk == vsysThis.mapVirtualDisks.end()
2058 )
2059 throw setError(E_FAIL,
2060 tr("Internal inconsistency looking up disk images."));
2061
2062 const DiskImage &di = itDiskImage->second;
2063 const VirtualDisk &vd = itVirtualDisk->second;
2064
2065 /* Make sure all target directories exists */
2066 rc = VirtualBox::ensureFilePathExists(pcszDstFilePath);
2067 if (FAILED(rc))
2068 throw rc;
2069
2070 ComPtr<IProgress> progress;
2071
2072 ComPtr<IHardDisk> dstHdVBox;
2073 /* If strHref is empty we have to create a new file */
2074 if (di.strHref.c_str()[0] == 0)
2075 {
2076 /* Which format to use? */
2077 Bstr srcFormat = L"VDI";
2078 if ( (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#sparse"))
2079 || (!RTStrICmp(di.strFormat.c_str(), "http://www.vmware.com/specifications/vmdk.html#compressed")))
2080 srcFormat = L"VMDK";
2081 /* Create an empty hard disk */
2082 rc = pVirtualBox->CreateHardDisk(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
2083 if (FAILED(rc)) throw rc;
2084
2085 /* Create a dynamic growing disk image with the given capacity */
2086 ComPtr<IProgress> progress;
2087 rc = dstHdVBox->CreateDynamicStorage(di.iCapacity / _1M, progress.asOutParam());
2088 if (FAILED(rc)) throw rc;
2089
2090 /* Advance to the next operation */
2091 if (!task->progress.isNull())
2092 task->progress->advanceOperation (BstrFmt(tr("Creating virtual disk image '%s'"), pcszDstFilePath));
2093 }
2094 else
2095 {
2096 /* Construct the source file path */
2097 Utf8StrFmt strSrcFilePath("%s%c%s", strSrcDir.c_str(), RTPATH_DELIMITER, di.strHref.c_str());
2098 /* Check if the source file exists */
2099 if (!RTPathExists(strSrcFilePath.c_str()))
2100 /* This isn't allowed */
2101 throw setError(VBOX_E_FILE_ERROR,
2102 tr("Source virtual disk image file '%s' doesn't exist"),
2103 strSrcFilePath.c_str());
2104
2105 /* Clone the disk image (this is necessary cause the id has
2106 * to be recreated for the case the same hard disk is
2107 * attached already from a previous import) */
2108
2109 /* First open the existing disk image */
2110 rc = pVirtualBox->OpenHardDisk(Bstr(strSrcFilePath), srcHdVBox.asOutParam());
2111 if (FAILED(rc)) throw rc;
2112 fSourceHdNeedsClosing = true;
2113
2114 /* We need the format description of the source disk image */
2115 Bstr srcFormat;
2116 rc = srcHdVBox->COMGETTER(Format)(srcFormat.asOutParam());
2117 if (FAILED(rc)) throw rc;
2118 /* Create a new hard disk interface for the destination disk image */
2119 rc = pVirtualBox->CreateHardDisk(srcFormat, Bstr(pcszDstFilePath), dstHdVBox.asOutParam());
2120 if (FAILED(rc)) throw rc;
2121 /* Clone the source disk image */
2122 rc = srcHdVBox->CloneTo(dstHdVBox, progress.asOutParam());
2123 if (FAILED(rc)) throw rc;
2124
2125 /* Advance to the next operation */
2126 if (!task->progress.isNull())
2127 task->progress->advanceOperation (BstrFmt(tr("Importing virtual disk image '%s'"), strSrcFilePath.c_str()));
2128 }
2129
2130 // now loop until the asynchronous operation completes and then
2131 // report its result
2132 BOOL fCompleted;
2133 LONG currentPercent;
2134 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
2135 {
2136 rc = progress->COMGETTER(Percent(&currentPercent));
2137 if (FAILED(rc)) throw rc;
2138 if (!task->progress.isNull())
2139 task->progress->notifyProgress(currentPercent);
2140 if (fCompleted)
2141 break;
2142 /* Make sure the loop is not too tight */
2143 rc = progress->WaitForCompletion(100);
2144 if (FAILED(rc)) throw rc;
2145 }
2146 // report result of asynchronous operation
2147 HRESULT vrc;
2148 rc = progress->COMGETTER(ResultCode)(&vrc);
2149 if (FAILED(rc)) throw rc;
2150
2151 // if the thread of the progress object has an error, then
2152 // retrieve the error info from there, or it'll be lost
2153 if (FAILED(vrc))
2154 {
2155 com::ErrorInfo info(progress);
2156 const char *pcsz = Utf8Str(info.getText()).c_str();
2157 HRESULT rc2 = setError(vrc,
2158 pcsz);
2159 throw rc2;
2160 }
2161
2162 if (fSourceHdNeedsClosing)
2163 {
2164 rc = srcHdVBox->Close();
2165 if (FAILED(rc)) throw rc;
2166 fSourceHdNeedsClosing = false;
2167 }
2168
2169 llHardDisksCreated.push_back(dstHdVBox);
2170
2171 /* Now use the new uuid to attach the disk image to our new machine */
2172 ComPtr<IMachine> sMachine;
2173 rc = session->COMGETTER(Machine)(sMachine.asOutParam());
2174 if (FAILED(rc)) throw rc;
2175 Guid hdId;
2176 rc = dstHdVBox->COMGETTER(Id)(hdId.asOutParam());
2177 if (FAILED(rc)) throw rc;
2178
2179 /* For now we assume we have one controller of every type only */
2180 HardDiskController hdc = (*vsysThis.mapControllers.find(vd.idController)).second;
2181
2182 // this is for rollback later
2183 MyHardDiskAttachment mhda;
2184 mhda.uuid = newMachineId;
2185 mhda.pMachine = pNewMachine;
2186 mhda.busType = StorageBus_IDE;
2187
2188 switch (hdc.system)
2189 {
2190 case HardDiskController::IDE:
2191 // For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
2192 // or secondary IDE controller, respectively. For the primary controller of the IDE bus,
2193 // the device number can be either 0 or 1, to specify the master or the slave device,
2194 // respectively. For the secondary IDE controller, the device number is always 1 because
2195 // the master device is reserved for the CD-ROM drive.
2196 switch (vd.ulAddressOnParent)
2197 {
2198 case 0: // interpret this as primary master
2199 mhda.lChannel = (long)0;
2200 mhda.lDevice = (long)0;
2201 break;
2202
2203 case 1: // interpret this as primary slave
2204 mhda.lChannel = (long)0;
2205 mhda.lDevice = (long)1;
2206 break;
2207
2208 case 2: // interpret this as secondary slave
2209 mhda.lChannel = (long)1;
2210 mhda.lDevice = (long)1;
2211 break;
2212
2213 default:
2214 throw setError(VERR_NOT_IMPLEMENTED,
2215 tr("Invalid channel %RI16 specified; IDE conrollers support only 0, 1 or 2"), vd.ulAddressOnParent);
2216 break;
2217 }
2218 break;
2219
2220 case HardDiskController::SATA:
2221 mhda.busType = StorageBus_SATA;
2222 mhda.lChannel = (long)vd.ulAddressOnParent;
2223 mhda.lDevice = (long)0;
2224 break;
2225
2226 case HardDiskController::SCSI:
2227// mhda.busType = StorageBus_SCSI;
2228 throw setError(VERR_NOT_IMPLEMENTED,
2229 tr("SCSI controller support is not available yet in VirtualBox"));
2230 // @ŧodo
2231 break;
2232
2233 default: break;
2234 }
2235
2236 Log(("Attaching disk %s to channel %d on device %d\n", pcszDstFilePath, mhda.lChannel, mhda.lDevice));
2237
2238 rc = sMachine->AttachHardDisk(hdId,
2239 mhda.busType,
2240 mhda.lChannel,
2241 mhda.lDevice);
2242 if (FAILED(rc)) throw rc;
2243
2244 llHardDiskAttachments.push_back(mhda);
2245
2246 rc = sMachine->SaveSettings();
2247 if (FAILED(rc)) throw rc;
2248 } // end for (itHD = avsdeHDs.begin();
2249
2250 // only now that we're done with all disks, close the session
2251 rc = session->Close();
2252 if (FAILED(rc)) throw rc;
2253 fSessionOpen = false;
2254 }
2255 catch(HRESULT aRC)
2256 {
2257 if (fSourceHdNeedsClosing)
2258 srcHdVBox->Close();
2259
2260 if (fSessionOpen)
2261 session->Close();
2262
2263 throw;
2264 }
2265 }
2266 }
2267 catch(HRESULT aRC)
2268 {
2269 rc = aRC;
2270 }
2271
2272 if (FAILED(rc))
2273 break;
2274
2275 } // for (it = app->m->llVirtualSystems.begin(),
2276
2277 if (FAILED(rc))
2278 {
2279 // with _whatever_ error we've had, do a complete roll-back of
2280 // machines and disks we've created; unfortunately this is
2281 // not so trivially done...
2282
2283 HRESULT rc2;
2284 // detach all hard disks from all machines we created
2285 list<MyHardDiskAttachment>::iterator itM;
2286 for (itM = llHardDiskAttachments.begin();
2287 itM != llHardDiskAttachments.end();
2288 ++itM)
2289 {
2290 const MyHardDiskAttachment &mhda = *itM;
2291 rc2 = pVirtualBox->OpenSession(session, mhda.uuid);
2292 if (SUCCEEDED(rc2))
2293 {
2294 ComPtr<IMachine> sMachine;
2295 rc2 = session->COMGETTER(Machine)(sMachine.asOutParam());
2296 if (SUCCEEDED(rc2))
2297 {
2298 rc2 = sMachine->DetachHardDisk(mhda.busType, mhda.lChannel, mhda.lDevice);
2299 rc2 = sMachine->SaveSettings();
2300 }
2301 session->Close();
2302 }
2303 }
2304
2305 // now clean up all hard disks we created
2306 list< ComPtr<IHardDisk> >::iterator itHD;
2307 for (itHD = llHardDisksCreated.begin();
2308 itHD != llHardDisksCreated.end();
2309 ++itHD)
2310 {
2311 ComPtr<IHardDisk> pDisk = *itHD;
2312 ComPtr<IProgress> pProgress;
2313 rc2 = pDisk->DeleteStorage(pProgress.asOutParam());
2314 rc2 = pProgress->WaitForCompletion(-1);
2315 }
2316
2317 // finally, deregister and remove all machines
2318 list<Guid>::iterator itID;
2319 for (itID = llMachinesRegistered.begin();
2320 itID != llMachinesRegistered.end();
2321 ++itID)
2322 {
2323 const Guid &guid = *itID;
2324 ComPtr<IMachine> failedMachine;
2325 rc2 = pVirtualBox->UnregisterMachine(guid, failedMachine.asOutParam());
2326 if (SUCCEEDED(rc2))
2327 rc2 = failedMachine->DeleteSettings();
2328 }
2329 }
2330
2331 task->rc = rc;
2332
2333 if (!task->progress.isNull())
2334 task->progress->notifyComplete(rc);
2335
2336 LogFlowFunc(("rc=%Rhrc\n", rc));
2337 LogFlowFuncLeave();
2338
2339 return VINF_SUCCESS;
2340}
2341
2342////////////////////////////////////////////////////////////////////////////////
2343//
2344// IVirtualSystemDescription constructor / destructor
2345//
2346////////////////////////////////////////////////////////////////////////////////
2347
2348DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
2349struct shutup3 {};
2350
2351struct VirtualSystemDescription::Data
2352{
2353 list<VirtualSystemDescriptionEntry> descriptions;
2354 list<Utf8Str> warnings;
2355};
2356
2357/**
2358 * COM initializer.
2359 * @return
2360 */
2361HRESULT VirtualSystemDescription::init()
2362{
2363 /* Enclose the state transition NotReady->InInit->Ready */
2364 AutoInitSpan autoInitSpan(this);
2365 AssertReturn(autoInitSpan.isOk(), E_FAIL);
2366
2367 /* Initialize data */
2368 m = new Data();
2369
2370 /* Confirm a successful initialization */
2371 autoInitSpan.setSucceeded();
2372 return S_OK;
2373}
2374
2375/**
2376* COM uninitializer.
2377*/
2378
2379void VirtualSystemDescription::uninit()
2380{
2381 delete m;
2382 m = NULL;
2383}
2384
2385////////////////////////////////////////////////////////////////////////////////
2386//
2387// IVirtualSystemDescription public methods
2388//
2389////////////////////////////////////////////////////////////////////////////////
2390
2391/**
2392 * Public method implementation.
2393 * @param
2394 * @return
2395 */
2396STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
2397{
2398 if (!aCount)
2399 return E_POINTER;
2400
2401 AutoCaller autoCaller(this);
2402 CheckComRCReturnRC(autoCaller.rc());
2403
2404 AutoReadLock alock(this);
2405
2406 *aCount = (ULONG)m->descriptions.size();
2407
2408 return S_OK;
2409}
2410
2411/**
2412 * Public method implementation.
2413 * @return
2414 */
2415STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
2416 ComSafeArrayOut(BSTR, aRefs),
2417 ComSafeArrayOut(BSTR, aOrigValues),
2418 ComSafeArrayOut(BSTR, aConfigValues),
2419 ComSafeArrayOut(BSTR, aExtraConfigValues))
2420{
2421 if (ComSafeArrayOutIsNull(aTypes) ||
2422 ComSafeArrayOutIsNull(aRefs) ||
2423 ComSafeArrayOutIsNull(aOrigValues) ||
2424 ComSafeArrayOutIsNull(aConfigValues) ||
2425 ComSafeArrayOutIsNull(aExtraConfigValues))
2426 return E_POINTER;
2427
2428 AutoCaller autoCaller(this);
2429 CheckComRCReturnRC(autoCaller.rc());
2430
2431 AutoReadLock alock(this);
2432
2433 ULONG c = (ULONG)m->descriptions.size();
2434 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
2435 com::SafeArray<BSTR> sfaRefs(c);
2436 com::SafeArray<BSTR> sfaOrigValues(c);
2437 com::SafeArray<BSTR> sfaConfigValues(c);
2438 com::SafeArray<BSTR> sfaExtraConfigValues(c);
2439
2440 list<VirtualSystemDescriptionEntry>::const_iterator it;
2441 size_t i = 0;
2442 for (it = m->descriptions.begin();
2443 it != m->descriptions.end();
2444 ++it, ++i)
2445 {
2446 const VirtualSystemDescriptionEntry &vsde = (*it);
2447
2448 sfaTypes[i] = vsde.type;
2449
2450 Bstr bstr = vsde.strRef;
2451 bstr.cloneTo(&sfaRefs[i]);
2452
2453 bstr = vsde.strOrig;
2454 bstr.cloneTo(&sfaOrigValues[i]);
2455
2456 bstr = vsde.strConfig;
2457 bstr.cloneTo(&sfaConfigValues[i]);
2458
2459 bstr = vsde.strExtraConfig;
2460 bstr.cloneTo(&sfaExtraConfigValues[i]);
2461 }
2462
2463 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
2464 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
2465 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
2466 sfaConfigValues.detachTo(ComSafeArrayOutArg(aConfigValues));
2467 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
2468
2469 return S_OK;
2470}
2471
2472/**
2473 * Public method implementation.
2474 * @return
2475 */
2476STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
2477 ComSafeArrayIn(IN_BSTR, argConfigValues),
2478 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
2479{
2480 CheckComArgSafeArrayNotNull(argConfigValues);
2481 CheckComArgSafeArrayNotNull(argExtraConfigValues);
2482
2483 AutoCaller autoCaller(this);
2484 CheckComRCReturnRC(autoCaller.rc());
2485
2486 AutoWriteLock alock(this);
2487
2488 com::SafeArray<IN_BSTR> aConfigValues(ComSafeArrayInArg(argConfigValues));
2489 com::SafeArray<IN_BSTR> aExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
2490
2491 if ( (aConfigValues.size() != m->descriptions.size())
2492 || (aExtraConfigValues.size() != m->descriptions.size())
2493 )
2494 return E_INVALIDARG;
2495
2496 list<VirtualSystemDescriptionEntry>::iterator it;
2497 size_t i = 0;
2498 for (it = m->descriptions.begin();
2499 it != m->descriptions.end();
2500 ++it, ++i)
2501 {
2502 VirtualSystemDescriptionEntry& vsde = *it;
2503
2504 if (aEnabled[i])
2505 {
2506 vsde.strConfig = aConfigValues[i];
2507 vsde.strExtraConfig = aExtraConfigValues[i];
2508 }
2509 else
2510 vsde.type = VirtualSystemDescriptionType_Ignore;
2511 }
2512
2513 return S_OK;
2514}
2515
2516/**
2517* Public method implementation.
2518 * @return
2519 */
2520STDMETHODIMP VirtualSystemDescription::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
2521{
2522 if (ComSafeArrayOutIsNull(aWarnings))
2523 return E_POINTER;
2524
2525 AutoCaller autoCaller(this);
2526 CheckComRCReturnRC(autoCaller.rc());
2527
2528 AutoReadLock alock(this);
2529
2530 com::SafeArray<BSTR> sfaWarnings(m->warnings.size());
2531
2532 list<Utf8Str>::const_iterator it;
2533 size_t i = 0;
2534 for (it = m->warnings.begin();
2535 it != m->warnings.end();
2536 ++it, ++i)
2537 {
2538 Bstr bstr = *it;
2539 bstr.cloneTo(&sfaWarnings[i]);
2540 }
2541
2542 sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
2543
2544 return S_OK;
2545}
2546
2547/**
2548 * Internal method; adds a new description item to the member list.
2549 * @param aType Type of description for the new item.
2550 * @param strRef Reference item; only used with hard disk controllers.
2551 * @param aOrigValue Corresponding original value from OVF.
2552 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
2553 * @param strExtraConfig Extra configuration; meaning dependent on type.
2554 */
2555void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
2556 const Utf8Str &strRef,
2557 const Utf8Str &aOrigValue,
2558 const Utf8Str &aAutoValue,
2559 const Utf8Str &strExtraConfig /*= ""*/)
2560{
2561 VirtualSystemDescriptionEntry vsde;
2562 vsde.ulIndex = m->descriptions.size(); // each entry gets an index so the client side can reference them
2563 vsde.type = aType;
2564 vsde.strRef = strRef;
2565 vsde.strOrig = aOrigValue;
2566 vsde.strConfig = aAutoValue;
2567 vsde.strExtraConfig = strExtraConfig;
2568
2569 m->descriptions.push_back(vsde);
2570}
2571
2572void VirtualSystemDescription::addWarning(const char* aWarning, ...)
2573{
2574 va_list args;
2575 va_start(args, aWarning);
2576 Utf8StrFmtVA str(aWarning, args);
2577 va_end(args);
2578 m->warnings.push_back(str);
2579}
2580
2581/**
2582 * Private method; returns a list of description items containing all the items from the member
2583 * description items of this virtual system that match the given type.
2584 * @param aType
2585 * @return
2586 */
2587std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
2588{
2589 std::list<VirtualSystemDescriptionEntry*> vsd;
2590
2591 list<VirtualSystemDescriptionEntry>::iterator it;
2592 for (it = m->descriptions.begin();
2593 it != m->descriptions.end();
2594 ++it)
2595 {
2596 if (it->type == aType)
2597 vsd.push_back(&(*it));
2598 }
2599
2600 return vsd;
2601}
2602
2603/**
2604 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
2605 * the given reference ID. Useful when needing the controller for a particular
2606 * virtual disk.
2607 * @param id
2608 * @return
2609 */
2610const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
2611{
2612 Utf8Str strRef = Utf8StrFmt("%RI32", id);
2613 list<VirtualSystemDescriptionEntry>::const_iterator it;
2614 for (it = m->descriptions.begin();
2615 it != m->descriptions.end();
2616 ++it)
2617 {
2618 switch (it->type)
2619 {
2620 case VirtualSystemDescriptionType_HardDiskControllerIDE:
2621 case VirtualSystemDescriptionType_HardDiskControllerSATA:
2622 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
2623 if (it->strRef == strRef)
2624 return &(*it);
2625 break;
2626 }
2627 }
2628
2629 return NULL;
2630}
2631
2632////////////////////////////////////////////////////////////////////////////////
2633//
2634// IMachine public methods
2635//
2636////////////////////////////////////////////////////////////////////////////////
2637
2638// This code is here so we won't have to include the appliance headers in the
2639// IMachine implementation, and we also need to access private appliance data.
2640
2641/**
2642* Public method implementation.
2643* @param appliance
2644* @return
2645*/
2646
2647STDMETHODIMP Machine::Export(IAppliance *appliance)
2648{
2649 HRESULT rc = S_OK;
2650
2651 if (!appliance)
2652 return E_POINTER;
2653
2654 AutoCaller autoCaller(this);
2655 CheckComRCReturnRC(autoCaller.rc());
2656
2657 AutoReadLock alock(this);
2658
2659 ComObjPtr<VirtualSystemDescription> pNewDesc;
2660
2661 try
2662 {
2663 Bstr bstrName;
2664 Bstr bstrDescription;
2665 Bstr bstrGuestOSType;
2666 uint32_t cCPUs;
2667 uint32_t ulMemSizeMB;
2668 BOOL fDVDEnabled;
2669 BOOL fFloppyEnabled;
2670 ComPtr<IUSBController> pUsbController;
2671 ComPtr<IAudioAdapter> pAudioAdapter;
2672
2673 // get name
2674 bstrName = mUserData->mName;
2675 // get description
2676 bstrName = mUserData->mDescription;
2677 // get guest OS
2678 bstrGuestOSType = mUserData->mOSTypeId;
2679 // CPU count
2680 cCPUs = mHWData->mCPUCount;
2681 // memory size in MB
2682 ulMemSizeMB = mHWData->mMemorySize;
2683 // VRAM size?
2684 // BIOS settings?
2685 // 3D acceleration enabled?
2686 // hardware virtualization enabled?
2687 // nested paging enabled?
2688 // HWVirtExVPIDEnabled?
2689 // PAEEnabled?
2690 // snapshotFolder?
2691 // VRDPServer?
2692
2693 // floppy
2694 rc = mFloppyDrive->COMGETTER(Enabled)(&fFloppyEnabled);
2695 if (FAILED(rc)) throw rc;
2696
2697 // CD-ROM ?!?
2698 // ComPtr<IDVDDrive> pDVDDrive;
2699 fDVDEnabled = 1;
2700
2701 // hardDiskAttachments
2702// mHDData->mAttachments @todo
2703
2704 // this is more tricky so use the COM method
2705 rc = COMGETTER(USBController)(pUsbController.asOutParam());
2706 if (FAILED(rc)) throw rc;
2707
2708 pAudioAdapter = mAudioAdapter;
2709
2710 // create a new virtual system
2711 rc = pNewDesc.createObject();
2712 CheckComRCThrowRC(rc);
2713 rc = pNewDesc->init();
2714 CheckComRCThrowRC(rc);
2715
2716 /* Guest OS type */
2717 Utf8Str strOsTypeVBox(bstrGuestOSType),
2718 strCIMOSType = "Linux"; // @todo convert back
2719 pNewDesc->addEntry(VirtualSystemDescriptionType_OS,
2720 "",
2721 strCIMOSType,
2722 strOsTypeVBox);
2723
2724 /* VM name */
2725 Utf8Str strVMName(bstrName);
2726 pNewDesc->addEntry(VirtualSystemDescriptionType_Name,
2727 "",
2728 strVMName,
2729 Utf8Str(bstrName));
2730
2731 /* CPU count*/
2732 Utf8Str strCpuCount = Utf8StrFmt("%RI32", cCPUs);
2733 pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
2734 "",
2735 strCpuCount,
2736 strCpuCount);
2737
2738 /* Memory */
2739 Utf8Str strMemory = Utf8StrFmt("%RI32", (uint64_t)ulMemSizeMB * _1M);
2740 pNewDesc->addEntry(VirtualSystemDescriptionType_CPU,
2741 "",
2742 strMemory,
2743 strMemory);
2744
2745// <const name="HardDiskControllerIDE" value="6" />
2746// <const name="HardDiskControllerSATA" value="7" />
2747// <const name="HardDiskControllerSCSI" value="8" />
2748// <const name="HardDiskImage" value="9" />
2749
2750 /* Floppy Drive */
2751 if (fFloppyEnabled)
2752 pNewDesc->addEntry(VirtualSystemDescriptionType_Floppy, "", "", "");
2753
2754 /* CD Drive */
2755 if (fDVDEnabled)
2756 pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");
2757
2758// <const name="LogicalNetwork" value="12" />
2759
2760// <const name="NetworkAdapter" value="13" />
2761
2762// <const name="USBController" value="14" />
2763
2764// <const name="SoundCard" value="15" />
2765
2766 // finally, add the virtual system to the appliance
2767 Appliance *pAppliance = static_cast<Appliance*>(appliance);
2768 AutoCaller autoCaller(pAppliance);
2769 if (FAILED(rc)) throw rc;
2770
2771 AutoWriteLock alock(pAppliance);
2772
2773 pAppliance->m->virtualSystemDescriptions.push_back(pNewDesc);
2774 }
2775 catch(HRESULT arc)
2776 {
2777 rc = arc;
2778 }
2779
2780 return rc;
2781}
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