VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/ApplianceImpl.cpp@ 38636

Last change on this file since 38636 was 37200, checked in by vboxsync, 14 years ago

API+Frontends: Generic network attachment driver support which obsoletes the special case for VDE. Big API cleanup in the same area. Adapt all frontends to these changes (full implementation in VBoxManage, minimum implementation in GUI).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.3 KB
Line 
1/* $Id: ApplianceImpl.cpp 37200 2011-05-24 15:34:06Z vboxsync $ */
2/** @file
3 *
4 * IAppliance and IVirtualSystem COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2008-2011 Oracle Corporation
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
19#include <iprt/path.h>
20#include <iprt/cpp/utils.h>
21
22#include <VBox/com/array.h>
23
24#include "ApplianceImpl.h"
25#include "VFSExplorerImpl.h"
26#include "VirtualBoxImpl.h"
27#include "GuestOSTypeImpl.h"
28#include "ProgressImpl.h"
29#include "MachineImpl.h"
30
31#include "AutoCaller.h"
32#include "Logging.h"
33
34#include "ApplianceImplPrivate.h"
35
36using namespace std;
37
38////////////////////////////////////////////////////////////////////////////////
39//
40// Internal helpers
41//
42////////////////////////////////////////////////////////////////////////////////
43
44static const struct
45{
46 ovf::CIMOSType_T cim;
47 const char *pcszVbox;
48}
49g_osTypes[] =
50{
51 { ovf::CIMOSType_CIMOS_Unknown, SchemaDefs_OSTypeId_Other },
52 { ovf::CIMOSType_CIMOS_OS2, SchemaDefs_OSTypeId_OS2 },
53 { ovf::CIMOSType_CIMOS_OS2, SchemaDefs_OSTypeId_OS2Warp3 },
54 { ovf::CIMOSType_CIMOS_OS2, SchemaDefs_OSTypeId_OS2Warp4 },
55 { ovf::CIMOSType_CIMOS_OS2, SchemaDefs_OSTypeId_OS2Warp45 },
56 { ovf::CIMOSType_CIMOS_MSDOS, SchemaDefs_OSTypeId_DOS },
57 { ovf::CIMOSType_CIMOS_WIN3x, SchemaDefs_OSTypeId_Windows31 },
58 { ovf::CIMOSType_CIMOS_WIN95, SchemaDefs_OSTypeId_Windows95 },
59 { ovf::CIMOSType_CIMOS_WIN98, SchemaDefs_OSTypeId_Windows98 },
60 { ovf::CIMOSType_CIMOS_WINNT, SchemaDefs_OSTypeId_WindowsNT },
61 { ovf::CIMOSType_CIMOS_WINNT, SchemaDefs_OSTypeId_WindowsNT4 },
62 { ovf::CIMOSType_CIMOS_NetWare, SchemaDefs_OSTypeId_Netware },
63 { ovf::CIMOSType_CIMOS_NovellOES, SchemaDefs_OSTypeId_Netware },
64 { ovf::CIMOSType_CIMOS_Solaris, SchemaDefs_OSTypeId_Solaris },
65 { ovf::CIMOSType_CIMOS_SunOS, SchemaDefs_OSTypeId_Solaris },
66 { ovf::CIMOSType_CIMOS_FreeBSD, SchemaDefs_OSTypeId_FreeBSD },
67 { ovf::CIMOSType_CIMOS_NetBSD, SchemaDefs_OSTypeId_NetBSD },
68 { ovf::CIMOSType_CIMOS_QNX, SchemaDefs_OSTypeId_QNX },
69 { ovf::CIMOSType_CIMOS_Windows2000, SchemaDefs_OSTypeId_Windows2000 },
70 { ovf::CIMOSType_CIMOS_WindowsMe, SchemaDefs_OSTypeId_WindowsMe },
71 { ovf::CIMOSType_CIMOS_OpenBSD, SchemaDefs_OSTypeId_OpenBSD },
72 { ovf::CIMOSType_CIMOS_WindowsXP, SchemaDefs_OSTypeId_WindowsXP },
73 { ovf::CIMOSType_CIMOS_WindowsXPEmbedded, SchemaDefs_OSTypeId_WindowsXP },
74 { ovf::CIMOSType_CIMOS_WindowsEmbeddedforPointofService, SchemaDefs_OSTypeId_WindowsXP },
75 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003, SchemaDefs_OSTypeId_Windows2003 },
76 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003_64, SchemaDefs_OSTypeId_Windows2003_64 },
77 { ovf::CIMOSType_CIMOS_WindowsXP_64, SchemaDefs_OSTypeId_WindowsXP_64 },
78 { ovf::CIMOSType_CIMOS_WindowsVista, SchemaDefs_OSTypeId_WindowsVista },
79 { ovf::CIMOSType_CIMOS_WindowsVista_64, SchemaDefs_OSTypeId_WindowsVista_64 },
80 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008, SchemaDefs_OSTypeId_Windows2008 },
81 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008_64, SchemaDefs_OSTypeId_Windows2008_64 },
82 { ovf::CIMOSType_CIMOS_FreeBSD_64, SchemaDefs_OSTypeId_FreeBSD_64 },
83 { ovf::CIMOSType_CIMOS_MACOS, SchemaDefs_OSTypeId_MacOS },
84 { ovf::CIMOSType_CIMOS_MACOS, SchemaDefs_OSTypeId_MacOS_64 }, // there is no CIM 64-bit type for this
85
86 // Linuxes
87 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, SchemaDefs_OSTypeId_RedHat },
88 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, SchemaDefs_OSTypeId_RedHat_64 },
89 { ovf::CIMOSType_CIMOS_Solaris_64, SchemaDefs_OSTypeId_Solaris_64 },
90 { ovf::CIMOSType_CIMOS_SUSE, SchemaDefs_OSTypeId_OpenSUSE },
91 { ovf::CIMOSType_CIMOS_SLES, SchemaDefs_OSTypeId_OpenSUSE },
92 { ovf::CIMOSType_CIMOS_NovellLinuxDesktop, SchemaDefs_OSTypeId_OpenSUSE },
93 { ovf::CIMOSType_CIMOS_SUSE_64, SchemaDefs_OSTypeId_OpenSUSE_64 },
94 { ovf::CIMOSType_CIMOS_SLES_64, SchemaDefs_OSTypeId_OpenSUSE_64 },
95 { ovf::CIMOSType_CIMOS_LINUX, SchemaDefs_OSTypeId_Linux },
96 { ovf::CIMOSType_CIMOS_LINUX, SchemaDefs_OSTypeId_Linux22 },
97 { ovf::CIMOSType_CIMOS_SunJavaDesktopSystem, SchemaDefs_OSTypeId_Linux },
98 { ovf::CIMOSType_CIMOS_TurboLinux, SchemaDefs_OSTypeId_Turbolinux },
99 { ovf::CIMOSType_CIMOS_TurboLinux_64, SchemaDefs_OSTypeId_Turbolinux_64 },
100 { ovf::CIMOSType_CIMOS_Mandriva, SchemaDefs_OSTypeId_Mandriva },
101 { ovf::CIMOSType_CIMOS_Mandriva_64, SchemaDefs_OSTypeId_Mandriva_64 },
102 { ovf::CIMOSType_CIMOS_Ubuntu, SchemaDefs_OSTypeId_Ubuntu },
103 { ovf::CIMOSType_CIMOS_Ubuntu_64, SchemaDefs_OSTypeId_Ubuntu_64 },
104 { ovf::CIMOSType_CIMOS_Debian, SchemaDefs_OSTypeId_Debian },
105 { ovf::CIMOSType_CIMOS_Debian_64, SchemaDefs_OSTypeId_Debian_64 },
106 { ovf::CIMOSType_CIMOS_Linux_2_4_x, SchemaDefs_OSTypeId_Linux24 },
107 { ovf::CIMOSType_CIMOS_Linux_2_4_x_64, SchemaDefs_OSTypeId_Linux24_64 },
108 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_Linux26 },
109 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_Linux26_64 },
110 { ovf::CIMOSType_CIMOS_Linux_64, SchemaDefs_OSTypeId_Linux26_64 },
111
112 // types that we have support for but CIM doesn't
113 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_ArchLinux },
114 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_ArchLinux_64 },
115 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_Fedora },
116 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_Fedora_64 },
117 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_Gentoo },
118 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_Gentoo_64 },
119 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_Xandros },
120 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_Xandros_64 },
121 { ovf::CIMOSType_CIMOS_Solaris, SchemaDefs_OSTypeId_OpenSolaris },
122 { ovf::CIMOSType_CIMOS_Solaris_64, SchemaDefs_OSTypeId_OpenSolaris_64 },
123
124 // types added with CIM 2.25.0 follow:
125 { ovf::CIMOSType_CIMOS_WindowsServer2008R2, SchemaDefs_OSTypeId_Windows2008 }, // duplicate, see above
126// { ovf::CIMOSType_CIMOS_VMwareESXi = 104, // we can't run ESX in a VM
127 { ovf::CIMOSType_CIMOS_Windows7, SchemaDefs_OSTypeId_Windows7 },
128 { ovf::CIMOSType_CIMOS_Windows7, SchemaDefs_OSTypeId_Windows7_64 }, // there is no CIM 64-bit type for this
129 { ovf::CIMOSType_CIMOS_CentOS, SchemaDefs_OSTypeId_RedHat },
130 { ovf::CIMOSType_CIMOS_CentOS_64, SchemaDefs_OSTypeId_RedHat_64 },
131 { ovf::CIMOSType_CIMOS_OracleEnterpriseLinux, SchemaDefs_OSTypeId_Oracle },
132 { ovf::CIMOSType_CIMOS_OracleEnterpriseLinux_64, SchemaDefs_OSTypeId_Oracle_64 },
133 { ovf::CIMOSType_CIMOS_eComStation, SchemaDefs_OSTypeId_OS2eCS }
134
135 // there are no CIM types for these, so these turn to "other" on export:
136 // SchemaDefs_OSTypeId_OpenBSD
137 // SchemaDefs_OSTypeId_OpenBSD_64
138 // SchemaDefs_OSTypeId_NetBSD
139 // SchemaDefs_OSTypeId_NetBSD_64
140
141};
142
143/* Pattern structure for matching the OS type description field */
144struct osTypePattern
145{
146 const char *pcszPattern;
147 const char *pcszVbox;
148};
149
150/* These are the 32-Bit ones. They are sorted by priority. */
151static const osTypePattern g_osTypesPattern[] =
152{
153 {"Windows NT", SchemaDefs_OSTypeId_WindowsNT4},
154 {"Windows XP", SchemaDefs_OSTypeId_WindowsXP},
155 {"Windows 2000", SchemaDefs_OSTypeId_Windows2000},
156 {"Windows 2003", SchemaDefs_OSTypeId_Windows2003},
157 {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista},
158 {"Windows 2008", SchemaDefs_OSTypeId_Windows2008},
159 {"SUSE", SchemaDefs_OSTypeId_OpenSUSE},
160 {"Novell", SchemaDefs_OSTypeId_OpenSUSE},
161 {"Red Hat", SchemaDefs_OSTypeId_RedHat},
162 {"Mandriva", SchemaDefs_OSTypeId_Mandriva},
163 {"Ubuntu", SchemaDefs_OSTypeId_Ubuntu},
164 {"Debian", SchemaDefs_OSTypeId_Debian},
165 {"QNX", SchemaDefs_OSTypeId_QNX},
166 {"Linux 2.4", SchemaDefs_OSTypeId_Linux24},
167 {"Linux 2.6", SchemaDefs_OSTypeId_Linux26},
168 {"Linux", SchemaDefs_OSTypeId_Linux},
169 {"OpenSolaris", SchemaDefs_OSTypeId_OpenSolaris},
170 {"Solaris", SchemaDefs_OSTypeId_OpenSolaris},
171 {"FreeBSD", SchemaDefs_OSTypeId_FreeBSD},
172 {"NetBSD", SchemaDefs_OSTypeId_NetBSD},
173 {"Windows 95", SchemaDefs_OSTypeId_Windows95},
174 {"Windows 98", SchemaDefs_OSTypeId_Windows98},
175 {"Windows Me", SchemaDefs_OSTypeId_WindowsMe},
176 {"Windows 3.", SchemaDefs_OSTypeId_Windows31},
177 {"DOS", SchemaDefs_OSTypeId_DOS},
178 {"OS2", SchemaDefs_OSTypeId_OS2}
179};
180
181/* These are the 64-Bit ones. They are sorted by priority. */
182static const osTypePattern g_osTypesPattern64[] =
183{
184 {"Windows XP", SchemaDefs_OSTypeId_WindowsXP_64},
185 {"Windows 2003", SchemaDefs_OSTypeId_Windows2003_64},
186 {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista_64},
187 {"Windows 2008", SchemaDefs_OSTypeId_Windows2008_64},
188 {"SUSE", SchemaDefs_OSTypeId_OpenSUSE_64},
189 {"Novell", SchemaDefs_OSTypeId_OpenSUSE_64},
190 {"Red Hat", SchemaDefs_OSTypeId_RedHat_64},
191 {"Mandriva", SchemaDefs_OSTypeId_Mandriva_64},
192 {"Ubuntu", SchemaDefs_OSTypeId_Ubuntu_64},
193 {"Debian", SchemaDefs_OSTypeId_Debian_64},
194 {"Linux 2.4", SchemaDefs_OSTypeId_Linux24_64},
195 {"Linux 2.6", SchemaDefs_OSTypeId_Linux26_64},
196 {"Linux", SchemaDefs_OSTypeId_Linux26_64},
197 {"OpenSolaris", SchemaDefs_OSTypeId_OpenSolaris_64},
198 {"Solaris", SchemaDefs_OSTypeId_OpenSolaris_64},
199 {"FreeBSD", SchemaDefs_OSTypeId_FreeBSD_64},
200};
201
202/**
203 * Private helper func that suggests a VirtualBox guest OS type
204 * for the given OVF operating system type.
205 * @param osTypeVBox
206 * @param c
207 * @param cStr
208 */
209void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf8Str &cStr)
210{
211 /* First check if the type is other/other_64 */
212 if (c == ovf::CIMOSType_CIMOS_Other)
213 {
214 for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern); ++i)
215 if (cStr.contains (g_osTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive))
216 {
217 strType = g_osTypesPattern[i].pcszVbox;
218 return;
219 }
220 }
221 else if (c == ovf::CIMOSType_CIMOS_Other_64)
222 {
223 for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern64); ++i)
224 if (cStr.contains (g_osTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive))
225 {
226 strType = g_osTypesPattern64[i].pcszVbox;
227 return;
228 }
229 }
230
231 for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
232 {
233 if (c == g_osTypes[i].cim)
234 {
235 strType = g_osTypes[i].pcszVbox;
236 return;
237 }
238 }
239
240 strType = SchemaDefs_OSTypeId_Other;
241}
242
243/**
244 * Private helper func that suggests a VirtualBox guest OS type
245 * for the given OVF operating system type.
246 * @param osTypeVBox
247 * @param c
248 */
249ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
250{
251 for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
252 {
253 if (!RTStrICmp(pcszVbox, g_osTypes[i].pcszVbox))
254 return g_osTypes[i].cim;
255 }
256
257 return ovf::CIMOSType_CIMOS_Other;
258}
259
260Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type)
261{
262 Utf8Str strType;
263 switch (type)
264 {
265 case NetworkAttachmentType_NAT: strType = "NAT"; break;
266 case NetworkAttachmentType_Bridged: strType = "Bridged"; break;
267 case NetworkAttachmentType_Internal: strType = "Internal"; break;
268 case NetworkAttachmentType_HostOnly: strType = "HostOnly"; break;
269 case NetworkAttachmentType_Generic: strType = "Generic"; break;
270 case NetworkAttachmentType_Null: strType = "Null"; break;
271 }
272 return strType;
273}
274
275////////////////////////////////////////////////////////////////////////////////
276//
277// IVirtualBox public methods
278//
279////////////////////////////////////////////////////////////////////////////////
280
281// This code is here so we won't have to include the appliance headers in the
282// IVirtualBox implementation.
283
284/**
285 * Implementation for IVirtualBox::createAppliance.
286 *
287 * @param anAppliance IAppliance object created if S_OK is returned.
288 * @return S_OK or error.
289 */
290STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
291{
292 HRESULT rc;
293
294 ComObjPtr<Appliance> appliance;
295 appliance.createObject();
296 rc = appliance->init(this);
297
298 if (SUCCEEDED(rc))
299 appliance.queryInterfaceTo(anAppliance);
300
301 return rc;
302}
303
304////////////////////////////////////////////////////////////////////////////////
305//
306// Appliance constructor / destructor
307//
308////////////////////////////////////////////////////////////////////////////////
309
310Appliance::Appliance()
311 : mVirtualBox(NULL)
312{
313}
314
315Appliance::~Appliance()
316{
317}
318
319/**
320 * Appliance COM initializer.
321 * @param
322 * @return
323 */
324HRESULT Appliance::init(VirtualBox *aVirtualBox)
325{
326 /* Enclose the state transition NotReady->InInit->Ready */
327 AutoInitSpan autoInitSpan(this);
328 AssertReturn(autoInitSpan.isOk(), E_FAIL);
329
330 /* Weak reference to a VirtualBox object */
331 unconst(mVirtualBox) = aVirtualBox;
332
333 // initialize data
334 m = new Data;
335
336 /* Confirm a successful initialization */
337 autoInitSpan.setSucceeded();
338
339 return S_OK;
340}
341
342/**
343 * Appliance COM uninitializer.
344 * @return
345 */
346void Appliance::uninit()
347{
348 /* Enclose the state transition Ready->InUninit->NotReady */
349 AutoUninitSpan autoUninitSpan(this);
350 if (autoUninitSpan.uninitDone())
351 return;
352
353 delete m;
354 m = NULL;
355}
356
357////////////////////////////////////////////////////////////////////////////////
358//
359// IAppliance public methods
360//
361////////////////////////////////////////////////////////////////////////////////
362
363/**
364 * Public method implementation.
365 * @param
366 * @return
367 */
368STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
369{
370 if (!aPath)
371 return E_POINTER;
372
373 AutoCaller autoCaller(this);
374 if (FAILED(autoCaller.rc())) return autoCaller.rc();
375
376 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
377
378 if (!isApplianceIdle())
379 return E_ACCESSDENIED;
380
381 Bstr bstrPath(m->locInfo.strPath);
382 bstrPath.cloneTo(aPath);
383
384 return S_OK;
385}
386
387/**
388 * Public method implementation.
389 * @param
390 * @return
391 */
392STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
393{
394 CheckComArgOutSafeArrayPointerValid(aDisks);
395
396 AutoCaller autoCaller(this);
397 if (FAILED(autoCaller.rc())) return autoCaller.rc();
398
399 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
400
401 if (!isApplianceIdle())
402 return E_ACCESSDENIED;
403
404 if (m->pReader) // OVFReader instantiated?
405 {
406 size_t c = m->pReader->m_mapDisks.size();
407 com::SafeArray<BSTR> sfaDisks(c);
408
409 ovf::DiskImagesMap::const_iterator it;
410 size_t i = 0;
411 for (it = m->pReader->m_mapDisks.begin();
412 it != m->pReader->m_mapDisks.end();
413 ++it, ++i)
414 {
415 // create a string representing this disk
416 const ovf::DiskImage &d = it->second;
417 char *psz = NULL;
418 RTStrAPrintf(&psz,
419 "%s\t"
420 "%RI64\t"
421 "%RI64\t"
422 "%s\t"
423 "%s\t"
424 "%RI64\t"
425 "%RI64\t"
426 "%s",
427 d.strDiskId.c_str(),
428 d.iCapacity,
429 d.iPopulatedSize,
430 d.strFormat.c_str(),
431 d.strHref.c_str(),
432 d.iSize,
433 d.iChunkSize,
434 d.strCompression.c_str());
435 Utf8Str utf(psz);
436 Bstr bstr(utf);
437 // push to safearray
438 bstr.cloneTo(&sfaDisks[i]);
439 RTStrFree(psz);
440 }
441
442 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
443 }
444
445 return S_OK;
446}
447
448/**
449 * Public method implementation.
450 * @param
451 * @return
452 */
453STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
454{
455 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
456
457 AutoCaller autoCaller(this);
458 if (FAILED(autoCaller.rc())) return autoCaller.rc();
459
460 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
461
462 if (!isApplianceIdle())
463 return E_ACCESSDENIED;
464
465 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
466 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
467
468 return S_OK;
469}
470
471/**
472 * Public method implementation.
473 * @param aDisks
474 * @return
475 */
476STDMETHODIMP Appliance::COMGETTER(Machines)(ComSafeArrayOut(BSTR, aMachines))
477{
478 CheckComArgOutSafeArrayPointerValid(aMachines);
479
480 AutoCaller autoCaller(this);
481 if (FAILED(autoCaller.rc())) return autoCaller.rc();
482
483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
484
485 if (!isApplianceIdle())
486 return E_ACCESSDENIED;
487
488 com::SafeArray<BSTR> sfaMachines(m->llGuidsMachinesCreated.size());
489 size_t u = 0;
490 for (std::list<Guid>::const_iterator it = m->llGuidsMachinesCreated.begin();
491 it != m->llGuidsMachinesCreated.end();
492 ++it)
493 {
494 const Guid &uuid = *it;
495 Bstr bstr(uuid.toUtf16());
496 bstr.detachTo(&sfaMachines[u]);
497 ++u;
498 }
499
500 sfaMachines.detachTo(ComSafeArrayOutArg(aMachines));
501
502 return S_OK;
503}
504
505STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
506{
507 CheckComArgOutPointerValid(aExplorer);
508
509 AutoCaller autoCaller(this);
510 if (FAILED(autoCaller.rc())) return autoCaller.rc();
511
512 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
513
514 ComObjPtr<VFSExplorer> explorer;
515 HRESULT rc = S_OK;
516 try
517 {
518 Utf8Str uri(aURI);
519 /* Check which kind of export the user has requested */
520 LocationInfo li;
521 parseURI(uri, li);
522 /* Create the explorer object */
523 explorer.createObject();
524 rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
525 }
526 catch (HRESULT aRC)
527 {
528 rc = aRC;
529 }
530
531 if (SUCCEEDED(rc))
532 /* Return explorer to the caller */
533 explorer.queryInterfaceTo(aExplorer);
534
535 return rc;
536}
537
538/**
539* Public method implementation.
540 * @return
541 */
542STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
543{
544 if (ComSafeArrayOutIsNull(aWarnings))
545 return E_POINTER;
546
547 AutoCaller autoCaller(this);
548 if (FAILED(autoCaller.rc())) return autoCaller.rc();
549
550 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
551
552 com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
553
554 list<Utf8Str>::const_iterator it;
555 size_t i = 0;
556 for (it = m->llWarnings.begin();
557 it != m->llWarnings.end();
558 ++it, ++i)
559 {
560 Bstr bstr = *it;
561 bstr.cloneTo(&sfaWarnings[i]);
562 }
563
564 sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
565
566 return S_OK;
567}
568
569////////////////////////////////////////////////////////////////////////////////
570//
571// Appliance private methods
572//
573////////////////////////////////////////////////////////////////////////////////
574
575/**
576 * Returns true if the appliance is in "idle" state. This should always be the
577 * case unless an import or export is currently in progress. Similar to machine
578 * states, this permits the Appliance implementation code to let go of the
579 * Appliance object lock while a time-consuming disk conversion is in progress
580 * without exposing the appliance to conflicting calls.
581 *
582 * This sets an error on "this" (the appliance) and returns false if the appliance
583 * is busy. The caller should then return E_ACCESSDENIED.
584 *
585 * Must be called from under the object lock!
586 *
587 * @return
588 */
589bool Appliance::isApplianceIdle()
590{
591 if (m->state == Data::ApplianceImporting)
592 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy importing files"));
593 else if (m->state == Data::ApplianceExporting)
594 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy exporting files"));
595 else
596 return true;
597
598 return false;
599}
600
601HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
602{
603 IMachine *machine = NULL;
604 char *tmpName = RTStrDup(aName.c_str());
605 int i = 1;
606 /** @todo: Maybe too cost-intensive; try to find a lighter way */
607 while (mVirtualBox->FindMachine(Bstr(tmpName).raw(), &machine) != VBOX_E_OBJECT_NOT_FOUND)
608 {
609 RTStrFree(tmpName);
610 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
611 ++i;
612 }
613 aName = tmpName;
614 RTStrFree(tmpName);
615
616 return S_OK;
617}
618
619HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
620{
621 IMedium *harddisk = NULL;
622 char *tmpName = RTStrDup(aName.c_str());
623 int i = 1;
624 /* Check if the file exists or if a file with this path is registered
625 * already */
626 /** @todo: Maybe too cost-intensive; try to find a lighter way */
627 while ( RTPathExists(tmpName)
628 || mVirtualBox->FindMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, &harddisk) != VBOX_E_OBJECT_NOT_FOUND
629 )
630 {
631 RTStrFree(tmpName);
632 char *tmpDir = RTStrDup(aName.c_str());
633 RTPathStripFilename(tmpDir);;
634 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
635 RTPathStripExt(tmpFile);
636 const char *tmpExt = RTPathExt(aName.c_str());
637 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
638 RTStrFree(tmpFile);
639 RTStrFree(tmpDir);
640 ++i;
641 }
642 aName = tmpName;
643 RTStrFree(tmpName);
644
645 return S_OK;
646}
647
648/**
649 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
650 * progress object with the proper weights and maximum progress values.
651 *
652 * @param pProgress
653 * @param bstrDescription
654 * @param mode
655 * @return
656 */
657HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress,
658 const Bstr &bstrDescription,
659 SetUpProgressMode mode)
660{
661 HRESULT rc;
662
663 /* Create the progress object */
664 pProgress.createObject();
665
666 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
667 disksWeight();
668
669 m->ulWeightForManifestOperation = 0;
670
671 ULONG cOperations;
672 ULONG ulTotalOperationsWeight;
673
674 cOperations = 1 // one for XML setup
675 + m->cDisks; // plus one per disk
676 if (m->ulTotalDisksMB)
677 {
678 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
679 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
680 }
681 else
682 {
683 // no disks to export:
684 m->ulWeightForXmlOperation = 1;
685 ulTotalOperationsWeight = 1;
686 }
687
688 switch (mode)
689 {
690 case ImportFile:
691 {
692 break;
693 }
694 case WriteFile:
695 {
696 // assume that creating the manifest will take .1% of the time it takes to export the disks
697 if (m->fManifest)
698 {
699 ++cOperations; // another one for creating the manifest
700
701 m->ulWeightForManifestOperation = (ULONG)((double)m->ulTotalDisksMB * .1 / 100); // use .5% of the progress for the manifest
702 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
703 }
704 break;
705 }
706 case ImportS3:
707 {
708 cOperations += 1 + 1; // another one for the manifest file & another one for the import
709 ulTotalOperationsWeight = m->ulTotalDisksMB;
710 if (!m->ulTotalDisksMB)
711 // no disks to export:
712 ulTotalOperationsWeight = 1;
713
714 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
715 ulTotalOperationsWeight += ulImportWeight;
716
717 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
718
719 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
720 ulTotalOperationsWeight += ulInitWeight;
721 break;
722 }
723 case WriteS3:
724 {
725 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
726
727 if (m->ulTotalDisksMB)
728 {
729 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for OVF file upload (we didn't know the size at this point)
730 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
731 }
732 else
733 {
734 // no disks to export:
735 ulTotalOperationsWeight = 1;
736 m->ulWeightForXmlOperation = 1;
737 }
738 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
739 ulTotalOperationsWeight += ulOVFCreationWeight;
740 break;
741 }
742 }
743
744 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
745 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
746
747 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
748 bstrDescription.raw(),
749 TRUE /* aCancelable */,
750 cOperations, // ULONG cOperations,
751 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
752 bstrDescription.raw(), // CBSTR bstrFirstOperationDescription,
753 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
754 return rc;
755}
756
757/**
758 * Called from the import and export background threads to synchronize the second
759 * background disk thread's progress object with the current progress object so
760 * that the user interface sees progress correctly and that cancel signals are
761 * passed on to the second thread.
762 * @param pProgressThis Progress object of the current thread.
763 * @param pProgressAsync Progress object of asynchronous task running in background.
764 */
765void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
766 ComPtr<IProgress> &pProgressAsync)
767{
768 HRESULT rc;
769
770 // now loop until the asynchronous operation completes and then report its result
771 BOOL fCompleted;
772 BOOL fCanceled;
773 ULONG currentPercent;
774 ULONG cOp = 0;
775 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
776 {
777 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
778 if (FAILED(rc)) throw rc;
779 if (fCanceled)
780 pProgressAsync->Cancel();
781 /* Check if the current operation has changed. It is also possible
782 that in the meantime more than one async operation was finished. So
783 we have to loop as long as we reached the same operation count. */
784 ULONG curOp;
785 for(;;)
786 {
787 rc = pProgressAsync->COMGETTER(Operation(&curOp));
788 if (FAILED(rc)) throw rc;
789 if (cOp != curOp)
790 {
791 Bstr bstr;
792 ULONG currentWeight;
793 rc = pProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
794 if (FAILED(rc)) throw rc;
795 rc = pProgressAsync->COMGETTER(OperationWeight(&currentWeight));
796 if (FAILED(rc)) throw rc;
797 rc = pProgressThis->SetNextOperation(bstr.raw(), currentWeight);
798 if (FAILED(rc)) throw rc;
799 ++cOp;
800 }else
801 break;
802 }
803
804 rc = pProgressAsync->COMGETTER(OperationPercent(&currentPercent));
805 if (FAILED(rc)) throw rc;
806 pProgressThis->SetCurrentOperationProgress(currentPercent);
807 if (fCompleted)
808 break;
809
810 /* Make sure the loop is not too tight */
811 rc = pProgressAsync->WaitForCompletion(100);
812 if (FAILED(rc)) throw rc;
813 }
814 // report result of asynchronous operation
815 LONG iRc;
816 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
817 if (FAILED(rc)) throw rc;
818
819
820 // if the thread of the progress object has an error, then
821 // retrieve the error info from there, or it'll be lost
822 if (FAILED(iRc))
823 {
824 ProgressErrorInfo info(pProgressAsync);
825 Utf8Str str(info.getText());
826 const char *pcsz = str.c_str();
827 HRESULT rc2 = setError(iRc, pcsz);
828 throw rc2;
829 }
830}
831
832void Appliance::addWarning(const char* aWarning, ...)
833{
834 va_list args;
835 va_start(args, aWarning);
836 Utf8Str str(aWarning, args);
837 va_end(args);
838 m->llWarnings.push_back(str);
839}
840
841/**
842 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
843 * Requires that virtual system descriptions are present.
844 */
845void Appliance::disksWeight()
846{
847 m->ulTotalDisksMB = 0;
848 m->cDisks = 0;
849 // weigh the disk images according to their sizes
850 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
851 for (it = m->virtualSystemDescriptions.begin();
852 it != m->virtualSystemDescriptions.end();
853 ++it)
854 {
855 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
856 /* One for every hard disk of the Virtual System */
857 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
858 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
859 for (itH = avsdeHDs.begin();
860 itH != avsdeHDs.end();
861 ++itH)
862 {
863 const VirtualSystemDescriptionEntry *pHD = *itH;
864 m->ulTotalDisksMB += pHD->ulSizeMB;
865 ++m->cDisks;
866 }
867 }
868
869}
870
871void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
872{
873 /* Buckets are S3 specific. So parse the bucket out of the file path */
874 if (!aPath.startsWith("/"))
875 throw setError(E_INVALIDARG,
876 tr("The path '%s' must start with /"), aPath.c_str());
877 size_t bpos = aPath.find("/", 1);
878 if (bpos != Utf8Str::npos)
879 {
880 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
881 aPath = aPath.substr(bpos); /* The rest of the file path */
882 }
883 /* If there is no bucket name provided reject it */
884 if (aBucket.isEmpty())
885 throw setError(E_INVALIDARG,
886 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
887}
888
889/**
890 *
891 * @return
892 */
893int Appliance::TaskOVF::startThread()
894{
895 int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOrExport, this,
896 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
897 "Appliance::Task");
898
899 if (RT_FAILURE(vrc))
900 return Appliance::setErrorStatic(E_FAIL,
901 Utf8StrFmt("Could not create OVF task thread (%Rrc)\n", vrc));
902
903 return S_OK;
904}
905
906/**
907 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
908 * and Appliance::writeImpl().
909 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
910 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
911 *
912 * @param aThread
913 * @param pvUser
914 */
915/* static */
916DECLCALLBACK(int) Appliance::taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
917{
918 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
919 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
920
921 Appliance *pAppliance = task->pAppliance;
922
923 LogFlowFuncEnter();
924 LogFlowFunc(("Appliance %p\n", pAppliance));
925
926 HRESULT taskrc = S_OK;
927
928 switch (task->taskType)
929 {
930 case TaskOVF::Read:
931 if (task->locInfo.storageType == VFSType_File)
932 taskrc = pAppliance->readFS(task.get());
933 else if (task->locInfo.storageType == VFSType_S3)
934#ifdef VBOX_WITH_S3
935 taskrc = pAppliance->readS3(task.get());
936#else
937 taskrc = VERR_NOT_IMPLEMENTED;
938#endif
939 break;
940
941 case TaskOVF::Import:
942 if (task->locInfo.storageType == VFSType_File)
943 taskrc = pAppliance->importFS(task.get());
944 else if (task->locInfo.storageType == VFSType_S3)
945#ifdef VBOX_WITH_S3
946 taskrc = pAppliance->importS3(task.get());
947#else
948 taskrc = VERR_NOT_IMPLEMENTED;
949#endif
950 break;
951
952 case TaskOVF::Write:
953 if (task->locInfo.storageType == VFSType_File)
954 taskrc = pAppliance->writeFS(task.get());
955 else if (task->locInfo.storageType == VFSType_S3)
956#ifdef VBOX_WITH_S3
957 taskrc = pAppliance->writeS3(task.get());
958#else
959 taskrc = VERR_NOT_IMPLEMENTED;
960#endif
961 break;
962 }
963
964 task->rc = taskrc;
965
966 if (!task->pProgress.isNull())
967 task->pProgress->notifyComplete(taskrc);
968
969 LogFlowFuncLeave();
970
971 return VINF_SUCCESS;
972}
973
974/* static */
975int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
976{
977 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
978
979 if ( pTask
980 && !pTask->pProgress.isNull())
981 {
982 BOOL fCanceled;
983 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
984 if (fCanceled)
985 return -1;
986 pTask->pProgress->SetCurrentOperationProgress(uPercent);
987 }
988 return VINF_SUCCESS;
989}
990
991void parseURI(Utf8Str strUri, LocationInfo &locInfo)
992{
993 /* Check the URI for the protocol */
994 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
995 {
996 locInfo.storageType = VFSType_File;
997 strUri = strUri.substr(sizeof("file://") - 1);
998 }
999 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
1000 {
1001 locInfo.storageType = VFSType_S3;
1002 strUri = strUri.substr(sizeof("SunCloud://") - 1);
1003 }
1004 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
1005 {
1006 locInfo.storageType = VFSType_S3;
1007 strUri = strUri.substr(sizeof("S3://") - 1);
1008 }
1009 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
1010 throw E_NOTIMPL;
1011
1012 /* Not necessary on a file based URI */
1013 if (locInfo.storageType != VFSType_File)
1014 {
1015 size_t uppos = strUri.find("@"); /* username:password combo */
1016 if (uppos != Utf8Str::npos)
1017 {
1018 locInfo.strUsername = strUri.substr(0, uppos);
1019 strUri = strUri.substr(uppos + 1);
1020 size_t upos = locInfo.strUsername.find(":");
1021 if (upos != Utf8Str::npos)
1022 {
1023 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
1024 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
1025 }
1026 }
1027 size_t hpos = strUri.find("/"); /* hostname part */
1028 if (hpos != Utf8Str::npos)
1029 {
1030 locInfo.strHostname = strUri.substr(0, hpos);
1031 strUri = strUri.substr(hpos);
1032 }
1033 }
1034
1035 locInfo.strPath = strUri;
1036}
1037
1038////////////////////////////////////////////////////////////////////////////////
1039//
1040// IVirtualSystemDescription constructor / destructor
1041//
1042////////////////////////////////////////////////////////////////////////////////
1043
1044DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1045
1046/**
1047 * COM initializer.
1048 * @return
1049 */
1050HRESULT VirtualSystemDescription::init()
1051{
1052 /* Enclose the state transition NotReady->InInit->Ready */
1053 AutoInitSpan autoInitSpan(this);
1054 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1055
1056 /* Initialize data */
1057 m = new Data();
1058 m->pConfig = NULL;
1059
1060 /* Confirm a successful initialization */
1061 autoInitSpan.setSucceeded();
1062 return S_OK;
1063}
1064
1065/**
1066* COM uninitializer.
1067*/
1068
1069void VirtualSystemDescription::uninit()
1070{
1071 if (m->pConfig)
1072 delete m->pConfig;
1073 delete m;
1074 m = NULL;
1075}
1076
1077////////////////////////////////////////////////////////////////////////////////
1078//
1079// IVirtualSystemDescription public methods
1080//
1081////////////////////////////////////////////////////////////////////////////////
1082
1083/**
1084 * Public method implementation.
1085 * @param
1086 * @return
1087 */
1088STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
1089{
1090 if (!aCount)
1091 return E_POINTER;
1092
1093 AutoCaller autoCaller(this);
1094 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1095
1096 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1097
1098 *aCount = (ULONG)m->llDescriptions.size();
1099
1100 return S_OK;
1101}
1102
1103/**
1104 * Public method implementation.
1105 * @return
1106 */
1107STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1108 ComSafeArrayOut(BSTR, aRefs),
1109 ComSafeArrayOut(BSTR, aOrigValues),
1110 ComSafeArrayOut(BSTR, aVboxValues),
1111 ComSafeArrayOut(BSTR, aExtraConfigValues))
1112{
1113 if (ComSafeArrayOutIsNull(aTypes) ||
1114 ComSafeArrayOutIsNull(aRefs) ||
1115 ComSafeArrayOutIsNull(aOrigValues) ||
1116 ComSafeArrayOutIsNull(aVboxValues) ||
1117 ComSafeArrayOutIsNull(aExtraConfigValues))
1118 return E_POINTER;
1119
1120 AutoCaller autoCaller(this);
1121 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1122
1123 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1124
1125 ULONG c = (ULONG)m->llDescriptions.size();
1126 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1127 com::SafeArray<BSTR> sfaRefs(c);
1128 com::SafeArray<BSTR> sfaOrigValues(c);
1129 com::SafeArray<BSTR> sfaVboxValues(c);
1130 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1131
1132 list<VirtualSystemDescriptionEntry>::const_iterator it;
1133 size_t i = 0;
1134 for (it = m->llDescriptions.begin();
1135 it != m->llDescriptions.end();
1136 ++it, ++i)
1137 {
1138 const VirtualSystemDescriptionEntry &vsde = (*it);
1139
1140 sfaTypes[i] = vsde.type;
1141
1142 Bstr bstr = vsde.strRef;
1143 bstr.cloneTo(&sfaRefs[i]);
1144
1145 bstr = vsde.strOvf;
1146 bstr.cloneTo(&sfaOrigValues[i]);
1147
1148 bstr = vsde.strVboxCurrent;
1149 bstr.cloneTo(&sfaVboxValues[i]);
1150
1151 bstr = vsde.strExtraConfigCurrent;
1152 bstr.cloneTo(&sfaExtraConfigValues[i]);
1153 }
1154
1155 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1156 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1157 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1158 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1159 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1160
1161 return S_OK;
1162}
1163
1164/**
1165 * Public method implementation.
1166 * @return
1167 */
1168STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
1169 ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1170 ComSafeArrayOut(BSTR, aRefs),
1171 ComSafeArrayOut(BSTR, aOrigValues),
1172 ComSafeArrayOut(BSTR, aVboxValues),
1173 ComSafeArrayOut(BSTR, aExtraConfigValues))
1174{
1175 if (ComSafeArrayOutIsNull(aTypes) ||
1176 ComSafeArrayOutIsNull(aRefs) ||
1177 ComSafeArrayOutIsNull(aOrigValues) ||
1178 ComSafeArrayOutIsNull(aVboxValues) ||
1179 ComSafeArrayOutIsNull(aExtraConfigValues))
1180 return E_POINTER;
1181
1182 AutoCaller autoCaller(this);
1183 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1184
1185 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1186
1187 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1188 ULONG c = (ULONG)vsd.size();
1189 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1190 com::SafeArray<BSTR> sfaRefs(c);
1191 com::SafeArray<BSTR> sfaOrigValues(c);
1192 com::SafeArray<BSTR> sfaVboxValues(c);
1193 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1194
1195 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1196 size_t i = 0;
1197 for (it = vsd.begin();
1198 it != vsd.end();
1199 ++it, ++i)
1200 {
1201 const VirtualSystemDescriptionEntry *vsde = (*it);
1202
1203 sfaTypes[i] = vsde->type;
1204
1205 Bstr bstr = vsde->strRef;
1206 bstr.cloneTo(&sfaRefs[i]);
1207
1208 bstr = vsde->strOvf;
1209 bstr.cloneTo(&sfaOrigValues[i]);
1210
1211 bstr = vsde->strVboxCurrent;
1212 bstr.cloneTo(&sfaVboxValues[i]);
1213
1214 bstr = vsde->strExtraConfigCurrent;
1215 bstr.cloneTo(&sfaExtraConfigValues[i]);
1216 }
1217
1218 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1219 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1220 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1221 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1222 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1223
1224 return S_OK;
1225}
1226
1227/**
1228 * Public method implementation.
1229 * @return
1230 */
1231STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
1232 VirtualSystemDescriptionValueType_T aWhich,
1233 ComSafeArrayOut(BSTR, aValues))
1234{
1235 if (ComSafeArrayOutIsNull(aValues))
1236 return E_POINTER;
1237
1238 AutoCaller autoCaller(this);
1239 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1240
1241 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1242
1243 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1244 com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
1245
1246 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1247 size_t i = 0;
1248 for (it = vsd.begin();
1249 it != vsd.end();
1250 ++it, ++i)
1251 {
1252 const VirtualSystemDescriptionEntry *vsde = (*it);
1253
1254 Bstr bstr;
1255 switch (aWhich)
1256 {
1257 case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
1258 case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
1259 case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break;
1260 case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break;
1261 }
1262
1263 bstr.cloneTo(&sfaValues[i]);
1264 }
1265
1266 sfaValues.detachTo(ComSafeArrayOutArg(aValues));
1267
1268 return S_OK;
1269}
1270
1271/**
1272 * Public method implementation.
1273 * @return
1274 */
1275STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
1276 ComSafeArrayIn(IN_BSTR, argVboxValues),
1277 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
1278{
1279#ifndef RT_OS_WINDOWS
1280 NOREF(aEnabledSize);
1281#endif /* RT_OS_WINDOWS */
1282
1283 CheckComArgSafeArrayNotNull(aEnabled);
1284 CheckComArgSafeArrayNotNull(argVboxValues);
1285 CheckComArgSafeArrayNotNull(argExtraConfigValues);
1286
1287 AutoCaller autoCaller(this);
1288 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1289
1290 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1291
1292 com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
1293 com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
1294 com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
1295
1296 if ( (sfaEnabled.size() != m->llDescriptions.size())
1297 || (sfaVboxValues.size() != m->llDescriptions.size())
1298 || (sfaExtraConfigValues.size() != m->llDescriptions.size())
1299 )
1300 return E_INVALIDARG;
1301
1302 list<VirtualSystemDescriptionEntry>::iterator it;
1303 size_t i = 0;
1304 for (it = m->llDescriptions.begin();
1305 it != m->llDescriptions.end();
1306 ++it, ++i)
1307 {
1308 VirtualSystemDescriptionEntry& vsde = *it;
1309
1310 if (sfaEnabled[i])
1311 {
1312 vsde.strVboxCurrent = sfaVboxValues[i];
1313 vsde.strExtraConfigCurrent = sfaExtraConfigValues[i];
1314 }
1315 else
1316 vsde.type = VirtualSystemDescriptionType_Ignore;
1317 }
1318
1319 return S_OK;
1320}
1321
1322/**
1323 * Public method implementation.
1324 * @return
1325 */
1326STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
1327 IN_BSTR aVboxValue,
1328 IN_BSTR aExtraConfigValue)
1329{
1330 AutoCaller autoCaller(this);
1331 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1332
1333 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1334
1335 addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
1336
1337 return S_OK;
1338}
1339
1340/**
1341 * Internal method; adds a new description item to the member list.
1342 * @param aType Type of description for the new item.
1343 * @param strRef Reference item; only used with hard disk controllers.
1344 * @param aOrigValue Corresponding original value from OVF.
1345 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1346 * @param ulSizeMB Weight for IProgress
1347 * @param strExtraConfig Extra configuration; meaning dependent on type.
1348 */
1349void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1350 const Utf8Str &strRef,
1351 const Utf8Str &aOvfValue,
1352 const Utf8Str &aVboxValue,
1353 uint32_t ulSizeMB,
1354 const Utf8Str &strExtraConfig /*= ""*/)
1355{
1356 VirtualSystemDescriptionEntry vsde;
1357 vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
1358 vsde.type = aType;
1359 vsde.strRef = strRef;
1360 vsde.strOvf = aOvfValue;
1361 vsde.strVboxSuggested // remember original value
1362 = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues()
1363 = aVboxValue;
1364 vsde.strExtraConfigSuggested
1365 = vsde.strExtraConfigCurrent
1366 = strExtraConfig;
1367 vsde.ulSizeMB = ulSizeMB;
1368
1369 m->llDescriptions.push_back(vsde);
1370}
1371
1372/**
1373 * Private method; returns a list of description items containing all the items from the member
1374 * description items of this virtual system that match the given type.
1375 * @param aType
1376 * @return
1377 */
1378std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1379{
1380 std::list<VirtualSystemDescriptionEntry*> vsd;
1381
1382 list<VirtualSystemDescriptionEntry>::iterator it;
1383 for (it = m->llDescriptions.begin();
1384 it != m->llDescriptions.end();
1385 ++it)
1386 {
1387 if (it->type == aType)
1388 vsd.push_back(&(*it));
1389 }
1390
1391 return vsd;
1392}
1393
1394/**
1395 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1396 * the given reference ID. Useful when needing the controller for a particular
1397 * virtual disk.
1398 * @param id
1399 * @return
1400 */
1401const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
1402{
1403 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1404 list<VirtualSystemDescriptionEntry>::const_iterator it;
1405 for (it = m->llDescriptions.begin();
1406 it != m->llDescriptions.end();
1407 ++it)
1408 {
1409 const VirtualSystemDescriptionEntry &d = *it;
1410 switch (d.type)
1411 {
1412 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1413 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1414 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1415 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1416 if (d.strRef == strRef)
1417 return &d;
1418 break;
1419 }
1420 }
1421
1422 return NULL;
1423}
1424
1425/**
1426 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1427 * contains a <vbox:Machine> element. This method then attempts to parse that and
1428 * create a MachineConfigFile instance from it which is stored in this instance data
1429 * and can then be used to create a machine.
1430 *
1431 * This must only be called once per instance.
1432 *
1433 * This rethrows all XML and logic errors from MachineConfigFile.
1434 *
1435 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1436 * DOM tree.
1437 */
1438void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
1439{
1440 settings::MachineConfigFile *pConfig = NULL;
1441
1442 Assert(m->pConfig == NULL);
1443
1444 try
1445 {
1446 pConfig = new settings::MachineConfigFile(NULL);
1447 pConfig->importMachineXML(elmMachine);
1448
1449 m->pConfig = pConfig;
1450 }
1451 catch (...)
1452 {
1453 if (pConfig)
1454 delete pConfig;
1455 throw;
1456 }
1457}
1458
1459/**
1460 * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
1461 * @return
1462 */
1463const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
1464{
1465 return m->pConfig;
1466}
1467
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