VirtualBox

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

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

OVF: Make the progress object show some progress.

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