VirtualBox

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

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

typo

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