VirtualBox

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

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

OVF: VBoxManage import implementation (to be continued), back-end fixes, documentation updates

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