VirtualBox

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

Last change on this file since 33451 was 33417, checked in by vboxsync, 14 years ago

FE;Main;OVF: On export name the disks like the ovf + disk + number.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.5 KB
Line 
1/* $Id: ApplianceImpl.cpp 33417 2010-10-25 12:32:50Z vboxsync $ */
2/** @file
3 *
4 * IAppliance and IVirtualSystem COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2008-2010 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 doesnt
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
260////////////////////////////////////////////////////////////////////////////////
261//
262// IVirtualBox public methods
263//
264////////////////////////////////////////////////////////////////////////////////
265
266// This code is here so we won't have to include the appliance headers in the
267// IVirtualBox implementation.
268
269/**
270 * Implementation for IVirtualBox::createAppliance.
271 *
272 * @param anAppliance IAppliance object created if S_OK is returned.
273 * @return S_OK or error.
274 */
275STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
276{
277 HRESULT rc;
278
279 ComObjPtr<Appliance> appliance;
280 appliance.createObject();
281 rc = appliance->init(this);
282
283 if (SUCCEEDED(rc))
284 appliance.queryInterfaceTo(anAppliance);
285
286 return rc;
287}
288
289////////////////////////////////////////////////////////////////////////////////
290//
291// Appliance constructor / destructor
292//
293////////////////////////////////////////////////////////////////////////////////
294
295Appliance::Appliance()
296 : mVirtualBox(NULL)
297{
298}
299
300Appliance::~Appliance()
301{
302}
303
304/**
305 * Appliance COM initializer.
306 * @param
307 * @return
308 */
309HRESULT Appliance::init(VirtualBox *aVirtualBox)
310{
311 /* Enclose the state transition NotReady->InInit->Ready */
312 AutoInitSpan autoInitSpan(this);
313 AssertReturn(autoInitSpan.isOk(), E_FAIL);
314
315 /* Weak reference to a VirtualBox object */
316 unconst(mVirtualBox) = aVirtualBox;
317
318 // initialize data
319 m = new Data;
320
321 /* Confirm a successful initialization */
322 autoInitSpan.setSucceeded();
323
324 return S_OK;
325}
326
327/**
328 * Appliance COM uninitializer.
329 * @return
330 */
331void Appliance::uninit()
332{
333 /* Enclose the state transition Ready->InUninit->NotReady */
334 AutoUninitSpan autoUninitSpan(this);
335 if (autoUninitSpan.uninitDone())
336 return;
337
338 delete m;
339 m = NULL;
340}
341
342////////////////////////////////////////////////////////////////////////////////
343//
344// IAppliance public methods
345//
346////////////////////////////////////////////////////////////////////////////////
347
348/**
349 * Public method implementation.
350 * @param
351 * @return
352 */
353STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
354{
355 if (!aPath)
356 return E_POINTER;
357
358 AutoCaller autoCaller(this);
359 if (FAILED(autoCaller.rc())) return autoCaller.rc();
360
361 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
362
363 if (!isApplianceIdle())
364 return E_ACCESSDENIED;
365
366 Bstr bstrPath(m->locInfo.strPath);
367 bstrPath.cloneTo(aPath);
368
369 return S_OK;
370}
371
372/**
373 * Public method implementation.
374 * @param
375 * @return
376 */
377STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
378{
379 CheckComArgOutSafeArrayPointerValid(aDisks);
380
381 AutoCaller autoCaller(this);
382 if (FAILED(autoCaller.rc())) return autoCaller.rc();
383
384 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
385
386 if (!isApplianceIdle())
387 return E_ACCESSDENIED;
388
389 if (m->pReader) // OVFReader instantiated?
390 {
391 size_t c = m->pReader->m_mapDisks.size();
392 com::SafeArray<BSTR> sfaDisks(c);
393
394 ovf::DiskImagesMap::const_iterator it;
395 size_t i = 0;
396 for (it = m->pReader->m_mapDisks.begin();
397 it != m->pReader->m_mapDisks.end();
398 ++it, ++i)
399 {
400 // create a string representing this disk
401 const ovf::DiskImage &d = it->second;
402 char *psz = NULL;
403 RTStrAPrintf(&psz,
404 "%s\t"
405 "%RI64\t"
406 "%RI64\t"
407 "%s\t"
408 "%s\t"
409 "%RI64\t"
410 "%RI64\t"
411 "%s",
412 d.strDiskId.c_str(),
413 d.iCapacity,
414 d.iPopulatedSize,
415 d.strFormat.c_str(),
416 d.strHref.c_str(),
417 d.iSize,
418 d.iChunkSize,
419 d.strCompression.c_str());
420 Utf8Str utf(psz);
421 Bstr bstr(utf);
422 // push to safearray
423 bstr.cloneTo(&sfaDisks[i]);
424 RTStrFree(psz);
425 }
426
427 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
428 }
429
430 return S_OK;
431}
432
433/**
434 * Public method implementation.
435 * @param
436 * @return
437 */
438STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
439{
440 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
441
442 AutoCaller autoCaller(this);
443 if (FAILED(autoCaller.rc())) return autoCaller.rc();
444
445 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
446
447 if (!isApplianceIdle())
448 return E_ACCESSDENIED;
449
450 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
451 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
452
453 return S_OK;
454}
455
456/**
457 * Public method implementation.
458 * @param aDisks
459 * @return
460 */
461STDMETHODIMP Appliance::COMGETTER(Machines)(ComSafeArrayOut(BSTR, aMachines))
462{
463 CheckComArgOutSafeArrayPointerValid(aMachines);
464
465 AutoCaller autoCaller(this);
466 if (FAILED(autoCaller.rc())) return autoCaller.rc();
467
468 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
469
470 if (!isApplianceIdle())
471 return E_ACCESSDENIED;
472
473 com::SafeArray<BSTR> sfaMachines(m->llGuidsMachinesCreated.size());
474 size_t u = 0;
475 for (std::list<Guid>::const_iterator it = m->llGuidsMachinesCreated.begin();
476 it != m->llGuidsMachinesCreated.end();
477 ++it)
478 {
479 const Guid &uuid = *it;
480 Bstr bstr(uuid.toUtf16());
481 bstr.detachTo(&sfaMachines[u]);
482 ++u;
483 }
484
485 sfaMachines.detachTo(ComSafeArrayOutArg(aMachines));
486
487 return S_OK;
488}
489
490STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
491{
492 CheckComArgOutPointerValid(aExplorer);
493
494 AutoCaller autoCaller(this);
495 if (FAILED(autoCaller.rc())) return autoCaller.rc();
496
497 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
498
499 ComObjPtr<VFSExplorer> explorer;
500 HRESULT rc = S_OK;
501 try
502 {
503 Utf8Str uri(aURI);
504 /* Check which kind of export the user has requested */
505 LocationInfo li;
506 parseURI(uri, li);
507 /* Create the explorer object */
508 explorer.createObject();
509 rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
510 }
511 catch (HRESULT aRC)
512 {
513 rc = aRC;
514 }
515
516 if (SUCCEEDED(rc))
517 /* Return explorer to the caller */
518 explorer.queryInterfaceTo(aExplorer);
519
520 return rc;
521}
522
523/**
524* Public method implementation.
525 * @return
526 */
527STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
528{
529 if (ComSafeArrayOutIsNull(aWarnings))
530 return E_POINTER;
531
532 AutoCaller autoCaller(this);
533 if (FAILED(autoCaller.rc())) return autoCaller.rc();
534
535 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
536
537 com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
538
539 list<Utf8Str>::const_iterator it;
540 size_t i = 0;
541 for (it = m->llWarnings.begin();
542 it != m->llWarnings.end();
543 ++it, ++i)
544 {
545 Bstr bstr = *it;
546 bstr.cloneTo(&sfaWarnings[i]);
547 }
548
549 sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
550
551 return S_OK;
552}
553
554////////////////////////////////////////////////////////////////////////////////
555//
556// Appliance private methods
557//
558////////////////////////////////////////////////////////////////////////////////
559
560/**
561 * Returns true if the appliance is in "idle" state. This should always be the
562 * case unless an import or export is currently in progress. Similar to machine
563 * states, this permits the Appliance implementation code to let go of the
564 * Appliance object lock while a time-consuming disk conversion is in progress
565 * without exposing the appliance to conflicting calls.
566 *
567 * This sets an error on "this" (the appliance) and returns false if the appliance
568 * is busy. The caller should then return E_ACCESSDENIED.
569 *
570 * Must be called from under the object lock!
571 *
572 * @return
573 */
574bool Appliance::isApplianceIdle()
575{
576 if (m->state == Data::ApplianceImporting)
577 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy importing files"));
578 else if (m->state == Data::ApplianceExporting)
579 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy exporting files"));
580 else
581 return true;
582
583 return false;
584}
585
586HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
587{
588 IMachine *machine = NULL;
589 char *tmpName = RTStrDup(aName.c_str());
590 int i = 1;
591 /* @todo: Maybe too cost-intensive; try to find a lighter way */
592 while (mVirtualBox->FindMachine(Bstr(tmpName).raw(), &machine) != VBOX_E_OBJECT_NOT_FOUND)
593 {
594 RTStrFree(tmpName);
595 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
596 ++i;
597 }
598 aName = tmpName;
599 RTStrFree(tmpName);
600
601 return S_OK;
602}
603
604HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
605{
606 IMedium *harddisk = NULL;
607 char *tmpName = RTStrDup(aName.c_str());
608 int i = 1;
609 /* Check if the file exists or if a file with this path is registered
610 * already */
611 /* @todo: Maybe too cost-intensive; try to find a lighter way */
612 while ( RTPathExists(tmpName)
613 || mVirtualBox->FindMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, &harddisk) != VBOX_E_OBJECT_NOT_FOUND
614 )
615 {
616 RTStrFree(tmpName);
617 char *tmpDir = RTStrDup(aName.c_str());
618 RTPathStripFilename(tmpDir);;
619 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
620 RTPathStripExt(tmpFile);
621 const char *tmpExt = RTPathExt(aName.c_str());
622 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
623 RTStrFree(tmpFile);
624 RTStrFree(tmpDir);
625 ++i;
626 }
627 aName = tmpName;
628 RTStrFree(tmpName);
629
630 return S_OK;
631}
632
633/**
634 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
635 * progress object with the proper weights and maximum progress values.
636 *
637 * @param pProgress
638 * @param bstrDescription
639 * @param mode
640 * @return
641 */
642HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress,
643 const Bstr &bstrDescription,
644 SetUpProgressMode mode)
645{
646 HRESULT rc;
647
648 /* Create the progress object */
649 pProgress.createObject();
650
651 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
652 disksWeight();
653
654 m->ulWeightForManifestOperation = 0;
655
656 ULONG cOperations;
657 ULONG ulTotalOperationsWeight;
658
659 cOperations = 1 // one for XML setup
660 + m->cDisks; // plus one per disk
661 if (m->ulTotalDisksMB)
662 {
663 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
664 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
665 }
666 else
667 {
668 // no disks to export:
669 m->ulWeightForXmlOperation = 1;
670 ulTotalOperationsWeight = 1;
671 }
672
673 switch (mode)
674 {
675 case ImportFile:
676 {
677 break;
678 }
679 case WriteFile:
680 {
681 // assume that creating the manifest will take .1% of the time it takes to export the disks
682 if (m->fManifest)
683 {
684 ++cOperations; // another one for creating the manifest
685
686 m->ulWeightForManifestOperation = (ULONG)((double)m->ulTotalDisksMB * .1 / 100); // use .5% of the progress for the manifest
687 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
688 }
689 break;
690 }
691 case ImportS3:
692 {
693 cOperations += 1 + 1; // another one for the manifest file & another one for the import
694 ulTotalOperationsWeight = m->ulTotalDisksMB;
695 if (!m->ulTotalDisksMB)
696 // no disks to export:
697 ulTotalOperationsWeight = 1;
698
699 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
700 ulTotalOperationsWeight += ulImportWeight;
701
702 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
703
704 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
705 ulTotalOperationsWeight += ulInitWeight;
706 break;
707 }
708 case WriteS3:
709 {
710 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
711
712 if (m->ulTotalDisksMB)
713 {
714 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)
715 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
716 }
717 else
718 {
719 // no disks to export:
720 ulTotalOperationsWeight = 1;
721 m->ulWeightForXmlOperation = 1;
722 }
723 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
724 ulTotalOperationsWeight += ulOVFCreationWeight;
725 break;
726 }
727 }
728
729 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
730 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
731
732 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
733 bstrDescription.raw(),
734 TRUE /* aCancelable */,
735 cOperations, // ULONG cOperations,
736 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
737 bstrDescription.raw(), // CBSTR bstrFirstOperationDescription,
738 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
739 return rc;
740}
741
742/**
743 * Called from the import and export background threads to synchronize the second
744 * background disk thread's progress object with the current progress object so
745 * that the user interface sees progress correctly and that cancel signals are
746 * passed on to the second thread.
747 * @param pProgressThis Progress object of the current thread.
748 * @param pProgressAsync Progress object of asynchronous task running in background.
749 */
750void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
751 ComPtr<IProgress> &pProgressAsync)
752{
753 HRESULT rc;
754
755 // now loop until the asynchronous operation completes and then report its result
756 BOOL fCompleted;
757 BOOL fCanceled;
758 ULONG currentPercent;
759 ULONG cOp = 0;
760 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
761 {
762 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
763 if (FAILED(rc)) throw rc;
764 if (fCanceled)
765 pProgressAsync->Cancel();
766 /* Check if the current operation has changed. It is also possible
767 that in the meantime more than one async operation was finished. So
768 we have to loop as long as we reached the same operation count. */
769 ULONG curOp;
770 for(;;)
771 {
772 rc = pProgressAsync->COMGETTER(Operation(&curOp));
773 if (FAILED(rc)) throw rc;
774 if (cOp != curOp)
775 {
776 Bstr bstr;
777 ULONG currentWeight;
778 rc = pProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
779 if (FAILED(rc)) throw rc;
780 rc = pProgressAsync->COMGETTER(OperationWeight(&currentWeight));
781 if (FAILED(rc)) throw rc;
782 rc = pProgressThis->SetNextOperation(bstr.raw(), currentWeight);
783 if (FAILED(rc)) throw rc;
784 ++cOp;
785 }else
786 break;
787 }
788
789 rc = pProgressAsync->COMGETTER(OperationPercent(&currentPercent));
790 if (FAILED(rc)) throw rc;
791 pProgressThis->SetCurrentOperationProgress(currentPercent);
792 if (fCompleted)
793 break;
794
795 /* Make sure the loop is not too tight */
796 rc = pProgressAsync->WaitForCompletion(100);
797 if (FAILED(rc)) throw rc;
798 }
799 // report result of asynchronous operation
800 LONG iRc;
801 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
802 if (FAILED(rc)) throw rc;
803
804
805 // if the thread of the progress object has an error, then
806 // retrieve the error info from there, or it'll be lost
807 if (FAILED(iRc))
808 {
809 ProgressErrorInfo info(pProgressAsync);
810 Utf8Str str(info.getText());
811 const char *pcsz = str.c_str();
812 HRESULT rc2 = setError(iRc, pcsz);
813 throw rc2;
814 }
815}
816
817void Appliance::addWarning(const char* aWarning, ...)
818{
819 va_list args;
820 va_start(args, aWarning);
821 Utf8StrFmtVA str(aWarning, args);
822 va_end(args);
823 m->llWarnings.push_back(str);
824}
825
826/**
827 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
828 * Requires that virtual system descriptions are present.
829 */
830void Appliance::disksWeight()
831{
832 m->ulTotalDisksMB = 0;
833 m->cDisks = 0;
834 // weigh the disk images according to their sizes
835 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
836 for (it = m->virtualSystemDescriptions.begin();
837 it != m->virtualSystemDescriptions.end();
838 ++it)
839 {
840 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
841 /* One for every hard disk of the Virtual System */
842 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
843 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
844 for (itH = avsdeHDs.begin();
845 itH != avsdeHDs.end();
846 ++itH)
847 {
848 const VirtualSystemDescriptionEntry *pHD = *itH;
849 m->ulTotalDisksMB += pHD->ulSizeMB;
850 ++m->cDisks;
851 }
852 }
853
854}
855
856void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
857{
858 /* Buckets are S3 specific. So parse the bucket out of the file path */
859 if (!aPath.startsWith("/"))
860 throw setError(E_INVALIDARG,
861 tr("The path '%s' must start with /"), aPath.c_str());
862 size_t bpos = aPath.find("/", 1);
863 if (bpos != Utf8Str::npos)
864 {
865 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
866 aPath = aPath.substr(bpos); /* The rest of the file path */
867 }
868 /* If there is no bucket name provided reject it */
869 if (aBucket.isEmpty())
870 throw setError(E_INVALIDARG,
871 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
872}
873
874/**
875 *
876 * @return
877 */
878int Appliance::TaskOVF::startThread()
879{
880 int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOrExport, this,
881 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
882 "Appliance::Task");
883
884 if (RT_FAILURE(vrc))
885 return Appliance::setErrorStatic(E_FAIL,
886 Utf8StrFmt("Could not create OVF task thread (%Rrc)\n", vrc));
887
888 return S_OK;
889}
890
891/**
892 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
893 * and Appliance::writeImpl().
894 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
895 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
896 *
897 * @param aThread
898 * @param pvUser
899 */
900/* static */
901DECLCALLBACK(int) Appliance::taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
902{
903 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
904 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
905
906 Appliance *pAppliance = task->pAppliance;
907
908 LogFlowFuncEnter();
909 LogFlowFunc(("Appliance %p\n", pAppliance));
910
911 HRESULT taskrc = S_OK;
912
913 switch (task->taskType)
914 {
915 case TaskOVF::Read:
916 if (task->locInfo.storageType == VFSType_File)
917 taskrc = pAppliance->readFS(task.get());
918 else if (task->locInfo.storageType == VFSType_S3)
919 taskrc = pAppliance->readS3(task.get());
920 break;
921
922 case TaskOVF::Import:
923 if (task->locInfo.storageType == VFSType_File)
924 taskrc = pAppliance->importFS(task.get());
925 else if (task->locInfo.storageType == VFSType_S3)
926 taskrc = pAppliance->importS3(task.get());
927 break;
928
929 case TaskOVF::Write:
930 if (task->locInfo.storageType == VFSType_File)
931 taskrc = pAppliance->writeFS(task.get());
932 else if (task->locInfo.storageType == VFSType_S3)
933 taskrc = pAppliance->writeS3(task.get());
934 break;
935 }
936
937 task->rc = taskrc;
938
939 if (!task->pProgress.isNull())
940 task->pProgress->notifyComplete(taskrc);
941
942 LogFlowFuncLeave();
943
944 return VINF_SUCCESS;
945}
946
947/* static */
948int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
949{
950 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
951
952 if ( pTask
953 && !pTask->pProgress.isNull())
954 {
955 BOOL fCanceled;
956 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
957 if (fCanceled)
958 return -1;
959 pTask->pProgress->SetCurrentOperationProgress(uPercent);
960 }
961 return VINF_SUCCESS;
962}
963
964void parseURI(Utf8Str strUri, LocationInfo &locInfo)
965{
966 /* Check the URI for the protocol */
967 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
968 {
969 locInfo.storageType = VFSType_File;
970 strUri = strUri.substr(sizeof("file://") - 1);
971 }
972 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
973 {
974 locInfo.storageType = VFSType_S3;
975 strUri = strUri.substr(sizeof("SunCloud://") - 1);
976 }
977 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
978 {
979 locInfo.storageType = VFSType_S3;
980 strUri = strUri.substr(sizeof("S3://") - 1);
981 }
982 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
983 throw E_NOTIMPL;
984
985 /* Not necessary on a file based URI */
986 if (locInfo.storageType != VFSType_File)
987 {
988 size_t uppos = strUri.find("@"); /* username:password combo */
989 if (uppos != Utf8Str::npos)
990 {
991 locInfo.strUsername = strUri.substr(0, uppos);
992 strUri = strUri.substr(uppos + 1);
993 size_t upos = locInfo.strUsername.find(":");
994 if (upos != Utf8Str::npos)
995 {
996 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
997 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
998 }
999 }
1000 size_t hpos = strUri.find("/"); /* hostname part */
1001 if (hpos != Utf8Str::npos)
1002 {
1003 locInfo.strHostname = strUri.substr(0, hpos);
1004 strUri = strUri.substr(hpos);
1005 }
1006 }
1007
1008 locInfo.strPath = strUri;
1009}
1010
1011////////////////////////////////////////////////////////////////////////////////
1012//
1013// IVirtualSystemDescription constructor / destructor
1014//
1015////////////////////////////////////////////////////////////////////////////////
1016
1017DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1018
1019/**
1020 * COM initializer.
1021 * @return
1022 */
1023HRESULT VirtualSystemDescription::init()
1024{
1025 /* Enclose the state transition NotReady->InInit->Ready */
1026 AutoInitSpan autoInitSpan(this);
1027 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1028
1029 /* Initialize data */
1030 m = new Data();
1031 m->pConfig = NULL;
1032
1033 /* Confirm a successful initialization */
1034 autoInitSpan.setSucceeded();
1035 return S_OK;
1036}
1037
1038/**
1039* COM uninitializer.
1040*/
1041
1042void VirtualSystemDescription::uninit()
1043{
1044 if (m->pConfig)
1045 delete m->pConfig;
1046 delete m;
1047 m = NULL;
1048}
1049
1050////////////////////////////////////////////////////////////////////////////////
1051//
1052// IVirtualSystemDescription public methods
1053//
1054////////////////////////////////////////////////////////////////////////////////
1055
1056/**
1057 * Public method implementation.
1058 * @param
1059 * @return
1060 */
1061STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
1062{
1063 if (!aCount)
1064 return E_POINTER;
1065
1066 AutoCaller autoCaller(this);
1067 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1068
1069 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1070
1071 *aCount = (ULONG)m->llDescriptions.size();
1072
1073 return S_OK;
1074}
1075
1076/**
1077 * Public method implementation.
1078 * @return
1079 */
1080STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1081 ComSafeArrayOut(BSTR, aRefs),
1082 ComSafeArrayOut(BSTR, aOrigValues),
1083 ComSafeArrayOut(BSTR, aVboxValues),
1084 ComSafeArrayOut(BSTR, aExtraConfigValues))
1085{
1086 if (ComSafeArrayOutIsNull(aTypes) ||
1087 ComSafeArrayOutIsNull(aRefs) ||
1088 ComSafeArrayOutIsNull(aOrigValues) ||
1089 ComSafeArrayOutIsNull(aVboxValues) ||
1090 ComSafeArrayOutIsNull(aExtraConfigValues))
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 ULONG c = (ULONG)m->llDescriptions.size();
1099 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1100 com::SafeArray<BSTR> sfaRefs(c);
1101 com::SafeArray<BSTR> sfaOrigValues(c);
1102 com::SafeArray<BSTR> sfaVboxValues(c);
1103 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1104
1105 list<VirtualSystemDescriptionEntry>::const_iterator it;
1106 size_t i = 0;
1107 for (it = m->llDescriptions.begin();
1108 it != m->llDescriptions.end();
1109 ++it, ++i)
1110 {
1111 const VirtualSystemDescriptionEntry &vsde = (*it);
1112
1113 sfaTypes[i] = vsde.type;
1114
1115 Bstr bstr = vsde.strRef;
1116 bstr.cloneTo(&sfaRefs[i]);
1117
1118 bstr = vsde.strOvf;
1119 bstr.cloneTo(&sfaOrigValues[i]);
1120
1121 bstr = vsde.strVboxCurrent;
1122 bstr.cloneTo(&sfaVboxValues[i]);
1123
1124 bstr = vsde.strExtraConfigCurrent;
1125 bstr.cloneTo(&sfaExtraConfigValues[i]);
1126 }
1127
1128 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1129 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1130 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1131 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1132 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1133
1134 return S_OK;
1135}
1136
1137/**
1138 * Public method implementation.
1139 * @return
1140 */
1141STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
1142 ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1143 ComSafeArrayOut(BSTR, aRefs),
1144 ComSafeArrayOut(BSTR, aOrigValues),
1145 ComSafeArrayOut(BSTR, aVboxValues),
1146 ComSafeArrayOut(BSTR, aExtraConfigValues))
1147{
1148 if (ComSafeArrayOutIsNull(aTypes) ||
1149 ComSafeArrayOutIsNull(aRefs) ||
1150 ComSafeArrayOutIsNull(aOrigValues) ||
1151 ComSafeArrayOutIsNull(aVboxValues) ||
1152 ComSafeArrayOutIsNull(aExtraConfigValues))
1153 return E_POINTER;
1154
1155 AutoCaller autoCaller(this);
1156 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1157
1158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1159
1160 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1161 ULONG c = (ULONG)vsd.size();
1162 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1163 com::SafeArray<BSTR> sfaRefs(c);
1164 com::SafeArray<BSTR> sfaOrigValues(c);
1165 com::SafeArray<BSTR> sfaVboxValues(c);
1166 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1167
1168 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1169 size_t i = 0;
1170 for (it = vsd.begin();
1171 it != vsd.end();
1172 ++it, ++i)
1173 {
1174 const VirtualSystemDescriptionEntry *vsde = (*it);
1175
1176 sfaTypes[i] = vsde->type;
1177
1178 Bstr bstr = vsde->strRef;
1179 bstr.cloneTo(&sfaRefs[i]);
1180
1181 bstr = vsde->strOvf;
1182 bstr.cloneTo(&sfaOrigValues[i]);
1183
1184 bstr = vsde->strVboxCurrent;
1185 bstr.cloneTo(&sfaVboxValues[i]);
1186
1187 bstr = vsde->strExtraConfigCurrent;
1188 bstr.cloneTo(&sfaExtraConfigValues[i]);
1189 }
1190
1191 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1192 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1193 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1194 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1195 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1196
1197 return S_OK;
1198}
1199
1200/**
1201 * Public method implementation.
1202 * @return
1203 */
1204STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
1205 VirtualSystemDescriptionValueType_T aWhich,
1206 ComSafeArrayOut(BSTR, aValues))
1207{
1208 if (ComSafeArrayOutIsNull(aValues))
1209 return E_POINTER;
1210
1211 AutoCaller autoCaller(this);
1212 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1213
1214 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1215
1216 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1217 com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
1218
1219 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1220 size_t i = 0;
1221 for (it = vsd.begin();
1222 it != vsd.end();
1223 ++it, ++i)
1224 {
1225 const VirtualSystemDescriptionEntry *vsde = (*it);
1226
1227 Bstr bstr;
1228 switch (aWhich)
1229 {
1230 case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
1231 case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
1232 case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break;
1233 case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break;
1234 }
1235
1236 bstr.cloneTo(&sfaValues[i]);
1237 }
1238
1239 sfaValues.detachTo(ComSafeArrayOutArg(aValues));
1240
1241 return S_OK;
1242}
1243
1244/**
1245 * Public method implementation.
1246 * @return
1247 */
1248STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
1249 ComSafeArrayIn(IN_BSTR, argVboxValues),
1250 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
1251{
1252#ifndef RT_OS_WINDOWS
1253 NOREF(aEnabledSize);
1254#endif /* RT_OS_WINDOWS */
1255
1256 CheckComArgSafeArrayNotNull(aEnabled);
1257 CheckComArgSafeArrayNotNull(argVboxValues);
1258 CheckComArgSafeArrayNotNull(argExtraConfigValues);
1259
1260 AutoCaller autoCaller(this);
1261 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1262
1263 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1264
1265 com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
1266 com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
1267 com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
1268
1269 if ( (sfaEnabled.size() != m->llDescriptions.size())
1270 || (sfaVboxValues.size() != m->llDescriptions.size())
1271 || (sfaExtraConfigValues.size() != m->llDescriptions.size())
1272 )
1273 return E_INVALIDARG;
1274
1275 list<VirtualSystemDescriptionEntry>::iterator it;
1276 size_t i = 0;
1277 for (it = m->llDescriptions.begin();
1278 it != m->llDescriptions.end();
1279 ++it, ++i)
1280 {
1281 VirtualSystemDescriptionEntry& vsde = *it;
1282
1283 if (sfaEnabled[i])
1284 {
1285 vsde.strVboxCurrent = sfaVboxValues[i];
1286 vsde.strExtraConfigCurrent = sfaExtraConfigValues[i];
1287 }
1288 else
1289 vsde.type = VirtualSystemDescriptionType_Ignore;
1290 }
1291
1292 return S_OK;
1293}
1294
1295/**
1296 * Public method implementation.
1297 * @return
1298 */
1299STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
1300 IN_BSTR aVboxValue,
1301 IN_BSTR aExtraConfigValue)
1302{
1303 AutoCaller autoCaller(this);
1304 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1305
1306 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1307
1308 addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
1309
1310 return S_OK;
1311}
1312
1313/**
1314 * Internal method; adds a new description item to the member list.
1315 * @param aType Type of description for the new item.
1316 * @param strRef Reference item; only used with hard disk controllers.
1317 * @param aOrigValue Corresponding original value from OVF.
1318 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1319 * @param ulSizeMB Weight for IProgress
1320 * @param strExtraConfig Extra configuration; meaning dependent on type.
1321 */
1322void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1323 const Utf8Str &strRef,
1324 const Utf8Str &aOvfValue,
1325 const Utf8Str &aVboxValue,
1326 uint32_t ulSizeMB,
1327 const Utf8Str &strExtraConfig /*= ""*/)
1328{
1329 VirtualSystemDescriptionEntry vsde;
1330 vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
1331 vsde.type = aType;
1332 vsde.strRef = strRef;
1333 vsde.strOvf = aOvfValue;
1334 vsde.strVboxSuggested // remember original value
1335 = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues()
1336 = aVboxValue;
1337 vsde.strExtraConfigSuggested
1338 = vsde.strExtraConfigCurrent
1339 = strExtraConfig;
1340 vsde.ulSizeMB = ulSizeMB;
1341
1342 m->llDescriptions.push_back(vsde);
1343}
1344
1345/**
1346 * Private method; returns a list of description items containing all the items from the member
1347 * description items of this virtual system that match the given type.
1348 * @param aType
1349 * @return
1350 */
1351std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1352{
1353 std::list<VirtualSystemDescriptionEntry*> vsd;
1354
1355 list<VirtualSystemDescriptionEntry>::iterator it;
1356 for (it = m->llDescriptions.begin();
1357 it != m->llDescriptions.end();
1358 ++it)
1359 {
1360 if (it->type == aType)
1361 vsd.push_back(&(*it));
1362 }
1363
1364 return vsd;
1365}
1366
1367/**
1368 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1369 * the given reference ID. Useful when needing the controller for a particular
1370 * virtual disk.
1371 * @param id
1372 * @return
1373 */
1374const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
1375{
1376 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1377 list<VirtualSystemDescriptionEntry>::const_iterator it;
1378 for (it = m->llDescriptions.begin();
1379 it != m->llDescriptions.end();
1380 ++it)
1381 {
1382 const VirtualSystemDescriptionEntry &d = *it;
1383 switch (d.type)
1384 {
1385 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1386 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1387 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1388 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1389 if (d.strRef == strRef)
1390 return &d;
1391 break;
1392 }
1393 }
1394
1395 return NULL;
1396}
1397
1398/**
1399 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1400 * contains a <vbox:Machine> element. This method then attempts to parse that and
1401 * create a MachineConfigFile instance from it which is stored in this instance data
1402 * and can then be used to create a machine.
1403 *
1404 * This must only be called once per instance.
1405 *
1406 * This rethrows all XML and logic errors from MachineConfigFile.
1407 *
1408 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1409 * DOM tree.
1410 */
1411void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
1412{
1413 settings::MachineConfigFile *pConfig = NULL;
1414
1415 Assert(m->pConfig == NULL);
1416
1417 try
1418 {
1419 pConfig = new settings::MachineConfigFile(NULL);
1420 pConfig->importMachineXML(elmMachine);
1421
1422 m->pConfig = pConfig;
1423 }
1424 catch (...)
1425 {
1426 if (pConfig)
1427 delete pConfig;
1428 throw;
1429 }
1430}
1431
1432/**
1433 * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
1434 * @return
1435 */
1436const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
1437{
1438 return m->pConfig;
1439}
1440
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